lvm2-2.02.98/0000750000175000017500000000000012037016273011510 5ustar blankblanklvm2-2.02.98/README0000640000175000017500000000224412037016272012372 0ustar blankblankThis 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/ The source code is stored in git: http://git.fedorahosted.org/git/lvm2.git git clone git://git.fedorahosted.org/git/lvm2.git Mailing list for general discussion related to LVM2: linux-lvm@redhat.com Subscribe from https://www.redhat.com/mailman/listinfo/linux-lvm Mailing lists for LVM2 development, patches and commits: lvm-devel@redhat.com Subscribe from https://www.redhat.com/mailman/listinfo/linux-lvm lvm2-commits@lists.fedorahosted.org (Read-only archive of commits) Subscribe from https://fedorahosted.org/mailman/listinfo/lvm2-commits Mailing list for device-mapper development, including kernel patches and multipath-tools: dm-devel@redhat.com Subscribe from https://www.redhat.com/mailman/listinfo/dm-devel The source code repository used until 7th June 2012 is accessible here: http://sources.redhat.com/cgi-bin/cvsweb.cgi/LVM2/?cvsroot=lvm2. lvm2-2.02.98/po/0000750000175000017500000000000012037016272012125 5ustar blankblanklvm2-2.02.98/po/lvm2.po0000640000175000017500000051375412037016272013365 0ustar blankblank# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2007-04-27 21:46+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #: activate/activate.c:44 msgid "LVM1 proc global snprintf failed" msgstr "" #: activate/activate.c:63 msgid "module string allocation failed" msgstr "" #: activate/activate.c:74 activate/activate.c:91 activate/activate.c:109 #: activate/activate.c:364 activate/activate.c:417 activate/activate.c:438 #: activate/activate.c:445 activate/activate.c:492 activate/activate.c:495 #: activate/activate.c:514 activate/activate.c:520 activate/activate.c:523 #: activate/activate.c:536 activate/activate.c:548 activate/activate.c:561 #: activate/activate.c:564 activate/activate.c:576 activate/activate.c:579 #: activate/activate.c:591 activate/activate.c:594 activate/activate.c:606 #: activate/activate.c:609 activate/activate.c:764 activate/activate.c:768 #: activate/activate.c:776 activate/activate.c:785 activate/activate.c:791 #: activate/activate.c:836 activate/activate.c:848 activate/activate.c:882 #: activate/activate.c:894 activate/activate.c:953 activate/activate.c:967 #: activate/activate.c:996 activate/dev_manager.c:104 #: activate/dev_manager.c:130 activate/dev_manager.c:139 #: activate/dev_manager.c:142 activate/dev_manager.c:168 #: activate/dev_manager.c:176 activate/dev_manager.c:250 #: activate/dev_manager.c:258 activate/dev_manager.c:261 #: activate/dev_manager.c:339 activate/dev_manager.c:347 #: activate/dev_manager.c:350 activate/dev_manager.c:379 #: activate/dev_manager.c:434 activate/dev_manager.c:439 #: activate/dev_manager.c:452 activate/dev_manager.c:489 #: activate/dev_manager.c:492 activate/dev_manager.c:500 #: activate/dev_manager.c:523 activate/dev_manager.c:535 #: activate/dev_manager.c:611 activate/dev_manager.c:628 #: activate/dev_manager.c:631 activate/dev_manager.c:654 #: activate/dev_manager.c:658 activate/dev_manager.c:661 #: activate/dev_manager.c:664 activate/dev_manager.c:682 #: activate/dev_manager.c:689 activate/dev_manager.c:698 #: activate/dev_manager.c:737 activate/dev_manager.c:757 #: activate/dev_manager.c:760 activate/dev_manager.c:780 #: activate/dev_manager.c:783 activate/dev_manager.c:788 #: activate/dev_manager.c:842 activate/dev_manager.c:851 #: activate/dev_manager.c:854 activate/dev_manager.c:860 #: activate/dev_manager.c:866 activate/dev_manager.c:869 #: activate/dev_manager.c:871 activate/dev_manager.c:877 #: activate/dev_manager.c:891 activate/dev_manager.c:894 #: activate/dev_manager.c:920 activate/dev_manager.c:929 #: activate/dev_manager.c:996 activate/dev_manager.c:1010 #: activate/dev_manager.c:1018 activate/dev_manager.c:1025 #: activate/dev_manager.c:1030 activate/dev_manager.c:1038 #: activate/dev_manager.c:1044 activate/dev_manager.c:1048 #: activate/dev_manager.c:1052 activate/dev_manager.c:1075 #: activate/dev_manager.c:1138 activate/fs.c:179 activate/fs.c:229 #: activate/fs.c:236 activate/fs.c:243 activate/fs.c:246 activate/fs.c:320 #: archiver.c:68 archiver.c:75 archiver.c:87 archiver.c:163 archiver.c:236 #: archiver.c:286 archiver.c:303 archiver.c:345 archiver.c:350 #: cache/lvmcache.c:486 cache/lvmcache.c:490 cache/lvmcache.c:704 #: cache/lvmcache.c:724 cache/lvmcache.c:750 cache/lvmcache.c:810 #: commands/toolcontext.c:276 commands/toolcontext.c:295 #: commands/toolcontext.c:302 commands/toolcontext.c:379 #: commands/toolcontext.c:394 commands/toolcontext.c:418 #: commands/toolcontext.c:469 commands/toolcontext.c:685 #: commands/toolcontext.c:781 config/config.c:148 config/config.c:161 #: config/config.c:176 config/config.c:194 config/config.c:215 #: config/config.c:235 config/config.c:282 config/config.c:285 #: config/config.c:467 config/config.c:485 config/config.c:490 #: config/config.c:500 config/config.c:514 config/config.c:530 #: config/config.c:586 config/config.c:777 datastruct/btree.c:90 #: datastruct/str_list.c:24 datastruct/str_list.c:38 datastruct/str_list.c:47 #: datastruct/str_list.c:77 device/dev-cache.c:240 device/dev-cache.c:253 #: device/dev-cache.c:298 device/dev-cache.c:302 device/dev-cache.c:373 #: device/dev-cache.c:404 device/dev-cache.c:443 device/dev-cache.c:511 #: device/dev-cache.c:547 device/dev-cache.c:552 device/dev-cache.c:567 #: device/dev-io.c:174 device/dev-io.c:204 device/dev-io.c:358 #: device/dev-io.c:556 device/dev-io.c:606 device/dev-io.c:624 #: device/dev-io.c:643 device/dev-io.c:671 device/dev-md.c:41 #: device/dev-md.c:49 device/dev-md.c:66 device/device.c:61 device/device.c:66 #: device/device.c:90 display/display.c:243 display/display.c:274 #: display/display.c:333 display/display.c:379 display/display.c:605 #: display/display.c:641 error/errseg.c:101 filters/filter-composite.c:54 #: filters/filter-persistent.c:46 filters/filter-persistent.c:110 #: filters/filter-persistent.c:114 filters/filter-persistent.c:117 #: filters/filter-persistent.c:197 filters/filter-persistent.c:299 #: filters/filter-persistent.c:305 filters/filter-persistent.c:316 #: filters/filter-regex.c:74 filters/filter-regex.c:101 #: filters/filter-regex.c:119 filters/filter-regex.c:142 #: filters/filter-regex.c:196 filters/filter-regex.c:201 #: filters/filter-regex.c:206 filters/filter-regex.c:209 #: filters/filter-sysfs.c:288 filters/filter.c:278 format1/disk-rep.c:221 #: format1/disk-rep.c:233 format1/disk-rep.c:238 format1/disk-rep.c:257 #: format1/disk-rep.c:260 format1/disk-rep.c:291 format1/disk-rep.c:294 #: format1/disk-rep.c:313 format1/disk-rep.c:316 format1/disk-rep.c:334 #: format1/disk-rep.c:351 format1/disk-rep.c:361 format1/disk-rep.c:421 #: format1/disk-rep.c:428 format1/disk-rep.c:522 format1/disk-rep.c:547 #: format1/disk-rep.c:563 format1/disk-rep.c:591 format1/disk-rep.c:609 #: format1/disk-rep.c:646 format1/disk-rep.c:711 format1/disk-rep.c:718 #: format1/disk-rep.c:734 format1/format1.c:134 format1/format1.c:137 #: format1/format1.c:149 format1/format1.c:154 format1/format1.c:157 #: format1/format1.c:160 format1/format1.c:163 format1/format1.c:166 #: format1/format1.c:171 format1/format1.c:186 format1/format1.c:195 #: format1/format1.c:198 format1/format1.c:213 format1/format1.c:227 #: format1/format1.c:245 format1/format1.c:256 format1/format1.c:271 #: format1/format1.c:297 format1/format1.c:302 format1/format1.c:307 #: format1/format1.c:312 format1/format1.c:348 format1/format1.c:394 #: format1/format1.c:410 format1/format1.c:415 format1/format1.c:421 #: format1/format1.c:431 format1/format1.c:477 format1/format1.c:498 #: format1/format1.c:507 format1/format1.c:551 format1/import-export.c:63 #: format1/import-export.c:118 format1/import-export.c:151 #: format1/import-export.c:168 format1/import-export.c:185 #: format1/import-export.c:193 format1/import-export.c:228 #: format1/import-export.c:233 format1/import-export.c:238 #: format1/import-export.c:316 format1/import-export.c:448 #: format1/import-export.c:453 format1/import-export.c:474 #: format1/import-export.c:481 format1/import-export.c:503 #: format1/import-export.c:524 format1/import-export.c:529 #: format1/import-export.c:538 format1/import-export.c:548 #: format1/import-export.c:558 format1/import-export.c:563 #: format1/import-export.c:666 format1/import-export.c:714 #: format1/import-extents.c:63 format1/import-extents.c:68 #: format1/import-extents.c:71 format1/import-extents.c:122 #: format1/import-extents.c:193 format1/import-extents.c:220 #: format1/import-extents.c:235 format1/import-extents.c:284 #: format1/import-extents.c:314 format1/import-extents.c:338 #: format1/import-extents.c:354 format1/import-extents.c:369 #: format1/layout.c:126 format1/lvm1-label.c:75 format1/vg_number.c:37 #: format1/vg_number.c:42 format_pool/disk_rep.c:49 format_pool/disk_rep.c:102 #: format_pool/disk_rep.c:256 format_pool/disk_rep.c:358 #: format_pool/disk_rep.c:368 format_pool/disk_rep.c:373 #: format_pool/format_pool.c:132 format_pool/format_pool.c:137 #: format_pool/format_pool.c:142 format_pool/format_pool.c:152 #: format_pool/format_pool.c:161 format_pool/format_pool.c:166 #: format_pool/format_pool.c:186 format_pool/format_pool.c:195 #: format_pool/format_pool.c:201 format_pool/format_pool.c:231 #: format_pool/format_pool.c:236 format_pool/format_pool.c:246 #: format_pool/format_pool.c:251 format_pool/import_export.c:93 #: format_pool/import_export.c:180 format_pool/import_export.c:218 #: format_pool/import_export.c:232 format_pool/import_export.c:256 #: format_pool/import_export.c:276 format_pool/import_export.c:304 #: format_pool/import_export.c:309 format_text/archive.c:117 #: format_text/archive.c:138 format_text/archive.c:165 #: format_text/archive.c:258 format_text/archive.c:274 #: format_text/archive.c:350 format_text/archive.c:370 #: format_text/archiver.c:82 format_text/archiver.c:89 #: format_text/archiver.c:101 format_text/archiver.c:189 #: format_text/archiver.c:267 format_text/archiver.c:317 #: format_text/archiver.c:334 format_text/archiver.c:376 #: format_text/archiver.c:381 format_text/export.c:138 #: format_text/export.c:198 format_text/export.c:206 format_text/export.c:293 #: format_text/export.c:294 format_text/export.c:295 format_text/export.c:296 #: format_text/export.c:298 format_text/export.c:299 format_text/export.c:300 #: format_text/export.c:303 format_text/export.c:313 format_text/export.c:317 #: format_text/export.c:319 format_text/export.c:322 format_text/export.c:325 #: format_text/export.c:329 format_text/export.c:332 format_text/export.c:336 #: format_text/export.c:340 format_text/export.c:343 format_text/export.c:344 #: format_text/export.c:348 format_text/export.c:349 format_text/export.c:373 #: format_text/export.c:380 format_text/export.c:384 format_text/export.c:385 #: format_text/export.c:389 format_text/export.c:393 format_text/export.c:395 #: format_text/export.c:398 format_text/export.c:401 format_text/export.c:404 #: format_text/export.c:408 format_text/export.c:411 format_text/export.c:415 #: format_text/export.c:419 format_text/export.c:422 format_text/export.c:427 #: format_text/export.c:431 format_text/export.c:440 format_text/export.c:443 #: format_text/export.c:446 format_text/export.c:450 format_text/export.c:451 #: format_text/export.c:455 format_text/export.c:458 format_text/export.c:463 #: format_text/export.c:468 format_text/export.c:479 format_text/export.c:481 #: format_text/export.c:488 format_text/export.c:492 format_text/export.c:497 #: format_text/export.c:508 format_text/export.c:518 format_text/export.c:519 #: format_text/export.c:524 format_text/export.c:528 format_text/export.c:531 #: format_text/export.c:534 format_text/export.c:538 format_text/export.c:541 #: format_text/export.c:545 format_text/export.c:549 format_text/export.c:551 #: format_text/export.c:553 format_text/export.c:554 format_text/export.c:555 #: format_text/export.c:560 format_text/export.c:566 format_text/export.c:581 #: format_text/export.c:591 format_text/export.c:600 format_text/export.c:606 #: format_text/export.c:624 format_text/export.c:627 format_text/export.c:634 #: format_text/export.c:637 format_text/export.c:640 format_text/export.c:652 #: format_text/export.c:657 format_text/export.c:660 format_text/export.c:665 #: format_text/export.c:667 format_text/export.c:669 format_text/export.c:671 #: format_text/export.c:673 format_text/export.c:677 format_text/export.c:680 #: format_text/export.c:702 format_text/export.c:729 format_text/export.c:747 #: format_text/flags.c:94 format_text/flags.c:138 #: format_text/format-text.c:158 format_text/format-text.c:161 #: format_text/format-text.c:195 format_text/format-text.c:199 #: format_text/format-text.c:238 format_text/format-text.c:295 #: format_text/format-text.c:346 format_text/format-text.c:378 #: format_text/format-text.c:420 format_text/format-text.c:425 #: format_text/format-text.c:433 format_text/format-text.c:451 #: format_text/format-text.c:456 format_text/format-text.c:481 #: format_text/format-text.c:494 format_text/format-text.c:542 #: format_text/format-text.c:547 format_text/format-text.c:587 #: format_text/format-text.c:601 format_text/format-text.c:619 #: format_text/format-text.c:650 format_text/format-text.c:700 #: format_text/format-text.c:757 format_text/format-text.c:762 #: format_text/format-text.c:785 format_text/format-text.c:799 #: format_text/format-text.c:1059 format_text/format-text.c:1064 #: format_text/format-text.c:1072 format_text/format-text.c:1082 #: format_text/format-text.c:1103 format_text/format-text.c:1107 #: format_text/format-text.c:1113 format_text/format-text.c:1125 #: format_text/format-text.c:1309 format_text/format-text.c:1365 #: format_text/format-text.c:1370 format_text/format-text.c:1380 #: format_text/format-text.c:1382 format_text/format-text.c:1390 #: format_text/format-text.c:1430 format_text/format-text.c:1436 #: format_text/format-text.c:1621 format_text/format-text.c:1627 #: format_text/format-text.c:1666 format_text/format-text.c:1711 #: format_text/format-text.c:1730 format_text/format-text.c:1746 #: format_text/format-text.c:1751 format_text/format-text.c:1765 #: format_text/format-text.c:1777 format_text/format-text.c:1783 #: format_text/format-text.c:1813 format_text/format-text.c:1818 #: format_text/format-text.c:1823 format_text/format-text.c:1832 #: format_text/format-text.c:1935 format_text/import.c:47 #: format_text/import.c:52 format_text/import.c:63 format_text/import.c:98 #: format_text/import.c:115 format_text/import_vsn1.c:123 #: format_text/import_vsn1.c:134 format_text/import_vsn1.c:167 #: format_text/import_vsn1.c:237 format_text/import_vsn1.c:303 #: format_text/import_vsn1.c:309 format_text/import_vsn1.c:322 #: format_text/import_vsn1.c:387 format_text/import_vsn1.c:429 #: format_text/import_vsn1.c:457 format_text/import_vsn1.c:465 #: format_text/import_vsn1.c:482 format_text/import_vsn1.c:489 #: format_text/import_vsn1.c:518 format_text/import_vsn1.c:576 #: format_text/import_vsn1.c:629 format_text/import_vsn1.c:654 #: format_text/import_vsn1.c:664 format_text/import_vsn1.c:667 #: format_text/import_vsn1.c:735 format_text/import_vsn1.c:846 #: format_text/tags.c:28 format_text/tags.c:35 format_text/tags.c:42 #: format_text/tags.c:48 format_text/tags.c:67 format_text/text_label.c:210 #: format_text/text_label.c:246 label/label.c:90 label/label.c:207 #: label/label.c:258 label/label.c:274 label/label.c:284 label/label.c:291 #: label/label.c:321 label/label.c:329 label/label.c:341 label/label.c:360 #: label/label.c:364 label/label.c:370 locking/cluster_locking.c:85 #: locking/cluster_locking.c:420 locking/cluster_locking.c:432 #: locking/cluster_locking.c:436 locking/external_locking.c:77 lvchange.c:57 #: lvchange.c:99 lvchange.c:116 lvchange.c:122 lvchange.c:136 lvchange.c:143 #: lvchange.c:150 lvchange.c:268 lvchange.c:282 lvchange.c:353 lvchange.c:361 #: lvchange.c:395 lvchange.c:472 lvchange.c:479 lvchange.c:526 lvchange.c:534 #: lvconvert.c:96 lvconvert.c:147 lvconvert.c:211 lvconvert.c:222 #: lvconvert.c:273 lvconvert.c:285 lvconvert.c:298 lvconvert.c:332 #: lvconvert.c:354 lvconvert.c:369 lvconvert.c:378 lvconvert.c:397 #: lvconvert.c:404 lvconvert.c:470 lvconvert.c:481 lvconvert.c:544 #: lvconvert.c:585 lvcreate.c:133 lvcreate.c:349 lvcreate.c:373 lvcreate.c:399 #: lvcreate.c:529 lvcreate.c:661 lvcreate.c:698 lvcreate.c:728 lvcreate.c:755 #: lvcreate.c:763 lvcreate.c:769 lvcreate.c:776 lvcreate.c:868 #: lvmcmdline.c:830 lvmcmdline.c:836 lvmcmdline.c:839 lvmcmdline.c:842 #: lvmcmdline.c:846 lvmcmdline.c:853 lvmcmdline.c:885 lvmcmdline.c:896 #: lvmcmdline.c:906 lvmcmdline.c:936 lvmcmdline.c:1022 lvremove.c:99 #: lvrename.c:85 lvrename.c:164 lvrename.c:175 lvrename.c:182 lvrename.c:188 #: lvresize.c:466 lvresize.c:522 lvresize.c:529 lvresize.c:536 lvresize.c:547 #: lvresize.c:554 lvresize.c:560 lvresize.c:579 lvresize.c:593 lvresize.c:618 #: metadata/lv_manip.c:85 metadata/lv_manip.c:91 metadata/lv_manip.c:192 #: metadata/lv_manip.c:227 metadata/lv_manip.c:258 metadata/lv_manip.c:316 #: metadata/lv_manip.c:325 metadata/lv_manip.c:340 metadata/lv_manip.c:349 #: metadata/lv_manip.c:379 metadata/lv_manip.c:580 metadata/lv_manip.c:588 #: metadata/lv_manip.c:623 metadata/lv_manip.c:735 metadata/lv_manip.c:738 #: metadata/lv_manip.c:748 metadata/lv_manip.c:846 metadata/lv_manip.c:874 #: metadata/lv_manip.c:1048 metadata/lv_manip.c:1095 metadata/lv_manip.c:1100 #: metadata/lv_manip.c:1130 metadata/lv_manip.c:1221 metadata/lv_manip.c:1228 #: metadata/lv_manip.c:1265 metadata/lv_manip.c:1277 metadata/lv_manip.c:1306 #: metadata/lv_manip.c:1316 metadata/lv_manip.c:1364 metadata/lv_manip.c:1429 #: metadata/lv_manip.c:1436 metadata/lv_manip.c:1548 metadata/lv_manip.c:1619 #: metadata/merge.c:253 metadata/merge.c:292 metadata/merge.c:297 #: metadata/metadata.c:119 metadata/metadata.c:154 metadata/metadata.c:182 #: metadata/metadata.c:252 metadata/metadata.c:276 metadata/metadata.c:284 #: metadata/metadata.c:322 metadata/metadata.c:372 metadata/metadata.c:378 #: metadata/metadata.c:384 metadata/metadata.c:395 metadata/metadata.c:401 #: metadata/metadata.c:413 metadata/metadata.c:419 metadata/metadata.c:431 #: metadata/metadata.c:439 metadata/metadata.c:446 metadata/metadata.c:453 #: metadata/metadata.c:460 metadata/metadata.c:473 metadata/metadata.c:481 #: metadata/metadata.c:490 metadata/metadata.c:549 metadata/metadata.c:564 #: metadata/metadata.c:754 metadata/metadata.c:779 metadata/metadata.c:815 #: metadata/metadata.c:846 metadata/metadata.c:874 metadata/metadata.c:880 #: metadata/metadata.c:887 metadata/metadata.c:898 metadata/metadata.c:903 #: metadata/metadata.c:925 metadata/metadata.c:947 metadata/metadata.c:964 #: metadata/metadata.c:1063 metadata/metadata.c:1068 metadata/metadata.c:1079 #: metadata/metadata.c:1137 metadata/metadata.c:1142 metadata/metadata.c:1168 #: metadata/metadata.c:1183 metadata/metadata.c:1191 metadata/metadata.c:1246 #: metadata/metadata.c:1250 metadata/metadata.c:1399 metadata/metadata.c:1433 #: metadata/metadata.c:1490 metadata/metadata.c:1494 metadata/metadata.c:1527 #: metadata/mirror.c:106 metadata/mirror.c:109 metadata/mirror.c:112 #: metadata/mirror.c:205 metadata/mirror.c:484 metadata/mirror.c:526 #: metadata/mirror.c:560 metadata/mirror.c:599 metadata/mirror.c:608 #: metadata/mirror.c:736 metadata/mirror.c:757 metadata/mirror.c:762 #: metadata/mirror.c:836 metadata/pv_manip.c:54 metadata/pv_manip.c:73 #: metadata/pv_manip.c:94 metadata/pv_manip.c:131 metadata/pv_manip.c:156 #: metadata/pv_manip.c:197 metadata/pv_manip.c:332 metadata/pv_map.c:44 #: metadata/pv_map.c:92 metadata/pv_map.c:112 metadata/pv_map.c:122 #: metadata/pv_map.c:149 metadata/pv_map.c:159 metadata/snapshot_manip.c:70 #: metadata/snapshot_manip.c:77 mirror/mirrored.c:144 mirror/mirrored.c:149 #: mirror/mirrored.c:151 mirror/mirrored.c:304 mirror/mirrored.c:328 #: mirror/mirrored.c:331 mirror/mirrored.c:501 mirror/mirrored.c:552 #: misc/lvm-file.c:291 misc/timestamp.c:44 pvchange.c:191 pvmove.c:102 #: pvmove.c:107 pvmove.c:192 pvmove.c:220 pvmove.c:227 pvmove.c:292 #: pvmove.c:299 pvmove.c:308 pvmove.c:337 pvmove.c:349 pvmove.c:356 #: pvmove.c:363 pvmove.c:371 pvmove.c:383 pvmove.c:524 pvresize.c:165 #: pvscan.c:55 report/report.c:187 report/report.c:513 report/report.c:543 #: report/report.c:699 reporter.c:289 snapshot/snapshot.c:74 #: snapshot/snapshot.c:83 snapshot/snapshot.c:84 snapshot/snapshot.c:85 #: snapshot/snapshot.c:169 striped/striped.c:89 striped/striped.c:169 #: striped/striped.c:172 striped/striped.c:216 toollib.c:912 toollib.c:962 #: toollib.c:1020 toollib.c:1060 toollib.c:1085 toollib.c:1194 toollib.c:1332 #: toollib.c:1337 toollib.c:1350 toollib.c:1357 uuid/uuid.c:90 uuid/uuid.c:94 #: vgcfgbackup.c:69 vgcfgbackup.c:78 vgcfgbackup.c:85 vgchange.c:420 #: vgmerge.c:193 vgreduce.c:29 vgreduce.c:96 vgreduce.c:102 vgreduce.c:124 #: vgreduce.c:130 vgreduce.c:148 vgreduce.c:196 vgreduce.c:217 vgreduce.c:241 #: vgreduce.c:307 vgreduce.c:353 zero/zero.c:99 msgid "" msgstr "" #: activate/activate.c:81 msgid "snap_seg module string allocation failed" msgstr "" #: activate/activate.c:245 msgid "Activation enabled. Device-mapper kernel driver will be used." msgstr "" #: activate/activate.c:248 msgid "" "WARNING: Activation disabled. No device-mapper interaction will be attempted." msgstr "" #: activate/activate.c:281 msgid "Ignoring invalid string in config file activation/volume_list" msgstr "" #: activate/activate.c:287 msgid "Ignoring empty string in config file activation/volume_list" msgstr "" #: activate/activate.c:296 msgid "Ignoring empty tag in config file activation/volume_list" msgstr "" #: activate/activate.c:326 #, c-format msgid "dm_snprintf error from %s/%s" msgstr "" #: activate/activate.c:350 msgid "Getting driver version" msgstr "" #: activate/activate.c:362 #, c-format msgid "Getting target version for %s" msgstr "" #: activate/activate.c:367 #, c-format msgid "Failed to get %s target version" msgstr "" #: activate/activate.c:411 #, c-format msgid "target_present module name too long: %s" msgstr "" #: activate/activate.c:440 #, c-format msgid "Getting device info for %s" msgstr "" #: activate/activate.c:771 #, c-format msgid "Skipping: Suspending '%s'." msgstr "" #: activate/activate.c:831 #, c-format msgid "Skipping: Resuming '%s'." msgstr "" #: activate/activate.c:877 #, c-format msgid "Skipping: Deactivating '%s'." msgstr "" #: activate/activate.c:888 #, c-format msgid "LV %s/%s in use: not deactivating" msgstr "" #: activate/activate.c:917 activate/activate.c:942 #, c-format msgid "Not activating %s/%s due to config file settings" msgstr "" #: activate/activate.c:948 #, c-format msgid "Skipping: Activating '%s'." msgstr "" #: activate/dev_manager.c:75 #, c-format msgid "_build_dlid: pool allocation failed for %zu %s %s." msgstr "" #: activate/dev_manager.c:136 activate/dev_manager.c:255 #: activate/dev_manager.c:344 msgid "Failed to disable open_count" msgstr "" #: activate/dev_manager.c:163 msgid "Failed to allocate dm_task struct to check dev status" msgstr "" #: activate/dev_manager.c:171 msgid "Failed to get state of mapped device" msgstr "" #: activate/dev_manager.c:229 activate/dev_manager.c:528 #, c-format msgid "dlid build failed for %s" msgstr "" #: activate/dev_manager.c:360 activate/dev_manager.c:384 #, c-format msgid "Number of segments in active LV %s does not match metadata" msgstr "" #: activate/dev_manager.c:394 #, c-format msgid "LV percent: %f" msgstr "" #: activate/dev_manager.c:497 #, c-format msgid "Getting device status percentage for %s" msgstr "" #: activate/dev_manager.c:532 #, c-format msgid "Getting device mirror status percentage for %s" msgstr "" #: activate/dev_manager.c:633 #, c-format msgid "Getting device info for %s [%s]" msgstr "" #: activate/dev_manager.c:635 #, c-format msgid "Failed to get info for %s [%s]." msgstr "" #: activate/dev_manager.c:640 #, c-format msgid "Failed to add device (%u:%u) to dtree" msgstr "" #: activate/dev_manager.c:677 #, c-format msgid "Partial dtree creation failed for %s." msgstr "" #: activate/dev_manager.c:741 #, c-format msgid "Internal error: Unassigned area found in LV %s." msgstr "" #: activate/dev_manager.c:775 #, c-format msgid "Couldn't find snapshot for '%s'." msgstr "" #: activate/dev_manager.c:800 #, c-format msgid "_emit_target: Internal error: Can't handle segment type %s" msgstr "" #: activate/dev_manager.c:828 #, c-format msgid "Checking kernel supports %s segment type for %s%s%s" msgstr "" #: activate/dev_manager.c:834 #, c-format msgid "Can't expand LV %s: %s target support missing from kernel?" msgstr "" #: activate/dev_manager.c:847 msgid "Clustered snapshots are not yet supported" msgstr "" #: activate/dev_manager.c:902 #, c-format msgid "_add_new_lv_to_dtree: pool alloc failed for %s %s." msgstr "" #: activate/dev_manager.c:961 #, c-format msgid "_create_lv_symlinks: Couldn't split up old device name %s" msgstr "" #: activate/dev_manager.c:987 #, c-format msgid "_clean_tree: Couldn't split up device name %s." msgstr "" #: activate/dev_manager.c:1013 activate/dev_manager.c:1133 msgid "Lost dependency tree root node" msgstr "" #: activate/dev_manager.c:1055 #, c-format msgid "Failed to create symlinks for %s." msgstr "" #: activate/dev_manager.c:1060 #, c-format msgid "_tree_action: Action %u not supported." msgstr "" #: activate/dev_manager.c:1119 msgid "partial dtree creation failed" msgstr "" #: activate/dev_manager.c:1124 #, c-format msgid "Failed to add device %s (%u:%u) to dtree" msgstr "" #: activate/fs.c:35 activate/fs.c:58 msgid "Couldn't construct name of volume group directory." msgstr "" #: activate/fs.c:43 #, c-format msgid "Creating directory %s" msgstr "" #: activate/fs.c:45 activate/fs.c:80 activate/fs.c:100 activate/fs.c:153 #: activate/fs.c:166 activate/fs.c:173 activate/fs.c:208 #: commands/toolcontext.c:342 commands/toolcontext.c:820 config/config.c:209 #: config/config.c:247 config/config.c:262 config/config.c:328 #: config/config.c:428 config/config.c:452 device/dev-cache.c:208 #: device/dev-cache.c:212 device/dev-cache.c:394 device/dev-cache.c:417 #: device/dev-cache.c:424 device/dev-cache.c:681 device/dev-cache.c:683 #: device/dev-io.c:131 device/dev-io.c:231 device/dev-io.c:249 #: device/dev-io.c:254 device/dev-io.c:256 device/dev-io.c:262 #: device/dev-io.c:396 device/dev-io.c:398 device/dev-io.c:481 #: filters/filter-persistent.c:203 filters/filter-persistent.c:207 #: filters/filter-persistent.c:230 filters/filter-persistent.c:243 #: filters/filter-sysfs.c:42 filters/filter-sysfs.c:58 #: filters/filter-sysfs.c:156 filters/filter-sysfs.c:163 #: filters/filter-sysfs.c:182 filters/filter-sysfs.c:225 filters/filter.c:164 #: filters/filter.c:221 filters/filter.c:232 filters/filter.c:240 #: filters/filter.c:253 format_text/archive.c:214 format_text/archive.c:223 #: format_text/archive.c:253 format_text/archive.c:260 #: format_text/archive.c:265 format_text/format-text.c:873 #: format_text/format-text.c:875 format_text/format-text.c:884 #: format_text/format-text.c:889 format_text/format-text.c:891 #: format_text/format-text.c:896 format_text/format-text.c:921 #: format_text/format-text.c:983 format_text/format-text.c:988 #: format_text/format-text.c:1013 format_text/format-text.c:1040 #: locking/file_locking.c:61 locking/file_locking.c:69 #: locking/file_locking.c:72 locking/file_locking.c:105 #: locking/file_locking.c:167 locking/file_locking.c:171 #: locking/file_locking.c:187 locking/file_locking.c:296 #: locking/file_locking.c:301 locking/locking.c:45 locking/locking.c:50 #: locking/locking.c:66 locking/locking.c:221 log/log.c:69 lvmcmdline.c:1092 #: lvmcmdline.c:1130 misc/lvm-exec.c:42 misc/lvm-file.c:47 misc/lvm-file.c:70 #: misc/lvm-file.c:97 misc/lvm-file.c:107 misc/lvm-file.c:157 #: misc/lvm-file.c:170 misc/lvm-file.c:199 misc/lvm-file.c:208 #: misc/lvm-file.c:236 misc/lvm-file.c:241 misc/lvm-file.c:244 #: misc/lvm-file.c:289 misc/lvm-file.c:297 misc/timestamp.c:47 mm/memlock.c:97 #: mm/memlock.c:105 mm/memlock.c:116 uuid/uuid.c:83 uuid/uuid.c:88 #, c-format msgid "%s: %s failed: %s" msgstr "" #: activate/fs.c:64 #, c-format msgid "Removing directory %s" msgstr "" #: activate/fs.c:91 #, c-format msgid "Couldn't create path for %s" msgstr "" #: activate/fs.c:98 activate/fs.c:151 activate/fs.c:164 #, c-format msgid "Removing %s" msgstr "" #: activate/fs.c:114 #, c-format msgid "Couldn't create path for volume group dir %s" msgstr "" #: activate/fs.c:121 #, c-format msgid "Couldn't create source pathname for logical volume link %s" msgstr "" #: activate/fs.c:128 #, c-format msgid "Couldn't create destination pathname for logical volume link for %s" msgstr "" #: activate/fs.c:135 #, c-format msgid "Couldn't create pathname for LVM1 group file for %s" msgstr "" #: activate/fs.c:146 #, c-format msgid "Non-LVM1 character device found at %s" msgstr "" #: activate/fs.c:159 #, c-format msgid "Symbolic link %s not created: file exists" msgstr "" #: activate/fs.c:171 #, c-format msgid "Linking %s -> %s" msgstr "" #: activate/fs.c:195 msgid "Couldn't determine link pathname." msgstr "" #: activate/fs.c:202 #, c-format msgid "%s not symbolic link - not removing" msgstr "" #: activate/fs.c:206 #, c-format msgid "Removing link %s" msgstr "" #: activate/fs.c:282 msgid "No space to stack fs operation" msgstr "" #: archiver.c:40 format_text/archiver.c:53 msgid "Couldn't copy archive directory name." msgstr "" #: archiver.c:102 format_text/archiver.c:116 msgid "Test mode: Skipping archiving of volume group." msgstr "" #: archiver.c:109 #, c-format msgid "Archiving volume group \"%s\" metadata." msgstr "" #: archiver.c:111 format_text/archiver.c:131 #, c-format msgid "Volume group \"%s\" metadata archive failed." msgstr "" #: archiver.c:138 format_text/archiver.c:164 msgid "Couldn't copy backup directory name." msgstr "" #: archiver.c:169 format_text/archiver.c:195 msgid "Failed to generate volume group metadata backup filename." msgstr "" #: archiver.c:180 format_text/archiver.c:206 msgid "WARNING: This metadata update is NOT backed up" msgstr "" #: archiver.c:185 format_text/archiver.c:211 msgid "Test mode: Skipping volume group backup." msgstr "" #: archiver.c:193 format_text/archiver.c:224 #, c-format msgid "Backup of volume group %s metadata failed." msgstr "" #: archiver.c:207 format_text/archiver.c:238 msgid "Failed to generate backup filename (for removal)." msgstr "" #: archiver.c:230 format_text/archiver.c:261 msgid "Couldn't create text format object." msgstr "" #: archiver.c:259 format_text/archiver.c:290 msgid "Failed to allocate format instance" msgstr "" #: archiver.c:267 format_text/archiver.c:298 #, c-format msgid "PV %s missing from cache" msgstr "" #: archiver.c:272 #, c-format msgid "PV %s is a different format (%s)" msgstr "" #: archiver.c:279 format_text/archiver.c:310 #, c-format msgid "Format-specific setup for %s failed" msgstr "" #: archiver.c:316 format_text/archiver.c:347 msgid "Failed to generate backup filename (for restore)." msgstr "" #: archiver.c:333 #, c-format msgid "Creating volume group backup \"%s\"" msgstr "" #: archiver.c:338 format_text/archiver.c:369 msgid "Couldn't create backup object." msgstr "" #: cache/lvmcache.c:56 cache/lvmcache.c:235 cache/lvmcache.c:740 msgid "Internal cache initialisation failed" msgstr "" #: cache/lvmcache.c:61 #, c-format msgid "Cache locking failure for %s" msgstr "" #: cache/lvmcache.c:127 msgid "device_list element allocation failed" msgstr "" #: cache/lvmcache.c:245 toollib.c:638 msgid "dev_iter creation failed" msgstr "" #: cache/lvmcache.c:278 msgid "vgids list allocation failed" msgstr "" #: cache/lvmcache.c:285 cache/lvmcache.c:308 cache/lvmcache.c:334 #: toollib.c:271 toollib.c:306 toollib.c:314 toollib.c:326 toollib.c:405 #: toollib.c:547 toollib.c:561 toollib.c:698 msgid "strlist allocation failed" msgstr "" #: cache/lvmcache.c:301 msgid "vgnames list allocation failed" msgstr "" #: cache/lvmcache.c:324 msgid "pvids list allocation failed" msgstr "" #: cache/lvmcache.c:395 #, c-format msgid "vg hash re-insertion failed: %s" msgstr "" #: cache/lvmcache.c:440 #, c-format msgid "_lvmcache_update: pvid insertion failed: %s" msgstr "" #: cache/lvmcache.c:456 #, c-format msgid "lvmcache: %s: clearing VGID" msgstr "" #: cache/lvmcache.c:463 #, c-format msgid "_lvmcache_update: vgid hash insertion failed: %s" msgstr "" #: cache/lvmcache.c:468 #, c-format msgid "lvmcache: %s: setting %s VGID to %s" msgstr "" #: cache/lvmcache.c:502 #, c-format msgid "" "WARNING: Duplicate VG name %s: Existing %s takes precedence over exported %s" msgstr "" #: cache/lvmcache.c:508 #, c-format msgid "WARNING: Duplicate VG name %s: %s takes precedence over exported %s" msgstr "" #: cache/lvmcache.c:516 #, c-format msgid "" "WARNING: Duplicate VG name %s: Existing %s (created here) takes precedence " "over %s" msgstr "" #: cache/lvmcache.c:521 #, c-format msgid "" "WARNING: Duplicate VG name %s: %s (with creation_host) takes precedence over " "%s" msgstr "" #: cache/lvmcache.c:529 #, c-format msgid "" "WARNING: Duplicate VG name %s: %s (created here) takes precedence over %s" msgstr "" #: cache/lvmcache.c:547 #, c-format msgid "cache_update: vg hash insertion failed: %s" msgstr "" #: cache/lvmcache.c:619 msgid "lvmcache_update_vgname: list alloc failed" msgstr "" #: cache/lvmcache.c:625 #, c-format msgid "cache vgname alloc failed for %s" msgstr "" #: cache/lvmcache.c:652 #, c-format msgid "lvmcache: %s: now %s%s%s%s%s" msgstr "" #: cache/lvmcache.c:668 #, c-format msgid "lvmcache: %s: VG %s %s exported" msgstr "" #: cache/lvmcache.c:685 #, c-format msgid "cache creation host alloc failed for %s" msgstr "" #: cache/lvmcache.c:690 #, c-format msgid "lvmcache: %s: VG %s: Set creation host to %s." msgstr "" #: cache/lvmcache.c:754 msgid "lvmcache_info allocation failed" msgstr "" #: cache/lvmcache.c:769 #, c-format msgid "Ignoring duplicate PV %s on %s - using md %s" msgstr "" #: cache/lvmcache.c:776 #, c-format msgid "Ignoring duplicate PV %s on %s - using dm %s" msgstr "" #: cache/lvmcache.c:783 #, c-format msgid "Duplicate PV %s on %s - using md %s" msgstr "" #: cache/lvmcache.c:789 #, c-format msgid "Duplicate PV %s on %s - using dm %s" msgstr "" #: cache/lvmcache.c:798 #, c-format msgid "Found duplicate PV %s: using %s not %s" msgstr "" #: cache/lvmcache.c:872 msgid "Wiping internal VG cache" msgstr "" #: commands/toolcontext.c:70 msgid "LVM_SYSTEM_DIR environment variable is too long." msgstr "" #: commands/toolcontext.c:146 #, c-format msgid "Logging initialised at %s" msgstr "" #: commands/toolcontext.c:165 #, c-format msgid "Set umask to %04o" msgstr "" #: commands/toolcontext.c:171 commands/toolcontext.c:182 msgid "Device directory given in config file too long" msgstr "" #: commands/toolcontext.c:187 #, c-format msgid "Warning: proc dir %s not found - some checks will be bypassed" msgstr "" #: commands/toolcontext.c:207 lvmcmdline.c:723 msgid "Invalid units specification" msgstr "" #: commands/toolcontext.c:216 #, c-format msgid "Setting host tag: %s" msgstr "" #: commands/toolcontext.c:219 #, c-format msgid "_set_tag: str_list_add %s failed" msgstr "" #: commands/toolcontext.c:243 #, c-format msgid "Invalid hostname string for tag %s" msgstr "" #: commands/toolcontext.c:254 msgid "host_filter not supported yet" msgstr "" #: commands/toolcontext.c:289 #, c-format msgid "Invalid tag in config file: %s" msgstr "" #: commands/toolcontext.c:322 msgid "LVM_SYSTEM_DIR or tag was too long" msgstr "" #: commands/toolcontext.c:327 msgid "config_tree_list allocation failed" msgstr "" #: commands/toolcontext.c:332 msgid "config_tree allocation failed" msgstr "" #: commands/toolcontext.c:347 #, c-format msgid "Loading config file: %s" msgstr "" #: commands/toolcontext.c:349 #, c-format msgid "Failed to load config file %s" msgstr "" #: commands/toolcontext.c:372 commands/toolcontext.c:410 msgid "Failed to create config tree" msgstr "" #: commands/toolcontext.c:473 msgid "Failed to add /dev to internal device cache" msgstr "" #: commands/toolcontext.c:477 msgid "device/scan not in config file: Defaulting to /dev" msgstr "" #: commands/toolcontext.c:484 msgid "Invalid string in config file: devices/scan" msgstr "" #: commands/toolcontext.c:490 format_text/format-text.c:1980 #, c-format msgid "Failed to add %s to internal device cache" msgstr "" #: commands/toolcontext.c:501 msgid "Invalid string in config file: devices/loopfiles" msgstr "" #: commands/toolcontext.c:507 #, c-format msgid "Failed to add loopfile %s to internal device cache" msgstr "" #: commands/toolcontext.c:546 msgid "devices/filter not found in config file: no regex filter installed" msgstr "" #: commands/toolcontext.c:550 msgid "Failed to create regex device filter" msgstr "" #: commands/toolcontext.c:557 msgid "Failed to create lvm type filter" msgstr "" #: commands/toolcontext.c:602 commands/toolcontext.c:610 msgid "Persistent cache filename too long." msgstr "" #: commands/toolcontext.c:615 msgid "Failed to create persistent device filter" msgstr "" #: commands/toolcontext.c:634 #, c-format msgid "Failed to load existing device cache from %s" msgstr "" #: commands/toolcontext.c:679 msgid "Invalid string in config file: global/format_libraries" msgstr "" #: commands/toolcontext.c:690 #, c-format msgid "Shared library %s does not contain format functions" msgstr "" #: commands/toolcontext.c:722 #, c-format msgid "_init_formats: Default format (%s) not found" msgstr "" #: commands/toolcontext.c:775 msgid "Invalid string in config file: global/segment_libraries" msgstr "" #: commands/toolcontext.c:786 #, c-format msgid "Shared library %s does not contain segment type functions" msgstr "" #: commands/toolcontext.c:801 #, c-format msgid "Duplicate segment type %s: unloading shared library %s" msgstr "" #: commands/toolcontext.c:825 msgid "_init_hostname: dm_pool_strdup failed" msgstr "" #: commands/toolcontext.c:830 msgid "_init_hostname: dm_pool_strdup kernel_vsn failed" msgstr "" #: commands/toolcontext.c:844 msgid "WARNING: Metadata changes will NOT be backed up" msgstr "" #: commands/toolcontext.c:864 #, c-format msgid "Couldn't create default archive path '%s/%s'." msgstr "" #: commands/toolcontext.c:873 commands/toolcontext.c:893 msgid "backup_init failed." msgstr "" #: commands/toolcontext.c:885 #, c-format msgid "Couldn't create default backup path '%s/%s'." msgstr "" #: commands/toolcontext.c:911 msgid "setlocale failed" msgstr "" #: commands/toolcontext.c:920 msgid "Failed to allocate command context" msgstr "" #: commands/toolcontext.c:940 msgid "" "Failed to create LVM2 system dir for metadata backups, config files and " "internal cache." msgstr "" #: commands/toolcontext.c:942 msgid "" "Set environment variable LVM_SYSTEM_DIR to alternative location or empty " "string." msgstr "" #: commands/toolcontext.c:948 msgid "Library memory pool creation failed" msgstr "" #: commands/toolcontext.c:979 msgid "Command memory pool creation failed" msgstr "" #: commands/toolcontext.c:1042 msgid "Reloading config files" msgstr "" #: config/config.c:111 msgid "Failed to allocate config pool." msgstr "" #: config/config.c:116 msgid "Failed to allocate config tree." msgstr "" #: config/config.c:165 msgid "Failed to allocate config tree parser." msgstr "" #: config/config.c:228 #, c-format msgid "%s: Checksum error" msgstr "" #: config/config.c:268 #, c-format msgid "%s is not a regular file" msgstr "" #: config/config.c:276 #, c-format msgid "%s is empty" msgstr "" #: config/config.c:324 #, c-format msgid "Config file %s has disappeared!" msgstr "" #: config/config.c:329 msgid "Failed to reload configuration files" msgstr "" #: config/config.c:334 #, c-format msgid "Configuration file %s is not a regular file" msgstr "" #: config/config.c:344 #, c-format msgid "Detected config file change to %s" msgstr "" #: config/config.c:368 #, c-format msgid "_write_value: Unknown value type: %d" msgstr "" #: config/config.c:432 #, c-format msgid "Dumping configuration to %s" msgstr "" #: config/config.c:435 config/config.c:441 #, c-format msgid "Failure while writing to %s" msgstr "" #: config/config.c:445 #, c-format msgid "Configuration node %s not found" msgstr "" #: config/config.c:494 config/config.c:497 config/config.c:510 #: config/config.c:512 config/config.c:527 config/config.c:541 #: config/config.c:543 config/config.c:572 config/config.c:578 #: config/config.c:590 #, c-format msgid "Parse error at byte %td (line %d): unexpected token" msgstr "" #: config/config.c:594 #, c-format msgid "Parse error at byte %td (line %d): expected a value" msgstr "" #: config/config.c:810 #, c-format msgid "WARNING: Ignoring duplicate config node: %s (seeking %s)" msgstr "" #: config/config.c:858 #, c-format msgid "Setting %s to %s" msgstr "" #: config/config.c:863 #, c-format msgid "%s not found in config: defaulting to %s" msgstr "" #: config/config.c:881 #, c-format msgid "Setting %s to %ld" msgstr "" #: config/config.c:885 #, c-format msgid "%s not found in config: defaulting to %ld" msgstr "" #: config/config.c:903 #, c-format msgid "Setting %s to %f" msgstr "" #: config/config.c:907 #, c-format msgid "%s not found in config: defaulting to %f" msgstr "" #: device/dev-cache.c:64 device/dev-cache.c:81 device/dev-cache.c:118 msgid "struct device allocation failed" msgstr "" #: device/dev-cache.c:68 device/dev-cache.c:85 msgid "struct str_list allocation failed" msgstr "" #: device/dev-cache.c:73 device/dev-cache.c:90 device/dev-cache.c:95 msgid "filename strdup failed" msgstr "" #: device/dev-cache.c:142 #, c-format msgid "%s: New preferred name" msgstr "" #: device/dev-cache.c:247 #, c-format msgid "%s: Already in device cache" msgstr "" #: device/dev-cache.c:260 #, c-format msgid "%s: Aliased to %s in device cache%s" msgstr "" #: device/dev-cache.c:264 #, c-format msgid "%s: Added to device cache" msgstr "" #: device/dev-cache.c:307 msgid "Couldn't insert device into binary tree." msgstr "" #: device/dev-cache.c:314 msgid "Couldn't add alias to dev cache." msgstr "" #: device/dev-cache.c:319 msgid "Couldn't add name to hash in dev cache." msgstr "" #: device/dev-cache.c:399 #, c-format msgid "%s: Not a regular file" msgstr "" #: device/dev-cache.c:429 #, c-format msgid "%s: Symbolic link to directory" msgstr "" #: device/dev-cache.c:438 #, c-format msgid "%s: Not a block device" msgstr "" #: device/dev-cache.c:496 msgid "" "devices/preferred_names not found in config file: using built-in preferences" msgstr "" #: device/dev-cache.c:503 msgid "preferred_names patterns must be enclosed in quotes" msgstr "" #: device/dev-cache.c:514 msgid "Failed to allocate preferred device name pattern list." msgstr "" #: device/dev-cache.c:521 msgid "Failed to allocate a preferred device name pattern." msgstr "" #: device/dev-cache.c:529 msgid "Preferred device name pattern matcher creation failed." msgstr "" #: device/dev-cache.c:559 msgid "Couldn't create binary tree for dev-cache." msgstr "" #: device/dev-cache.c:579 #, c-format msgid "Device '%s' has been left open." msgstr "" #: device/dev-cache.c:617 device/dev-cache.c:643 #, c-format msgid "Ignoring %s: %s" msgstr "" #: device/dev-cache.c:623 #, c-format msgid "Ignoring %s: Not a directory" msgstr "" #: device/dev-cache.c:628 msgid "dir_list allocation failed" msgstr "" #: device/dev-cache.c:649 #, c-format msgid "Ignoring %s: Not a regular file" msgstr "" #: device/dev-cache.c:654 msgid "dir_list allocation failed for file" msgstr "" #: device/dev-cache.c:686 device/dev-cache.c:690 #, c-format msgid "Path %s no longer valid for device(%d,%d)" msgstr "" #: device/dev-cache.c:707 #, c-format msgid "Aborting - please provide new pathname for what used to be %s" msgstr "" #: device/dev-cache.c:747 msgid "dev_iter allocation failed" msgstr "" #: device/dev-io.c:67 #, c-format msgid "Attempt to read an unopened device (%s)." msgstr "" #: device/dev-io.c:79 #, c-format msgid "Read size too large: %lu" msgstr "" #: device/dev-io.c:84 #, c-format msgid "%s: lseek %lu failed: %s" msgstr "" #: device/dev-io.c:98 #, c-format msgid "%s: %s failed after %lu of %lu at %lu: %s" msgstr "" #: device/dev-io.c:134 #, c-format msgid "%s: block size is %u bytes" msgstr "" #: device/dev-io.c:191 msgid "Bounce buffer alloca failed" msgstr "" #: device/dev-io.c:238 device/dev-io.c:264 #, c-format msgid "%s: size is %lu sectors" msgstr "" #: device/dev-io.c:343 #, c-format msgid "WARNING: %s already opened read-only" msgstr "" #: device/dev-io.c:352 #, c-format msgid "WARNING: dev_open(%s) called while suspended" msgstr "" #: device/dev-io.c:364 #, c-format msgid "%s: stat failed: Has device name changed?" msgstr "" #: device/dev-io.c:390 #, c-format msgid "%s: Not using O_DIRECT" msgstr "" #: device/dev-io.c:422 #, c-format msgid "%s: fstat failed: Has device name changed?" msgstr "" #: device/dev-io.c:437 #, c-format msgid "Opened %s %s%s%s" msgstr "" #: device/dev-io.c:486 #, c-format msgid "Closed %s" msgstr "" #: device/dev-io.c:501 #, c-format msgid "Attempt to close device '%s' which is not open." msgstr "" #: device/dev-io.c:515 #, c-format msgid "%s: Immediate close attempt while still referenced" msgstr "" #: device/dev-io.c:576 #, c-format msgid "Read from %s failed" msgstr "" #: device/dev-io.c:588 #, c-format msgid "Circular read from %s failed" msgstr "" #: device/dev-io.c:648 #, c-format msgid "Wiping %s at %lu length %zu" msgstr "" #: device/dev-io.c:651 #, c-format msgid "Wiping %s at sector %lu length %zu sectors" msgstr "" #: display/display.c:145 #, c-format msgid "Unrecognised allocation policy %s" msgstr "" #: display/display.c:172 msgid "no memory for size display buffer" msgstr "" #: display/display.c:247 #, c-format msgid "%s:%s:%lu:-1:%u:%u:-1:%u:%u:%u:%u:%s" msgstr "" #: display/display.c:278 #, c-format msgid "--- %sPhysical volume ---" msgstr "" #: display/display.c:279 #, c-format msgid "PV Name %s" msgstr "" #: display/display.c:280 #, c-format msgid "VG Name %s%s" msgstr "" #: display/display.c:290 #, c-format msgid "PV Size %s / not usable %s" msgstr "" #: display/display.c:296 #, c-format msgid "PV Size %s" msgstr "" #: display/display.c:304 #, c-format msgid "Allocatable yes %s" msgstr "" #: display/display.c:307 msgid "Allocatable NO" msgstr "" #: display/display.c:312 #, c-format msgid "PE Size (KByte) %u" msgstr "" #: display/display.c:313 display/display.c:592 #, c-format msgid "Total PE %u" msgstr "" #: display/display.c:314 #, c-format msgid "Free PE %u" msgstr "" #: display/display.c:315 #, c-format msgid "Allocated PE %u" msgstr "" #: display/display.c:316 display/display.c:339 #, c-format msgid "PV UUID %s" msgstr "" #: display/display.c:317 display/display.c:345 display/display.c:476 #: display/display.c:527 display/display.c:610 format_text/archive.c:315 #: lvmcmdline.c:769 mirror/mirrored.c:73 striped/striped.c:49 msgid " " msgstr "" #: display/display.c:337 #, c-format msgid "PV Name %s " msgstr "" #: display/display.c:340 #, c-format msgid "PV Status %sallocatable" msgstr "" #: display/display.c:342 #, c-format msgid "Total PE / Free PE %u / %u" msgstr "" #: display/display.c:355 #, c-format msgid "%s%s/%s:%s:%d:%d:-1:%d:%lu:%d:-1:%d:%d:%d:%d" msgstr "" #: display/display.c:385 msgid "--- Logical volume ---" msgstr "" #: display/display.c:387 #, c-format msgid "LV Name %s%s/%s" msgstr "" #: display/display.c:389 #, c-format msgid "VG Name %s" msgstr "" #: display/display.c:391 #, c-format msgid "LV UUID %s" msgstr "" #: display/display.c:393 #, c-format msgid "LV Write Access %s" msgstr "" #: display/display.c:397 msgid "LV snapshot status source of" msgstr "" #: display/display.c:406 #, c-format msgid " %s%s/%s [%s]" msgstr "" #: display/display.c:419 #, c-format msgid "LV snapshot status %s destination for %s%s/%s" msgstr "" #: display/display.c:426 msgid "LV Status suspended" msgstr "" #: display/display.c:428 #, c-format msgid "LV Status %savailable" msgstr "" #: display/display.c:436 #, c-format msgid "# open %u" msgstr "" #: display/display.c:438 #, c-format msgid "LV Size %s" msgstr "" #: display/display.c:442 #, c-format msgid "Current LE %u" msgstr "" #: display/display.c:446 #, c-format msgid "COW-table size %s" msgstr "" #: display/display.c:448 #, c-format msgid "COW-table LE %u" msgstr "" #: display/display.c:451 #, c-format msgid "Allocated to snapshot %.2f%% " msgstr "" #: display/display.c:453 #, c-format msgid "Snapshot chunk size %s" msgstr "" #: display/display.c:457 #, c-format msgid "Segments %u" msgstr "" #: display/display.c:463 #, c-format msgid "Allocation %s" msgstr "" #: display/display.c:464 #, c-format msgid "Read ahead sectors %u" msgstr "" #: display/display.c:468 #, c-format msgid "Persistent major %d" msgstr "" #: display/display.c:469 #, c-format msgid "Persistent minor %d" msgstr "" #: display/display.c:473 #, c-format msgid "Block device %d:%d" msgstr "" #: display/display.c:486 #, c-format msgid "%sPhysical volume\t%s" msgstr "" #: display/display.c:492 #, c-format msgid "%sPhysical extents\t%d to %d" msgstr "" #: display/display.c:497 #, c-format msgid "%sLogical volume\t%s" msgstr "" #: display/display.c:502 #, c-format msgid "%sLogical extents\t%d to %d" msgstr "" #: display/display.c:507 #, c-format msgid "%sUnassigned area" msgstr "" #: display/display.c:515 msgid "--- Segments ---" msgstr "" #: display/display.c:518 #, c-format msgid "Logical extent %u to %u:" msgstr "" #: display/display.c:521 #, c-format msgid " Type\t\t%s" msgstr "" #: display/display.c:547 msgid "--- Volume group ---" msgstr "" #: display/display.c:548 #, c-format msgid "VG Name %s" msgstr "" #: display/display.c:549 #, c-format msgid "System ID %s" msgstr "" #: display/display.c:550 #, c-format msgid "Format %s" msgstr "" #: display/display.c:552 #, c-format msgid "Metadata Areas %d" msgstr "" #: display/display.c:554 #, c-format msgid "Metadata Sequence No %d" msgstr "" #: display/display.c:557 #, c-format msgid "VG Access %s%s%s%s" msgstr "" #: display/display.c:562 #, c-format msgid "VG Status %s%sresizable" msgstr "" #: display/display.c:569 msgid "Clustered yes" msgstr "" #: display/display.c:570 #, c-format msgid "Shared %s" msgstr "" #: display/display.c:573 #, c-format msgid "MAX LV %u" msgstr "" #: display/display.c:574 #, c-format msgid "Cur LV %u" msgstr "" #: display/display.c:575 #, c-format msgid "Open LV %u" msgstr "" #: display/display.c:581 #, c-format msgid "Max PV %u" msgstr "" #: display/display.c:582 #, c-format msgid "Cur PV %u" msgstr "" #: display/display.c:583 #, c-format msgid "Act PV %u" msgstr "" #: display/display.c:585 #, c-format msgid "VG Size %s" msgstr "" #: display/display.c:589 #, c-format msgid "PE Size %s" msgstr "" #: display/display.c:594 #, c-format msgid "Alloc PE / Size %u / %s" msgstr "" #: display/display.c:600 #, c-format msgid "Free PE / Size %u / %s" msgstr "" #: display/display.c:609 #, c-format msgid "VG UUID %s" msgstr "" #: display/display.c:645 #, c-format msgid "%s:%s:%d:-1:%u:%u:%u:-1:%u:%u:%u:%lu:%u:%u:%u:%u:%s" msgstr "" #: display/display.c:669 #, c-format msgid "\"%s\" %-9s [%-9s used / %s free]" msgstr "" #: display/display.c:686 display/display.c:695 pvscan.c:34 #, c-format msgid "%s" msgstr "" #: error/errseg.c:73 msgid "error module string list allocation failed" msgstr "" #: error/errseg.c:109 mirror/mirrored.c:562 snapshot/snapshot.c:179 #: striped/striped.c:227 zero/zero.c:109 #, c-format msgid "Initialised segtype: %s" msgstr "" #: filters/filter-composite.c:31 #, c-format msgid "Using %s" msgstr "" #: filters/filter-composite.c:59 msgid "composite filters allocation failed" msgstr "" #: filters/filter-composite.c:67 msgid "compsoite filters allocation failed" msgstr "" #: filters/filter-md.c:31 #, c-format msgid "%s: Skipping md component device" msgstr "" #: filters/filter-md.c:36 #, c-format msgid "%s: Skipping: error in md component detection" msgstr "" #: filters/filter-md.c:54 msgid "md filter allocation failed" msgstr "" #: filters/filter-persistent.c:57 msgid "Wiping cache of LVM-capable devices" msgstr "" #: filters/filter-persistent.c:73 #, c-format msgid "Couldn't find %s array in '%s'" msgstr "" #: filters/filter-persistent.c:84 msgid "Devices array contains a value which is not a string ... ignoring" msgstr "" #: filters/filter-persistent.c:90 #, c-format msgid "Couldn't add '%s' to filter ... ignoring" msgstr "" #: filters/filter-persistent.c:108 #, c-format msgid "%s: stat failed: %s" msgstr "" #: filters/filter-persistent.c:132 #, c-format msgid "Loaded persistent filter cache from %s" msgstr "" #: filters/filter-persistent.c:183 #, c-format msgid "Internal persistent device cache empty - not writing to %s" msgstr "" #: filters/filter-persistent.c:188 #, c-format msgid "Device cache incomplete - not writing to %s" msgstr "" #: filters/filter-persistent.c:193 #, c-format msgid "Dumping persistent device cache to %s" msgstr "" #: filters/filter-persistent.c:248 format_text/format-text.c:902 #: format_text/format-text.c:928 format_text/format-text.c:965 #: misc/lvm-file.c:91 #, c-format msgid "%s: rename to %s failed: %s" msgstr "" #: filters/filter-persistent.c:276 #, c-format msgid "%s: Skipping (cached)" msgstr "" #: filters/filter-persistent.c:311 msgid "Couldn't create hash table for persistent filter." msgstr "" #: filters/filter-regex.c:44 msgid "pattern must begin with 'a' or 'r'" msgstr "" #: filters/filter-regex.c:83 msgid "invalid separator at end of regex" msgstr "" #: filters/filter-regex.c:108 msgid "filter patterns must be enclosed in quotes" msgstr "" #: filters/filter-regex.c:133 msgid "invalid filter pattern" msgstr "" #: filters/filter-regex.c:174 #, c-format msgid "%s: Skipping (regex)" msgstr "" #: filters/filter-sysfs.c:31 msgid "No proc filesystem found: skipping sysfs filter" msgstr "" #: filters/filter-sysfs.c:37 msgid "Failed to create /proc/mounts string" msgstr "" #: filters/filter-sysfs.c:137 #, c-format msgid "Empty sysfs device file: %s" msgstr "" #: filters/filter-sysfs.c:142 msgid "sysfs device file not correct format" msgstr "" #: filters/filter-sysfs.c:192 #, c-format msgid "sysfs path name too long: %s in %s" msgstr "" #: filters/filter-sysfs.c:255 #, c-format msgid "%s: Skipping (sysfs)" msgstr "" #: filters/filter-sysfs.c:278 msgid "sysfs pool creation failed" msgstr "" #: filters/filter-sysfs.c:283 msgid "sysfs dev_set creation failed" msgstr "" #: filters/filter.c:90 #, c-format msgid "%s: Skipping: Unrecognised LVM device type %lu" msgstr "" #: filters/filter.c:98 #, c-format msgid "%s: Skipping: Suspended dm device" msgstr "" #: filters/filter.c:104 #, c-format msgid "%s: Skipping: open failed" msgstr "" #: filters/filter.c:110 #, c-format msgid "%s: Skipping: dev_get_size failed" msgstr "" #: filters/filter.c:115 #, c-format msgid "%s: Skipping: Too small to hold a PV" msgstr "" #: filters/filter.c:120 #, c-format msgid "%s: Skipping: Partition table signature found" msgstr "" #: filters/filter.c:147 msgid "No proc filesystem found: using all block device types" msgstr "" #: filters/filter.c:159 msgid "Failed to create /proc/devices string" msgstr "" #: filters/filter.c:218 msgid "Expecting string in devices/types in config file" msgstr "" #: filters/filter.c:228 #, c-format msgid "Max partition count missing for %s in devices/types in config file" msgstr "" #: filters/filter.c:236 #, c-format msgid "Zero partition count invalid for %s in devices/types in config file" msgstr "" #: filters/filter.c:269 msgid "LVM type filter allocation failed" msgstr "" #: format1/disk-rep.c:190 #, c-format msgid "%s does not have a valid LVM1 PV identifier" msgstr "" #: format1/disk-rep.c:196 #, c-format msgid "format1: Unknown metadata version %d found on %s" msgstr "" #: format1/disk-rep.c:210 format_pool/disk_rep.c:43 #, c-format msgid "Failed to read PV data from %s" msgstr "" #: format1/disk-rep.c:367 #, c-format msgid "%s is not a member of any format1 VG" msgstr "" #: format1/disk-rep.c:374 #, c-format msgid "Failed to read VG data from PV (%s)" msgstr "" #: format1/disk-rep.c:380 #, c-format msgid "%s is not a member of the VG %s" msgstr "" #: format1/disk-rep.c:390 #, c-format msgid "Failed to read PV uuid list from %s" msgstr "" #: format1/disk-rep.c:395 #, c-format msgid "Failed to read LV's from %s" msgstr "" #: format1/disk-rep.c:400 #, c-format msgid "Failed to read extents from %s" msgstr "" #: format1/disk-rep.c:404 #, c-format msgid "Found %s in %sVG %s" msgstr "" #: format1/disk-rep.c:443 format_pool/disk_rep.c:67 #, c-format msgid "Ignoring duplicate PV %s on %s" msgstr "" #: format1/disk-rep.c:448 format_pool/disk_rep.c:72 #, c-format msgid "Duplicate PV %s - using md %s" msgstr "" #: format1/disk-rep.c:494 msgid "read_pvs_in_vg: dev_iter_create failed" msgstr "" #: format1/disk-rep.c:517 #, c-format msgid "Writing %s VG metadata to %s at %lu len %zu" msgstr "" #: format1/disk-rep.c:537 #, c-format msgid "Too many uuids to fit on %s" msgstr "" #: format1/disk-rep.c:542 #, c-format msgid "Writing %s uuidlist to %s at %lu len %d" msgstr "" #: format1/disk-rep.c:557 #, c-format msgid "Writing %s LV %s metadata to %s at %lu len %zu" msgstr "" #: format1/disk-rep.c:578 #, c-format msgid "Couldn't zero lv area on device '%s'" msgstr "" #: format1/disk-rep.c:586 #, c-format msgid "lv_number %d too large" msgstr "" #: format1/disk-rep.c:603 #, c-format msgid "Writing %s extents metadata to %s at %lu len %zu" msgstr "" #: format1/disk-rep.c:623 msgid "Invalid PV structure size." msgstr "" #: format1/disk-rep.c:632 msgid "Couldn't allocate temporary PV buffer." msgstr "" #: format1/disk-rep.c:639 #, c-format msgid "Writing %s PV metadata to %s at %lu len %zu" msgstr "" #: format1/disk-rep.c:662 #, c-format msgid "Failed to write PV structure onto %s" msgstr "" #: format1/disk-rep.c:681 #, c-format msgid "Failed to write VG data to %s" msgstr "" #: format1/disk-rep.c:686 #, c-format msgid "Failed to write PV uuid list to %s" msgstr "" #: format1/disk-rep.c:691 #, c-format msgid "Failed to write LV's to %s" msgstr "" #: format1/disk-rep.c:696 #, c-format msgid "Failed to write extents to %s" msgstr "" #: format1/disk-rep.c:736 #, c-format msgid "Successfully wrote data to %s" msgstr "" #: format1/format1.c:72 #, c-format msgid "VG data differs between PVs %s and %s" msgstr "" #: format1/format1.c:74 format1/format1.c:89 #, c-format msgid "VG data on %s: %s %s %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u" msgstr "" #: format1/format1.c:115 #, c-format msgid "%d PV(s) found for VG %s: expected %d" msgstr "" #: format1/format1.c:294 format_pool/format_pool.c:228 #, c-format msgid "Reading physical volume data %s from disk" msgstr "" #: format1/format1.c:335 #, c-format msgid "Physical volumes cannot be bigger than %s" msgstr "" #: format1/format1.c:355 msgid "Metadata would overwrite physical extents" msgstr "" #: format1/format1.c:370 #, c-format msgid "logical volumes cannot contain more than %d extents." msgstr "" #: format1/format1.c:375 #, c-format msgid "logical volumes cannot be larger than %s" msgstr "" #: format1/format1.c:451 #, c-format msgid "Extent size must be between %s and %s" msgstr "" #: format1/format1.c:459 #, c-format msgid "Extent size must be multiple of %s" msgstr "" #: format1/format1.c:466 format_text/format-text.c:79 msgid "Extent size must be power of 2" msgstr "" #: format1/format1.c:563 msgid "Couldn't create lvm1 label handler." msgstr "" #: format1/format1.c:568 msgid "Couldn't register lvm1 label handler." msgstr "" #: format1/format1.c:572 format_pool/format_pool.c:354 #: format_text/format-text.c:1994 #, c-format msgid "Initialised format: %s" msgstr "" #: format1/import-export.c:75 #, c-format msgid "System ID %s on %s differs from %s for volume group" msgstr "" #: format1/import-export.c:98 format_text/import_vsn1.c:220 #: metadata/metadata.c:569 metadata/metadata.c:1542 pvresize.c:121 #: vgreduce.c:395 vgremove.c:62 #, c-format msgid "%s: Couldn't get size." msgstr "" #: format1/import-export.c:101 format_text/import_vsn1.c:223 #, c-format msgid "Fixing up missing format1 size (%s) for PV %s" msgstr "" #: format1/import-export.c:108 format_text/import_vsn1.c:230 #, c-format msgid "WARNING: Physical Volume %s is too large for underlying device" msgstr "" #: format1/import-export.c:130 msgid "Generated system_id too long" msgstr "" #: format1/import-export.c:174 #, c-format msgid "Volume group name %s too long to export" msgstr "" #: format1/import-export.c:412 #, c-format msgid "Segment type %s in LV %s: unsupported by format1" msgstr "" #: format1/import-export.c:418 #, c-format msgid "Non-PV stripe found in LV %s: unsupported by format1" msgstr "" #: format1/import-export.c:610 msgid "Logical volume number out of bounds." msgstr "" #: format1/import-export.c:617 #, c-format msgid "Couldn't find logical volume '%s'." msgstr "" #: format1/import-export.c:637 #, c-format msgid "Couldn't find origin logical volume for snapshot '%s'." msgstr "" #: format1/import-export.c:650 msgid "Couldn't add snapshot." msgstr "" #: format1/import-extents.c:53 msgid "Unable to create hash table for holding extent maps." msgstr "" #: format1/import-extents.c:92 #, c-format msgid "Physical volume (%s) contains an unknown logical volume (%s)." msgstr "" #: format1/import-extents.c:137 #, c-format msgid "Invalid LV in extent map (PV %s, PE %u, LV %u, LE %u)" msgstr "" #: format1/import-extents.c:149 msgid "logical extent number out of bounds" msgstr "" #: format1/import-extents.c:155 #, c-format msgid "logical extent (%u) already mapped." msgstr "" #: format1/import-extents.c:175 #, c-format msgid "Logical volume (%s) contains an incomplete mapping table." msgstr "" #: format1/import-extents.c:229 msgid "Failed to allocate linear segment." msgstr "" #: format1/import-extents.c:276 #, c-format msgid "" "Number of stripes (%u) incompatible with logical extent count (%u) for %s" msgstr "" #: format1/import-extents.c:303 msgid "Failed to allocate striped segment." msgstr "" #: format1/import-extents.c:359 msgid "Couldn't allocate logical volume maps." msgstr "" #: format1/import-extents.c:364 msgid "Couldn't fill logical volume maps." msgstr "" #: format1/import-extents.c:374 msgid "Couldn't build extent segments." msgstr "" #: format1/layout.c:79 #, c-format msgid "MaxLogicalVolumes of %d exceeds format limit of %d for VG '%s'" msgstr "" #: format1/layout.c:86 #, c-format msgid "MaxPhysicalVolumes of %d exceeds format limit of %d for VG '%s'" msgstr "" #: format1/layout.c:105 msgid "Insufficient space for metadata and PE's." msgstr "" #: format1/layout.c:141 #, c-format msgid "Too few extents on %s. Try smaller extent size." msgstr "" #: format1/layout.c:162 #, c-format msgid "Metadata extent limit (%u) exceeded for %s - %u required" msgstr "" #: format1/lvm1-label.c:29 #, c-format msgid "The '%s' operation is not supported for the lvm1 labeller." msgstr "" #: format1/lvm1-label.c:120 format_pool/pool_label.c:99 #: format_text/text_label.c:285 msgid "Couldn't allocate labeller object." msgstr "" #: format_pool/disk_rep.c:94 format_pool/disk_rep.c:98 #, c-format msgid "Calculated uuid %s for %s" msgstr "" #: format_pool/disk_rep.c:274 #, c-format msgid "Unable to allocate %d 32-bit uints" msgstr "" #: format_pool/disk_rep.c:341 #, c-format msgid "No devices for vg %s found in cache" msgstr "" #: format_pool/disk_rep.c:363 msgid "Unable to allocate pool list structure" msgstr "" #: format_pool/format_pool.c:44 #, c-format msgid "Unable to allocate %d subpool structures" msgstr "" #: format_pool/format_pool.c:64 #, c-format msgid "Unable to allocate %d pool_device structures" msgstr "" #: format_pool/format_pool.c:87 #, c-format msgid "Missing subpool %d in pool %s" msgstr "" #: format_pool/format_pool.c:92 #, c-format msgid "Missing device %u for subpool %d in pool %s" msgstr "" #: format_pool/format_pool.c:113 msgid "Unable to allocate volume group structure" msgstr "" #: format_pool/format_pool.c:279 msgid "Unable to allocate format instance structure for pool format" msgstr "" #: format_pool/format_pool.c:289 msgid "Unable to allocate metadata area structure for pool format" msgstr "" #: format_pool/format_pool.c:332 msgid "Unable to allocate format type structure for pool format" msgstr "" #: format_pool/format_pool.c:345 msgid "Couldn't create pool label handler." msgstr "" #: format_pool/format_pool.c:350 msgid "Couldn't register pool label handler." msgstr "" #: format_pool/import_export.c:64 msgid "Unable to allocate lv list structure" msgstr "" #: format_pool/import_export.c:69 msgid "Unable to allocate logical volume structure" msgstr "" #: format_pool/import_export.c:98 #, c-format msgid "Calculated lv uuid for lv %s: %s" msgstr "" #: format_pool/import_export.c:133 msgid "Unable to allocate pv list structure" msgstr "" #: format_pool/import_export.c:137 msgid "Unable to allocate pv structure" msgstr "" #: format_pool/import_export.c:165 msgid "Unable to duplicate vg_name string" msgstr "" #: format_pool/import_export.c:195 #, c-format msgid "Found sptype %X and converted it to %s" msgstr "" #: format_pool/import_export.c:210 msgid "Stripe size must be a power of 2" msgstr "" #: format_pool/import_export.c:226 msgid "Unable to allocate striped lv_segment structure" msgstr "" #: format_pool/import_export.c:267 msgid "Unable to allocate linear lv_segment structure" msgstr "" #: format_pool/pool_label.c:28 #, c-format msgid "The '%s' operation is not supported for the pool labeller." msgstr "" #: format_text/archive.c:146 #, c-format msgid "Couldn't scan the archive directory (%s)." msgstr "" #: format_text/archive.c:173 msgid "Couldn't create new archive file." msgstr "" #: format_text/archive.c:221 #, c-format msgid "Expiring archive %s" msgstr "" #: format_text/archive.c:246 msgid "Couldn't create temporary archive name." msgstr "" #: format_text/archive.c:251 msgid "Couldn't create FILE object for archive." msgstr "" #: format_text/archive.c:288 msgid "Archive file name too long." msgstr "" #: format_text/archive.c:299 #, c-format msgid "Archive rename failed for %s" msgstr "" #: format_text/archive.c:316 #, c-format msgid "File:\t\t%s" msgstr "" #: format_text/archive.c:321 msgid "Couldn't create text instance object." msgstr "" #: format_text/archive.c:331 msgid "Unable to read archive file." msgstr "" #: format_text/archive.c:336 #, c-format msgid "VG name: \t%s" msgstr "" #: format_text/archive.c:337 #, c-format msgid "Description:\t%s" msgstr "" #: format_text/archive.c:338 #, c-format msgid "Backup Time:\t%s" msgstr "" #: format_text/archive.c:355 #, c-format msgid "No archives found in %s." msgstr "" #: format_text/archiver.c:43 format_text/archiver.c:155 msgid "archive_params alloc failed" msgstr "" #: format_text/archiver.c:128 #, c-format msgid "Archiving volume group \"%s\" metadata (seqno %u)." msgstr "" #: format_text/archiver.c:303 #, c-format msgid "PV %s is a different format (seqno %s)" msgstr "" #: format_text/archiver.c:364 #, c-format msgid "Creating volume group backup \"%s\" (seqno %u)." msgstr "" #: format_text/archiver.c:402 msgid "Failed to generate backup filename." msgstr "" #: format_text/export.c:80 #, c-format msgid "uname failed: %s" msgstr "" #: format_text/export.c:101 msgid "Internal error tracking indentation" msgstr "" #: format_text/export.c:120 #, c-format msgid "Doubling metadata output buffer to %u" msgstr "" #: format_text/export.c:124 msgid "Buffer reallocation failed." msgstr "" #: format_text/export.c:737 msgid "text_export buffer allocation failed" msgstr "" #: format_text/flags.c:79 msgid "Unknown flag set requested." msgstr "" #: format_text/flags.c:125 msgid "Metadata inconsistency: Not all flags successfully exported." msgstr "" #: format_text/flags.c:147 msgid "Status value is not a string." msgstr "" #: format_text/flags.c:158 #, c-format msgid "Unknown status flag '%s'." msgstr "" #: format_text/format-text.c:152 #, c-format msgid "Found text metadata area, offset=%lu, size=%lu" msgstr "" #: format_text/format-text.c:207 #, c-format msgid "" "Found LVM2 metadata record at offset=%lu, size=%lu, offset2=%lu size2=%lu" msgstr "" #: format_text/format-text.c:259 #, c-format msgid "Random lvid creation failed for %s/%s." msgstr "" #: format_text/format-text.c:290 msgid "struct mda_header allocation failed" msgstr "" #: format_text/format-text.c:302 msgid "Incorrect metadata area header checksum" msgstr "" #: format_text/format-text.c:309 msgid "Wrong magic number in metadata area header" msgstr "" #: format_text/format-text.c:314 #, c-format msgid "Incompatible metadata area header version: %d" msgstr "" #: format_text/format-text.c:320 #, c-format msgid "Incorrect start sector in metadata area header: %lu" msgstr "" #: format_text/format-text.c:461 #, c-format msgid "VG %s not found on %s" msgstr "" #: format_text/format-text.c:469 format_text/format-text.c:574 #, c-format msgid "VG %s metadata too large for circular buffer" msgstr "" #: format_text/format-text.c:484 #, c-format msgid "Read %s %smetadata (%u) from %s at %lu size %lu" msgstr "" #: format_text/format-text.c:557 #, c-format msgid "VG %s metadata writing failed" msgstr "" #: format_text/format-text.c:579 #, c-format msgid "Writing %s metadata to %s at %lu len %lu" msgstr "" #: format_text/format-text.c:592 #, c-format msgid "Writing metadata to %s at %lu len %u" msgstr "" #: format_text/format-text.c:681 #, c-format msgid "%sCommitting %s metadata (%u) to %s header at %lu" msgstr "" #: format_text/format-text.c:685 #, c-format msgid "Wiping pre-committed %s metadata from %s header at %lu" msgstr "" #: format_text/format-text.c:691 format_text/format-text.c:777 msgid "Failed to write metadata area header" msgstr "" #: format_text/format-text.c:810 #, c-format msgid "'%s' does not contain volume group '%s'." msgstr "" #: format_text/format-text.c:814 #, c-format msgid "Read volume group %s from %s" msgstr "" #: format_text/format-text.c:863 msgid "Text format failed to determine directory." msgstr "" #: format_text/format-text.c:868 msgid "Couldn't create temporary text file name." msgstr "" #: format_text/format-text.c:879 #, c-format msgid "Writing %s metadata to %s" msgstr "" #: format_text/format-text.c:882 #, c-format msgid "Failed to write metadata to %s." msgstr "" #: format_text/format-text.c:901 format_text/format-text.c:926 #: format_text/format-text.c:960 #, c-format msgid "Renaming %s to %s" msgstr "" #: format_text/format-text.c:917 #, c-format msgid "Test mode: Skipping committing %s metadata (%u)" msgstr "" #: format_text/format-text.c:920 #, c-format msgid "Unlinking %s" msgstr "" #: format_text/format-text.c:925 #, c-format msgid "Committing %s metadata (%u)" msgstr "" #: format_text/format-text.c:962 msgid "Test mode: Skipping rename" msgstr "" #: format_text/format-text.c:1025 format_text/format-text.c:1723 #, c-format msgid "Name too long %s/%s" msgstr "" #: format_text/format-text.c:1089 #, c-format msgid "%s: metadata too large for circular buffer" msgstr "" #: format_text/format-text.c:1118 #, c-format msgid "%s: Found metadata at %lu size %lu for %s (%s)" msgstr "" #: format_text/format-text.c:1186 #, c-format msgid "Physical extents end beyond end of device %s!" msgstr "" #: format_text/format-text.c:1207 #, c-format msgid "Warning: metadata area fills disk leaving no space for data on %s." msgstr "" #: format_text/format-text.c:1238 format_text/format-text.c:1283 msgid "Failed to wipe new metadata area" msgstr "" #: format_text/format-text.c:1329 #, c-format msgid "Creating metadata area on %s at sector %lu size %lu sectors" msgstr "" #: format_text/format-text.c:1410 msgid "_add_raw allocation failed" msgstr "" #: format_text/format-text.c:1470 #, c-format msgid "Must be exactly one data area (found %d) on PV %s" msgstr "" #: format_text/format-text.c:1485 format_text/format-text.c:1489 msgid "metadata_area allocation failed" msgstr "" #: format_text/format-text.c:1650 #, c-format msgid "PV %s too large for extent size %s." msgstr "" #: format_text/format-text.c:1693 msgid "Couldn't allocate format instance object." msgstr "" #: format_text/format-text.c:1699 msgid "Couldn't allocate text_fid_context." msgstr "" #: format_text/format-text.c:1807 #, c-format msgid "%s: Volume group filename may not end in .tmp" msgstr "" #: format_text/format-text.c:1841 msgid "Couldn't allocate text format context object." msgstr "" #: format_text/format-text.c:1863 msgid "_add_dir allocation failed" msgstr "" #: format_text/format-text.c:1866 #, c-format msgid "Adding text format metadata dir: %s" msgstr "" #: format_text/format-text.c:1883 msgid "Empty metadata disk_area section of config file" msgstr "" #: format_text/format-text.c:1888 msgid "Missing start_sector in metadata disk_area section of config file" msgstr "" #: format_text/format-text.c:1895 msgid "Missing size in metadata disk_area section of config file" msgstr "" #: format_text/format-text.c:1902 msgid "Missing uuid in metadata disk_area section of config file" msgstr "" #: format_text/format-text.c:1908 #, c-format msgid "Invalid uuid in metadata disk_area section of config file: %s" msgstr "" #: format_text/format-text.c:1917 format_text/import_vsn1.c:155 msgid "Couldn't find device." msgstr "" #: format_text/format-text.c:1919 format_text/import_vsn1.c:157 #, c-format msgid "Couldn't find device with uuid '%s'." msgstr "" #: format_text/format-text.c:1948 msgid "Failed to allocate dir_list" msgstr "" #: format_text/format-text.c:1960 msgid "Couldn't create text label handler." msgstr "" #: format_text/format-text.c:1966 msgid "Couldn't register text label handler." msgstr "" #: format_text/format-text.c:1974 msgid "Invalid string in config file: metadata/dirs" msgstr "" #: format_text/import.c:103 msgid "Couldn't read volume group metadata." msgstr "" #: format_text/import_vsn1.c:46 #, c-format msgid "Can't process text format file - %s." msgstr "" #: format_text/import_vsn1.c:94 msgid "Couldn't find uuid." msgstr "" #: format_text/import_vsn1.c:100 msgid "uuid must be a string." msgstr "" #: format_text/import_vsn1.c:105 msgid "Invalid uuid." msgstr "" #: format_text/import_vsn1.c:139 msgid "Empty pv section." msgstr "" #: format_text/import_vsn1.c:144 msgid "Couldn't read uuid for volume group." msgstr "" #: format_text/import_vsn1.c:174 msgid "Couldn't find status flags for physical volume." msgstr "" #: format_text/import_vsn1.c:179 msgid "Couldn't read status flags for physical volume." msgstr "" #: format_text/import_vsn1.c:187 msgid "Couldn't read extent size for volume group." msgstr "" #: format_text/import_vsn1.c:192 msgid "Couldn't find extent count (pe_count) for physical volume." msgstr "" #: format_text/import_vsn1.c:203 #, c-format msgid "Couldn't read tags for physical volume %s in %s." msgstr "" #: format_text/import_vsn1.c:275 msgid "Empty segment section." msgstr "" #: format_text/import_vsn1.c:280 #, c-format msgid "Couldn't read 'start_extent' for segment '%s'." msgstr "" #: format_text/import_vsn1.c:286 #, c-format msgid "Couldn't read 'extent_count' for segment '%s'." msgstr "" #: format_text/import_vsn1.c:296 msgid "Segment type must be a string." msgstr "" #: format_text/import_vsn1.c:316 msgid "Segment allocation failed" msgstr "" #: format_text/import_vsn1.c:329 #, c-format msgid "Couldn't read tags for a segment of %s/%s." msgstr "" #: format_text/import_vsn1.c:358 #, c-format msgid "Zero areas not allowed for segment '%s'" msgstr "" #: format_text/import_vsn1.c:394 #, c-format msgid "Couldn't find volume '%s' for segment '%s'." msgstr "" #: format_text/import_vsn1.c:407 #, c-format msgid "Incorrect number of areas in area array for segment '%s'." msgstr "" #: format_text/import_vsn1.c:437 msgid "Only one segment permitted for snapshot" msgstr "" #: format_text/import_vsn1.c:443 msgid "Couldn't read segment count for logical volume." msgstr "" #: format_text/import_vsn1.c:448 msgid "segment_count and actual number of segments disagree." msgstr "" #: format_text/import_vsn1.c:494 format_text/import_vsn1.c:562 msgid "Empty logical volume section." msgstr "" #: format_text/import_vsn1.c:499 msgid "Couldn't find status flags for logical volume." msgstr "" #: format_text/import_vsn1.c:504 msgid "Couldn't read status flags for logical volume." msgstr "" #: format_text/import_vsn1.c:512 format_text/import_vsn1.c:729 msgid "allocation_policy must be a string." msgstr "" #: format_text/import_vsn1.c:535 #, c-format msgid "Couldn't read tags for logical volume %s/%s." msgstr "" #: format_text/import_vsn1.c:555 #, c-format msgid "Lost logical volume reference %s" msgstr "" #: format_text/import_vsn1.c:568 #, c-format msgid "Couldn't read uuid for logical volume %s." msgstr "" #: format_text/import_vsn1.c:595 #, c-format msgid "Couldn't read minor number for logical volume %s." msgstr "" #: format_text/import_vsn1.c:603 #, c-format msgid "Couldn't read major number for logical volume %s." msgstr "" #: format_text/import_vsn1.c:620 #, c-format msgid "Couldn't find section '%s'." msgstr "" #: format_text/import_vsn1.c:649 format_text/import_vsn1.c:841 msgid "Couldn't find volume group in file." msgstr "" #: format_text/import_vsn1.c:673 msgid "system_id must be a string" msgstr "" #: format_text/import_vsn1.c:680 format_text/import_vsn1.c:851 #, c-format msgid "Couldn't read uuid for volume group %s." msgstr "" #: format_text/import_vsn1.c:685 #, c-format msgid "Couldn't read 'seqno' for volume group %s." msgstr "" #: format_text/import_vsn1.c:691 format_text/import_vsn1.c:856 #, c-format msgid "Couldn't find status flags for volume group %s." msgstr "" #: format_text/import_vsn1.c:697 format_text/import_vsn1.c:862 #, c-format msgid "Couldn't read status flags for volume group %s." msgstr "" #: format_text/import_vsn1.c:703 #, c-format msgid "Couldn't read extent size for volume group %s." msgstr "" #: format_text/import_vsn1.c:714 #, c-format msgid "Couldn't read 'max_lv' for volume group %s." msgstr "" #: format_text/import_vsn1.c:720 #, c-format msgid "Couldn't read 'max_pv' for volume group %s." msgstr "" #: format_text/import_vsn1.c:745 msgid "Couldn't create hash table." msgstr "" #: format_text/import_vsn1.c:752 #, c-format msgid "Couldn't find all physical volumes for volume group %s." msgstr "" #: format_text/import_vsn1.c:763 #, c-format msgid "Couldn't read tags for volume group %s." msgstr "" #: format_text/import_vsn1.c:769 #, c-format msgid "Couldn't read all logical volume names for volume group %s." msgstr "" #: format_text/import_vsn1.c:776 #, c-format msgid "Couldn't read all logical volumes for volume group %s." msgstr "" #: format_text/import_vsn1.c:782 #, c-format msgid "Failed to fixup mirror pointers after import for volume group %s." msgstr "" #: format_text/tags.c:62 msgid "Found a tag that is not a string" msgstr "" #: format_text/text_label.c:98 format_text/text_label.c:103 msgid "struct data_area_list allocation failed" msgstr "" #: format_text/text_label.c:138 format_text/text_label.c:149 msgid "struct mda_list allocation failed" msgstr "" #: format_text/text_label.c:143 format_text/text_label.c:154 msgid "struct mda_context allocation failed" msgstr "" #: label/label.c:49 msgid "Couldn't allocate memory for labeller list object." msgstr "" #: label/label.c:123 label/label.c:218 #, c-format msgid "%s: Failed to read label area" msgstr "" #: label/label.c:135 label/label.c:164 #, c-format msgid "Ignoring additional label on %s at sector %lu" msgstr "" #: label/label.c:140 #, c-format msgid "%s: Label for sector %lu found at sector %lu - ignoring" msgstr "" #: label/label.c:150 #, c-format msgid "Label checksum incorrect on %s - ignoring" msgstr "" #: label/label.c:161 #, c-format msgid "%s: %s label detected" msgstr "" #: label/label.c:185 #, c-format msgid "%s: No label detected" msgstr "" #: label/label.c:204 #, c-format msgid "Scanning for labels to wipe from %s" msgstr "" #: label/label.c:244 #, c-format msgid "%s: Wiping label at sector %lu" msgstr "" #: label/label.c:248 #, c-format msgid "Failed to remove label from %s at sector %lu" msgstr "" #: label/label.c:304 msgid "Label handler does not support label writes" msgstr "" #: label/label.c:309 #, c-format msgid "Label sector %lu beyond range (%ld)" msgstr "" #: label/label.c:333 #, c-format msgid "%s: Writing label to sector %lu" msgstr "" #: label/label.c:336 #, c-format msgid "Failed to write label to %s" msgstr "" #: label/label.c:386 msgid "label allocaction failed" msgstr "" #: locking/cluster_locking.c:69 #, c-format msgid "Local socket creation failed: %s" msgstr "" #: locking/cluster_locking.c:82 #, c-format msgid "connect() failed on local socket: %s" msgstr "" #: locking/cluster_locking.c:109 #, c-format msgid "Error writing data to clvmd: %s" msgstr "" #: locking/cluster_locking.c:118 #, c-format msgid "Error reading data from clvmd: %s" msgstr "" #: locking/cluster_locking.c:123 msgid "EOF reading CLVMD" msgstr "" #: locking/cluster_locking.c:156 #, c-format msgid "cluster request failed: %s" msgstr "" #: locking/cluster_locking.c:346 #, c-format msgid "clvmd not running on node %s" msgstr "" #: locking/cluster_locking.c:351 #, c-format msgid "Error locking on node %s: %s" msgstr "" #: locking/cluster_locking.c:402 locking/file_locking.c:266 #: locking/locking.c:265 locking/no_locking.c:71 #, c-format msgid "Unrecognised lock scope: %d" msgstr "" #: locking/cluster_locking.c:408 #, c-format msgid "Locking %s at 0x%x" msgstr "" #: locking/external_locking.c:64 msgid "External locking already initialised" msgstr "" #: locking/external_locking.c:86 #, c-format msgid "Shared library %s does not contain locking functions" msgstr "" #: locking/external_locking.c:93 #, c-format msgid "Loaded external locking library %s" msgstr "" #: locking/file_locking.c:59 #, c-format msgid "Unlocking %s" msgstr "" #: locking/file_locking.c:111 msgid "CTRL-c detected: giving up waiting for lock" msgstr "" #: locking/file_locking.c:149 #, c-format msgid "Unrecognised lock type: %d" msgstr "" #: locking/file_locking.c:163 #, c-format msgid "Locking %s %c%c" msgstr "" #: locking/file_locking.c:237 #, c-format msgid "Unlocking LV %s" msgstr "" #: locking/file_locking.c:242 #, c-format msgid "Locking LV %s (NL)" msgstr "" #: locking/file_locking.c:247 #, c-format msgid "Locking LV %s (R)" msgstr "" #: locking/file_locking.c:252 #, c-format msgid "Locking LV %s (W)" msgstr "" #: locking/file_locking.c:257 #, c-format msgid "Locking LV %s (EX)" msgstr "" #: locking/locking.c:133 msgid "" "WARNING: Locking disabled. Be careful! This could corrupt your metadata." msgstr "" #: locking/locking.c:138 msgid "File-based locking selected." msgstr "" #: locking/locking.c:146 msgid "External locking selected." msgstr "" #: locking/locking.c:156 msgid "Falling back to internal clustered locking." msgstr "" #: locking/locking.c:160 msgid "Cluster locking selected." msgstr "" #: locking/locking.c:167 msgid "Unknown locking type requested." msgstr "" #: locking/locking.c:174 msgid "WARNING: Falling back to local file-based locking." msgstr "" #: locking/locking.c:175 msgid "Volume Groups with the clustered attribute will be inaccessible." msgstr "" #: locking/locking.c:185 msgid "Locking disabled - only read operations permitted." msgstr "" #: locking/locking.c:212 #, c-format msgid "LVM1 proc VG pathname too long for %s" msgstr "" #: locking/locking.c:217 #, c-format msgid "%s exists: Is the original LVM driver using this volume group?" msgstr "" #: locking/locking.c:302 lvresize.c:573 #, c-format msgid "Failed to suspend %s" msgstr "" #: locking/locking.c:323 #, c-format msgid "Failed to activate %s" msgstr "" #: log/log.c:145 msgid "Test mode: Metadata will NOT be updated." msgstr "" #: lvchange.c:27 #, c-format msgid "Logical volume \"%s\" is already writable" msgstr "" #: lvchange.c:33 #, c-format msgid "Logical volume \"%s\" is already read only" msgstr "" #: lvchange.c:40 #, c-format msgid "Cannot change permissions of mirror \"%s\" while active." msgstr "" #: lvchange.c:47 #, c-format msgid "Setting logical volume \"%s\" read/write" msgstr "" #: lvchange.c:51 #, c-format msgid "Setting logical volume \"%s\" read-only" msgstr "" #: lvchange.c:55 lvchange.c:314 lvchange.c:350 lvchange.c:393 lvchange.c:470 #: lvchange.c:524 lvconvert.c:401 #, c-format msgid "Updating logical volume \"%s\" on disk(s)" msgstr "" #: lvchange.c:64 lvchange.c:402 lvconvert.c:409 metadata/mirror.c:227 #, c-format msgid "Failed to lock %s" msgstr "" #: lvchange.c:74 lvchange.c:412 #, c-format msgid "Updating permissions for \"%s\" in kernel" msgstr "" #: lvchange.c:76 lvchange.c:414 lvconvert.c:422 lvresize.c:585 #: metadata/mirror.c:240 #, c-format msgid "Problem reactivating %s" msgstr "" #: lvchange.c:89 #, c-format msgid "Logical volume, %s, is not active" msgstr "" #: lvchange.c:113 #, c-format msgid "Deactivating logical volume \"%s\" locally" msgstr "" #: lvchange.c:120 #, c-format msgid "Deactivating logical volume \"%s\"" msgstr "" #: lvchange.c:127 #, c-format msgid "Locking failed: ignoring clustered logical volume %s" msgstr "" #: lvchange.c:133 #, c-format msgid "Activating logical volume \"%s\" exclusively" msgstr "" #: lvchange.c:140 #, c-format msgid "Activating logical volume \"%s\" locally" msgstr "" #: lvchange.c:147 #, c-format msgid "Activating logical volume \"%s\"" msgstr "" #: lvchange.c:157 #, c-format msgid "Spawning background pvmove process for %s" msgstr "" #: lvchange.c:168 #, c-format msgid "Refreshing logical volume \"%s\" (if active)" msgstr "" #: lvchange.c:183 #, c-format msgid "Unable to resync %s because it is not mirrored." msgstr "" #: lvchange.c:189 #, c-format msgid "Unable to resync pvmove volume %s" msgstr "" #: lvchange.c:194 #, c-format msgid "Unable to resync locked volume %s" msgstr "" #: lvchange.c:200 #, c-format msgid "Can't resync open logical volume \"%s\"" msgstr "" #: lvchange.c:210 #, c-format msgid "Logical volume \"%s\" not resynced" msgstr "" #: lvchange.c:220 #, c-format msgid "Can't get exclusive access to clustered volume %s" msgstr "" #: lvchange.c:226 #, c-format msgid "Unable to deactivate %s for resync" msgstr "" #: lvchange.c:232 #, c-format msgid "Starting resync of %s%s%s mirror \"%s\"" msgstr "" #: lvchange.c:246 #, c-format msgid "Failed to reactivate %s to resynchronize mirror" msgstr "" #: lvchange.c:262 msgid "Failed to write intermediate VG metadata." msgstr "" #: lvchange.c:276 msgid "Failed to commit intermediate VG metadata." msgstr "" #: lvchange.c:288 #, c-format msgid "Unable to activate %s for mirror log resync" msgstr "" #: lvchange.c:293 #, c-format msgid "Clearing log device %s" msgstr "" #: lvchange.c:295 #, c-format msgid "Unable to reset sync status for %s" msgstr "" #: lvchange.c:297 msgid "Failed to deactivate log LV after wiping failed" msgstr "" #: lvchange.c:303 #, c-format msgid "Unable to deactivate log LV %s after wiping for resync" msgstr "" #: lvchange.c:316 msgid "Failed to update metadata on disk." msgstr "" #: lvchange.c:321 #, c-format msgid "Failed to reactivate %s after resync" msgstr "" #: lvchange.c:338 #, c-format msgid "Allocation policy of logical volume \"%s\" is already %s" msgstr "" #: lvchange.c:347 #, c-format msgid "Setting contiguous allocation policy for \"%s\" to %s" msgstr "" #: lvchange.c:383 #, c-format msgid "Read ahead is already %u for \"%s\"" msgstr "" #: lvchange.c:390 #, c-format msgid "Setting read ahead to %u for \"%s\"" msgstr "" #: lvchange.c:429 #, c-format msgid "Minor number is already not persistent for \"%s\"" msgstr "" #: lvchange.c:436 #, c-format msgid "Disabling persistent device number for \"%s\"" msgstr "" #: lvchange.c:440 msgid "Minor number must be specified with -My" msgstr "" #: lvchange.c:444 msgid "Major number must be specified with -My" msgstr "" #: lvchange.c:453 #, c-format msgid "%s device number not changed." msgstr "" #: lvchange.c:457 #, c-format msgid "Ensuring %s is inactive." msgstr "" #: lvchange.c:459 #, c-format msgid "%s: deactivation failed" msgstr "" #: lvchange.c:465 #, c-format msgid "Setting persistent device number to (%d, %d) for \"%s\"" msgstr "" #: lvchange.c:484 #, c-format msgid "Re-activating logical volume \"%s\"" msgstr "" #: lvchange.c:486 #, c-format msgid "%s: reactivation failed" msgstr "" #: lvchange.c:500 lvcreate.c:680 pvchange.c:49 vgchange.c:440 vgcreate.c:107 msgid "Failed to get tag" msgstr "" #: lvchange.c:505 #, c-format msgid "Logical volume %s/%s does not support tags" msgstr "" #: lvchange.c:512 lvcreate.c:746 #, c-format msgid "Failed to add tag %s to %s/%s" msgstr "" #: lvchange.c:518 #, c-format msgid "Failed to remove tag %s from %s/%s" msgstr "" #: lvchange.c:551 #, c-format msgid "Only -a permitted with read-only volume group \"%s\"" msgstr "" #: lvchange.c:560 #, c-format msgid "Can't change logical volume \"%s\" under snapshot" msgstr "" #: lvchange.c:566 #, c-format msgid "Can't change snapshot logical volume \"%s\"" msgstr "" #: lvchange.c:572 #, c-format msgid "Unable to change pvmove LV %s" msgstr "" #: lvchange.c:574 msgid "Use 'pvmove --abort' to abandon a pvmove" msgstr "" #: lvchange.c:579 #, c-format msgid "Unable to change mirror log LV %s directly" msgstr "" #: lvchange.c:584 #, c-format msgid "Unable to change mirror image LV %s directly" msgstr "" #: lvchange.c:590 #, c-format msgid "Unable to change internal LV %s directly" msgstr "" #: lvchange.c:648 #, c-format msgid "Logical volume \"%s\" changed" msgstr "" #: lvchange.c:683 msgid "" "Need 1 or more of -a, -C, -j, -m, -M, -p, -r, --resync, --refresh, --alloc, " "--addtag, --deltag or --monitor" msgstr "" #: lvchange.c:694 msgid "Only -a permitted with --ignorelockingfailure" msgstr "" #: lvchange.c:699 msgid "Please give logical volume path(s)" msgstr "" #: lvchange.c:705 msgid "--major and --minor require -My" msgstr "" #: lvchange.c:710 msgid "Only give one logical volume when specifying minor" msgstr "" #: lvchange.c:715 msgid "Only one of --alloc and --contiguous permitted" msgstr "" #: lvconvert.c:50 lvcreate.c:69 msgid "Please specify a logical volume to act as the snapshot origin." msgstr "" #: lvconvert.c:58 lvcreate.c:77 msgid "The origin name should include the volume group." msgstr "" #: lvconvert.c:69 msgid "Please provide logical volume path" msgstr "" #: lvconvert.c:79 lvrename.c:38 #, c-format msgid "Please use a single volume group name (\"%s\" or \"%s\")" msgstr "" #: lvconvert.c:88 lvrename.c:52 msgid "Please provide a valid volume group name" msgstr "" #: lvconvert.c:110 msgid "Exactly one of --mirrors or --snapshot arguments required." msgstr "" #: lvconvert.c:129 msgid "--regionsize is only available with mirrors" msgstr "" #: lvconvert.c:134 lvcreate.c:336 msgid "Negative chunk size is invalid" msgstr "" #: lvconvert.c:140 lvcreate.c:342 msgid "Chunk size must be a power of 2 in the range 4K to 512K" msgstr "" #: lvconvert.c:144 lvcreate.c:346 #, c-format msgid "Setting chunksize to %d sectors." msgstr "" #: lvconvert.c:156 msgid "--chunksize is only available with snapshots" msgstr "" #: lvconvert.c:162 msgid "--zero is only available with snapshots" msgstr "" #: lvconvert.c:174 lvcreate.c:253 msgid "Negative regionsize is invalid" msgstr "" #: lvconvert.c:184 lvcreate.c:262 msgid "Negative regionsize in configuration file is invalid" msgstr "" #: lvconvert.c:192 lvcreate.c:276 #, c-format msgid "Region size (%u) must be a multiple of machine memory page size (%d)" msgstr "" #: lvconvert.c:200 lvcreate.c:270 #, c-format msgid "Region size (%u) must be a power of 2" msgstr "" #: lvconvert.c:206 lvcreate.c:283 msgid "Non-zero region size must be supplied." msgstr "" #: lvconvert.c:216 lvcreate.c:390 metadata/mirror.c:566 #, c-format msgid "%s: Required device-mapper target(s) not detected in your kernel" msgstr "" #: lvconvert.c:249 #, c-format msgid "Logical volume %s only has %u mirrors." msgstr "" #: lvconvert.c:259 msgid "Mirror log region size cannot be changed on an existing mirror." msgstr "" #: lvconvert.c:266 #, c-format msgid "Logical volume %s is already not mirrored." msgstr "" #: lvconvert.c:277 #, c-format msgid "Logical volume %s has multiple mirror segments." msgstr "" #: lvconvert.c:287 lvconvert.c:320 msgid "Unable to determine mirror sync status." msgstr "" #: lvconvert.c:311 lvconvert.c:389 lvcreate.c:721 msgid "Failed to create mirror log." msgstr "" #: lvconvert.c:335 #, c-format msgid "Logical volume %s already has %u mirror(s)." msgstr "" #: lvconvert.c:346 msgid "Adding mirror images is not supported yet." msgstr "" #: lvconvert.c:363 msgid "Mirrors of striped volumes are not yet supported." msgstr "" #: lvconvert.c:419 metadata/mirror.c:237 #, c-format msgid "Updating \"%s\" in kernel" msgstr "" #: lvconvert.c:426 #, c-format msgid "Logical volume %s converted." msgstr "" #: lvconvert.c:438 lvcreate.c:608 #, c-format msgid "Couldn't find origin volume '%s'." msgstr "" #: lvconvert.c:443 #, c-format msgid "Unable to create a snapshot of a %s LV." msgstr "" #: lvconvert.c:450 lvcreate.c:799 #, c-format msgid "WARNING: \"%s\" not zeroed" msgstr "" #: lvconvert.c:452 msgid "Aborting. Failed to wipe snapshot exception store." msgstr "" #: lvconvert.c:458 #, c-format msgid "Couldn't deactivate LV %s." msgstr "" #: lvconvert.c:464 lvcreate.c:812 msgid "Couldn't create snapshot." msgstr "" #: lvconvert.c:475 lvcreate.c:821 #, c-format msgid "Failed to suspend origin %s" msgstr "" #: lvconvert.c:484 lvcreate.c:830 #, c-format msgid "Problem reactivating origin %s" msgstr "" #: lvconvert.c:488 #, c-format msgid "Logical volume %s converted to snapshot." msgstr "" #: lvconvert.c:499 #, c-format msgid "Cannot convert locked LV %s" msgstr "" #: lvconvert.c:504 #, c-format msgid "Can't convert logical volume \"%s\" under snapshot" msgstr "" #: lvconvert.c:510 #, c-format msgid "Can't convert snapshot logical volume \"%s\"" msgstr "" #: lvconvert.c:516 #, c-format msgid "Unable to convert pvmove LV %s" msgstr "" #: lvconvert.c:548 lvrename.c:100 vgrename.c:62 #, c-format msgid "Checking for existing volume group \"%s\"" msgstr "" #: lvconvert.c:551 lvcreate.c:863 lvrename.c:103 lvresize.c:613 pvchange.c:59 #: pvmove.c:59 pvresize.c:69 vgcreate.c:140 vgextend.c:53 vgmerge.c:34 #: vgmerge.c:65 vgreduce.c:476 vgrename.c:94 vgrename.c:133 vgsplit.c:240 #: vgsplit.c:277 #, c-format msgid "Can't get lock for %s" msgstr "" #: lvconvert.c:556 lvcreate.c:492 lvrename.c:108 pvmove.c:64 vgdisplay.c:24 #: vgmerge.c:39 vgmerge.c:72 vgreduce.c:482 vgsplit.c:245 #, c-format msgid "Volume group \"%s\" doesn't exist" msgstr "" #: lvconvert.c:562 lvcreate.c:498 lvrename.c:114 lvresize.c:146 pvchange.c:72 #: pvdisplay.c:41 pvmove.c:71 pvresize.c:83 reporter.c:76 reporter.c:124 #: toollib.c:363 toollib.c:383 toollib.c:490 toollib.c:741 vgextend.c:64 #: vgmerge.c:46 vgmerge.c:78 vgreduce.c:489 vgreduce.c:511 vgrename.c:107 #: vgsplit.c:252 #, c-format msgid "Skipping clustered volume group %s" msgstr "" #: lvconvert.c:567 lvcreate.c:503 lvrename.c:119 metadata/metadata.c:1377 #: polldaemon.c:195 pvchange.c:78 pvmove.c:76 pvresize.c:89 toollib.c:163 #: vgchange.c:534 vgck.c:34 vgconvert.c:54 vgextend.c:69 vgmerge.c:52 #: vgmerge.c:83 vgreduce.c:541 vgremove.c:35 vgrename.c:113 vgsplit.c:258 #, c-format msgid "Volume group \"%s\" is exported" msgstr "" #: lvconvert.c:572 lvcreate.c:508 lvremove.c:28 lvrename.c:124 pvchange.c:84 #: pvmove.c:82 pvresize.c:95 vgchange.c:529 vgconvert.c:49 vgexport.c:42 #: vgextend.c:74 vgmerge.c:58 vgmerge.c:88 vgreduce.c:547 vgrename.c:117 #: vgsplit.c:270 #, c-format msgid "Volume group \"%s\" is read-only" msgstr "" #: lvconvert.c:577 #, c-format msgid "Logical volume \"%s\" not found in volume group \"%s\"" msgstr "" #: lvcreate.c:93 lvresize.c:105 msgid "Please provide a volume group name" msgstr "" #: lvcreate.c:100 msgid "Volume group name expected (no slash)" msgstr "" #: lvcreate.c:115 #, c-format msgid "Inconsistent volume group names given: \"%s\" and \"%s\"" msgstr "" #: lvcreate.c:138 #, c-format msgid "Logical volume name \"%s\" is invalid" msgstr "" #: lvcreate.c:151 lvresize.c:65 msgid "Please specify either size or extents (not both)" msgstr "" #: lvcreate.c:157 msgid "Negative number of extents is invalid" msgstr "" #: lvcreate.c:167 msgid "Negative size is invalid" msgstr "" #: lvcreate.c:189 msgid "Negative stripesize is invalid" msgstr "" #: lvcreate.c:194 lvresize.c:192 #, c-format msgid "Stripe size cannot be larger than %s" msgstr "" #: lvcreate.c:202 msgid "Ignoring stripesize argument with single stripe" msgstr "" #: lvcreate.c:210 lvresize.c:330 #, c-format msgid "Using default stripesize %s" msgstr "" #: lvcreate.c:215 #, c-format msgid "Too few physical volumes on command line for %d-way striping" msgstr "" #: lvcreate.c:221 #, c-format msgid "Number of stripes (%d) must be between %d and %d" msgstr "" #: lvcreate.c:229 lvresize.c:407 #, c-format msgid "Invalid stripe size %s" msgstr "" #: lvcreate.c:246 #, c-format msgid "Too few physical volumes on command line for %d-way mirroring" msgstr "" #: lvcreate.c:309 msgid "Redundant stripes argument: default is 1" msgstr "" #: lvcreate.c:323 msgid "Redundant mirrors argument: default is 0" msgstr "" #: lvcreate.c:325 lvresize.c:180 msgid "Mirrors argument may not be negative" msgstr "" #: lvcreate.c:332 msgid "-Z is incompatible with snapshots" msgstr "" #: lvcreate.c:354 msgid "-c is only available with snapshots" msgstr "" #: lvcreate.c:361 msgid "mirrors and snapshots are currently incompatible" msgstr "" #: lvcreate.c:367 msgid "mirrors and stripes are currently incompatible" msgstr "" #: lvcreate.c:378 msgid "--corelog is only available with mirrors" msgstr "" #: lvcreate.c:383 msgid "--nosync is only available with mirrors" msgstr "" #: lvcreate.c:419 msgid "Conflicting contiguous and alloc arguments" msgstr "" #: lvcreate.c:448 msgid "Please specify minor number with --minor when using -My" msgstr "" #: lvcreate.c:453 msgid "Please specify major number with --major when using -My" msgstr "" #: lvcreate.c:459 msgid "--major and --minor incompatible with -Mn" msgstr "" #: lvcreate.c:489 pvmove.c:305 toollib.c:481 vgreduce.c:474 #, c-format msgid "Finding volume group \"%s\"" msgstr "" #: lvcreate.c:513 lvrename.c:129 #, c-format msgid "Logical volume \"%s\" already exists in volume group \"%s\"" msgstr "" #: lvcreate.c:519 msgid "Metadata does not support mirroring." msgstr "" #: lvcreate.c:536 #, c-format msgid "Reducing requested stripe size %s to maximum, physical extent size %s" msgstr "" #: lvcreate.c:547 #, c-format msgid "Stripe size may not exceed %s" msgstr "" #: lvcreate.c:559 lvresize.c:237 #, c-format msgid "Rounding up size to full physical extent %s" msgstr "" #: lvcreate.c:564 #, c-format msgid "Volume too large (%s) for extent size %s. Upper limit is %s." msgstr "" #: lvcreate.c:583 #, c-format msgid "Please express size as %%VG or %%FREE." msgstr "" #: lvcreate.c:590 #, c-format msgid "Rounding size (%d extents) up to stripe boundary size (%d extents)" msgstr "" #: lvcreate.c:598 msgid "Can't create snapshot without using device-mapper kernel driver" msgstr "" #: lvcreate.c:604 msgid "Clustered snapshots are not yet supported." msgstr "" #: lvcreate.c:613 msgid "Snapshots of snapshots are not supported yet." msgstr "" #: lvcreate.c:618 msgid "Snapshots of locked devices are not supported yet" msgstr "" #: lvcreate.c:625 msgid "Snapshots and mirrors may not yet be mixed." msgstr "" #: lvcreate.c:634 msgid "Unable to create new logical volume with no extents" msgstr "" #: lvcreate.c:640 #, c-format msgid "Insufficient free extents (%u) in volume group %s: %u required" msgstr "" #: lvcreate.c:646 #, c-format msgid "Number of stripes (%u) must not exceed number of physical volumes (%d)" msgstr "" #: lvcreate.c:653 msgid "Can't create mirror without using device-mapper kernel driver." msgstr "" #: lvcreate.c:672 msgid "Failed to generate LV name." msgstr "" #: lvcreate.c:685 vgchange.c:445 #, c-format msgid "Volume group %s does not support tags" msgstr "" #: lvcreate.c:709 msgid "" "WARNING: New mirror won't be synchronised. Don't read what you didn't write!" msgstr "" #: lvcreate.c:733 msgid "Setting read ahead sectors" msgstr "" #: lvcreate.c:741 #, c-format msgid "Setting device number to (%d, %d)" msgstr "" #: lvcreate.c:782 msgid "" "Aborting. Failed to activate snapshot exception store. Remove new LV and " "retry." msgstr "" #: lvcreate.c:787 msgid "Failed to activate new LV." msgstr "" #: lvcreate.c:794 msgid "" "Aborting. Failed to wipe snapshot exception store. Remove new LV and retry." msgstr "" #: lvcreate.c:837 #, c-format msgid "Logical volume \"%s\" created" msgstr "" #: lvdisplay.c:39 lvdisplay.c:48 pvdisplay.c:89 pvdisplay.c:99 vgdisplay.c:67 #: vgdisplay.c:76 msgid "Incompatible options selected" msgstr "" #: lvdisplay.c:53 msgid "Options -v and -c are incompatible" msgstr "" #: lvmchange.c:21 msgid "With LVM2 and the device mapper, this program is obsolete." msgstr "" #: lvmcmdline.c:289 msgid "Minor number outside range 0-255" msgstr "" #: lvmcmdline.c:304 msgid "Major number outside range 0-255" msgstr "" #: lvmcmdline.c:402 msgid "Couldn't allocate memory." msgstr "" #: lvmcmdline.c:451 msgid "Out of memory." msgstr "" #: lvmcmdline.c:504 #, c-format msgid "" "%s: %s\n" "\n" "%s" msgstr "" #: lvmcmdline.c:598 msgid "Unrecognised option." msgstr "" #: lvmcmdline.c:604 #, c-format msgid "Option%s%c%s%s may not be repeated" msgstr "" #: lvmcmdline.c:613 msgid "Option requires argument." msgstr "" #: lvmcmdline.c:620 #, c-format msgid "Invalid argument %s" msgstr "" #: lvmcmdline.c:639 #, c-format msgid "%s and %s are synonyms. Please only supply one." msgstr "" #: lvmcmdline.c:667 #, c-format msgid "LVM version: %s" msgstr "" #: lvmcmdline.c:669 #, c-format msgid "Library version: %s" msgstr "" #: lvmcmdline.c:671 #, c-format msgid "Driver version: %s" msgstr "" #: lvmcmdline.c:706 msgid "Partial mode. Incomplete volume groups will be activated read-only." msgstr "" #: lvmcmdline.c:729 msgid "--trustcache is incompatible with --all" msgstr "" #: lvmcmdline.c:733 msgid "" "WARNING: Cache file of PVs will be trusted. New devices holding PVs may get " "ignored." msgstr "" #: lvmcmdline.c:767 msgid "Available lvm commands:" msgstr "" #: lvmcmdline.c:768 msgid "Use 'lvm help ' for more information" msgstr "" #: lvmcmdline.c:774 #, c-format msgid "%-16.16s%s" msgstr "" #: lvmcmdline.c:794 msgid "Failed to set overridden configuration entries." msgstr "" #: lvmcmdline.c:858 msgid "Couldn't copy command line." msgstr "" #: lvmcmdline.c:871 #, c-format msgid "Parsing: %s" msgstr "" #: lvmcmdline.c:877 msgid "Error during parsing of command line." msgstr "" #: lvmcmdline.c:890 msgid "Updated config file invalid. Aborting." msgstr "" #: lvmcmdline.c:899 #, c-format msgid "Processing: %s" msgstr "" #: lvmcmdline.c:902 msgid "O_DIRECT will be used" msgstr "" #: lvmcmdline.c:915 #, c-format msgid "Locking type %d initialisation failed." msgstr "" #: lvmcmdline.c:927 msgid "Test mode: Wiping internal cache" msgstr "" #: lvmcmdline.c:951 #, c-format msgid "Completed: %s" msgstr "" #: lvmcmdline.c:1073 #, c-format msgid "Line too long (max 255) beginning: %s" msgstr "" #: lvmcmdline.c:1080 #, c-format msgid "Too many arguments: %s" msgstr "" #: lvmcmdline.c:1125 msgid "Failed to create LVM1 tool pathname" msgstr "" #: lvmcmdline.c:1173 msgid "Falling back to LVM1 tools, but no command specified." msgstr "" #: lvmcmdline.c:1189 msgid "Please supply an LVM command." msgstr "" #: lvmcmdline.c:1203 msgid "No such command. Try 'help'." msgstr "" #: lvmdiskscan.c:38 lvmdiskscan.c:108 msgid "dev_iter_create failed" msgstr "" #: lvmdiskscan.c:66 #, c-format msgid "%-*s [%15s] %s" msgstr "" #: lvmdiskscan.c:83 lvmdiskscan.c:117 #, c-format msgid "Couldn't get size of \"%s\"" msgstr "" #: lvmdiskscan.c:88 #, c-format msgid "dev_close on \"%s\" failed" msgstr "" #: lvmdiskscan.c:103 msgid "WARNING: only considering LVM devices" msgstr "" #: lvmdiskscan.c:137 #, c-format msgid "%d disk%s" msgstr "" #: lvmdiskscan.c:139 #, c-format msgid "%d partition%s" msgstr "" #: lvmdiskscan.c:142 #, c-format msgid "%d LVM physical volume whole disk%s" msgstr "" #: lvmdiskscan.c:144 #, c-format msgid "%d LVM physical volume%s" msgstr "" #: lvremove.c:33 #, c-format msgid "Can't remove logical volume \"%s\" under snapshot" msgstr "" #: lvremove.c:39 #, c-format msgid "Can't remove logical volume %s used by a mirror" msgstr "" #: lvremove.c:45 #, c-format msgid "Can't remove logical volume %s used as mirror log" msgstr "" #: lvremove.c:51 #, c-format msgid "Can't remove locked LV %s" msgstr "" #: lvremove.c:59 #, c-format msgid "Can't remove open logical volume \"%s\"" msgstr "" #: lvremove.c:68 #, c-format msgid "Logical volume \"%s\" not removed" msgstr "" #: lvremove.c:82 #, c-format msgid "Can't get exclusive access to volume \"%s\"" msgstr "" #: lvremove.c:90 #, c-format msgid "Unable to deactivate logical volume \"%s\"" msgstr "" #: lvremove.c:97 #, c-format msgid "Removing snapshot %s" msgstr "" #: lvremove.c:104 #, c-format msgid "Releasing logical volume \"%s\"" msgstr "" #: lvremove.c:106 #, c-format msgid "Error releasing logical volume \"%s\"" msgstr "" #: lvremove.c:122 #, c-format msgid "Failed to refresh %s without snapshot." msgstr "" #: lvremove.c:124 #, c-format msgid "Failed to resume %s." msgstr "" #: lvremove.c:127 #, c-format msgid "Logical volume \"%s\" successfully removed" msgstr "" #: lvremove.c:134 msgid "Please enter one or more logical volume paths" msgstr "" #: lvrename.c:47 msgid "Old and new logical volume names required" msgstr "" #: lvrename.c:59 #, c-format msgid "Logical volume names must have the same volume group (\"%s\" or \"%s\")" msgstr "" #: lvrename.c:74 #, c-format msgid "New logical volume path exceeds maximum length of %zu!" msgstr "" #: lvrename.c:80 msgid "New logical volume name may not be blank" msgstr "" #: lvrename.c:90 #, c-format msgid "New logical volume name \"%s\" is invalid" msgstr "" #: lvrename.c:96 msgid "Old and new logical volume names must differ" msgstr "" #: lvrename.c:135 #, c-format msgid "Existing logical volume \"%s\" not found in volume group \"%s\"" msgstr "" #: lvrename.c:143 #, c-format msgid "Cannot rename locked LV %s" msgstr "" #: lvrename.c:150 lvrename.c:158 #, c-format msgid "Mirrored LV, \"%s\" cannot be renamed: %s" msgstr "" #: lvrename.c:169 msgid "Failed to allocate space for new name" msgstr "" #: lvrename.c:173 vgmerge.c:223 vgrename.c:165 msgid "Writing out updated volume group" msgstr "" #: lvrename.c:197 #, c-format msgid "Renamed \"%s\" to \"%s\" in volume group \"%s\"" msgstr "" #: lvresize.c:83 msgid "Negative argument not permitted - use lvreduce" msgstr "" #: lvresize.c:88 msgid "Positive sign not permitted - use lvextend" msgstr "" #: lvresize.c:96 msgid "Please provide the logical volume name" msgstr "" #: lvresize.c:140 #, c-format msgid "Volume group %s doesn't exist" msgstr "" #: lvresize.c:151 #, c-format msgid "Volume group %s is exported" msgstr "" #: lvresize.c:156 #, c-format msgid "Volume group %s is read-only" msgstr "" #: lvresize.c:162 #, c-format msgid "Logical volume %s not found in volume group %s" msgstr "" #: lvresize.c:171 msgid "Varied striping not supported. Ignoring." msgstr "" #: lvresize.c:178 msgid "Mirrors not supported. Ignoring." msgstr "" #: lvresize.c:187 msgid "Stripesize may not be negative." msgstr "" #: lvresize.c:198 msgid "Varied stripesize not supported. Ignoring." msgstr "" #: lvresize.c:200 #, c-format msgid "Reducing stripe size %s to maximum, physical extent size %s" msgstr "" #: lvresize.c:211 msgid "Mirrors and striping cannot be combined yet." msgstr "" #: lvresize.c:215 msgid "Stripe size must be power of 2" msgstr "" #: lvresize.c:223 #, c-format msgid "Can't resize locked LV %s" msgstr "" #: lvresize.c:263 #, c-format msgid "Unable to reduce %s below 1 extent" msgstr "" #: lvresize.c:272 msgid "New size of 0 not permitted" msgstr "" #: lvresize.c:277 lvresize.c:414 #, c-format msgid "New size (%d extents) matches existing size (%d extents)" msgstr "" #: lvresize.c:291 #, c-format msgid "VolumeType does not match (%s)" msgstr "" #: lvresize.c:308 msgid "Please specify number of stripes (-i) and stripesize (-I)" msgstr "" #: lvresize.c:322 #, c-format msgid "Using stripesize of last segment %s" msgstr "" #: lvresize.c:346 #, c-format msgid "Extending %u mirror images." msgstr "" #: lvresize.c:352 msgid "Cannot vary number of mirrors in LV yet." msgstr "" #: lvresize.c:362 msgid "Ignoring stripes, stripesize and mirrors arguments when reducing" msgstr "" #: lvresize.c:391 msgid "Stripesize for striped segment should not be 0!" msgstr "" #: lvresize.c:400 #, c-format msgid "" "Rounding size (%d extents) down to stripe boundary size for segment (%d " "extents)" msgstr "" #: lvresize.c:421 #, c-format msgid "New size given (%d extents) not larger than existing size (%d extents)" msgstr "" #: lvresize.c:431 #, c-format msgid "New size given (%d extents) not less than existing size (%d extents)" msgstr "" #: lvresize.c:441 msgid "Mirrors cannot be resized while active yet." msgstr "" #: lvresize.c:447 msgid "Snapshot origin volumes cannot be reduced in size yet." msgstr "" #: lvresize.c:455 msgid "" "Snapshot origin volumes can be resized only while inactive: try lvchange -an" msgstr "" #: lvresize.c:463 msgid "Ignoring PVs on command line when reducing" msgstr "" #: lvresize.c:474 msgid "lv_info failed: aborting" msgstr "" #: lvresize.c:479 #, c-format msgid "Logical volume %s must be activated before resizing filesystem" msgstr "" #: lvresize.c:485 #, c-format msgid "WARNING: Reducing active%s logical volume to %s" msgstr "" #: lvresize.c:490 msgid "THIS MAY DESTROY YOUR DATA (filesystem etc.)" msgstr "" #: lvresize.c:497 #, c-format msgid "Logical volume %s NOT reduced" msgstr "" #: lvresize.c:508 #, c-format msgid "Couldn't create LV path for %s" msgstr "" #: lvresize.c:516 msgid "Couldn't generate new LV size string" msgstr "" #: lvresize.c:540 #, c-format msgid "%sing logical volume %s to %s" msgstr "" #: lvresize.c:589 #, c-format msgid "Logical volume %s successfully resized" msgstr "" #: lvresize.c:611 #, c-format msgid "Finding volume group %s" msgstr "" #: lvscan.c:64 #, c-format msgid "%s%s '%s%s/%s' [%s] %s" msgstr "" #: lvscan.c:79 msgid "No additional command line arguments allowed" msgstr "" #: metadata/lv_manip.c:96 msgid "alloc_lv_segment: Missing segtype." msgstr "" #: metadata/lv_manip.c:131 msgid "Failed to find snapshot segtype" msgstr "" #: metadata/lv_manip.c:139 msgid "Couldn't allocate new snapshot segment." msgstr "" #: metadata/lv_manip.c:280 #, c-format msgid "Segment extent reduction %unot divisible by #stripes %u" msgstr "" #: metadata/lv_manip.c:445 msgid "Striped mirrors are not supported yet" msgstr "" #: metadata/lv_manip.c:450 msgid "Can't mix striping or mirroring with creation of a mirrored PV yet" msgstr "" #: metadata/lv_manip.c:456 msgid "Can't mix striping or pvmove with a mirror log yet." msgstr "" #: metadata/lv_manip.c:471 msgid "allocation handle allocation failed" msgstr "" #: metadata/lv_manip.c:481 msgid "allocation pool creation failed" msgstr "" #: metadata/lv_manip.c:516 report/report.c:92 report/report.c:152 msgid "dm_pool_begin_object failed" msgstr "" #: metadata/lv_manip.c:523 metadata/lv_manip.c:528 metadata/lv_manip.c:535 #: report/report.c:112 report/report.c:123 report/report.c:129 #: report/report.c:135 report/report.c:159 report/report.c:165 msgid "dm_pool_grow_object failed" msgstr "" #: metadata/lv_manip.c:541 #, c-format msgid "Parallel PVs at LE %u length %u: %s" msgstr "" #: metadata/lv_manip.c:574 msgid "Couldn't allocate new LV segment." msgstr "" #: metadata/lv_manip.c:654 msgid "alloced_area allocation failed" msgstr "" #: metadata/lv_manip.c:705 #, c-format msgid "Failed to find segment for %s extent %u" msgstr "" #: metadata/lv_manip.c:907 #, c-format msgid "Insufficient free space: %u extents needed, but only %u available" msgstr "" #: metadata/lv_manip.c:1081 msgid "_allocate called with no work to do!" msgstr "" #: metadata/lv_manip.c:1105 msgid "Not enough PVs with free space available for parallel allocation." msgstr "" #: metadata/lv_manip.c:1107 msgid "Consider --alloc anywhere if desperate." msgstr "" #: metadata/lv_manip.c:1120 msgid "Couldn't allocate areas array." msgstr "" #: metadata/lv_manip.c:1137 #, c-format msgid "" "Insufficient suitable %sallocatable extents for logical volume %s: %u more " "required" msgstr "" #: metadata/lv_manip.c:1147 #, c-format msgid "Insufficient extents for log allocation for logical volume %s." msgstr "" #: metadata/lv_manip.c:1168 msgid "Couldn't allocate new zero segment." msgstr "" #: metadata/lv_manip.c:1201 msgid "allocate_extents does not handle virtual segments" msgstr "" #: metadata/lv_manip.c:1207 #, c-format msgid "Metadata format (%s) does not support required LV segment type (%s)." msgstr "" #: metadata/lv_manip.c:1210 msgid "Consider changing the metadata format by running vgconvert." msgstr "" #: metadata/lv_manip.c:1251 msgid "Missing segtype in lv_add_segment()." msgstr "" #: metadata/lv_manip.c:1256 msgid "lv_add_segment cannot handle virtual segments" msgstr "" #: metadata/lv_manip.c:1270 msgid "Couldn't merge segments after extending logical volume." msgstr "" #: metadata/lv_manip.c:1292 msgid "Log segments can only be added to an empty LV" msgstr "" #: metadata/lv_manip.c:1301 msgid "Couldn't allocate new mirror log segment." msgstr "" #: metadata/lv_manip.c:1339 #, c-format msgid "Log LV %s is empty." msgstr "" #: metadata/lv_manip.c:1349 msgid "Couldn't allocate new mirror segment." msgstr "" #: metadata/lv_manip.c:1384 msgid "Mirrored LV must only have one segment." msgstr "" #: metadata/lv_manip.c:1394 #, c-format msgid "Failed to allocate widened LV segment for %s." msgstr "" #: metadata/lv_manip.c:1446 #, c-format msgid "Aborting. Failed to extend %s." msgstr "" #: metadata/lv_manip.c:1499 #, c-format msgid "Maximum number of logical volumes (%u) reached in volume group %s" msgstr "" #: metadata/lv_manip.c:1506 msgid "Failed to generate unique name for the new logical volume" msgstr "" #: metadata/lv_manip.c:1512 #, c-format msgid "Creating logical volume %s" msgstr "" #: metadata/lv_manip.c:1516 msgid "lv_list allocation failed" msgstr "" #: metadata/lv_manip.c:1526 msgid "lv name strdup failed" msgstr "" #: metadata/lv_manip.c:1574 metadata/metadata.c:986 msgid "pv_list allocation failed" msgstr "" #: metadata/lv_manip.c:1596 msgid "parallel_areas allocation failed" msgstr "" #: metadata/lv_manip.c:1604 msgid "allocation failed" msgstr "" #: metadata/merge.c:72 #, c-format msgid "LV %s invalid: segment %u should begin at LE %u (found %u)." msgstr "" #: metadata/merge.c:82 #, c-format msgid "LV %s: segment %u has inconsistent area_len %u" msgstr "" #: metadata/merge.c:90 #, c-format msgid "LV %s: segment %u has log LV but is not mirrored" msgstr "" #: metadata/merge.c:97 #, c-format msgid "LV %s: segment %u log LV %s is not a mirror log" msgstr "" #: metadata/merge.c:105 #, c-format msgid "LV %s: segment %u log LV does not point back to mirror segment" msgstr "" #: metadata/merge.c:115 #, c-format msgid "LV %s: segment %u mirror image is not mirrored" msgstr "" #: metadata/merge.c:124 #, c-format msgid "LV %s: segment %u has unassigned area %u." msgstr "" #: metadata/merge.c:132 #, c-format msgid "LV %s: segment %u has inconsistent PV area %u" msgstr "" #: metadata/merge.c:141 #, c-format msgid "LV %s: segment %u has inconsistent LV area %u" msgstr "" #: metadata/merge.c:152 #, c-format msgid "LV %s: segment %u mirror image %u missing mirror ptr" msgstr "" #: metadata/merge.c:174 #, c-format msgid "LV %s: inconsistent LE count %u != %u" msgstr "" #: metadata/merge.c:195 #, c-format msgid "Unable to split the %s segment at LE %u in LV %s" msgstr "" #: metadata/merge.c:208 msgid "Couldn't allocate cloned LV segment." msgstr "" #: metadata/merge.c:213 msgid "LV segment tags duplication failed" msgstr "" #: metadata/merge.c:240 #, c-format msgid "Split %s:%u[%u] at %u: %s LE %u" msgstr "" #: metadata/merge.c:256 #, c-format msgid "Split %s:%u[%u] at %u: %s PE %u" msgstr "" #: metadata/merge.c:263 metadata/metadata.c:495 #, c-format msgid "Unassigned area %u found in segment" msgstr "" #: metadata/merge.c:282 #, c-format msgid "Segment with extent %u in LV %s not found" msgstr "" #: metadata/metadata.c:43 #, c-format msgid "Adding physical volume '%s' to volume group '%s'" msgstr "" #: metadata/metadata.c:47 metadata/metadata.c:1008 #, c-format msgid "pv_list allocation for '%s' failed" msgstr "" #: metadata/metadata.c:53 #, c-format msgid "%s not identified as an existing physical volume" msgstr "" #: metadata/metadata.c:59 #, c-format msgid "Physical volume '%s' is already in volume group '%s'" msgstr "" #: metadata/metadata.c:65 #, c-format msgid "Physical volume %s is of different format type (%s)" msgstr "" #: metadata/metadata.c:72 #, c-format msgid "Physical volume %s might be constructed from same volume group %s" msgstr "" #: metadata/metadata.c:78 metadata/metadata.c:199 #, c-format msgid "vg->name allocation failed for '%s'" msgstr "" #: metadata/metadata.c:100 #, c-format msgid "Format-specific setup of physical volume '%s' failed." msgstr "" #: metadata/metadata.c:106 #, c-format msgid "Physical volume '%s' listed more than once." msgstr "" #: metadata/metadata.c:112 #, c-format msgid "No space for '%s' - volume group '%s' holds max %d physical volume(s)." msgstr "" #: metadata/metadata.c:127 #, c-format msgid "Unable to add %s to %s: new extent count (%lu) exceeds limit (%u)." msgstr "" #: metadata/metadata.c:148 msgid "PV tags duplication failed" msgstr "" #: metadata/metadata.c:170 #, c-format msgid "get_pv_from_vg_by_id: vg_read failed to read VG %s" msgstr "" #: metadata/metadata.c:176 #, c-format msgid "Warning: Volume group %s is not consistent" msgstr "" #: metadata/metadata.c:205 #, c-format msgid "pv->vg_name allocation failed for '%s'" msgstr "" #: metadata/metadata.c:222 #, c-format msgid "Unable to add physical volume '%s' to volume group '%s'." msgstr "" #: metadata/metadata.c:260 #, c-format msgid "A volume group called '%s' already exists." msgstr "" #: metadata/metadata.c:266 #, c-format msgid "Couldn't create uuid for volume group '%s'." msgstr "" #: metadata/metadata.c:309 metadata/metadata.c:1085 metadata/metadata.c:1151 msgid "Failed to create format instance" msgstr "" #: metadata/metadata.c:315 #, c-format msgid "Format specific setup of volume group '%s' failed." msgstr "" #: metadata/metadata.c:338 #, c-format msgid "New size %lu for %s%s not an exact number of new extents." msgstr "" #: metadata/metadata.c:346 #, c-format msgid "New extent count %lu for %s%s exceeds 32 bits." msgstr "" #: metadata/metadata.c:556 #, c-format msgid "Failed to create random uuid for %s." msgstr "" #: metadata/metadata.c:575 pvresize.c:128 #, c-format msgid "WARNING: %s: Overriding real size. You could lose data." msgstr "" #: metadata/metadata.c:577 #, c-format msgid "%s: Pretending size is %lu sectors." msgstr "" #: metadata/metadata.c:583 pvresize.c:136 #, c-format msgid "%s: Size must exceed minimum of %ld sectors." msgstr "" #: metadata/metadata.c:601 #, c-format msgid "%s: Format-specific setup of physical volume failed." msgstr "" #: metadata/metadata.c:699 #, c-format msgid "Physical volume %s not found" msgstr "" #: metadata/metadata.c:704 #, c-format msgid "Physical volume %s not in a volume group" msgstr "" #: metadata/metadata.c:780 #, c-format msgid "Internal error: Duplicate PV id %s detected for %s in %s." msgstr "" #: metadata/metadata.c:789 #, c-format msgid "Internal error: VG name for PV %s is corrupted" msgstr "" #: metadata/metadata.c:796 metadata/metadata.c:1278 #, c-format msgid "Internal error: PV segments corrupted in %s." msgstr "" #: metadata/metadata.c:806 #, c-format msgid "Internal error: Duplicate LV name %s detected in %s." msgstr "" #: metadata/metadata.c:816 #, c-format msgid "Internal error: Duplicate LV id %s detected for %s and %s in %s." msgstr "" #: metadata/metadata.c:827 metadata/metadata.c:1285 #, c-format msgid "Internal error: LV segments corrupted in %s." msgstr "" #: metadata/metadata.c:851 #, c-format msgid "Cannot change metadata for partial volume group %s" msgstr "" #: metadata/metadata.c:857 msgid "Aborting vg_write: No metadata areas to write to!" msgstr "" #: metadata/metadata.c:866 msgid "Format does not support writing volumegroup metadata areas" msgstr "" #: metadata/metadata.c:969 msgid "vg allocation failed" msgstr "" #: metadata/metadata.c:977 msgid "vg name allocation failed" msgstr "" #: metadata/metadata.c:1049 msgid "Internal error: vg_read requires vgname with pre-commit." msgstr "" #: metadata/metadata.c:1113 metadata/metadata.c:1122 #, c-format msgid "Cached VG %s had incorrect PV list" msgstr "" #: metadata/metadata.c:1201 #, c-format msgid "Inconsistent pre-commit metadata copies for volume group %s" msgstr "" #: metadata/metadata.c:1212 #, c-format msgid "Inconsistent metadata copies found for partial volume group %s" msgstr "" #: metadata/metadata.c:1220 #, c-format msgid "Inconsistent metadata UUIDs found for volume group %s" msgstr "" #: metadata/metadata.c:1226 #, c-format msgid "Inconsistent metadata found for VG %s - updating to use version %u" msgstr "" #: metadata/metadata.c:1230 msgid "Automatic metadata correction failed" msgstr "" #: metadata/metadata.c:1235 msgid "Automatic metadata correction commit failed" msgstr "" #: metadata/metadata.c:1247 #, c-format msgid "Removing PV %s (%s) that no longer belongs to VG %s" msgstr "" #: metadata/metadata.c:1257 #, c-format msgid "WARNING: Interrupted pvmove detected in volume group %s" msgstr "" #: metadata/metadata.c:1259 msgid "Please restore the metadata by running vgcfgrestore." msgstr "" #: metadata/metadata.c:1316 metadata/metadata.c:1348 #, c-format msgid "Volume group %s metadata is inconsistent" msgstr "" #: metadata/metadata.c:1335 msgid "vg_read_by_vgid: get_vgs failed" msgstr "" #: metadata/metadata.c:1369 #, c-format msgid "Finding volume group for uuid %s" msgstr "" #: metadata/metadata.c:1371 #, c-format msgid "Volume group for uuid not found: %s" msgstr "" #: metadata/metadata.c:1375 #, c-format msgid "Found volume group \"%s\"" msgstr "" #: metadata/metadata.c:1381 #, c-format msgid "Can't find logical volume id %s" msgstr "" #: metadata/metadata.c:1405 #, c-format msgid "No physical volume label read from %s" msgstr "" #: metadata/metadata.c:1415 #, c-format msgid "pv allocation for '%s' failed" msgstr "" #: metadata/metadata.c:1424 #, c-format msgid "Failed to read existing physical volume '%s'" msgstr "" #: metadata/metadata.c:1466 msgid "PV list allocation failed" msgstr "" #: metadata/metadata.c:1474 msgid "get_pvs: get_vgs failed" msgstr "" #: metadata/metadata.c:1498 #, c-format msgid "Warning: Volume Group %s is not consistent" msgstr "" #: metadata/metadata.c:1516 msgid "Format does not support writing physical volumes" msgstr "" #: metadata/metadata.c:1521 #, c-format msgid "Assertion failed: can't _pv_write non-orphan PV (in VG %s)" msgstr "" #: metadata/metadata.c:1547 vgreduce.c:410 #, c-format msgid "" "Failed to clear metadata from physical volume \"%s\" after removal from \"%s" "\"" msgstr "" #: metadata/metadata.c:1570 pvcreate.c:81 #, c-format msgid "Device %s not found (or ignored by filtering)." msgstr "" #: metadata/metadata.c:1579 #, c-format msgid "Could not find LVM label on %s" msgstr "" #: metadata/metadata.c:1584 #, c-format msgid "Found label on %s, sector %lu, type=%s" msgstr "" #: metadata/mirror.c:52 mirror/mirrored.c:322 #, c-format msgid "Using reduced mirror region size of %u sectors" msgstr "" #: metadata/mirror.c:94 msgid "Aborting. Unable to tag." msgstr "" #: metadata/mirror.c:100 msgid "Intermediate VG commit for orphan volume failed." msgstr "" #: metadata/mirror.c:138 #, c-format msgid "Reducing mirror set from %u to %u image(s)%s." msgstr "" #: metadata/mirror.c:183 msgid "No mirror images found using specified PVs." msgstr "" #: metadata/mirror.c:222 msgid "intermediate VG write failed." msgstr "" #: metadata/mirror.c:277 msgid "Bad activation/mirror_log_fault_policy" msgstr "" #: metadata/mirror.c:279 msgid "Bad activation/mirror_device_fault_policy" msgstr "" #: metadata/mirror.c:317 #, c-format msgid "WARNING: Failed to replace mirror device in %s/%s" msgstr "" #: metadata/mirror.c:321 #, c-format msgid "" "WARNING: Use 'lvconvert -m %d %s/%s --corelog' to replace failed devices" msgstr "" #: metadata/mirror.c:324 metadata/mirror.c:341 #, c-format msgid "WARNING: Use 'lvconvert -m %d %s/%s' to replace failed devices" msgstr "" #: metadata/mirror.c:338 #, c-format msgid "WARNING: Failed to replace mirror log device in %s/%s" msgstr "" #: metadata/mirror.c:362 #, c-format msgid "WARNING: Unable to determine mirror sync status of %s/%s." msgstr "" #: metadata/mirror.c:380 #, c-format msgid "WARNING: Bad device removed from mirror volume, %s/%s" msgstr "" #: metadata/mirror.c:393 #, c-format msgid "WARNING: Unable to find substitute device for mirror volume, %s/%s" msgstr "" #: metadata/mirror.c:397 #, c-format msgid "" "WARNING: Mirror volume, %s/%s restored - substitute for failed device found." msgstr "" #: metadata/mirror.c:402 #, c-format msgid "" "WARNING: Mirror volume, %s/%s converted to linear due to device failure." msgstr "" #: metadata/mirror.c:405 #, c-format msgid "WARNING: Mirror volume, %s/%s disk log removed due to device failure." msgstr "" #: metadata/mirror.c:428 metadata/mirror.c:434 msgid "img_name allocation failed. Remove new LV and retry." msgstr "" #: metadata/mirror.c:443 msgid "Aborting. Failed to create mirror image LV. Remove new LV and retry." msgstr "" #: metadata/mirror.c:455 #, c-format msgid "" "Aborting. Failed to add mirror image segment to %s. Remove new LV and retry." msgstr "" #: metadata/mirror.c:477 metadata/mirror.c:518 msgid "img_lvs allocation failed. Remove new LV and retry." msgstr "" #: metadata/mirror.c:499 msgid "Aborting. Failed to add mirror segment. Remove new LV and retry." msgstr "" #: metadata/mirror.c:632 #, c-format msgid "Matched PE range %u-%u against %s %u len %u" msgstr "" #: metadata/mirror.c:641 metadata/mirror.c:872 vgreduce.c:139 msgid "lv_list alloc failed" msgstr "" #: metadata/mirror.c:651 #, c-format msgid "Moving %s:%u-%u of %s/%s" msgstr "" #: metadata/mirror.c:664 msgid "Unable to allocate temporary LV for pvmove." msgstr "" #: metadata/mirror.c:679 #, c-format msgid "Moving %u extents of logical volume %s/%s" msgstr "" #: metadata/mirror.c:711 msgid "No segment found with LE" msgstr "" #: metadata/mirror.c:722 msgid "Incompatible segments" msgstr "" #: metadata/mirror.c:747 msgid "Missing error segtype" msgstr "" #: metadata/mirror.c:853 msgid "lvs list alloc failed" msgstr "" #: metadata/pv_manip.c:30 msgid "pv_segment allocation failed" msgstr "" #: metadata/pv_manip.c:121 #, c-format msgid "Segment with extent %u in PV %s not found" msgstr "" #: metadata/pv_manip.c:161 #, c-format msgid "Missing PV segment on %s at %u." msgstr "" #: metadata/pv_manip.c:178 #, c-format msgid "release_pv_segment with unallocated segment: %s PE %u" msgstr "" #: metadata/pv_manip.c:238 #, c-format msgid "%s %u: %6u %6u: %s(%u:%u)" msgstr "" #: metadata/pv_manip.c:244 #, c-format msgid "Gap in pvsegs: %u, %u" msgstr "" #: metadata/pv_manip.c:250 msgid "Wrong lvseg area type" msgstr "" #: metadata/pv_manip.c:254 msgid "Inconsistent pvseg pointers" msgstr "" #: metadata/pv_manip.c:258 #, c-format msgid "Inconsistent length: %u %u" msgstr "" #: metadata/pv_manip.c:269 #, c-format msgid "PV segment pe_count mismatch: %u != %u" msgstr "" #: metadata/pv_manip.c:275 #, c-format msgid "PV segment pe_alloc_count mismatch: %u != %u" msgstr "" #: metadata/pv_manip.c:285 #, c-format msgid "PV segment VG pv_count mismatch: %u != %u" msgstr "" #: metadata/pv_manip.c:291 #, c-format msgid "PV segment VG free_count mismatch: %u != %u" msgstr "" #: metadata/pv_manip.c:297 #, c-format msgid "PV segment VG extent_count mismatch: %u != %u" msgstr "" #: metadata/pv_manip.c:311 #, c-format msgid "%s: cannot resize to %u extents as %u are allocated." msgstr "" #: metadata/pv_manip.c:324 #, c-format msgid "%s: cannot resize to %u extents as later ones are allocated." msgstr "" #: metadata/pv_manip.c:356 #, c-format msgid "%s: cannot resize to %u extents as there is only room for %lu." msgstr "" #: metadata/pv_manip.c:385 #, c-format msgid "No change to size of physical volume %s." msgstr "" #: metadata/pv_manip.c:390 #, c-format msgid "Resizing physical volume %s from %u to %u extents." msgstr "" #: metadata/pv_map.c:48 #, c-format msgid "Allowing allocation on %s start PE %u length %u" msgstr "" #: metadata/pv_map.c:176 msgid "create_pv_maps alloc failed" msgstr "" #: metadata/pv_map.c:183 #, c-format msgid "Couldn't create physical volume maps in %s" msgstr "" #: metadata/segtype.c:30 #, c-format msgid "Unrecognised segment type %s" msgstr "" #: metadata/snapshot_manip.c:63 #, c-format msgid "'%s' is already in use as a snapshot." msgstr "" #: metadata/snapshot_manip.c:104 #, c-format msgid "Failed to remove internal snapshot LV %s" msgstr "" #: mirror/mirrored.c:57 #, c-format msgid " Mirrors\t\t%u" msgstr "" #: mirror/mirrored.c:58 #, c-format msgid " Mirror size\t\t%u" msgstr "" #: mirror/mirrored.c:60 #, c-format msgid " Mirror log volume\t%s" msgstr "" #: mirror/mirrored.c:65 #, c-format msgid " Mirror region size\t%s" msgstr "" #: mirror/mirrored.c:68 msgid " Mirror original:" msgstr "" #: mirror/mirrored.c:70 msgid " Mirror destinations:" msgstr "" #: mirror/mirrored.c:79 #, c-format msgid "Couldn't read 'mirror_count' for segment '%s'." msgstr "" #: mirror/mirrored.c:98 #, c-format msgid "Couldn't read 'extents_moved' for segment '%s'." msgstr "" #: mirror/mirrored.c:107 #, c-format msgid "Couldn't read 'region_size' for segment '%s'." msgstr "" #: mirror/mirrored.c:115 msgid "Mirror log type must be a string." msgstr "" #: mirror/mirrored.c:120 #, c-format msgid "Unrecognised mirror log in segment %s." msgstr "" #: mirror/mirrored.c:128 #, c-format msgid "Missing region size for mirror log for segment '%s'." msgstr "" #: mirror/mirrored.c:134 #, c-format msgid "Couldn't find mirrors array for segment '%s'." msgstr "" #: mirror/mirrored.c:163 msgid "struct mirr_state allocation failed" msgstr "" #: mirror/mirrored.c:193 #, c-format msgid "Mirror status: %s" msgstr "" #: mirror/mirrored.c:196 #, c-format msgid "Failure parsing mirror status mirror count: %s" msgstr "" #: mirror/mirrored.c:204 #, c-format msgid "Failure parsing mirror status devices: %s" msgstr "" #: mirror/mirrored.c:213 #, c-format msgid "Failure parsing mirror status fraction: %s" msgstr "" #: mirror/mirrored.c:245 #, c-format msgid "Failed to build uuid for log LV %s." msgstr "" #: mirror/mirrored.c:252 #, c-format msgid "Failed to build uuid for mirror LV %s." msgstr "" #: mirror/mirrored.c:310 msgid "Missing region size for mirror segment." msgstr "" #: mirror/mirrored.c:505 msgid "cluster log string list allocation failed" msgstr "" #: mirror/mirrored.c:510 msgid "mirror string list allocation failed" msgstr "" #: misc/lvm-exec.c:31 #, c-format msgid "Executing: %s %s %s %s" msgstr "" #: misc/lvm-exec.c:34 polldaemon.c:39 #, c-format msgid "fork failed: %s" msgstr "" #: misc/lvm-exec.c:48 #, c-format msgid "wait4 child process %u failed: %s" msgstr "" #: misc/lvm-exec.c:54 #, c-format msgid "Child %u exited abnormally" msgstr "" #: misc/lvm-exec.c:59 #, c-format msgid "%s failed: %u" msgstr "" #: misc/lvm-file.c:55 msgid "Not enough space to build temporary file string." msgstr "" #: misc/lvm-file.c:102 #, c-format msgid "%s: rename to %s failed" msgstr "" #: misc/lvm-file.c:148 #, c-format msgid "Creating directory \"%s\"" msgstr "" #: misc/lvm-file.c:189 #, c-format msgid "Directory \"%s\" not found" msgstr "" #: misc/lvm-file.c:220 msgid "sync_dir failed in strdup" msgstr "" #: misc/lvm-file.c:269 msgid "fcntl_lock_file failed in strdup." msgstr "" #: misc/lvm-file.c:283 #, c-format msgid "Locking %s (%s, %hd)" msgstr "" #: misc/lvm-file.c:313 #, c-format msgid "Unlocking fd %d" msgstr "" #: misc/lvm-file.c:316 #, c-format msgid "fcntl unlock failed on fd %d: %s" msgstr "" #: misc/lvm-file.c:320 #, c-format msgid "lock file close failed on fd %d: %s" msgstr "" #: misc/lvm-string.c:107 #, c-format msgid "build_dm_name: Allocation failed for %zu for %s %s %s." msgstr "" #: misc/sharedlib.c:48 #, c-format msgid "Not loading shared %s library %s in static mode." msgstr "" #: misc/sharedlib.c:55 #, c-format msgid "Opening shared %s library %s" msgstr "" #: misc/sharedlib.c:59 misc/sharedlib.c:62 #, c-format msgid "Unable to open external %s library %s: %s" msgstr "" #: mm/memlock.c:99 msgid "Locking memory" msgstr "" #: mm/memlock.c:108 mm/memlock.c:122 #, c-format msgid "setpriority %u failed: %s" msgstr "" #: mm/memlock.c:118 msgid "Unlocking memory" msgstr "" #: mm/memlock.c:130 #, c-format msgid "memlock_count inc to %d" msgstr "" #: mm/memlock.c:137 #, c-format msgid "memlock_count dec to %d" msgstr "" #: polldaemon.c:34 msgid "Forking background process" msgstr "" #: polldaemon.c:49 #, c-format msgid "Background process failed to setsid: %s" msgstr "" #: polldaemon.c:80 msgid "Failed to generate list of copied LVs: can't abort." msgstr "" #: polldaemon.c:90 msgid "ABORTING: Mirror percentage check failed." msgstr "" #: polldaemon.c:96 polldaemon.c:98 #, c-format msgid "%s: Moved: %.1f%%" msgstr "" #: polldaemon.c:107 msgid "ABORTING: Failed to generate list of copied LVs" msgstr "" #: polldaemon.c:119 msgid "ABORTING: Segment progression failed." msgstr "" #: polldaemon.c:149 #, c-format msgid "ABORTING: Can't reread VG for %s" msgstr "" #: polldaemon.c:156 #, c-format msgid "ABORTING: Can't find mirror LV in %s for %s" msgstr "" #: polldaemon.c:184 #, c-format msgid "Couldn't read volume group %s" msgstr "" #: polldaemon.c:189 #, c-format msgid "Volume Group %s inconsistent - skipping" msgstr "" #: polldaemon.c:241 #, c-format msgid "Checking progress every %u seconds" msgstr "" #: pvchange.c:55 #, c-format msgid "Finding volume group of physical volume \"%s\"" msgstr "" #: pvchange.c:65 pvresize.c:75 #, c-format msgid "Unable to find volume group of \"%s\"" msgstr "" #: pvchange.c:90 pvresize.c:101 #, c-format msgid "Unable to find \"%s\" in volume group \"%s\"" msgstr "" #: pvchange.c:97 #, c-format msgid "Volume group containing %s does not support tags" msgstr "" #: pvchange.c:103 #, c-format msgid "Volume group containing %s has active logical volumes" msgstr "" #: pvchange.c:112 #, c-format msgid "Can't change tag on Physical Volume %s not in volume group" msgstr "" #: pvchange.c:117 pvresize.c:48 msgid "Can't get lock for orphans" msgstr "" #: pvchange.c:123 pvresize.c:54 #, c-format msgid "Unable to read PV \"%s\"" msgstr "" #: pvchange.c:132 #, c-format msgid "Allocatability not supported by orphan %s format PV %s" msgstr "" #: pvchange.c:140 #, c-format msgid "Physical volume \"%s\" is already allocatable" msgstr "" #: pvchange.c:150 #, c-format msgid "Physical volume \"%s\" is already unallocatable" msgstr "" #: pvchange.c:160 #, c-format msgid "Setting physical volume \"%s\" allocatable" msgstr "" #: pvchange.c:164 #, c-format msgid "Setting physical volume \"%s\" NOT allocatable" msgstr "" #: pvchange.c:172 #, c-format msgid "Failed to add tag %s to physical volume %s" msgstr "" #: pvchange.c:178 #, c-format msgid "Failed to remove tag %s from physical volume%s" msgstr "" #: pvchange.c:186 #, c-format msgid "Failed to generate new random UUID for %s." msgstr "" #: pvchange.c:194 #, c-format msgid "Changing uuid of %s to %s." msgstr "" #: pvchange.c:201 #, c-format msgid "pv_write with new uuid failed for %s." msgstr "" #: pvchange.c:210 pvresize.c:174 #, c-format msgid "Updating physical volume \"%s\"" msgstr "" #: pvchange.c:214 pvresize.c:178 #, c-format msgid "Failed to store physical volume \"%s\" in volume group \"%s\"" msgstr "" #: pvchange.c:223 pvresize.c:187 #, c-format msgid "Failed to store physical volume \"%s\"" msgstr "" #: pvchange.c:230 pvresize.c:194 #, c-format msgid "Physical volume \"%s\" changed" msgstr "" #: pvchange.c:252 msgid "Please give exactly one option of -x, -uuid, --addtag or --deltag" msgstr "" #: pvchange.c:258 msgid "Please give a physical volume path" msgstr "" #: pvchange.c:263 msgid "Option a and PhysicalVolumePath are exclusive" msgstr "" #: pvchange.c:268 toollib.c:683 msgid "Using physical volume(s) on command line" msgstr "" #: pvchange.c:273 #, c-format msgid "Failed to read physical volume %s" msgstr "" #: pvchange.c:281 toollib.c:766 msgid "Scanning for physical volume names" msgstr "" #: pvchange.c:292 #, c-format msgid "%d physical volume%s changed / %d physical volume%s not changed" msgstr "" #: pvck.c:32 #, c-format msgid "Scanning %s" msgstr "" #: pvcreate.c:37 pvremove.c:31 #, c-format msgid "%s: Not LVM partition type: use -f to override" msgstr "" #: pvcreate.c:49 #, c-format msgid "" "Can't initialize physical volume \"%s\" of volume group \"%s\" without -ff" msgstr "" #: pvcreate.c:57 #, c-format msgid "%s: physical volume not initialized" msgstr "" #: pvcreate.c:72 pvcreate.c:168 pvremove.c:81 vgcreate.c:135 vgextend.c:40 #: vgremove.c:96 msgid "Can't get lock for orphan PVs" msgstr "" #: pvcreate.c:86 #, c-format msgid "Can't open %s exclusively. Mounted filesystem?" msgstr "" #: pvcreate.c:98 #, c-format msgid "Wiping software RAID md superblock on %s" msgstr "" #: pvcreate.c:100 #, c-format msgid "Failed to wipe RAID md superblock on %s" msgstr "" #: pvcreate.c:107 #, c-format msgid "WARNING: Forcing physical volume creation on %s%s%s%s" msgstr "" #: pvcreate.c:140 #, c-format msgid "uuid %s already in use on \"%s\"" msgstr "" #: pvcreate.c:152 #, c-format msgid "Unable to read volume group from %s" msgstr "" #: pvcreate.c:158 #, c-format msgid "Can't find uuid %s in backup file %s" msgstr "" #: pvcreate.c:176 pvresize.c:212 msgid "Physical volume size may not be negative" msgstr "" #: pvcreate.c:182 vgconvert.c:66 msgid "Metadata size may not be negative" msgstr "" #: pvcreate.c:199 pvremove.c:89 #, c-format msgid "%s: Couldn't find device. Check your filters?" msgstr "" #: pvcreate.c:208 vgconvert.c:127 #, c-format msgid "Failed to setup physical volume \"%s\"" msgstr "" #: pvcreate.c:212 vgconvert.c:138 #, c-format msgid "Set up physical volume for \"%s\" with %lu available sectors" msgstr "" #: pvcreate.c:217 vgconvert.c:143 #, c-format msgid "Failed to wipe existing label on %s" msgstr "" #: pvcreate.c:222 #, c-format msgid "Zeroing start of device %s" msgstr "" #: pvcreate.c:224 #, c-format msgid "%s not opened: device not zeroed" msgstr "" #: pvcreate.c:229 #, c-format msgid "%s not wiped: aborting" msgstr "" #: pvcreate.c:236 vgconvert.c:150 #, c-format msgid "Writing physical volume data to disk \"%s\"" msgstr "" #: pvcreate.c:240 vgconvert.c:155 #, c-format msgid "Failed to write physical volume \"%s\"" msgstr "" #: pvcreate.c:244 vgconvert.c:161 #, c-format msgid "Physical volume \"%s\" successfully created" msgstr "" #: pvcreate.c:261 pvremove.c:123 msgid "Please enter a physical volume path" msgstr "" #: pvcreate.c:266 msgid "--uuid is required with --restorefile" msgstr "" #: pvcreate.c:271 msgid "Can only set uuid on one volume at once" msgstr "" #: pvcreate.c:276 pvremove.c:128 msgid "Option y can only be given with option f" msgstr "" #: pvcreate.c:281 vgconvert.c:205 #, c-format msgid "labelsector must be less than %lu" msgstr "" #: pvcreate.c:289 vgconvert.c:213 msgid "Metadata parameters only apply to text format" msgstr "" #: pvcreate.c:295 vgconvert.c:219 msgid "Metadatacopies may only be 0, 1 or 2" msgstr "" #: pvdisplay.c:30 reporter.c:65 reporter.c:113 toollib.c:347 toollib.c:477 #, c-format msgid "Can't lock %s: skipping" msgstr "" #: pvdisplay.c:35 reporter.c:70 reporter.c:118 #, c-format msgid "Can't read %s: skipping" msgstr "" #: pvdisplay.c:54 #, c-format msgid "Device \"%s\" has a capacity of %s" msgstr "" #: pvdisplay.c:60 #, c-format msgid "Physical volume \"%s\" of volume group \"%s\" is exported" msgstr "" #: pvdisplay.c:64 #, c-format msgid "\"%s\" is a new physical volume of \"%s\"" msgstr "" #: pvdisplay.c:104 msgid "Option -v not allowed with option -c" msgstr "" #: pvmove.c:34 msgid "--name takes a logical volume name" msgstr "" #: pvmove.c:39 msgid "Named LV and old PV must be in the same VG" msgstr "" #: pvmove.c:45 msgid "Incomplete LV name supplied with --name" msgstr "" #: pvmove.c:127 msgid "No extents available for allocation" msgstr "" #: pvmove.c:150 msgid "Creation of temporary pvmove LV failed" msgstr "" #: pvmove.c:157 msgid "lvs_changed list struct allocation failed" msgstr "" #: pvmove.c:170 #, c-format msgid "Skipping snapshot-related LV %s" msgstr "" #: pvmove.c:174 #, c-format msgid "Skipping mirror LV %s" msgstr "" #: pvmove.c:178 #, c-format msgid "Skipping mirror log LV %s" msgstr "" #: pvmove.c:182 #, c-format msgid "Skipping mirror image LV %s" msgstr "" #: pvmove.c:186 #, c-format msgid "Skipping locked LV %s" msgstr "" #: pvmove.c:199 #, c-format msgid "No data to move for %s" msgstr "" #: pvmove.c:210 msgid "Updating volume group metadata" msgstr "" #: pvmove.c:212 pvmove.c:236 msgid "ABORTING: Volume group metadata update failed." msgstr "" #: pvmove.c:249 msgid "ABORTING: Temporary mirror activation failed. Run pvmove --abort." msgstr "" #: pvmove.c:257 pvmove.c:438 #, c-format msgid "Unable to reactivate logical volume \"%s\"" msgstr "" #: pvmove.c:265 msgid "Unable to resume logical volumes" msgstr "" #: pvmove.c:313 #, c-format msgid "Detected pvmove in progress for %s" msgstr "" #: pvmove.c:315 msgid "Ignoring remaining command line arguments" msgstr "" #: pvmove.c:318 msgid "ABORTING: Failed to generate list of moving LVs" msgstr "" #: pvmove.c:326 msgid "ABORTING: Temporary mirror activation failed." msgstr "" #: pvmove.c:403 msgid "ABORTING: Removal of temporary mirror failed" msgstr "" #: pvmove.c:409 pvmove.c:428 pvmove.c:462 msgid "ABORTING: Failed to write new data locations to disk." msgstr "" #: pvmove.c:416 msgid "Locking LVs to remove temporary mirror failed" msgstr "" #: pvmove.c:422 msgid "Suspension of temporary mirror LV failed" msgstr "" #: pvmove.c:448 #, c-format msgid "ABORTING: Unable to deactivate temporary logical volume \"%s\"" msgstr "" #: pvmove.c:453 msgid "Removing temporary pvmove LV" msgstr "" #: pvmove.c:455 msgid "ABORTING: Removal of temporary pvmove LV failed" msgstr "" #: pvmove.c:460 msgid "Writing out final volume group after pvmove" msgstr "" #: pvmove.c:480 #, c-format msgid "ABORTING: Can't reread PV %s" msgstr "" #: pvmove.c:516 toollib.c:1074 msgid "Failed to clone PV name" msgstr "" #: pvremove.c:41 vgsplit.c:107 #, c-format msgid "Physical Volume %s not found" msgstr "" #: pvremove.c:52 #, c-format msgid "" "Can't pvremove physical volume \"%s\" of volume group \"%s\" without -ff" msgstr "" #: pvremove.c:60 #, c-format msgid "%s: physical volume label not removed" msgstr "" #: pvremove.c:65 #, c-format msgid "WARNING: Wiping physical volume label from %s%s%s%s" msgstr "" #: pvremove.c:95 #, c-format msgid "Can't open %s exclusively - not removing. Mounted filesystem?" msgstr "" #: pvremove.c:102 #, c-format msgid "Failed to wipe existing label(s) on %s" msgstr "" #: pvremove.c:106 #, c-format msgid "Labels on physical volume \"%s\" successfully wiped" msgstr "" #: pvresize.c:60 #, c-format msgid "%s: too many metadata areas for pvresize" msgstr "" #: pvresize.c:113 #, c-format msgid "Physical volume %s format does not support resizing." msgstr "" #: pvresize.c:130 #, c-format msgid "%s: Pretending size is %lu not %lu sectors." msgstr "" #: pvresize.c:143 #, c-format msgid "%s: Size must exceed physical extent start of %lu sectors." msgstr "" #: pvresize.c:156 #, c-format msgid "" "%s: Size must leave space for at least one physical extent of %u sectors." msgstr "" #: pvresize.c:171 #, c-format msgid "Resizing volume \"%s\" to %lu sectors." msgstr "" #: pvresize.c:207 msgid "Please supply physical volume(s)" msgstr "" #: pvresize.c:224 #, c-format msgid "%d physical volume(s) resized / %d physical volume(s) not resized" msgstr "" #: pvscan.c:66 #, c-format msgid "PV %-*s %-*s %s [%s]" msgstr "" #: pvscan.c:76 #, c-format msgid "PV %-*s is in exported VG %s [%s / %s free]" msgstr "" #: pvscan.c:89 #, c-format msgid "PV %-*s VG %-*s %s [%s / %s free]" msgstr "" #: pvscan.c:117 msgid "Options -e and -n are incompatible" msgstr "" #: pvscan.c:122 #, c-format msgid "WARNING: only considering physical volumes %s" msgstr "" #: pvscan.c:129 msgid "Walking through all physical volumes" msgstr "" #: pvscan.c:182 msgid "No matching physical volumes found" msgstr "" #: pvscan.c:186 #, c-format msgid "Total: %d [%s] / in use: %d [%s] / in no VG: %d [%s]" msgstr "" #: report/report.c:118 msgid "Extent number dm_snprintf failed" msgstr "" #: report/report.c:182 msgid "modules str_list allocation failed" msgstr "" #: report/report.c:259 report/report.c:342 report/report.c:368 #: report/report.c:466 report/report.c:523 report/report.c:553 #: report/report.c:694 report/report.c:750 report/report.c:768 #: report/report.c:793 report/report.c:807 msgid "dm_pool_alloc failed" msgstr "" #: report/report.c:471 msgid "lvname snprintf failed" msgstr "" #: report/report.c:476 report/report.c:518 report/report.c:548 msgid "dm_pool_strdup failed" msgstr "" #: report/report.c:773 msgid "snapshot percentage too large" msgstr "" #: report/report.c:812 msgid "copy percentage too large" msgstr "" #: reporter.c:24 reporter.c:146 reporter.c:158 #, c-format msgid "Volume group %s not found" msgstr "" #: reporter.c:254 #, c-format msgid "Invalid options string: %s" msgstr "" #: reporter.c:260 msgid "options string allocation failed" msgstr "" #: reporter.c:297 msgid "Can't report LV and PV fields at the same time" msgstr "" #: snapshot/snapshot.c:40 msgid "Couldn't read chunk size for snapshot." msgstr "" #: snapshot/snapshot.c:48 msgid "Snapshot cow storage not specified." msgstr "" #: snapshot/snapshot.c:54 msgid "Snapshot origin not specified." msgstr "" #: snapshot/snapshot.c:61 msgid "Unknown logical volume specified for snapshot cow store." msgstr "" #: snapshot/snapshot.c:67 msgid "Unknown logical volume specified for snapshot origin." msgstr "" #: snapshot/snapshot.c:135 msgid "snapshot string list allocation failed" msgstr "" #: striped/striped.c:41 #, c-format msgid " Stripes\t\t%u" msgstr "" #: striped/striped.c:42 #, c-format msgid " Stripe size\t\t%u KB" msgstr "" #: striped/striped.c:45 #, c-format msgid " Stripe %d:" msgstr "" #: striped/striped.c:55 #, c-format msgid "Couldn't read 'stripe_count' for segment '%s'." msgstr "" #: striped/striped.c:70 #, c-format msgid "Couldn't read stripe_size for segment '%s'." msgstr "" #: striped/striped.c:76 #, c-format msgid "Couldn't find stripes array for segment '%s'." msgstr "" #: striped/striped.c:163 #, c-format msgid "Internal error: striped add_target_line called with no areas for %s." msgstr "" #: stub.h:24 stub.h:31 msgid "Command not implemented yet." msgstr "" #: stub.h:38 msgid "There's no 'pvdata' command in LVM2." msgstr "" #: stub.h:39 msgid "" "Use lvs, pvs, vgs instead; or use vgcfgbackup and read the text file backup." msgstr "" #: stub.h:40 msgid "" "Metadata in LVM1 format can still be displayed using LVM1's pvdata command." msgstr "" #: toollib.c:115 #, c-format msgid "skip_dev_dir: Couldn't split up device name %s" msgstr "" #: toollib.c:124 toollib.c:322 msgid "vg/lv string alloc failed" msgstr "" #: toollib.c:215 msgid "One or more specified logical volume(s) not found." msgstr "" #: toollib.c:251 msgid "Using logical volume(s) on command line" msgstr "" #: toollib.c:264 toollib.c:540 toollib.c:689 toollib.c:1051 #, c-format msgid "Skipping invalid tag %s" msgstr "" #: toollib.c:281 toollib.c:807 toollib.c:818 #, c-format msgid "\"%s\": Invalid path for Logical Volume" msgstr "" #: toollib.c:335 msgid "Finding all logical volumes" msgstr "" #: toollib.c:337 toollib.c:572 msgid "No volume groups found" msgstr "" #: toollib.c:357 toollib.c:483 toollib.c:731 vgcfgbackup.c:59 vgck.c:24 #: vgreduce.c:505 vgscan.c:23 #, c-format msgid "Volume group \"%s\" not found" msgstr "" #: toollib.c:369 vgchange.c:523 vgck.c:29 vgconvert.c:43 vgscan.c:30 #, c-format msgid "Volume group \"%s\" inconsistent" msgstr "" #: toollib.c:534 msgid "Using volume group(s) on command line" msgstr "" #: toollib.c:555 #, c-format msgid "Invalid volume group name: %s" msgstr "" #: toollib.c:570 msgid "Finding all volume groups" msgstr "" #: toollib.c:705 toollib.c:1080 #, c-format msgid "Physical Volume \"%s\" not found in Volume Group \"%s\"" msgstr "" #: toollib.c:716 #, c-format msgid "Failed to read physical volume \"%s\"" msgstr "" #: toollib.c:755 msgid "Using all physical volume(s) in volume group" msgstr "" #: toollib.c:825 msgid "Allocation of vg_name failed" msgstr "" #: toollib.c:835 #, c-format msgid "Path required for Logical Volume \"%s\"" msgstr "" #: toollib.c:858 #, c-format msgid "Environment Volume Group in LVM_VG_NAME invalid: \"%s\"" msgstr "" #: toollib.c:874 #, c-format msgid "Adding PE range: start PE %u length %u on %s" msgstr "" #: toollib.c:882 #, c-format msgid "Overlapping PE ranges specified (%u-%u, %u-%u) on %s" msgstr "" #: toollib.c:892 toollib.c:1039 toollib.c:1103 msgid "Allocation of list failed" msgstr "" #: toollib.c:956 #, c-format msgid "PE range error: start extent %u to end extent %u" msgstr "" #: toollib.c:971 #, c-format msgid "Physical extent parsing error at %s" msgstr "" #: toollib.c:984 #, c-format msgid "Physical volume %s not allocatable" msgstr "" #: toollib.c:990 #, c-format msgid "No free extents on physical volume \"%s\"" msgstr "" #: toollib.c:1002 toollib.c:1110 msgid "Unable to allocate physical volume list." msgstr "" #: toollib.c:1009 msgid "Allocation of pe_ranges list failed" msgstr "" #: toollib.c:1091 msgid "No specified PVs have space available" msgstr "" #: toollib.c:1137 #, c-format msgid "Can't lock %s for metadata recovery: skipping" msgstr "" #: toollib.c:1148 msgid "" "Names starting \"snapshot\" are reserved. Please choose a different LV name." msgstr "" #: toollib.c:1154 msgid "" "Names starting \"pvmove\" are reserved. Please choose a different LV name." msgstr "" #: toollib.c:1160 msgid "" "Names including \"_mlog\" are reserved. Please choose a different LV name." msgstr "" #: toollib.c:1166 msgid "" "Names including \"_mimage\" are reserved. Please choose a different LV name." msgstr "" #: toollib.c:1183 #, c-format msgid "%s: already exists in filesystem" msgstr "" #: toollib.c:1227 msgid "Name allocation failed - device not cleared" msgstr "" #: toollib.c:1233 #, c-format msgid "Name too long - device not cleared (%s)" msgstr "" #: toollib.c:1237 #, c-format msgid "Clearing start of logical volume \"%s\"" msgstr "" #: toollib.c:1240 #, c-format msgid "%s: not found: device not cleared" msgstr "" #: toollib.c:1276 #, c-format msgid "Name allocation failed - log header not written (%s)" msgstr "" #: toollib.c:1283 #, c-format msgid "Name too long - log header not written (%s)" msgstr "" #: toollib.c:1287 #, c-format msgid "Writing log header to device, %s" msgstr "" #: toollib.c:1290 #, c-format msgid "%s: not found: log header not written" msgstr "" #: toollib.c:1298 #, c-format msgid "Failed to write log header to %s" msgstr "" #: toollib.c:1324 msgid "log_name allocation failed. Remove new LV and retry." msgstr "" #: toollib.c:1344 msgid "Aborting. Unable to tag mirror log." msgstr "" #: toollib.c:1362 msgid "" "Aborting. Unable to create in-sync mirror log while activation is disabled." msgstr "" #: toollib.c:1368 msgid "Aborting. Failed to activate mirror log. Remove new LVs and retry." msgstr "" #: toollib.c:1375 #, c-format msgid "Failed to remove tag %s from mirror log." msgstr "" #: toollib.c:1380 msgid "Aborting. Failed to wipe mirror log. Remove new LV and retry." msgstr "" #: toollib.c:1386 msgid "Aborting. Failed to write mirror log header. Remove new LV and retry." msgstr "" #: toollib.c:1392 msgid "Aborting. Failed to deactivate mirror log. Remove new LV and retry." msgstr "" #: uuid/uuid.c:132 msgid "UUID contains invalid character" msgstr "" #: uuid/uuid.c:156 msgid "Couldn't write uuid, buffer too small." msgstr "" #: uuid/uuid.c:184 msgid "Too many characters to be uuid." msgstr "" #: uuid/uuid.c:192 msgid "Couldn't read uuid, incorrect number of characters." msgstr "" #: vgcfgbackup.c:27 msgid "Failed to allocate filename." msgstr "" #: vgcfgbackup.c:32 #, c-format msgid "Error processing filename template %s" msgstr "" #: vgcfgbackup.c:39 #, c-format msgid "" "VGs must be backed up into different files. Use %%s in filename for VG name." msgstr "" #: vgcfgbackup.c:64 #, c-format msgid "Warning: Volume group \"%s\" inconsistent" msgstr "" #: vgcfgbackup.c:76 msgid "No backup taken: specify filename with -f to backup an inconsistent VG" msgstr "" #: vgcfgbackup.c:90 #, c-format msgid "Volume group \"%s\" successfully backed up." msgstr "" #: vgcfgrestore.c:23 msgid "Please specify a *single* volume group to restore." msgstr "" #: vgcfgrestore.c:30 vgextend.c:45 vgreduce.c:469 vgsplit.c:228 #, c-format msgid "Volume group name \"%s\" is invalid" msgstr "" #: vgcfgrestore.c:46 msgid "Unable to lock orphans" msgstr "" #: vgcfgrestore.c:51 #, c-format msgid "Unable to lock volume group %s" msgstr "" #: vgcfgrestore.c:62 msgid "Restore failed." msgstr "" #: vgcfgrestore.c:66 #, c-format msgid "Restored volume group %s" msgstr "" #: vgchange.c:92 #, c-format msgid "Spawning background process for %s %s" msgstr "" #: vgchange.c:111 #, c-format msgid "%d logical volume(s) in volume group \"%s\" %smonitored" msgstr "" #: vgchange.c:132 #, c-format msgid "Can't deactivate volume group \"%s\" with %d open logical volume(s)" msgstr "" #: vgchange.c:138 #, c-format msgid "Locking inactive: ignoring clustered volume group %s" msgstr "" #: vgchange.c:148 #, c-format msgid "%d logical volume(s) in volume group \"%s\" already active" msgstr "" #: vgchange.c:152 #, c-format msgid "%d existing logical volume(s) in volume group \"%s\" %smonitored" msgstr "" #: vgchange.c:160 #, c-format msgid "Activated logical volumes in volume group \"%s\"" msgstr "" #: vgchange.c:164 #, c-format msgid "Deactivated logical volumes in volume group \"%s\"" msgstr "" #: vgchange.c:167 #, c-format msgid "%d logical volume(s) in volume group \"%s\" now active" msgstr "" #: vgchange.c:179 vgcreate.c:47 msgid "Volume Group allocation policy cannot inherit from anything" msgstr "" #: vgchange.c:185 #, c-format msgid "Volume group allocation policy is already %s" msgstr "" #: vgchange.c:200 vgchange.c:235 vgchange.c:282 vgchange.c:324 vgchange.c:371 #: vgchange.c:429 vgchange.c:471 vgchange.c:504 #, c-format msgid "Volume group \"%s\" successfully changed" msgstr "" #: vgchange.c:211 #, c-format msgid "Volume group \"%s\" is already resizeable" msgstr "" #: vgchange.c:217 #, c-format msgid "Volume group \"%s\" is already not resizeable" msgstr "" #: vgchange.c:247 #, c-format msgid "Volume group \"%s\" is already clustered" msgstr "" #: vgchange.c:253 #, c-format msgid "Volume group \"%s\" is already not clustered" msgstr "" #: vgchange.c:261 #, c-format msgid "Volume group %s contains snapshots that are not yet supported." msgstr "" #: vgchange.c:293 #, c-format msgid "Volume group \"%s\" must be resizeable to change MaxLogicalVolume" msgstr "" #: vgchange.c:302 msgid "MaxLogicalVolume limit is 255" msgstr "" #: vgchange.c:308 #, c-format msgid "MaxLogicalVolume is less than the current number %d of LVs for \"%s\"" msgstr "" #: vgchange.c:335 #, c-format msgid "Volume group \"%s\" must be resizeable to change MaxPhysicalVolumes" msgstr "" #: vgchange.c:341 msgid "MaxPhysicalVolumes may not be negative" msgstr "" #: vgchange.c:349 msgid "MaxPhysicalVolume limit is 255" msgstr "" #: vgchange.c:355 #, c-format msgid "MaxPhysicalVolumes is less than the current number %d of PVs for \"%s\"" msgstr "" #: vgchange.c:381 #, c-format msgid "Volume group \"%s\" must be resizeable to change PE size" msgstr "" #: vgchange.c:387 vgcreate.c:64 msgid "Physical extent size may not be negative" msgstr "" #: vgchange.c:393 vgcreate.c:83 msgid "Physical extent size may not be zero" msgstr "" #: vgchange.c:398 #, c-format msgid "Physical extent size of VG %s is already %s" msgstr "" #: vgchange.c:404 msgid "Physical extent size must be a power of 2." msgstr "" #: vgchange.c:411 msgid "New extent size is not a perfect fit" msgstr "" #: vgchange.c:454 vgcreate.c:117 #, c-format msgid "Failed to add tag %s to volume group %s" msgstr "" #: vgchange.c:460 #, c-format msgid "Failed to remove tag %s from volume group %s" msgstr "" #: vgchange.c:482 msgid "Volume group has active logical volumes" msgstr "" #: vgchange.c:490 #, c-format msgid "Failed to generate new random UUID for VG %s." msgstr "" #: vgchange.c:516 vgconvert.c:36 vgexport.c:27 #, c-format msgid "Unable to find volume group \"%s\"" msgstr "" #: vgchange.c:588 msgid "" "One of -a, -c, -l, -p, -s, -x, --uuid, --alloc, --addtag or --deltag required" msgstr "" #: vgchange.c:600 msgid "" "Only one of -a, -c, -l, -p, -s, -x, --uuid, --alloc, --addtag or --deltag " "allowed" msgstr "" #: vgchange.c:607 msgid "--ignorelockingfailure only available with -a" msgstr "" #: vgchange.c:613 msgid "-A option not necessary with -a option" msgstr "" #: vgconvert.c:59 #, c-format msgid "Volume group \"%s\" already uses format %s" msgstr "" #: vgconvert.c:87 #, c-format msgid "Archive of \"%s\" metadata failed." msgstr "" #: vgconvert.c:100 #, c-format msgid "Logical volume %s must be deactivated before conversion." msgstr "" #: vgconvert.c:130 vgconvert.c:145 vgconvert.c:157 vgconvert.c:170 #: vgconvert.c:186 msgid "Use pvcreate and vgcfgrestore to repair from archived metadata." msgstr "" #: vgconvert.c:166 #, c-format msgid "Deleting existing metadata for VG %s" msgstr "" #: vgconvert.c:168 #, c-format msgid "Removal of existing metadata for %s failed." msgstr "" #: vgconvert.c:177 #, c-format msgid "Test mode: Skipping metadata writing for VG %s in format %s" msgstr "" #: vgconvert.c:182 #, c-format msgid "Writing metadata for VG %s using format %s" msgstr "" #: vgconvert.c:185 #, c-format msgid "Conversion failed for volume group %s." msgstr "" #: vgconvert.c:190 #, c-format msgid "Volume group %s successfully converted" msgstr "" #: vgconvert.c:200 msgid "Please enter volume group(s)" msgstr "" #: vgcreate.c:31 msgid "Please provide volume group name and physical volumes" msgstr "" #: vgcreate.c:37 msgid "Please enter physical volume name(s)" msgstr "" #: vgcreate.c:58 msgid "Number of volumes may not exceed 255" msgstr "" #: vgcreate.c:69 msgid "Max Logical Volumes may not be negative" msgstr "" #: vgcreate.c:74 msgid "Max Physical Volumes may not be negative" msgstr "" #: vgcreate.c:88 vgrename.c:52 vgsplit.c:290 #, c-format msgid "New volume group name \"%s\" is invalid" msgstr "" #: vgcreate.c:98 #, c-format msgid "Warning: Setting maxlogicalvolumes to %d (0 means unlimited)" msgstr "" #: vgcreate.c:102 #, c-format msgid "Warning: Setting maxphysicalvolumes to %d (0 means unlimited)" msgstr "" #: vgcreate.c:112 msgid "Volume group format does not support tags" msgstr "" #: vgcreate.c:163 #, c-format msgid "Volume group \"%s\" successfully created" msgstr "" #: vgdisplay.c:29 #, c-format msgid "WARNING: Volume group \"%s\" inconsistent" msgstr "" #: vgdisplay.c:32 #, c-format msgid "WARNING: volume group \"%s\" is exported" msgstr "" #: vgdisplay.c:52 msgid "--- Physical volumes ---" msgstr "" #: vgdisplay.c:81 msgid "Option -c is not allowed with option -s" msgstr "" #: vgdisplay.c:86 msgid "Option -A is not allowed with volume group names" msgstr "" #: vgexport.c:32 #, c-format msgid "Volume group %s inconsistent" msgstr "" #: vgexport.c:37 #, c-format msgid "Volume group \"%s\" is already exported" msgstr "" #: vgexport.c:47 #, c-format msgid "Volume group \"%s\" has active logical volumes" msgstr "" #: vgexport.c:67 #, c-format msgid "Volume group \"%s\" successfully exported" msgstr "" #: vgexport.c:78 vgimport.c:68 msgid "Please supply volume groups or use -a for all." msgstr "" #: vgexport.c:83 vgimport.c:73 msgid "No arguments permitted when using -a for all." msgstr "" #: vgextend.c:25 msgid "Please enter volume group name and physical volume(s)" msgstr "" #: vgextend.c:31 msgid "Please enter physical volume(s)" msgstr "" #: vgextend.c:50 vgmerge.c:32 vgmerge.c:63 vgsplit.c:238 vgsplit.c:275 #, c-format msgid "Checking for volume group \"%s\"" msgstr "" #: vgextend.c:58 #, c-format msgid "Volume group \"%s\" not found." msgstr "" #: vgextend.c:79 #, c-format msgid "Volume group \"%s\" is not resizeable." msgstr "" #: vgextend.c:98 #, c-format msgid "Volume group \"%s\" will be extended by %d new physical volumes" msgstr "" #: vgextend.c:110 #, c-format msgid "Volume group \"%s\" successfully extended" msgstr "" #: vgimport.c:27 #, c-format msgid "Unable to find exported volume group \"%s\"" msgstr "" #: vgimport.c:33 #, c-format msgid "Volume group \"%s\" is not exported" msgstr "" #: vgimport.c:38 #, c-format msgid "Volume group \"%s\" is partially missing" msgstr "" #: vgimport.c:57 #, c-format msgid "Volume group \"%s\" successfully imported" msgstr "" #: vgmerge.c:28 vgsplit.c:234 #, c-format msgid "Duplicate volume group name \"%s\"" msgstr "" #: vgmerge.c:93 vgsplit.c:297 #, c-format msgid "Logical volumes in \"%s\" must be inactive" msgstr "" #: vgmerge.c:100 #, c-format msgid "Extent sizes differ: %d (%s) and %d (%s)" msgstr "" #: vgmerge.c:108 #, c-format msgid "Maximum number of physical volumes (%d) exceeded for \"%s\" and \"%s\"" msgstr "" #: vgmerge.c:116 #, c-format msgid "Maximum number of logical volumes (%d) exceeded for \"%s\" and \"%s\"" msgstr "" #: vgmerge.c:130 #, c-format msgid "Duplicate logical volume name \"%s\" in \"%s\" and \"%s\"" msgstr "" #: vgmerge.c:142 vgmerge.c:151 #, c-format msgid "Physical volume %s might be constructed from same volume group %s." msgstr "" #: vgmerge.c:186 #, c-format msgid "Failed to generate new random LVID for %s" msgstr "" #: vgmerge.c:197 #, c-format msgid "Changed LVID for %s to %s" msgstr "" #: vgmerge.c:235 #, c-format msgid "Volume group \"%s\" successfully merged into \"%s\"" msgstr "" #: vgmerge.c:252 msgid "Please enter 2 or more volume groups to merge" msgstr "" #: vgreduce.c:24 msgid "Volume Groups must always contain at least one PV" msgstr "" #: vgreduce.c:33 #, c-format msgid "Removing PV with UUID %s from VG %s" msgstr "" #: vgreduce.c:36 #, c-format msgid "LVs still present on PV with UUID %s: Can't remove from VG %s" msgstr "" #: vgreduce.c:61 #, c-format msgid "%s/%s has missing extents: removing (including dependencies)" msgstr "" #: vgreduce.c:68 #, c-format msgid "Deactivating (if active) logical volume %s (origin of %s)" msgstr "" #: vgreduce.c:72 vgreduce.c:89 vgreduce.c:333 #, c-format msgid "Failed to deactivate LV %s" msgstr "" #: vgreduce.c:99 vgreduce.c:146 vgreduce.c:348 #, c-format msgid "Removing LV %s from VG %s" msgstr "" #: vgreduce.c:191 #, c-format msgid "Non-mirror-image LV %s found: can't remove." msgstr "" #: vgreduce.c:207 msgid "Aborting because --mirrorsonly was specified." msgstr "" #: vgreduce.c:232 vgreduce.c:529 #, c-format msgid "Failed to write out a consistent VG for %s" msgstr "" #: vgreduce.c:250 #, c-format msgid "Failed to commit consistent VG for %s" msgstr "" #: vgreduce.c:258 msgid "Failed to resume LVs using error segments." msgstr "" #: vgreduce.c:290 #, c-format msgid "The log device for %s/%s has failed." msgstr "" #: vgreduce.c:296 #, c-format msgid "Log device for %s/%s has failed." msgstr "" #: vgreduce.c:312 #, c-format msgid "Failed to write out updated VG for %s" msgstr "" #: vgreduce.c:318 #, c-format msgid "Failed to commit updated VG for %s" msgstr "" #: vgreduce.c:329 #, c-format msgid "Deactivating (if active) logical volume %s" msgstr "" #: vgreduce.c:371 #, c-format msgid "Physical volume \"%s\" still in use" msgstr "" #: vgreduce.c:376 #, c-format msgid "Can't remove final physical volume \"%s\" from volume group \"%s\"" msgstr "" #: vgreduce.c:386 #, c-format msgid "Removing \"%s\" from volume group \"%s\"" msgstr "" #: vgreduce.c:404 #, c-format msgid "Removal of physical volume \"%s\" from \"%s\" failed" msgstr "" #: vgreduce.c:418 #, c-format msgid "Removed \"%s\" from volume group \"%s\"" msgstr "" #: vgreduce.c:431 msgid "Please give volume group name and physical volume paths" msgstr "" #: vgreduce.c:437 msgid "Please give volume group name" msgstr "" #: vgreduce.c:443 msgid "--mirrorsonly requires --removemissing" msgstr "" #: vgreduce.c:449 msgid "Please enter physical volume paths or option -a" msgstr "" #: vgreduce.c:454 msgid "Option -a and physical volume paths mutually exclusive" msgstr "" #: vgreduce.c:460 msgid "Please only specify the volume group" msgstr "" #: vgreduce.c:496 #, c-format msgid "Volume group \"%s\" is already consistent" msgstr "" #: vgreduce.c:537 #, c-format msgid "Wrote out consistent volume group %s" msgstr "" #: vgreduce.c:553 #, c-format msgid "Volume group \"%s\" is not reducible" msgstr "" #: vgremove.c:27 #, c-format msgid "Volume group \"%s\" not found or inconsistent." msgstr "" #: vgremove.c:29 msgid "Consider vgreduce --removemissing if metadata is inconsistent." msgstr "" #: vgremove.c:40 #, c-format msgid "Volume group \"%s\" still contains %d logical volume(s)" msgstr "" #: vgremove.c:49 #, c-format msgid "vg_remove %s failed" msgstr "" #: vgremove.c:56 #, c-format msgid "Removing physical volume \"%s\" from volume group \"%s\"" msgstr "" #: vgremove.c:69 #, c-format msgid "Failed to remove physical volume \"%s\" from volume group \"%s\"" msgstr "" #: vgremove.c:79 #, c-format msgid "Volume group \"%s\" successfully removed" msgstr "" #: vgremove.c:81 #, c-format msgid "Volume group \"%s\" not properly removed" msgstr "" #: vgremove.c:91 msgid "Please enter one or more volume group paths" msgstr "" #: vgrename.c:34 msgid "Old and new volume group names need specifying" msgstr "" #: vgrename.c:46 #, c-format msgid "New volume group path exceeds maximum length of %d!" msgstr "" #: vgrename.c:58 msgid "Old and new volume group names must differ" msgstr "" #: vgrename.c:66 msgid "No complete volume groups found" msgstr "" #: vgrename.c:76 #, c-format msgid "Found more than one VG called %s. Please supply VG uuid." msgstr "" #: vgrename.c:99 #, c-format msgid "Volume group %s %s%s%snot found." msgstr "" #: vgrename.c:123 #, c-format msgid "Volume group \"%s\" still has active LVs" msgstr "" #: vgrename.c:129 #, c-format msgid "Checking for new volume group \"%s\"" msgstr "" #: vgrename.c:139 #, c-format msgid "New volume group \"%s\" already exists" msgstr "" #: vgrename.c:154 #, c-format msgid "Renaming \"%s\" to \"%s\"" msgstr "" #: vgrename.c:156 msgid "Test mode: Skipping rename." msgstr "" #: vgrename.c:158 #, c-format msgid "Renaming \"%s\" to \"%s\" failed: %s" msgstr "" #: vgrename.c:177 #, c-format msgid "Volume group \"%s\" successfully renamed to \"%s\"" msgstr "" #: vgscan.c:36 #, c-format msgid "Found %svolume group \"%s\" using metadata type %s" msgstr "" #: vgscan.c:50 msgid "Too many parameters on command line" msgstr "" #: vgscan.c:57 msgid "Reading all physical volumes. This may take a while..." msgstr "" #: vgsplit.c:25 #, c-format msgid "Physical volume %s not in volume group %s" msgstr "" #: vgsplit.c:90 #, c-format msgid "Can't split Logical Volume %s between two Volume Groups" msgstr "" #: vgsplit.c:152 #, c-format msgid "Snapshot %s split" msgstr "" #: vgsplit.c:193 #, c-format msgid "Mirror %s split" msgstr "" #: vgsplit.c:218 msgid "Existing VG, new VG and physical volumes required." msgstr "" #: vgsplit.c:264 #, c-format msgid "Volume group \"%s\" is not resizeable" msgstr "" #: vgsplit.c:285 #, c-format msgid "Volume group \"%s\" already exists" msgstr "" #: vgsplit.c:339 msgid "Cannot split: Nowhere to store metadata for new Volume Group" msgstr "" #: vgsplit.c:348 msgid "Writing out updated volume groups" msgstr "" #: vgsplit.c:370 #, c-format msgid "Volume group \"%s\" became inconsistent: please fix manually" msgstr "" #: vgsplit.c:385 #, c-format msgid "Volume group \"%s\" successfully split from \"%s\"" msgstr "" #: zero/zero.c:71 msgid "zero module string list allocation failed" msgstr "" lvm2-2.02.98/po/Makefile.in0000640000175000017500000000375712037016272014207 0ustar blankblank# # 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@ LANGS=de TARGETS=$(LANGS:%=lvm2_%.mo) $(LANGS:%=dm_%.mo) DM_POSOURCES = $(top_srcdir)/dmsetup/*.pot $(top_srcdir)/libdm/*.pot \ $(top_srcdir)/libdm/*/*.pot LVM_POSOURCES = $(top_srcdir)/tools/*.pot $(top_srcdir)/lib/*/*.pot include $(top_builddir)/make.tmpl lvm2.po: Makefile $(LVM_POSOURCES) @echo Compiling string table @xgettext -C -F --keyword=print_log --keyword=log_debug \ --keyword=log_info --keyword=_ --keyword=N_ \ --keyword=log_notice --keyword=log_warn --keyword=log_err \ --keyword=log_fatal --keyword=log_debug --keyword=log_error \ --keyword=log_print --keyword=log_verbose \ --keyword=log_very_verbose -d - \ $(LVM_POSOURCES) > $@ device-mapper.po: Makefile $(DM_POSOURCES) @echo Compiling string table @xgettext -C -F --keyword=dm_log --keyword=log_debug \ --keyword=log_info --keyword=_ --keyword=N_ \ --keyword=log_notice --keyword=log_warn --keyword=log_err \ --keyword=log_fatal --keyword=log_debug --keyword=log_error \ --keyword=log_print --keyword=log_verbose \ --keyword=log_very_verbose -d - \ $(DM_POSOURCES) > $@ pofile: lvm2.po device-mapper.po # FIXME install: $(TARGETS) @echo Installing translation files in $(localedir) @( \ for lang in $(LANGS); do \ $(INSTALL_DATA) -D $$lang.mo \ $(localedir)/$$lang/LC_MESSAGES/lvm2.mo;\ done; \ ) @( \ for lang in $(LANGS); do \ $(INSTALL_DATA) -D $$lang.mo \ $(localedir)/$$lang/LC_MESSAGES/device-mapper.mo;\ done; \ ) lvm2-2.02.98/po/pogen.h0000640000175000017500000000170112037016272013406 0ustar blankblank/* * 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 */ /* * Macros to change log messages into a format that xgettext can handle. * * Note that different PRI* definitions lead to different strings for * different architectures. */ #define print_log(level, dm_errno, file, line, format, args...) print_log(format, args) #define dm_log(level, file, line, format, args...) dm_log(format, args) #define dm_log_with_errno(level, dm_errno, file, line, format, args...) \ dm_log(level, file, line, format, args) lvm2-2.02.98/po/de.po0000640000175000017500000000042312037016272013055 0ustar blankblank# Dummy test file msgid "" msgstr "" "PO-Revision-Date: 2004-02-13 20:35+0000\n" "Last-Translator: Nobody \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=ISO-8859-15\n" "Content-Transfer-Encoding: 8bit\n" lvm2-2.02.98/autoconf/0000750000175000017500000000000012037016272013325 5ustar blankblanklvm2-2.02.98/autoconf/config.sub0000750000175000017500000010316712037016272015320 0ustar blankblank#! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 # Free Software Foundation, Inc. timestamp='2009-11-20' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software # can handle that machine. It does not imply ALL GNU software can. # # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # 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., 51 Franklin Street - Fifth Floor, Boston, MA # 02110-1301, 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. # Please send patches to . Submit a context # diff and a properly formatted GNU ChangeLog entry. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \ uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \ kopensolaris*-gnu* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis | -knuth | -cray | -microblaze) os= basic_machine=$1 ;; -bluegene*) os=-cnk ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco6) os=-sco5v6 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5v6*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ | bfin \ | c4x | clipper \ | d10v | d30v | dlx | dsp16xx \ | fido | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | lm32 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ | maxq | mb | microblaze | mcore | mep | metag \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64octeon | mips64octeonel \ | mips64orion | mips64orionel \ | mips64r5900 | mips64r5900el \ | mips64vr | mips64vrel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | moxie \ | mt \ | msp430 \ | nios | nios2 \ | ns16k | ns32k \ | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ | pyramid \ | rx \ | score \ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ | spu | strongarm \ | tahoe | thumb | tic4x | tic80 | tron \ | ubicom32 \ | v850 | v850e \ | we32k \ | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \ | z8k | z80) basic_machine=$basic_machine-unknown ;; m6811 | m68hc11 | m6812 | m68hc12 | picochip) # Motorola 68HC11/12. basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; ms1) basic_machine=mt-unknown ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ | lm32-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64octeon-* | mips64octeonel-* \ | mips64orion-* | mips64orionel-* \ | mips64r5900-* | mips64r5900el-* \ | mips64vr-* | mips64vrel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ | nios-* | nios2-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ | pyramid-* \ | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \ | tahoe-* | thumb-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* | tile-* \ | tron-* \ | ubicom32-* \ | v850-* | v850e-* | vax-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \ | xstormy16-* | xtensa*-* \ | ymp-* \ | z8k-* | z80-*) ;; # Recognize the basic CPU types without company name, with glob match. xtensa*) basic_machine=$basic_machine-unknown ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; abacus) basic_machine=abacus-unknown ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aros) basic_machine=i386-pc os=-aros ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; blackfin) basic_machine=bfin-unknown os=-linux ;; blackfin-*) basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; bluegene*) basic_machine=powerpc-ibm os=-cnk ;; c90) basic_machine=c90-cray os=-unicos ;; cegcc) basic_machine=arm-unknown os=-cegcc ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; craynv) basic_machine=craynv-cray os=-unicosmp ;; cr16) basic_machine=cr16-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds ;; crisv32 | crisv32-* | etraxfs*) basic_machine=crisv32-axis ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; crx) basic_machine=crx-unknown os=-elf ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dicos) basic_machine=i686-pc os=-dicos ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; # I'm not sure what "Sysv32" means. Should this be sysv3.2? i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m68knommu) basic_machine=m68k-unknown os=-linux ;; m68knommu-*) basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; microblaze) basic_machine=microblaze-xilinx ;; mingw32) basic_machine=i386-pc os=-mingw32 ;; mingw32ce) basic_machine=arm-unknown os=-mingw32ce ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; msdos) basic_machine=i386-pc os=-msdos ;; ms1-*) basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` ;; mvs) basic_machine=i370-ibm os=-mvs ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; openrisc | openrisc-*) basic_machine=or32-unknown ;; os400) basic_machine=powerpc-ibm os=-os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; parisc) basic_machine=hppa-unknown os=-linux ;; parisc-*) basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pc98) basic_machine=i386-pc ;; pc98-*) basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc) basic_machine=powerpc-unknown ;; ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rdos) basic_machine=i386-pc os=-rdos ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sde) basic_machine=mipsisa32-sde os=-elf ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh5el) basic_machine=sh5le-unknown ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tic54x | c54x*) basic_machine=tic54x-unknown os=-coff ;; tic55x | c55x*) basic_machine=tic55x-unknown os=-coff ;; tic6x | c6x*) basic_machine=tic6x-unknown os=-coff ;; tile*) basic_machine=tile-unknown os=-linux-gnu ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; tpf) basic_machine=s390x-ibm os=-tpf ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xbox) basic_machine=i686-pc os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; z80-*-coff) basic_machine=z80-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; mmix) basic_machine=mmix-knuth ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -auroraux) os=-auroraux ;; -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ | -sym* | -kopensolaris* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* | -aros* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ | -openbsd* | -solidbsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* | -cegcc* \ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -syllable*) os=-syllable ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -tpf*) os=-tpf ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -kaos*) os=-kaos ;; -zvmoe) os=-zvmoe ;; -dicos*) os=-dicos ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in score-*) os=-elf ;; spu-*) os=-elf ;; *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 # This also exists in the configure program, but was not the # default. # os=-sunos4 ;; m68*-cisco) os=-aout ;; mep-*) os=-elf ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-haiku) os=-haiku ;; *-ibm) os=-aix ;; *-knuth) os=-mmixware ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -cnk*|-aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -os400*) vendor=ibm ;; -ptx*) vendor=sequent ;; -tpf*) vendor=ibm ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: lvm2-2.02.98/autoconf/install-sh0000750000175000017500000003160012037016272015331 0ustar blankblank#!/bin/sh # install - install a program, script, or datafile 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 (C) 1994 X Consortium # # 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. 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 file names if you don't have them in your path; # or use environment vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" 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= dstarg= no_target_directory= usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. 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. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test $# -ne 0; do case $1 in -c) shift continue;; -d) dir_arg=true shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; --help) echo "$usage"; exit $?;; -m) mode=$2 shift shift case $mode in *' '* | *' '* | *' '* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -s) stripcmd=$stripprog shift continue;; -t) dstarg=$2 shift shift continue;; -T) no_target_directory=true shift continue;; --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 test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call `install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then trap '(exit $?); exit' 1 2 13 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[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 mkdir_mode= fi posix_mkdir=false case $umask in *[123567][0-7][0-7]) # POSIX mkdir -p sets u+wx bits regardless of umask, which # is incompatible with FreeBSD 'install' when (umask & 300) != 0. ;; *) tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 if (umask $mkdir_umask && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writeable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. ls_ld_tmpdir=`ls -ld "$tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/d" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null fi trap '' 0;; esac;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # The umask is ridiculous, or mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix=/ ;; -*) prefix=./ ;; *) prefix= ;; esac case $posix_glob in '') if (set -f) 2>/dev/null; then posix_glob=true else posix_glob=false fi ;; esac oIFS=$IFS IFS=/ $posix_glob && set -f set fnord $dstdir shift $posix_glob && set +f IFS=$oIFS prefixes= for d do test -z "$d" && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask=$mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \ && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \ && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \ && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # Now rename the file to the real destination. { $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null \ || { # 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. # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { if test -f "$dst"; then $doit $rmcmd -f "$dst" 2>/dev/null \ || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null \ && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }; }\ || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } else : fi } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } } || exit 1 trap '' 0 fi done # 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: lvm2-2.02.98/autoconf/config.guess0000750000175000017500000012761512037016272015661 0ustar blankblank#! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 # Free Software Foundation, Inc. timestamp='2009-11-20' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # 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., 51 Franklin Street - Fifth Floor, Boston, MA # 02110-1301, 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. # Originally written by Per Bothner. Please send patches (context # diff format) to and include a ChangeLog # entry. # # This script attempts to guess a canonical system name similar to # config.sub. If it succeeds, it prints the system name on stdout, and # exits with 0. Otherwise, it exits with 1. # # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ; set_cc_for_build= ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; *:SolidBSD:*:*) echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} exit ;; macppc:MirBSD:*:*) echo powerpc-unknown-mirbsd${UNAME_RELEASE} exit ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` exit ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; arm:riscos:*:*|arm:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; s390x:SunOS:*:*) echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) echo i386-pc-auroraux${UNAME_RELEASE} exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) eval $set_cc_for_build SUN_ARCH="i386" # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH="x86_64" fi fi echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`$dummy $dummyarg` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos${UNAME_RELEASE} exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit ;; *:AIX:*:[456]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then eval $set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) case ${UNAME_MACHINE} in pc98) echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; i*:windows32*:*) # uname -m includes "-pc" on this system. echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; *:Interix*:*) case ${UNAME_MACHINE} in x86) echo i586-pc-interix${UNAME_RELEASE} exit ;; authenticamd | genuineintel | EM64T) echo x86_64-unknown-interix${UNAME_RELEASE} exit ;; IA64) echo ia64-unknown-interix${UNAME_RELEASE} exit ;; esac ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; 8664:Windows_NT:*) echo x86_64-pc-mks exit ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} exit ;; arm*:Linux:*:*) eval $set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then echo ${UNAME_MACHINE}-unknown-linux-gnu else echo ${UNAME_MACHINE}-unknown-linux-gnueabi fi exit ;; avr32*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; cris:Linux:*:*) echo cris-axis-linux-gnu exit ;; crisv32:Linux:*:*) echo crisv32-axis-linux-gnu exit ;; frv:Linux:*:*) echo frv-unknown-linux-gnu exit ;; i*86:Linux:*:*) LIBC=gnu eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __dietlibc__ LIBC=dietlibc #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` echo "${UNAME_MACHINE}-pc-linux-${LIBC}" exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; mips:Linux:*:* | mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef ${UNAME_MACHINE} #undef ${UNAME_MACHINE}el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=${UNAME_MACHINE}el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=${UNAME_MACHINE} #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } ;; or32:Linux:*:*) echo or32-unknown-linux-gnu exit ;; padre:Linux:*:*) echo sparc-unknown-linux-gnu exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-gnu exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-gnu ;; PA8*) echo hppa2.0-unknown-linux-gnu ;; *) echo hppa-unknown-linux-gnu ;; esac exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-gnu exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-gnu exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux exit ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; vax:Linux:*:*) echo ${UNAME_MACHINE}-dec-linux-gnu exit ;; x86_64:Linux:*:*) echo x86_64-unknown-linux-gnu exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configury will decide that # this is a cross-build. echo i586-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo ${UNAME_MACHINE}-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. echo i586-pc-haiku exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit ;; SX-7:SUPER-UX:*:*) echo sx7-nec-superux${UNAME_RELEASE} exit ;; SX-8:SUPER-UX:*:*) echo sx8-nec-superux${UNAME_RELEASE} exit ;; SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux${UNAME_RELEASE} exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown case $UNAME_PROCESSOR in i386) eval $set_cc_for_build if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then UNAME_PROCESSOR="x86_64" fi fi ;; unknown) UNAME_PROCESSOR=powerpc ;; esac echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NSE-?:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' exit ;; i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos exit ;; i*86:AROS:*:*) echo ${UNAME_MACHINE}-pc-aros exit ;; esac #echo '(No uname command or uname output not recognized.)' 1>&2 #echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 eval $set_cc_for_build cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix\n"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; c34*) echo c34-convex-bsd exit ;; c38*) echo c38-convex-bsd exit ;; c4*) echo c4-convex-bsd exit ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: lvm2-2.02.98/udev/0000750000175000017500000000000012037016273012453 5ustar blankblanklvm2-2.02.98/udev/13-dm-disk.rules.in0000640000175000017500000000263312037016273015712 0ustar blankblank# Copyright (C) 2009 Red Hat, Inc. All rights reserved. # # This file is part of LVM2. # Udev rules for device-mapper devices. # # These rules create symlinks in /dev/disk directory. # Symlinks that depend on probing filesystem type, # label and uuid are created only if the device is not # suspended. # "add" event is processed on coldplug only! ACTION!="add|change", GOTO="dm_end" ENV{DM_UDEV_RULES_VSN}!="?*", GOTO="dm_end" ENV{DM_UDEV_DISABLE_DISK_RULES_FLAG}=="1", GOTO="dm_end" SYMLINK+="disk/by-id/dm-name-$env{DM_NAME}" ENV{DM_UUID}=="?*", SYMLINK+="disk/by-id/dm-uuid-$env{DM_UUID}" ENV{DM_SUSPENDED}=="1", GOTO="dm_end" (BLKID_RULE) ENV{DM_UDEV_LOW_PRIORITY_FLAG}=="1", OPTIONS="link_priority=-100" ENV{ID_FS_USAGE}=="filesystem|other|crypto", ENV{ID_FS_UUID_ENC}=="?*", SYMLINK+="disk/by-uuid/$env{ID_FS_UUID_ENC}" ENV{ID_FS_USAGE}=="filesystem|other", ENV{ID_FS_LABEL_ENC}=="?*", SYMLINK+="disk/by-label/$env{ID_FS_LABEL_ENC}" # Add inotify watch to track changes on this device. # Using the watch rule is not optimal - it generates a lot of spurious # and useless events whenever the device opened for read-write is closed. # The best would be to generete the event directly in the tool changing # relevant information so only relevant events will be processed # (like creating a filesystem, changing filesystem label etc.). # # But let's use this until we have something better... OPTIONS+="watch" LABEL="dm_end" lvm2-2.02.98/udev/95-dm-notify.rules.in0000640000175000017500000000074312037016273016302 0ustar blankblank# Copyright (C) 2009 Red Hat, Inc. All rights reserved. # # This file is part of LVM2. # Udev rules for device-mapper devices. # # These rules are responsible for sending a notification to a process # waiting for completion of udev rules. The process is identified by # a cookie value sent within "change" and "remove" events (the cookie # value is set before by that process for every action requested). ENV{DM_COOKIE}=="?*", RUN+="(DM_EXEC)/dmsetup udevcomplete $env{DM_COOKIE}" lvm2-2.02.98/udev/12-dm-permissions.rules0000640000175000017500000000616212037016273016726 0ustar blankblank# Copyright (C) 2009 Red Hat, Inc. All rights reserved. # # This file is part of LVM2. # Udev rules for device-mapper devices. # # These rules set permissions for DM devices. # # This file is considered to be a template where users can put their # own entries and then put a copy of it manually to a usual place with # user-edited udev rules (usually /etc/udev/rules.d). # # There are some environment variables set that can be used: # DM_UDEV_RULES_VSN - DM udev rules version # DM_NAME - actual DM device's name # DM_UUID - UUID set for DM device (blank if not specified) # DM_SUSPENDED - suspended state of DM device (0 or 1) # DM_LV_NAME - logical volume name (not set if LVM device not present) # DM_VG_NAME - volume group name (not set if LVM device not present) # DM_LV_LAYER - logical volume layer (not set if LVM device not present) # "add" event is processed on coldplug only! ACTION!="add|change", GOTO="dm_end" ENV{DM_UDEV_RULES_VSN}!="?*", GOTO="dm_end" # A few demonstrational examples... # PLAIN DM DEVICES # # Set permissions for a DM device named 'my_device' exactly # ENV{DM_NAME}=="my_device", OWNER:="root", GROUP:="root", MODE:="660" # Set permissions for all DM devices having 'MY_UUID-' UUID prefix # ENV{DM_UUID}=="MY_UUID-?*", OWNER:="root", GROUP:="root", MODE:="660" # LVM DEVICES # # Set permissions for all LVM devices # ENV{DM_UUID}=="LVM-?*", OWNER:="root", GROUP:="root", MODE:="660" # Set permissions for all devices that belong to one LVM VG # ENV{DM_VG_NAME}=="VolGroup00", OWNER:="root", GROUP:="root", MODE:="660" # Set permissions for an LVM device with VG named VolGroup00 and LV named LogVol00 exactly # ENV{DM_VG_NAME}=="VolGroup00", ENV{DM_LV_NAME}=="LogVol00", OWNER:="root", GROUP:="root", MODE:="660" # Set permissions for all LVM devices that does not belong to a VG named VolGroup00 # ENV{DM_VG_NAME}!="VolGroup00", OWNER:="root", GROUP:="root", MODE:="660" # ENCRYPTED DEVICES (using cryptsetup >= 1.1) # # Set permissions for all encrypted devices created by cryptsetup (plain devices) # ENV{DM_UUID}=="CRYPT-PLAIN-?*", OWNER:="root", GROUP:="root", MODE:="660" # Set permissions for all encrypted devices created by cryptsetup (LUKS extension) # ENV{DM_UUID}=="CRYPT-LUKS1-?*", OWNER:="root", GROUP:="root", MODE:="660" # Set permissions for an encrypted device created by cryptsetup and having an exact luks UUID # ENV{DM_UUID}=="CRYPT-LUKS1-22fce5c8313c43c68d84b50a3b0fee78-?*", OWNER:="root", GROUP:="root", MODE:="660" # MULTIPATH DEVICES # # Set permissions for all multipath devices # ENV{DM_UUID}=="mpath-?*", OWNER:="root", GROUP:="root", MODE:="660" # Set permissions for first two partitions created on a multipath device (and detected by kpartx) # ENV{DM_UUID}=="part[1-2]-mpath-?*", OWNER:="root", GROUP:="root", MODE:="660" # ...you can use any combination of the comparisons with the environment variables # listed at the beginning of this file (udev provides simple pattern matching by # using *, ? and [] that you can use, see 'man udev' for more information). # Set default permissions for all DM devices if not set before. # OWNER:="root", GROUP:="root", MODE:="660" LABEL="dm_end" lvm2-2.02.98/udev/Makefile.in0000640000175000017500000000356412037016273014531 0ustar blankblank# # 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@ include $(top_builddir)/make.tmpl vpath %.rules $(srcdir) DM_RULES=10-dm.rules 13-dm-disk.rules 95-dm-notify.rules LVM_RULES=11-dm-lvm.rules ifeq ("@BUILD_LVMETAD@", "yes") LVM_RULES+=69-dm-lvm-metad.rules endif DM_DIR=$(shell grep "\#define DM_DIR" $(top_srcdir)/libdm/misc/dm-ioctl.h | awk '{print $$3}') ifeq ("@UDEV_RULE_EXEC_DETECTION@", "yes") SBIN=\$$env{DM_SBIN_PATH} DM_EXEC_RULE=ENV{DM_SBIN_PATH}=\"\/sbin\"\\nTEST!=\"\$$env{DM_SBIN_PATH}\/dmsetup\", ENV{DM_SBIN_PATH}=\"\/usr\/sbin\" DM_EXEC=\$$env{DM_SBIN_PATH} LVM_EXEC_RULE=ENV{LVM_SBIN_PATH}=\"\/sbin\"\\nTEST!=\"\$$env{LVM_SBIN_PATH}\/lvm\", ENV{LVM_SBIN_PATH}=\"\/usr\/sbin\" LVM_EXEC=\$$env{LVM_SBIN_PATH} else SBIN="@sbindir@" DM_EXEC_RULE="" DM_EXEC=${SBIN} LVM_EXEC_RULE="" LVM_EXEC=${SBIN} endif ifeq ("@UDEV_HAS_BUILTIN_BLKID@", "yes") BLKID_RULE=IMPORT{builtin}=\"blkid\" else BLKID_RULE=IMPORT{program}=\"${SBIN}\/blkid -o udev -p \$$tempnode\" endif %.rules: %.rules.in $(SED) -e "s+(DM_DIR)+$(DM_DIR)+;s+(BLKID_RULE)+$(BLKID_RULE)+;s+(DM_EXEC_RULE)+$(DM_EXEC_RULE)+;s+(DM_EXEC)+$(DM_EXEC)+;s+(LVM_EXEC_RULE)+$(LVM_EXEC_RULE)+;s+(LVM_EXEC)+$(LVM_EXEC)+;" $< >$@ %_install: %.rules $(INSTALL_DATA) -D $< $(udevdir)/$(= 2.6.31 only. Cookie is not decoded for remove event. ENV{DM_COOKIE}=="?*", IMPORT{program}="(DM_EXEC)/dmsetup udevflags $env{DM_COOKIE}" # Rule out easy-to-detect inappropriate events first. ENV{DISK_RO}=="1", GOTO="dm_disable" # There is no cookie set nor any flags encoded in events not originating # in libdevmapper so we need to detect this and try to behave correctly. # For such spurious events, regenerate all flags from current udev database content # (this information would normally be inaccessible for spurious ADD and CHANGE events). ENV{DM_UDEV_PRIMARY_SOURCE_FLAG}=="1", GOTO="dm_flags_done" IMPORT{db}="DM_UDEV_DISABLE_DM_RULES_FLAG" IMPORT{db}="DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG" IMPORT{db}="DM_UDEV_DISABLE_DISK_RULES_FLAG" IMPORT{db}="DM_UDEV_DISABLE_OTHER_RULES_FLAG" IMPORT{db}="DM_UDEV_LOW_PRIORITY_FLAG" IMPORT{db}="DM_UDEV_DISABLE_LIBRARY_FALLBACK_FLAG" IMPORT{db}="DM_UDEV_PRIMARY_SOURCE_FLAG" IMPORT{db}="DM_UDEV_FLAG7" IMPORT{db}="DM_SUBSYSTEM_UDEV_FLAG0" IMPORT{db}="DM_SUBSYSTEM_UDEV_FLAG1" IMPORT{db}="DM_SUBSYSTEM_UDEV_FLAG2" IMPORT{db}="DM_SUBSYSTEM_UDEV_FLAG3" IMPORT{db}="DM_SUBSYSTEM_UDEV_FLAG4" IMPORT{db}="DM_SUBSYSTEM_UDEV_FLAG5" IMPORT{db}="DM_SUBSYSTEM_UDEV_FLAG6" IMPORT{db}="DM_SUBSYSTEM_UDEV_FLAG7" IMPORT{db}="DM_UDEV_RULES_VSN" LABEL="dm_flags_done" # Normally, we operate on "change" events. But when coldplugging, there's an # "add" event present. We have to recognize this and do our actions in this # particular situation, too. Also, we don't want the nodes to be created # prematurely on "add" events while not coldplugging. We check # DM_UDEV_PRIMARY_SOURCE_FLAG to see if the device was activated correctly # before and if not, we ignore the "add" event totally. This way we can support # udev triggers generating "add" events (e.g. "udevadm trigger --action=add" or # "echo add > /sys/block//uevent"). The trigger with "add" event is # also used at boot to reevaluate udev rules for all existing devices activated # before (e.g. in initrd). If udev is used in initrd, we require the udev init # script to not remove the existing udev database so we can reuse the information # stored at the time of device activation in the initrd. ACTION=="add", ENV{DM_UDEV_RULES_VSN}!="1", ENV{DM_UDEV_PRIMARY_SOURCE_FLAG}!="1", GOTO="dm_disable" # "dm" sysfs subdirectory is available in newer versions of DM # only (kernels >= 2.6.29). We have to check for its existence # and use dmsetup tool instead to get the DM name, uuid and # suspended state if the "dm" subdirectory is not present. # The "suspended" item was added even later (kernels >= 2.6.31), # so we also have to call dmsetup if the kernel version used # is in between these releases. TEST=="dm", ENV{DM_NAME}="$attr{dm/name}", ENV{DM_UUID}="$attr{dm/uuid}", ENV{DM_SUSPENDED}="$attr{dm/suspended}" TEST!="dm", IMPORT{program}="(DM_EXEC)/dmsetup info -j %M -m %m -c --nameprefixes --noheadings --rows -o name,uuid,suspended" ENV{DM_SUSPENDED}!="?*", IMPORT{program}="(DM_EXEC)/dmsetup info -j %M -m %m -c --nameprefixes --noheadings --rows -o suspended" # dmsetup tool provides suspended state information in textual # form with values "Suspended"/"Active". We translate it to # 0/1 respectively to be consistent with sysfs values. ENV{DM_SUSPENDED}=="Active", ENV{DM_SUSPENDED}="0" ENV{DM_SUSPENDED}=="Suspended", ENV{DM_SUSPENDED}="1" # This variable provides a reliable way to check that device-mapper # rules were installed. It means that all needed variables are set # by these rules directly so there's no need to acquire them again # later. Other rules can alternate the functionality based on this # fact (e.g. fallback to rules that behave correctly even without # these rules installed). It also provides versioning for any # possible future changes. # VSN 1 - original rules # VSN 2 - add support for synthesized events ENV{DM_UDEV_RULES_VSN}="2" ENV{DM_UDEV_DISABLE_DM_RULES_FLAG}!="1", ENV{DM_NAME}=="?*", SYMLINK+="(DM_DIR)/$env{DM_NAME}" # We have to ignore further rule application for inappropriate events # and devices. But still send the notification if cookie exists. ENV{DM_UUID}=="mpath-?*", ENV{DM_ACTION}=="PATH_FAILED", GOTO="dm_disable" ENV{DM_UUID}=="CRYPT-TEMP-?*", GOTO="dm_disable" ENV{DM_UUID}!="?*", ENV{DM_NAME}=="temporary-cryptsetup-?*", GOTO="dm_disable" # Avoid processing and scanning a DM device in the other (foreign) # rules if it is in suspended state. However, we still keep 'disk' # and 'DM subsystem' related rules enabled in this case. ENV{DM_SUSPENDED}=="1", ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}="1" GOTO="dm_end" LABEL="dm_disable" ENV{DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG}="1" ENV{DM_UDEV_DISABLE_DISK_RULES_FLAG}="1" ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}="1" OPTIONS:="nowatch" LABEL="dm_end" lvm2-2.02.98/udev/69-dm-lvm-metad.rules.in0000640000175000017500000000215512037016273016660 0ustar blankblank# Copyright (C) 2012 Red Hat, Inc. All rights reserved. # # This file is part of LVM2. # Udev rules for LVM. # # Scan all block devices having a PV label for LVM metadata. # Store this information in LVMetaD (the LVM metadata daemon) and maintain LVM # metadata state for improved performance by avoiding further scans while # running subsequent LVM commands or while using lvm2app library. # Also, notify LVMetaD about any relevant block device removal. # # This rule is essential for having the information in LVMetaD up-to-date. # It also requires blkid to be called on block devices before so only devices # used as LVM PVs are processed (ID_FS_TYPE="LVM2_member" or "LVM1_member"). SUBSYSTEM!="block", GOTO="lvm_end" (LVM_EXEC_RULE) # Device-mapper devices are processed only on change event or on supported synthesized event. KERNEL=="dm-[0-9]*", ENV{DM_UDEV_RULES_VSN}!="?*", GOTO="lvm_end" # Only process devices already marked as a PV - this requires blkid to be called before. ENV{ID_FS_TYPE}=="LVM2_member|LVM1_member", RUN+="(LVM_EXEC)/lvm pvscan --cache --activate ay --major $major --minor $minor" LABEL="lvm_end" lvm2-2.02.98/udev/11-dm-lvm.rules.in0000640000175000017500000000237512037016273015557 0ustar blankblank# Copyright (C) 2009 Red Hat, Inc. All rights reserved. # # This file is part of LVM2. # Udev rules for LVM. # # These rules create symlinks for LVM logical volumes in # /dev/VG directory (VG is an actual VG name). Some udev # environment variables are set (they can be used in later # rules as well): # DM_LV_NAME - logical volume name # DM_VG_NAME - volume group name # DM_LV_LAYER - logical volume layer (blank if not set) # "add" event is processed on coldplug only! ACTION!="add|change", GOTO="lvm_end" ENV{DM_UDEV_RULES_VSN}!="?*", GOTO="lvm_end" ENV{DM_UUID}!="LVM-?*", GOTO="lvm_end" # Use DM name and split it up into its VG/LV/layer constituents. IMPORT{program}="(DM_EXEC)/dmsetup splitname --nameprefixes --noheadings --rows $env{DM_NAME}" ENV{DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG}=="1", GOTO="lvm_end" # Do not create symlinks for inappropriate subdevices. ENV{DM_LV_NAME}=="pvmove?*|?*_vorigin", GOTO="lvm_disable" ENV{DM_LV_LAYER}=="?*", GOTO="lvm_disable" # Create symlinks for top-level devices only. ENV{DM_VG_NAME}=="?*", ENV{DM_LV_NAME}=="?*", SYMLINK+="$env{DM_VG_NAME}/$env{DM_LV_NAME}", GOTO="lvm_end" LABEL="lvm_disable" ENV{DM_UDEV_DISABLE_DISK_RULES_FLAG}="1" ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}="1" OPTIONS:="nowatch" LABEL="lvm_end" lvm2-2.02.98/VERSION_DM0000640000175000017500000000002512037016273013136 0ustar blankblank1.02.77 (2012-10-15) lvm2-2.02.98/liblvm/0000750000175000017500000000000012037016272012774 5ustar blankblanklvm2-2.02.98/liblvm/.exported_symbols0000640000175000017500000000000012037016272016366 0ustar blankblanklvm2-2.02.98/liblvm/lvm_pv.c0000640000175000017500000000546512037016272014456 0ustar blankblank/* * Copyright (C) 2008,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 "lib.h" #include "metadata.h" #include "lvm-string.h" #include "lvm_misc.h" #include "lvm2app.h" const char *lvm_pv_get_uuid(const pv_t pv) { return pv_uuid_dup(pv); } const char *lvm_pv_get_name(const pv_t pv) { return dm_pool_strndup(pv->vg->vgmem, (const char *)pv_dev_name(pv), NAME_LEN + 1); } uint64_t lvm_pv_get_mda_count(const pv_t pv) { return (uint64_t) pv_mda_count(pv); } uint64_t lvm_pv_get_dev_size(const pv_t pv) { return (uint64_t) SECTOR_SIZE * pv_dev_size(pv); } uint64_t lvm_pv_get_size(const pv_t pv) { return (uint64_t) SECTOR_SIZE * pv_size_field(pv); } uint64_t lvm_pv_get_free(const pv_t pv) { return (uint64_t) SECTOR_SIZE * pv_free(pv); } struct lvm_property_value lvm_pv_get_property(const pv_t pv, const char *name) { return get_property(pv, NULL, NULL, NULL, NULL, name); } struct lvm_property_value lvm_pvseg_get_property(const pvseg_t pvseg, const char *name) { return get_property(NULL, NULL, NULL, NULL, pvseg, name); } struct dm_list *lvm_pv_list_pvsegs(pv_t pv) { struct dm_list *list; pvseg_list_t *pvseg; struct pv_segment *pvl; if (dm_list_empty(&pv->segments)) return NULL; if (!(list = dm_pool_zalloc(pv->vg->vgmem, sizeof(*list)))) { log_errno(ENOMEM, "Memory allocation fail for dm_list."); return NULL; } dm_list_init(list); dm_list_iterate_items(pvl, &pv->segments) { if (!(pvseg = dm_pool_zalloc(pv->vg->vgmem, sizeof(*pvseg)))) { log_errno(ENOMEM, "Memory allocation fail for lvm_pvseg_list."); return NULL; } pvseg->pvseg = pvl; dm_list_add(list, &pvseg->list); } return list; } pv_t lvm_pv_from_name(vg_t vg, const char *name) { struct pv_list *pvl; dm_list_iterate_items(pvl, &vg->pvs) { if (!strcmp(name, pv_dev_name(pvl->pv))) return pvl->pv; } return NULL; } pv_t lvm_pv_from_uuid(vg_t vg, const char *uuid) { struct pv_list *pvl; struct id id; if (strlen(uuid) < ID_LEN) { log_errno (EINVAL, "Invalid UUID string length"); return NULL; } if (!id_read_format(&id, uuid)) { log_errno(EINVAL, "Invalid UUID format."); return NULL; } dm_list_iterate_items(pvl, &vg->pvs) { if (id_equal(&id, &pvl->pv->id)) return pvl->pv; } return NULL; } int lvm_pv_resize(const pv_t pv, uint64_t new_size) { /* FIXME: add pv resize code here */ log_error("NOT IMPLEMENTED YET"); return -1; } lvm2-2.02.98/liblvm/lvm_vg.c0000640000175000017500000001576612037016272014452 0ustar blankblank/* * Copyright (C) 2008,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 "lib.h" #include "toolcontext.h" #include "metadata.h" #include "archiver.h" #include "locking.h" #include "lvmcache.h" #include "lvm_misc.h" #include "lvm2app.h" int lvm_vg_add_tag(vg_t vg, const char *tag) { if (vg_read_error(vg)) return -1; if (!vg_check_write_mode(vg)) return -1; if (!vg_change_tag(vg, tag, 1)) return -1; return 0; } int lvm_vg_remove_tag(vg_t vg, const char *tag) { if (vg_read_error(vg)) return -1; if (!vg_check_write_mode(vg)) return -1; if (!vg_change_tag(vg, tag, 0)) return -1; return 0; } vg_t lvm_vg_create(lvm_t libh, const char *vg_name) { struct volume_group *vg; vg = vg_create((struct cmd_context *)libh, vg_name); /* FIXME: error handling is still TBD */ if (vg_read_error(vg)) { release_vg(vg); return NULL; } vg->open_mode = 'w'; return (vg_t) vg; } int lvm_vg_extend(vg_t vg, const char *device) { struct pvcreate_params pp; if (vg_read_error(vg)) return -1; if (!vg_check_write_mode(vg)) return -1; if (!lock_vol(vg->cmd, VG_ORPHANS, LCK_VG_WRITE)) { log_error("Can't get lock for orphan PVs"); return -1; } pvcreate_params_set_defaults(&pp); if (!vg_extend(vg, 1, &device, &pp)) { unlock_vg(vg->cmd, VG_ORPHANS); return -1; } /* * FIXME: Either commit to disk, or keep holding VG_ORPHANS and * release in lvm_vg_close(). */ unlock_vg(vg->cmd, VG_ORPHANS); return 0; } int lvm_vg_reduce(vg_t vg, const char *device) { if (vg_read_error(vg)) return -1; if (!vg_check_write_mode(vg)) return -1; if (!vg_reduce(vg, device)) return -1; return 0; } int lvm_vg_set_extent_size(vg_t vg, uint32_t new_size) { if (vg_read_error(vg)) return -1; if (!vg_check_write_mode(vg)) return -1; if (!vg_set_extent_size(vg, new_size / SECTOR_SIZE)) return -1; return 0; } int lvm_vg_write(vg_t vg) { struct pv_list *pvl; if (vg_read_error(vg)) return -1; if (!vg_check_write_mode(vg)) return -1; if (dm_list_empty(&vg->pvs)) { if (!vg_remove(vg)) return -1; return 0; } if (! dm_list_empty(&vg->removed_pvs)) { if (!lock_vol(vg->cmd, VG_ORPHANS, LCK_VG_WRITE)) { log_error("Can't get lock for orphan PVs"); return 0; } } if (!archive(vg)) return -1; /* Store VG on disk(s) */ if (!vg_write(vg) || !vg_commit(vg)) return -1; if (! dm_list_empty(&vg->removed_pvs)) { dm_list_iterate_items(pvl, &vg->removed_pvs) { pv_write_orphan(vg->cmd, pvl->pv); pv_set_fid(pvl->pv, NULL); /* FIXME: do pvremove / label_remove()? */ } dm_list_init(&vg->removed_pvs); unlock_vg(vg->cmd, VG_ORPHANS); } return 0; } int lvm_vg_close(vg_t vg) { if (vg_read_error(vg) == FAILED_LOCKING) release_vg(vg); else unlock_and_release_vg(vg->cmd, vg, vg->name); return 0; } int lvm_vg_remove(vg_t vg) { if (vg_read_error(vg)) return -1; if (!vg_check_write_mode(vg)) return -1; if (!vg_remove_check(vg)) return -1; vg_remove_pvs(vg); return 0; } vg_t lvm_vg_open(lvm_t libh, const char *vgname, const char *mode, uint32_t flags) { uint32_t internal_flags = 0; struct volume_group *vg; if (!strncmp(mode, "w", 1)) internal_flags |= READ_FOR_UPDATE; else if (strncmp(mode, "r", 1)) { log_errno(EINVAL, "Invalid VG open mode"); return NULL; } vg = vg_read((struct cmd_context *)libh, vgname, NULL, internal_flags); if (vg_read_error(vg)) { /* FIXME: use log_errno either here in inside vg_read */ release_vg(vg); return NULL; } /* FIXME: combine this with locking ? */ vg->open_mode = mode[0]; return (vg_t) vg; } struct dm_list *lvm_vg_list_pvs(vg_t vg) { struct dm_list *list; pv_list_t *pvs; struct pv_list *pvl; if (dm_list_empty(&vg->pvs)) return NULL; if (!(list = dm_pool_zalloc(vg->vgmem, sizeof(*list)))) { log_errno(ENOMEM, "Memory allocation fail for dm_list."); return NULL; } dm_list_init(list); dm_list_iterate_items(pvl, &vg->pvs) { if (!(pvs = dm_pool_zalloc(vg->vgmem, sizeof(*pvs)))) { log_errno(ENOMEM, "Memory allocation fail for lvm_pv_list."); return NULL; } pvs->pv = pvl->pv; dm_list_add(list, &pvs->list); } return list; } struct dm_list *lvm_vg_list_lvs(vg_t vg) { struct dm_list *list; lv_list_t *lvs; struct lv_list *lvl; if (dm_list_empty(&vg->lvs)) return NULL; if (!(list = dm_pool_zalloc(vg->vgmem, sizeof(*list)))) { log_errno(ENOMEM, "Memory allocation fail for dm_list."); return NULL; } dm_list_init(list); dm_list_iterate_items(lvl, &vg->lvs) { if (!(lvs = dm_pool_zalloc(vg->vgmem, sizeof(*lvs)))) { log_errno(ENOMEM, "Memory allocation fail for lvm_lv_list."); return NULL; } lvs->lv = lvl->lv; dm_list_add(list, &lvs->list); } return list; } struct dm_list *lvm_vg_get_tags(const vg_t vg) { return tag_list_copy(vg->vgmem, &vg->tags); } uint64_t lvm_vg_get_seqno(const vg_t vg) { return vg_seqno(vg); } uint64_t lvm_vg_is_clustered(const vg_t vg) { return vg_is_clustered(vg); } uint64_t lvm_vg_is_exported(const vg_t vg) { return vg_is_exported(vg); } uint64_t lvm_vg_is_partial(const vg_t vg) { return (vg_missing_pv_count(vg) != 0); } /* FIXME: invalid handle? return INTMAX? */ uint64_t lvm_vg_get_size(const vg_t vg) { return SECTOR_SIZE * vg_size(vg); } uint64_t lvm_vg_get_free_size(const vg_t vg) { return SECTOR_SIZE * vg_free(vg); } uint64_t lvm_vg_get_extent_size(const vg_t vg) { return SECTOR_SIZE * vg_extent_size(vg); } uint64_t lvm_vg_get_extent_count(const vg_t vg) { return vg_extent_count(vg); } uint64_t lvm_vg_get_free_extent_count(const vg_t vg) { return vg_free_count(vg); } uint64_t lvm_vg_get_pv_count(const vg_t vg) { return vg_pv_count(vg); } uint64_t lvm_vg_get_max_pv(const vg_t vg) { return vg_max_pv(vg); } uint64_t lvm_vg_get_max_lv(const vg_t vg) { return vg_max_lv(vg); } const char *lvm_vg_get_uuid(const vg_t vg) { return vg_uuid_dup(vg); } const char *lvm_vg_get_name(const vg_t vg) { return dm_pool_strndup(vg->vgmem, (const char *)vg->name, NAME_LEN+1); } struct lvm_property_value lvm_vg_get_property(const vg_t vg, const char *name) { return get_property(NULL, vg, NULL, NULL, NULL, name); } int lvm_vg_set_property(const vg_t vg, const char *name, struct lvm_property_value *value) { return set_property(NULL, vg, NULL, name, value); } struct dm_list *lvm_list_vg_names(lvm_t libh) { return get_vgnames((struct cmd_context *)libh, 0); } struct dm_list *lvm_list_vg_uuids(lvm_t libh) { return get_vgids((struct cmd_context *)libh, 0); } /* * FIXME: Elaborate on when to use, side-effects, .cache file, etc */ int lvm_scan(lvm_t libh) { if (!lvmcache_label_scan((struct cmd_context *)libh, 2)) return -1; return 0; } lvm2-2.02.98/liblvm/lvm_lv.c0000640000175000017500000001557712037016272014457 0ustar blankblank/* * Copyright (C) 2008,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 "lib.h" #include "metadata.h" #include "lvm-string.h" #include "defaults.h" #include "segtype.h" #include "locking.h" #include "activate.h" #include "lvm_misc.h" #include "lvm2app.h" static int _lv_check_handle(const lv_t lv, const int vg_writeable) { if (!lv || !lv->vg || vg_read_error(lv->vg)) return -1; if (vg_writeable && !vg_check_write_mode(lv->vg)) return -1; return 0; } /* FIXME: have lib/report/report.c _disp function call lv_size()? */ uint64_t lvm_lv_get_size(const lv_t lv) { return SECTOR_SIZE * lv_size(lv); } const char *lvm_lv_get_uuid(const lv_t lv) { return lv_uuid_dup(lv); } const char *lvm_lv_get_name(const lv_t lv) { return dm_pool_strndup(lv->vg->vgmem, (const char *)lv->name, NAME_LEN+1); } struct lvm_property_value lvm_lv_get_property(const lv_t lv, const char *name) { return get_property(NULL, NULL, lv, NULL, NULL, name); } struct lvm_property_value lvm_lvseg_get_property(const lvseg_t lvseg, const char *name) { return get_property(NULL, NULL, NULL, lvseg, NULL, name); } uint64_t lvm_lv_is_active(const lv_t lv) { struct lvinfo info; if (lv_info(lv->vg->cmd, lv, 0, &info, 0, 0) && info.exists && info.live_table) return 1; return 0; } uint64_t lvm_lv_is_suspended(const lv_t lv) { struct lvinfo info; if (lv_info(lv->vg->cmd, lv, 0, &info, 0, 0) && info.exists && info.suspended) return 1; return 0; } int lvm_lv_add_tag(lv_t lv, const char *tag) { if (_lv_check_handle(lv, 1)) return -1; if (!lv_change_tag(lv, tag, 1)) return -1; return 0; } int lvm_lv_remove_tag(lv_t lv, const char *tag) { if (_lv_check_handle(lv, 1)) return -1; if (!lv_change_tag(lv, tag, 0)) return -1; return 0; } struct dm_list *lvm_lv_get_tags(const lv_t lv) { return tag_list_copy(lv->vg->vgmem, &lv->tags); } /* Set defaults for non-segment specific LV parameters */ static void _lv_set_default_params(struct lvcreate_params *lp, vg_t vg, const char *lvname, uint64_t extents) { lp->zero = 1; lp->major = -1; lp->minor = -1; lp->activate = CHANGE_AY; lp->vg_name = vg->name; lp->lv_name = lvname; /* FIXME: check this for safety */ lp->pvh = &vg->pvs; lp->extents = extents; lp->permission = LVM_READ | LVM_WRITE; lp->read_ahead = DM_READ_AHEAD_NONE; lp->alloc = ALLOC_INHERIT; dm_list_init(&lp->tags); } /* Set default for linear segment specific LV parameters */ static int _lv_set_default_linear_params(struct cmd_context *cmd, struct lvcreate_params *lp) { if (!(lp->segtype = get_segtype_from_string(cmd, "striped"))) { log_error(INTERNAL_ERROR "Segtype striped not found."); return 0; } lp->stripes = 1; lp->stripe_size = DEFAULT_STRIPESIZE * 2; return 1; } /* * FIXME: This function should probably not commit to disk but require calling * lvm_vg_write. However, this appears to be non-trivial change until * lv_create_single is refactored by segtype. */ lv_t lvm_vg_create_lv_linear(vg_t vg, const char *name, uint64_t size) { struct lvcreate_params lp = { 0 }; uint64_t extents; struct lv_list *lvl; if (vg_read_error(vg)) return NULL; if (!vg_check_write_mode(vg)) return NULL; if (!(extents = extents_from_size(vg->cmd, size / SECTOR_SIZE, vg->extent_size))) { log_error("Unable to create LV without size."); return NULL; } _lv_set_default_params(&lp, vg, name, extents); if (!_lv_set_default_linear_params(vg->cmd, &lp)) return_NULL; if (!lv_create_single(vg, &lp)) return_NULL; if (!(lvl = find_lv_in_vg(vg, name))) return NULL; return (lv_t) lvl->lv; } /* * FIXME: This function should probably not commit to disk but require calling * lvm_vg_write. */ int lvm_vg_remove_lv(lv_t lv) { if (!lv || !lv->vg || vg_read_error(lv->vg)) return -1; if (!vg_check_write_mode(lv->vg)) return -1; if (!lv_remove_single(lv->vg->cmd, lv, DONT_PROMPT)) return -1; return 0; } int lvm_lv_activate(lv_t lv) { if (!lv || !lv->vg || vg_read_error(lv->vg) || !lv->vg->cmd) return -1; /* FIXME: handle pvmove stuff later */ if (lv->status & LOCKED) { log_error("Unable to activate locked LV"); return -1; } /* FIXME: handle lvconvert stuff later */ if (lv->status & CONVERTING) { log_error("Unable to activate LV with in-progress lvconvert"); return -1; } if (lv_is_origin(lv)) { log_verbose("Activating logical volume \"%s\" " "exclusively", lv->name); if (!activate_lv_excl(lv->vg->cmd, lv)) { log_error("Activate exclusive failed."); return -1; } } else { log_verbose("Activating logical volume \"%s\"", lv->name); if (!activate_lv(lv->vg->cmd, lv)) { log_error("Activate failed."); return -1; } } return 0; } int lvm_lv_deactivate(lv_t lv) { if (!lv || !lv->vg || vg_read_error(lv->vg) || !lv->vg->cmd) return -1; log_verbose("Deactivating logical volume \"%s\"", lv->name); if (!deactivate_lv(lv->vg->cmd, lv)) { log_error("Deactivate failed."); return -1; } return 0; } struct dm_list *lvm_lv_list_lvsegs(lv_t lv) { struct dm_list *list; lvseg_list_t *lvseg; struct lv_segment *lvl; if (dm_list_empty(&lv->segments)) return NULL; if (!(list = dm_pool_zalloc(lv->vg->vgmem, sizeof(*list)))) { log_errno(ENOMEM, "Memory allocation fail for dm_list."); return NULL; } dm_list_init(list); dm_list_iterate_items(lvl, &lv->segments) { if (!(lvseg = dm_pool_zalloc(lv->vg->vgmem, sizeof(*lvseg)))) { log_errno(ENOMEM, "Memory allocation fail for lvm_lvseg_list."); return NULL; } lvseg->lvseg = lvl; dm_list_add(list, &lvseg->list); } return list; } lv_t lvm_lv_from_name(vg_t vg, const char *name) { struct lv_list *lvl; dm_list_iterate_items(lvl, &vg->lvs) { if (!strcmp(name, lvl->lv->name)) return lvl->lv; } return NULL; } lv_t lvm_lv_from_uuid(vg_t vg, const char *uuid) { struct lv_list *lvl; struct id id; if (strlen(uuid) < ID_LEN) { log_errno (EINVAL, "Invalid UUID string length"); return NULL; } if (!id_read_format(&id, uuid)) { log_errno(EINVAL, "Invalid UUID format."); return NULL; } dm_list_iterate_items(lvl, &vg->lvs) { if (id_equal(&vg->id, &lvl->lv->lvid.id[0]) && id_equal(&id, &lvl->lv->lvid.id[1])) return lvl->lv; } return NULL; } int lvm_lv_rename(lv_t lv, const char *new_name) { if (!lv_rename(lv->vg->cmd, lv, new_name)) { log_verbose("LV Rename failed."); return -1; } return 0; } int lvm_lv_resize(const lv_t lv, uint64_t new_size) { /* FIXME: add lv resize code here */ log_error("NOT IMPLEMENTED YET"); return -1; } lvm2-2.02.98/liblvm/lvm_misc.h0000640000175000017500000000173212037016272014762 0ustar blankblank/* * Copyright (C) 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 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 _LVM2APP_MISC_H #define _LVM2APP_MISC_H #include "libdevmapper.h" #include "lvm2app.h" struct dm_list *tag_list_copy(struct dm_pool *p, struct dm_list *tag_list); struct lvm_property_value get_property(const pv_t pv, const vg_t vg, const lv_t lv, const lvseg_t lvseg, const pvseg_t pvseg, const char *name); int set_property(const pv_t pv, const vg_t vg, const lv_t lv, const char *name, struct lvm_property_value *value); #endif lvm2-2.02.98/liblvm/Doxyfile0000640000175000017500000002203612037016272014506 0ustar blankblank# Doxyfile 1.5.7.1 #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- DOXYFILE_ENCODING = UTF-8 PROJECT_NAME = PROJECT_NUMBER = OUTPUT_DIRECTORY = doxygen-output CREATE_SUBDIRS = NO OUTPUT_LANGUAGE = English BRIEF_MEMBER_DESC = YES REPEAT_BRIEF = YES ABBREVIATE_BRIEF = ALWAYS_DETAILED_SEC = NO INLINE_INHERITED_MEMB = NO FULL_PATH_NAMES = YES STRIP_FROM_PATH = STRIP_FROM_INC_PATH = SHORT_NAMES = NO JAVADOC_AUTOBRIEF = NO QT_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO INHERIT_DOCS = YES SEPARATE_MEMBER_PAGES = NO TAB_SIZE = 8 ALIASES = OPTIMIZE_OUTPUT_FOR_C = NO OPTIMIZE_OUTPUT_JAVA = NO OPTIMIZE_FOR_FORTRAN = NO OPTIMIZE_OUTPUT_VHDL = NO BUILTIN_STL_SUPPORT = NO CPP_CLI_SUPPORT = NO SIP_SUPPORT = NO IDL_PROPERTY_SUPPORT = YES DISTRIBUTE_GROUP_DOC = NO SUBGROUPING = YES TYPEDEF_HIDES_STRUCT = NO SYMBOL_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- EXTRACT_ALL = YES EXTRACT_PRIVATE = YES EXTRACT_STATIC = NO EXTRACT_LOCAL_CLASSES = YES EXTRACT_LOCAL_METHODS = NO EXTRACT_ANON_NSPACES = NO HIDE_UNDOC_MEMBERS = NO HIDE_UNDOC_CLASSES = NO HIDE_FRIEND_COMPOUNDS = NO HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO CASE_SENSE_NAMES = YES HIDE_SCOPE_NAMES = NO SHOW_INCLUDE_FILES = YES INLINE_INFO = YES SORT_MEMBER_DOCS = YES SORT_BRIEF_DOCS = NO SORT_GROUP_NAMES = NO SORT_BY_SCOPE_NAME = NO GENERATE_TODOLIST = YES GENERATE_TESTLIST = YES GENERATE_BUGLIST = YES GENERATE_DEPRECATEDLIST= YES ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = YES SHOW_DIRECTORIES = NO SHOW_FILES = YES SHOW_NAMESPACES = YES FILE_VERSION_FILTER = LAYOUT_FILE = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- QUIET = NO WARNINGS = YES WARN_IF_UNDOCUMENTED = YES WARN_IF_DOC_ERROR = YES WARN_NO_PARAMDOC = NO WARN_FORMAT = "$file:$line: $text" WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- INPUT = ./ INPUT_ENCODING = UTF-8 FILE_PATTERNS = *.c \ *.h RECURSIVE = NO EXCLUDE = EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = EXCLUDE_SYMBOLS = EXAMPLE_PATH = ../test/api EXAMPLE_PATTERNS = EXAMPLE_RECURSIVE = NO IMAGE_PATH = INPUT_FILTER = FILTER_PATTERNS = FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- SOURCE_BROWSER = NO INLINE_SOURCES = NO STRIP_CODE_COMMENTS = YES REFERENCED_BY_RELATION = NO REFERENCES_RELATION = NO REFERENCES_LINK_SOURCE = YES USE_HTAGS = NO VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- ALPHABETICAL_INDEX = NO COLS_IN_ALPHA_INDEX = 5 IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- GENERATE_HTML = YES HTML_OUTPUT = html HTML_FILE_EXTENSION = .html HTML_HEADER = HTML_FOOTER = HTML_STYLESHEET = HTML_ALIGN_MEMBERS = YES HTML_DYNAMIC_SECTIONS = NO GENERATE_DOCSET = NO DOCSET_FEEDNAME = "Doxygen generated docs" DOCSET_BUNDLE_ID = org.doxygen.Project GENERATE_HTMLHELP = NO CHM_FILE = HHC_LOCATION = GENERATE_CHI = NO CHM_INDEX_ENCODING = BINARY_TOC = NO TOC_EXPAND = NO GENERATE_QHP = NO QCH_FILE = QHP_NAMESPACE = org.doxygen.Project QHP_VIRTUAL_FOLDER = doc QHG_LOCATION = DISABLE_INDEX = NO ENUM_VALUES_PER_LINE = 4 GENERATE_TREEVIEW = NONE TREEVIEW_WIDTH = 250 FORMULA_FONTSIZE = 10 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- GENERATE_LATEX = YES LATEX_OUTPUT = latex LATEX_CMD_NAME = latex MAKEINDEX_CMD_NAME = makeindex COMPACT_LATEX = NO PAPER_TYPE = a4wide EXTRA_PACKAGES = LATEX_HEADER = PDF_HYPERLINKS = YES USE_PDFLATEX = YES LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- GENERATE_RTF = NO RTF_OUTPUT = rtf COMPACT_RTF = NO RTF_HYPERLINKS = NO RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- GENERATE_MAN = YES MAN_OUTPUT = man MAN_EXTENSION = .3 MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- GENERATE_XML = NO XML_OUTPUT = xml XML_SCHEMA = XML_DTD = XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- GENERATE_PERLMOD = NO PERLMOD_LATEX = NO PERLMOD_PRETTY = YES PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- ENABLE_PREPROCESSING = YES MACRO_EXPANSION = NO EXPAND_ONLY_PREDEF = NO SEARCH_INCLUDES = YES INCLUDE_PATH = ../libdm INCLUDE_FILE_PATTERNS = PREDEFINED = EXPAND_AS_DEFINED = SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- TAGFILES = GENERATE_TAGFILE = ALLEXTERNALS = NO EXTERNAL_GROUPS = YES PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- CLASS_DIAGRAMS = YES MSCGEN_PATH = HIDE_UNDOC_RELATIONS = YES HAVE_DOT = NO DOT_FONTNAME = FreeSans DOT_FONTSIZE = 10 DOT_FONTPATH = CLASS_GRAPH = YES COLLABORATION_GRAPH = YES GROUP_GRAPHS = YES UML_LOOK = NO TEMPLATE_RELATIONS = NO INCLUDE_GRAPH = YES INCLUDED_BY_GRAPH = YES CALL_GRAPH = YES CALLER_GRAPH = NO GRAPHICAL_HIERARCHY = YES DIRECTORY_GRAPH = YES DOT_IMAGE_FORMAT = png DOT_PATH = DOTFILE_DIRS = DOT_GRAPH_MAX_NODES = 50 MAX_DOT_GRAPH_DEPTH = 0 DOT_TRANSPARENT = NO DOT_MULTI_TARGETS = NO GENERATE_LEGEND = YES DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- SEARCHENGINE = NO lvm2-2.02.98/liblvm/lvm2app.h0000640000175000017500000012361312037016272014535 0ustar blankblank/* * Copyright (C) 2008,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 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 _LIB_LVM2APP_H #define _LIB_LVM2APP_H #include #include #ifdef __cplusplus extern "C" { #endif /******************************** WARNING *********************************** * * NOTE: This API is under development and subject to change at any time. * * Please send feedback to lvm-devel@redhat.com * *********************************** WARNING ********************************/ /*************************** Design Overview ********************************/ /** * \mainpage LVM library API * * The API is designed around the following basic LVM objects: * 1) Physical Volume (pv_t) 2) Volume Group (vg_t) 3) Logical Volume (lv_t). * * The library provides functions to list the objects in a system, * get and set object properties (such as names, UUIDs, and sizes), as well * as create/remove objects and perform more complex operations and * transformations. Each object instance is represented by a handle, and * handles are passed to and from the functions to perform the operations. * * A central object in the library is the Volume Group, represented by the * VG handle, vg_t. Performing an operation on a PV or LV object first * requires obtaining a VG handle. Once the vg_t has been obtained, it can * be used to enumerate the pv_t and lv_t objects within that vg_t. Attributes * of these objects can then be queried or changed. * * A volume group handle may be obtained with read or write permission. * Any attempt to change a property of a pv_t, vg_t, or lv_t without * obtaining write permission on the vg_t will fail with EPERM. * * An application first opening a VG read-only, then later wanting to change * a property of an object must first close the VG and re-open with write * permission. Currently liblvm provides no mechanism to determine whether * the VG has changed on-disk in between these operations - this is the * application's responsiblity. One way the application can ensure the VG * has not changed is to save the "vg_seqno" field after opening the VG with * READ permission. If the application later needs to modify the VG, it can * close the VG and re-open with WRITE permission. It should then check * whether the original "vg_seqno" obtained with READ permission matches * the new one obtained with WRITE permission. */ /** * Retrieve the library version. * * The library version is the same format as the full LVM version. * The format is as follows: * LVM_MAJOR.LVM_MINOR.LVM_PATCHLEVEL(LVM_LIBAPI)[-LVM_RELEASE] * An application wishing to determine compatibility with a particular version * of the library should check at least the LVM_MAJOR, LVM_MINOR, and * LVM_LIBAPI numbers. For example, assume the full LVM version is * 2.02.50(1)-1. The application should verify the "2.02" and the "(1)". * * \return A string describing the library version. */ const char *lvm_library_get_version(void); /******************************** structures ********************************/ /** * Opaque structures - do not use directly. Internal structures may change * without notice between releases, whereas this API will be changed much less * frequently. Backwards compatibility will normally be preserved in future * releases. On any occasion when the developers do decide to break backwards * compatibility in any significant way, the LVM_LIBAPI number (included in * the library's soname) will be incremented. */ struct lvm; struct physical_volume; struct volume_group; struct logical_volume; struct lv_segment; struct pv_segment; /** * \class lvm_t * * This is the base handle that is needed to open and create objects such as * volume groups and logical volumes. In addition, this handle provides a * context for error handling information, saving any error number (see * lvm_errno()) and error message (see lvm_errmsg()) that any function may * generate. */ typedef struct lvm *lvm_t; /** * \class vg_t * * The volume group object is a central object in the library, and can be * either a read-only object or a read-write object depending on the function * used to obtain the object handle. For example, lvm_vg_create() always * returns a read/write handle, while lvm_vg_open() has a "mode" argument * to define the read/write mode of the handle. */ typedef struct volume_group *vg_t; /** * \class lv_t * * This logical volume object is bound to a vg_t and has the same * read/write mode as the vg_t. Changes will be written to disk * when the vg_t gets committed to disk by calling lvm_vg_write(). */ typedef struct logical_volume *lv_t; /** * \class pv_t * * This physical volume object is bound to a vg_t and has the same * read/write mode as the vg_t. Changes will be written to disk * when the vg_t gets committed to disk by calling lvm_vg_write(). */ typedef struct physical_volume *pv_t; /** * \class lvseg_t * * This lv segment object is bound to a lv_t. */ typedef struct lv_segment *lvseg_t; /** * \class pvseg_t * * This pv segment object is bound to a pv_t. */ typedef struct pv_segment *pvseg_t; /** * Logical Volume object list. * * Lists of these structures are returned by lvm_vg_list_lvs(). */ typedef struct lvm_lv_list { struct dm_list list; lv_t lv; } lv_list_t; /** * Logical Volume Segment object list. * * Lists of these structures are returned by lvm_lv_list_lvsegs(). */ typedef struct lvm_lvseg_list { struct dm_list list; lvseg_t lvseg; } lvseg_list_t; /** * Physical volume object list. * * Lists of these structures are returned by lvm_vg_list_pvs(). */ typedef struct lvm_pv_list { struct dm_list list; pv_t pv; } pv_list_t; /** * Physical Volume Segment object list. * * Lists of these structures are returned by lvm_pv_list_pvsegs(). */ typedef struct lvm_pvseg_list { struct dm_list list; pvseg_t pvseg; } pvseg_list_t; /** * String list. * * This string list contains read-only strings. * Lists of these structures are returned by functions such as * lvm_list_vg_names() and lvm_list_vg_uuids(). */ typedef struct lvm_str_list { struct dm_list list; const char *str; } lvm_str_list_t; /** * Property Value * * This structure defines a single LVM property value for an LVM object. * The structures are returned by functions such as * lvm_vg_get_property(). * * is_settable: indicates whether a 'set' function exists for this property * is_string: indicates whether this property is a string (1) or not (0) * is_integer: indicates whether this property is an integer (1) or not (0) * is_valid: indicates whether 'value' is valid (1) or not (0) */ typedef struct lvm_property_value { uint32_t is_settable:1; uint32_t is_string:1; uint32_t is_integer:1; uint32_t is_valid:1; uint32_t padding:28; union { const char *string; uint64_t integer; } value; } lvm_property_value_t; /*************************** generic lvm handling ***************************/ /** * Create a LVM handle. * * \memberof lvm_t * * Once all LVM operations have been completed, use lvm_quit() to release * the handle and any associated resources. * * \param system_dir * Set an alternative LVM system directory. Use NULL to use the * default value. If the environment variable LVM_SYSTEM_DIR is set, * it will override any system_dir setting. * * \return * A valid LVM handle is returned or NULL if there has been a * memory allocation problem. You have to check if an error occured * with the lvm_error() function. */ lvm_t lvm_init(const char *system_dir); /** * Destroy a LVM handle allocated with lvm_init(). * * \memberof lvm_t * * This function should be used after all LVM operations are complete or after * an unrecoverable error. Destroying the LVM handle frees the memory and * other resources associated with the handle. Once destroyed, the handle * cannot be used subsequently. * * \param libh * Handle obtained from lvm_init(). */ void lvm_quit(lvm_t libh); /** * Reload the original configuration from the system directory. * * \memberof lvm_t * * This function should be used when any LVM configuration changes in the LVM * system_dir or by another lvm_config* function, and the change is needed by * the application. * * \param libh * Handle obtained from lvm_init(). * * \return * 0 (success) or -1 (failure). */ int lvm_config_reload(lvm_t libh); /** * Override the LVM configuration with a configuration string. * * \memberof lvm_t * * This function is equivalent to the --config option on lvm commands. * Once this API has been used to over-ride the configuration, * use lvm_config_reload() to apply the new settings. * * \param libh * Handle obtained from lvm_init(). * * \param config_string * LVM configuration string to apply. See the lvm.conf file man page * for the format of the config string. * * \return * 0 (success) or -1 (failure). */ int lvm_config_override(lvm_t libh, const char *config_string); /** * Find a boolean value in the LVM configuration. * * \memberof lvm_t * * This function finds a boolean value associated with a path * in current LVM configuration. * * \param libh * Handle obtained from lvm_init(). * * \param config_path * A path in LVM configuration * * \param fail * Value to return if the path is not found. * * \return * boolean value for 'config_path' (success) or the value of 'fail' (error) */ int lvm_config_find_bool(lvm_t libh, const char *config_path, int fail); /** * Return stored error no describing last LVM API error. * * \memberof lvm_t * * Users of liblvm should use lvm_errno to determine the details of a any * failure of the last call. A basic success or fail is always returned by * every function, either by returning a 0 or -1, or a non-NULL / NULL. * If a function has failed, lvm_errno may be used to get a more specific * error code describing the failure. In this way, lvm_errno may be used * after every function call, even after a 'get' function call that simply * returns a value. * * \param libh * Handle obtained from lvm_init(). * * \return * An errno value describing the last LVM error. */ int lvm_errno(lvm_t libh); /** * Return stored error message describing last LVM error. * * \memberof lvm_t * * This function may be used in conjunction with lvm_errno() to obtain more * specific error information for a function that is known to have failed. * * \param libh * Handle obtained from lvm_init(). * * \return * An error string describing the last LVM error. */ const char *lvm_errmsg(lvm_t libh); /** * Scan all devices on the system for VGs and LVM metadata. * * \memberof lvm_t * * \return * 0 (success) or -1 (failure). */ int lvm_scan(lvm_t libh); /** * Return the list of volume group names. * * \memberof lvm_t * * The memory allocated for the list is tied to the lvm_t handle and will be * released when lvm_quit() is called. * * NOTE: This function normally does not scan devices in the system for LVM * metadata. To scan the system, use lvm_scan(). * * To process the list, use the dm_list iterator functions. For example: * vg_t vg; * struct dm_list *vgnames; * struct lvm_str_list *strl; * * vgnames = lvm_list_vg_names(libh); * dm_list_iterate_items(strl, vgnames) { * vgname = strl->str; * vg = lvm_vg_open(libh, vgname, "r"); * // do something with vg * lvm_vg_close(vg); * } * * * \return * A list with entries of type struct lvm_str_list, containing the * VG name strings of the Volume Groups known to the system. * NULL is returned if unable to allocate memory. * An empty list (verify with dm_list_empty) is returned if no VGs * exist on the system. */ struct dm_list *lvm_list_vg_names(lvm_t libh); /** * Return the list of volume group uuids. * * \memberof lvm_t * * The memory allocated for the list is tied to the lvm_t handle and will be * released when lvm_quit() is called. * * NOTE: This function normally does not scan devices in the system for LVM * metadata. To scan the system, use lvm_scan(). * * \param libh * Handle obtained from lvm_init(). * * \return * A list with entries of type struct lvm_str_list, containing the * VG UUID strings of the Volume Groups known to the system. * NULL is returned if unable to allocate memory. * An empty list (verify with dm_list_empty) is returned if no VGs * exist on the system. */ struct dm_list *lvm_list_vg_uuids(lvm_t libh); /** * Return the volume group name given a PV UUID * * \memberof lvm_t * * The memory allocated for the name is tied to the lvm_t handle and will be * released when lvm_quit() is called. * * NOTE: This function may scan devices in the system for LVM metadata. * * \param libh * Handle obtained from lvm_init(). * * \return * The volume group name for the given PV UUID. * NULL is returned if the PV UUID is not associated with a volume group. */ const char *lvm_vgname_from_pvid(lvm_t libh, const char *pvid); /** * Return the volume group name given a device name * * \memberof lvm_t * * The memory allocated for the name is tied to the lvm_t handle and will be * released when lvm_quit() is called. * * NOTE: This function may scan devices in the system for LVM metadata. * * \param libh * Handle obtained from lvm_init(). * * \return * The volume group name for the given device name. * NULL is returned if the device is not an LVM device. * */ const char *lvm_vgname_from_device(lvm_t libh, const char *device); /** * Open an existing VG. * * Open a VG for reading or writing. * * \memberof lvm_t * * \param libh * Handle obtained from lvm_init(). * * \param vgname * Name of the VG to open. * * \param mode * Open mode - either "r" (read) or "w" (read/write). * Any other character results in an error with EINVAL set. * * \param flags * Open flags - currently ignored. * * \return non-NULL VG handle (success) or NULL (failure). */ vg_t lvm_vg_open(lvm_t libh, const char *vgname, const char *mode, uint32_t flags); /** * Create a VG with default parameters. * * \memberof lvm_t * * This function creates a Volume Group object in memory. * Upon success, other APIs may be used to set non-default parameters. * For example, to set a non-default extent size, use lvm_vg_set_extent_size(). * Next, to add physical storage devices to the volume group, use * lvm_vg_extend() for each device. * Once all parameters are set appropriately and all devices are added to the * VG, use lvm_vg_write() to commit the new VG to disk, and lvm_vg_close() to * release the VG handle. * * \param libh * Handle obtained from lvm_init(). * * \param vg_name * Name of the VG to open. * * \return * non-NULL vg handle (success) or NULL (failure) */ vg_t lvm_vg_create(lvm_t libh, const char *vg_name); /*************************** volume group handling **************************/ /** * Return a list of LV handles for a given VG handle. * * \memberof vg_t * * \param vg * VG handle obtained from lvm_vg_create() or lvm_vg_open(). * * \return * A list of lvm_lv_list structures containing lv handles for this vg. * If no LVs exist on the given VG, NULL is returned. */ struct dm_list *lvm_vg_list_lvs(vg_t vg); /** * Return a list of PV handles for a given VG handle. * * \memberof vg_t * * \param vg * VG handle obtained from lvm_vg_create() or lvm_vg_open(). * * \return * A list of lvm_pv_list structures containing pv handles for this vg. * If no PVs exist on the given VG, NULL is returned. */ struct dm_list *lvm_vg_list_pvs(vg_t vg); /** * Write a VG to disk. * * \memberof vg_t * * This function commits the Volume Group object referenced by the VG handle * to disk. Upon failure, retry the operation and/or release the VG handle * with lvm_vg_close(). * * \param vg * VG handle obtained from lvm_vg_create() or lvm_vg_open(). * * \return * 0 (success) or -1 (failure). */ int lvm_vg_write(vg_t vg); /** * Remove a VG from the system. * * \memberof vg_t * * This function removes a Volume Group object in memory, and requires * calling lvm_vg_write() to commit the removal to disk. * * \param vg * VG handle obtained from lvm_vg_create() or lvm_vg_open(). * * \return * 0 (success) or -1 (failure). */ int lvm_vg_remove(vg_t vg); /** * Close a VG opened with lvm_vg_create or lvm_vg_open(). * * \memberof vg_t * * This function releases a VG handle and any resources associated with the * handle. * * \param vg * VG handle obtained from lvm_vg_create() or lvm_vg_open(). * * \return * 0 (success) or -1 (failure). */ int lvm_vg_close(vg_t vg); /** * Extend a VG by adding a device. * * \memberof vg_t * * This function requires calling lvm_vg_write() to commit the change to disk. * After successfully adding a device, use lvm_vg_write() to commit the new VG * to disk. Upon failure, retry the operation or release the VG handle with * lvm_vg_close(). * If the device is not initialized for LVM use, it will be initialized * before adding to the VG. Although some internal checks are done, * the caller should be sure the device is not in use by other subsystems * before calling lvm_vg_extend(). * * \param vg * VG handle obtained from lvm_vg_create() or lvm_vg_open(). * * \param device * Absolute pathname of device to add to VG. * * \return * 0 (success) or -1 (failure). */ int lvm_vg_extend(vg_t vg, const char *device); /** * Reduce a VG by removing an unused device. * * \memberof vg_t * * This function requires calling lvm_vg_write() to commit the change to disk. * After successfully removing a device, use lvm_vg_write() to commit the new VG * to disk. Upon failure, retry the operation or release the VG handle with * lvm_vg_close(). * * \param vg * VG handle obtained from lvm_vg_create() or lvm_vg_open(). * * \param device * Name of device to remove from VG. * * \return * 0 (success) or -1 (failure). */ int lvm_vg_reduce(vg_t vg, const char *device); /** * Add a tag to a VG. * * \memberof vg_t * * This function requires calling lvm_vg_write() to commit the change to disk. * After successfully adding a tag, use lvm_vg_write() to commit the * new VG to disk. Upon failure, retry the operation or release the VG handle * with lvm_vg_close(). * * \param vg * VG handle obtained from lvm_vg_create() or lvm_vg_open(). * * \param tag * Tag to add to the VG. * * \return * 0 (success) or -1 (failure). */ int lvm_vg_add_tag(vg_t vg, const char *tag); /** * Remove a tag from a VG. * * \memberof vg_t * * This function requires calling lvm_vg_write() to commit the change to disk. * After successfully removing a tag, use lvm_vg_write() to commit the * new VG to disk. Upon failure, retry the operation or release the VG handle * with lvm_vg_close(). * * \param vg * VG handle obtained from lvm_vg_create() or lvm_vg_open(). * * \param tag * Tag to remove from VG. * * \return * 0 (success) or -1 (failure). */ int lvm_vg_remove_tag(vg_t vg, const char *tag); /** * Set the extent size of a VG. * * \memberof vg_t * * This function requires calling lvm_vg_write() to commit the change to disk. * After successfully setting a new extent size, use lvm_vg_write() to commit * the new VG to disk. Upon failure, retry the operation or release the VG * handle with lvm_vg_close(). * * \param vg * VG handle obtained from lvm_vg_create() or lvm_vg_open(). * * \param new_size * New extent size in bytes. * * \return * 0 (success) or -1 (failure). */ int lvm_vg_set_extent_size(vg_t vg, uint32_t new_size); /** * Get whether or not a volume group is clustered. * * \memberof vg_t * * \param vg * VG handle obtained from lvm_vg_create() or lvm_vg_open(). * * \return * 1 if the VG is clustered, 0 if not */ uint64_t lvm_vg_is_clustered(vg_t vg); /** * Get whether or not a volume group is exported. * * \memberof vg_t * * \param vg * VG handle obtained from lvm_vg_create() or lvm_vg_open(). * * \return * 1 if the VG is exported, 0 if not */ uint64_t lvm_vg_is_exported(vg_t vg); /** * Get whether or not a volume group is a partial volume group. * * \memberof vg_t * * When one or more physical volumes belonging to the volume group * are missing from the system the volume group is a partial volume * group. * * \param vg * VG handle obtained from lvm_vg_create() or lvm_vg_open(). * * \return * 1 if the VG is PVs, 0 if not */ uint64_t lvm_vg_is_partial(vg_t vg); /** * Get the current metadata sequence number of a volume group. * * \memberof vg_t * * The metadata sequence number is incrented for each metadata change. * Applications may use the sequence number to determine if any LVM objects * have changed from a prior query. * * \param vg * VG handle obtained from lvm_vg_create() or lvm_vg_open(). * * \return * Metadata sequence number. */ uint64_t lvm_vg_get_seqno(const vg_t vg); /** * Get the current uuid of a volume group. * * \memberof vg_t * * The memory allocated for the uuid is tied to the vg_t handle and will be * released when lvm_vg_close() is called. * * \param vg * VG handle obtained from lvm_vg_create() or lvm_vg_open(). * * \return * Copy of the uuid string. */ const char *lvm_vg_get_uuid(const vg_t vg); /** * Get the current name of a volume group. * * \memberof vg_t * * The memory allocated for the name is tied to the vg_t handle and will be * released when lvm_vg_close() is called. * * \param vg * VG handle obtained from lvm_vg_create() or lvm_vg_open(). * * \return * Copy of the name. */ const char *lvm_vg_get_name(const vg_t vg); /** * Get the current size in bytes of a volume group. * * \memberof vg_t * * \param vg * VG handle obtained from lvm_vg_create() or lvm_vg_open(). * * \return * Size in bytes. */ uint64_t lvm_vg_get_size(const vg_t vg); /** * Get the current unallocated space in bytes of a volume group. * * \memberof vg_t * * \param vg * VG handle obtained from lvm_vg_create() or lvm_vg_open(). * * \return * Free size in bytes. */ uint64_t lvm_vg_get_free_size(const vg_t vg); /** * Get the current extent size in bytes of a volume group. * * \memberof vg_t * * \param vg * VG handle obtained from lvm_vg_create() or lvm_vg_open(). * * \return * Extent size in bytes. */ uint64_t lvm_vg_get_extent_size(const vg_t vg); /** * Get the current number of total extents of a volume group. * * \memberof vg_t * * \param vg * VG handle obtained from lvm_vg_create() or lvm_vg_open(). * * \return * Extent count. */ uint64_t lvm_vg_get_extent_count(const vg_t vg); /** * Get the current number of free extents of a volume group. * * \memberof vg_t * * \param vg * VG handle obtained from lvm_vg_create() or lvm_vg_open(). * * \return * Free extent count. */ uint64_t lvm_vg_get_free_extent_count(const vg_t vg); /** * Get the current number of physical volumes of a volume group. * * \memberof vg_t * * \param vg * VG handle obtained from lvm_vg_create() or lvm_vg_open(). * * \return * Physical volume count. */ uint64_t lvm_vg_get_pv_count(const vg_t vg); /** * Get the maximum number of physical volumes allowed in a volume group. * * \memberof vg_t * * \param vg * VG handle obtained from lvm_vg_create() or lvm_vg_open(). * * \return * Maximum number of physical volumes allowed in a volume group. */ uint64_t lvm_vg_get_max_pv(const vg_t vg); /** * Get the maximum number of logical volumes allowed in a volume group. * * \memberof vg_t * * \param vg * VG handle obtained from lvm_vg_create() or lvm_vg_open(). * * \return * Maximum number of logical volumes allowed in a volume group. */ uint64_t lvm_vg_get_max_lv(const vg_t vg); /** * Return the list of volume group tags. * * \memberof vg_t * * The memory allocated for the list is tied to the vg_t handle and will be * released when lvm_vg_close() is called. * * To process the list, use the dm_list iterator functions. For example: * vg_t vg; * struct dm_list *tags; * struct lvm_str_list *strl; * * tags = lvm_vg_get_tags(vg); * dm_list_iterate_items(strl, tags) { * tag = strl->str; * // do something with tag * } * * * \return * A list with entries of type struct lvm_str_list, containing the * tag strings attached to volume group. * If no tags are attached to the given VG, an empty list is returned * (check with dm_list_empty()). * If there is a problem obtaining the list of tags, NULL is returned. */ struct dm_list *lvm_vg_get_tags(const vg_t vg); /** * Get the value of a VG property * * \memberof vg_t * * \param vg * VG handle obtained from lvm_vg_create() or lvm_vg_open(). * * \param name * Name of property to query. See vgs man page for full list of properties * that may be queried. * * The memory allocated for a string property value is tied to the vg_t * handle and will be released when lvm_vg_close() is called. * * Example: * lvm_property_value v; * char *prop_name = "vg_mda_count"; * * v = lvm_vg_get_property(vg, prop_name); * if (!v.is_valid) { * printf("Invalid property name or unable to query" * "'%s', errno = %d.\n", prop_name, lvm_errno(libh)); * return; * } * if (v.is_string) * printf(", value = %s\n", v.value.string); * if (v.is_integer) * printf(", value = %"PRIu64"\n", v.value.integer); * * * \return * lvm_property_value structure that will contain the current * value of the property. Caller should check 'is_valid' flag before using * the value. If 'is_valid' is not set, caller should check lvm_errno() * for specific error. */ struct lvm_property_value lvm_vg_get_property(const vg_t vg, const char *name); /** * Set the value of a VG property. Note that the property must be * a 'settable' property, as evidenced by the 'is_settable' flag * when querying the property. * * \memberof vg_t * * The memory allocated for a string property value is tied to the vg_t * handle and will be released when lvm_vg_close() is called. * * Example (integer): * lvm_property_value copies; * * if (lvm_vg_get_property(vg, "vg_mda_copies", &copies) < 0) { * // Error - unable to query property * } * if (!copies.is_settable) { * // Error - property not settable * } * copies.value.integer = 2; * if (lvm_vg_set_property(vg, "vg_mda_copies", &copies) < 0) { * // handle error * } * * \return * 0 (success) or -1 (failure). */ int lvm_vg_set_property(const vg_t vg, const char *name, struct lvm_property_value *value); /************************** logical volume handling *************************/ /** * Create a linear logical volume. * This function commits the change to disk and does _not_ require calling * lvm_vg_write(). * NOTE: The commit behavior of this function is subject to change * as the API is developed. * * \param vg * VG handle obtained from lvm_vg_create() or lvm_vg_open(). * * \param name * Name of logical volume to create. * * \param size * Size of logical volume in extents. * * \return * non-NULL handle to an LV object created, or NULL if creation fails. * */ lv_t lvm_vg_create_lv_linear(vg_t vg, const char *name, uint64_t size); /** * Return a list of lvseg handles for a given LV handle. * * \memberof lv_t * * \param lv * Logical volume handle. * * \return * A list of lvm_lvseg_list structures containing lvseg handles for this lv. */ struct dm_list *lvm_lv_list_lvsegs(lv_t lv); /** * Lookup an LV handle in a VG by the LV name. * * \memberof lv_t * * \param vg * VG handle obtained from lvm_vg_create() or lvm_vg_open(). * * \param name * Name of LV to lookup. * * \return * non-NULL handle to the LV 'name' attached to the VG. * NULL is returned if the LV name is not associated with the VG handle. */ lv_t lvm_lv_from_name(vg_t vg, const char *name); /** * Lookup an LV handle in a VG by the LV uuid. * The form of the uuid may be either the formatted, human-readable form, * or the non-formatted form. * * \memberof lv_t * * \param vg * VG handle obtained from lvm_vg_create() or lvm_vg_open(). * * \param uuid * UUID of LV to lookup. * * \return * non-NULL handle to the LV with 'uuid' attached to the VG. * NULL is returned if the LV uuid is not associated with the VG handle. */ lv_t lvm_lv_from_uuid(vg_t vg, const char *uuid); /** * Activate a logical volume. * * \memberof lv_t * * This function is the equivalent of the lvm command "lvchange -ay". * * NOTE: This function cannot currently handle LVs with an in-progress pvmove or * lvconvert. * * \param lv * Logical volume handle. * * \return * 0 (success) or -1 (failure). */ int lvm_lv_activate(lv_t lv); /** * Deactivate a logical volume. * * \memberof lv_t * * This function is the equivalent of the lvm command "lvchange -an". * * \param lv * Logical volume handle. * * \return * 0 (success) or -1 (failure). */ int lvm_lv_deactivate(lv_t lv); /** * Remove a logical volume from a volume group. * * \memberof lv_t * * This function commits the change to disk and does _not_ require calling * lvm_vg_write(). * NOTE: The commit behavior of this function is subject to change * as the API is developed. * Currently only removing linear LVs are possible. * * \param lv * Logical volume handle. * * \return * 0 (success) or -1 (failure). */ int lvm_vg_remove_lv(lv_t lv); /** * Get the current name of a logical volume. * * \memberof lv_t * * The memory allocated for the uuid is tied to the vg_t handle and will be * released when lvm_vg_close() is called. * * \param lv * Logical volume handle. * * \return * Copy of the uuid string. */ const char *lvm_lv_get_uuid(const lv_t lv); /** * Get the current uuid of a logical volume. * * \memberof lv_t * * The memory allocated for the name is tied to the vg_t handle and will be * released when lvm_vg_close() is called. * * \param lv * Logical volume handle. * * \return * Copy of the name. */ const char *lvm_lv_get_name(const lv_t lv); /** * Get the current size in bytes of a logical volume. * * \memberof lv_t * * \param lv * Logical volume handle. * * \return * Size in bytes. */ uint64_t lvm_lv_get_size(const lv_t lv); /** * Get the value of a LV property * * \memberof lv_t * * \param lv * Logical volume handle. * * \param name * Name of property to query. See lvs man page for full list of properties * that may be queried. * * The memory allocated for a string property value is tied to the vg_t * handle and will be released when lvm_vg_close() is called. * * Example: * lvm_property_value v; * char *prop_name = "seg_count"; * * v = lvm_lv_get_property(lv, prop_name); * if (!v.is_valid) { * printf("Invalid property name or unable to query" * "'%s', errno = %d.\n", prop_name, lvm_errno(libh)); * return; * } * if (v.is_string) * printf(", value = %s\n", v.value.string); * if (v.is_integer) * printf(", value = %"PRIu64"\n", v.value.integer); * * \return * lvm_property_value structure that will contain the current * value of the property. Caller should check 'is_valid' flag before using * the value. If 'is_valid' is not set, caller should check lvm_errno() * for specific error. */ struct lvm_property_value lvm_lv_get_property(const lv_t lv, const char *name); /** * Get the value of a LV segment property * * \memberof lv_t * * \param lvseg * Logical volume segment handle. * * \param name * Name of property to query. See lvs man page for full list of properties * that may be queried. * * The memory allocated for a string property value is tied to the vg_t * handle and will be released when lvm_vg_close() is called. * * Example: * lvm_property_value v; * char *prop_name = "seg_start_pe"; * * v = lvm_lvseg_get_property(lvseg, prop_name); * if (lvm_errno(libh) || !v.is_valid) { * // handle error * printf("Invalid property name or unable to query" * "'%s'.\n", prop_name); * return; * } * if (v.is_string) * printf(", value = %s\n", v.value.string); * else * printf(", value = %"PRIu64"\n", v.value.integer); * * \return * lvm_property_value structure that will contain the current * value of the property. Caller should check lvm_errno() as well * as 'is_valid' flag before using the value. */ struct lvm_property_value lvm_lvseg_get_property(const lvseg_t lvseg, const char *name); /** * Get the current activation state of a logical volume. * * \memberof lv_t * * \param lv * Logical volume handle. * * \return * 1 if the LV is active in the kernel, 0 if not */ uint64_t lvm_lv_is_active(const lv_t lv); /** * Get the current suspended state of a logical volume. * * \memberof lv_t * * \param lv * Logical volume handle. * * \return * 1 if the LV is suspended in the kernel, 0 if not */ uint64_t lvm_lv_is_suspended(const lv_t lv); /** * Add a tag to an LV. * * \memberof lv_t * * This function requires calling lvm_vg_write() to commit the change to disk. * After successfully adding a tag, use lvm_vg_write() to commit the * new VG to disk. Upon failure, retry the operation or release the VG handle * with lvm_vg_close(). * * \param lv * Logical volume handle. * * \param tag * Tag to add to an LV. * * \return * 0 (success) or -1 (failure). */ int lvm_lv_add_tag(lv_t lv, const char *tag); /** * Remove a tag from an LV. * * \memberof lv_t * * This function requires calling lvm_vg_write() to commit the change to disk. * After successfully removing a tag, use lvm_vg_write() to commit the * new VG to disk. Upon failure, retry the operation or release the VG handle * with lvm_vg_close(). * * \param lv * Logical volume handle. * * \param tag * Tag to remove from LV. * * \return * 0 (success) or -1 (failure). */ int lvm_lv_remove_tag(lv_t lv, const char *tag); /** * Return the list of logical volume tags. * * \memberof lv_t * * The memory allocated for the list is tied to the vg_t handle and will be * released when lvm_vg_close() is called. * * To process the list, use the dm_list iterator functions. For example: * lv_t lv; * struct dm_list *tags; * struct lvm_str_list *strl; * * tags = lvm_lv_get_tags(lv); * dm_list_iterate_items(strl, tags) { * tag = strl->str; * // do something with tag * } * * * \return * A list with entries of type struct lvm_str_list, containing the * tag strings attached to volume group. * If no tags are attached to the LV, an empty list is returned * (check with dm_list_empty()). * If there is a problem obtaining the list of tags, NULL is returned. */ struct dm_list *lvm_lv_get_tags(const lv_t lv); /** * Rename logical volume to new_name. * * \memberof lv_t * * \param lv * Logical volume handle. * * \param new_name * New name of logical volume. * * \return * 0 (success) or -1 (failure). * */ int lvm_lv_rename(lv_t lv, const char *new_name); /** * Resize logical volume to new_size bytes. * * \memberof lv_t * * NOTE: This function is currently not implemented. * * \param lv * Logical volume handle. * * \param new_size * New size in bytes. * * \return * 0 (success) or -1 (failure). * */ int lvm_lv_resize(const lv_t lv, uint64_t new_size); /************************** physical volume handling ************************/ /** * Physical volume handling should not be needed anymore. Only physical volumes * bound to a vg contain useful information. Therefore the creation, * modification and the removal of orphan physical volumes is not suported. */ /** * Get the current uuid of a physical volume. * * \memberof pv_t * * The memory allocated for the uuid is tied to the vg_t handle and will be * released when lvm_vg_close() is called. * * \param pv * Physical volume handle. * * \return * Copy of the uuid string. */ const char *lvm_pv_get_uuid(const pv_t pv); /** * Get the current name of a physical volume. * * \memberof pv_t * * The memory allocated for the name is tied to the vg_t handle and will be * released when lvm_vg_close() is called. * * \param pv * Physical volume handle. * * \return * Copy of the name. */ const char *lvm_pv_get_name(const pv_t pv); /** * Get the current number of metadata areas in the physical volume. * * \memberof pv_t * * \param pv * Physical volume handle. * * \return * Number of metadata areas in the PV. */ uint64_t lvm_pv_get_mda_count(const pv_t pv); /** * Get the current size in bytes of a device underlying a * physical volume. * * \memberof pv_t * * \param pv * Physical volume handle. * * \return * Size in bytes. */ uint64_t lvm_pv_get_dev_size(const pv_t pv); /** * Get the current size in bytes of a physical volume. * * \memberof pv_t * * \param pv * Physical volume handle. * * \return * Size in bytes. */ uint64_t lvm_pv_get_size(const pv_t pv); /** * Get the current unallocated space in bytes of a physical volume. * * \memberof pv_t * * \param pv * Physical volume handle. * * \return * Free size in bytes. */ uint64_t lvm_pv_get_free(const pv_t pv); /** * Get the value of a PV property * * \memberof pv_t * * \param pv * Physical volume handle. * * \param name * Name of property to query. See pvs man page for full list of properties * that may be queried. * * The memory allocated for a string property value is tied to the vg_t handle * and will be released when lvm_vg_close() is called. For "percent" values * (those obtained for copy_percent and snap_percent properties), please see * percent_range_t and lvm_percent_to_float(). * * Example: * lvm_property_value value; * char *prop_name = "pv_mda_count"; * * v = lvm_pv_get_property(pv, prop_name); * if (!v.is_valid) { * printf("Invalid property name or unable to query" * "'%s', errno = %d.\n", prop_name, lvm_errno(libh)); * return; * } * if (v.is_string) * printf(", value = %s\n", v.value.string); * if (v.is_integer) * printf(", value = %"PRIu64"\n", v.value.integer); * * \return * lvm_property_value structure that will contain the current * value of the property. Caller should check 'is_valid' flag before using * the value. If 'is_valid' is not set, caller should check lvm_errno() * for specific error. */ struct lvm_property_value lvm_pv_get_property(const pv_t pv, const char *name); /** * Get the value of a PV segment property * * \memberof pv_t * * \param pvseg * Physical volume segment handle. * * \param name * Name of property to query. See pvs man page for full list of properties * that may be queried. * * The memory allocated for a string property value is tied to the vg_t * handle and will be released when lvm_vg_close() is called. * * Example: * lvm_property_value v; * char *prop_name = "pvseg_start"; * * v = lvm_pvseg_get_property(pvseg, prop_name); * if (lvm_errno(libh) || !v.is_valid) { * // handle error * printf("Invalid property name or unable to query" * "'%s'.\n", prop_name); * return; * } * if (v.is_string) * printf(", value = %s\n", v.value.string); * else * printf(", value = %"PRIu64"\n", v.value.integer); * * \return * lvm_property_value structure that will contain the current * value of the property. Caller should check lvm_errno() as well * as 'is_valid' flag before using the value. */ struct lvm_property_value lvm_pvseg_get_property(const pvseg_t pvseg, const char *name); /** * Return a list of pvseg handles for a given PV handle. * * \memberof pv_t * * \param pv * Physical volume handle. * * \return * A list of lvm_pvseg_list structures containing pvseg handles for this pv. */ struct dm_list *lvm_pv_list_pvsegs(pv_t pv); /** * Lookup an PV handle in a VG by the PV name. * * \memberof pv_t * * \param vg * VG handle obtained from lvm_vg_create() or lvm_vg_open(). * * \param name * Name of PV to lookup. * * \return * non-NULL handle to the PV 'name' attached to the VG. * NULL is returned if the PV name is not associated with the VG handle. */ pv_t lvm_pv_from_name(vg_t vg, const char *name); /** * Lookup an PV handle in a VG by the PV uuid. * The form of the uuid may be either the formatted, human-readable form, * or the non-formatted form. * * \memberof pv_t * * \param vg * VG handle obtained from lvm_vg_create() or lvm_vg_open(). * * \param uuid * UUID of PV to lookup. * * \return * non-NULL handle to the PV with 'uuid' attached to the VG. * NULL is returned if the PV uuid is not associated with the VG handle. */ pv_t lvm_pv_from_uuid(vg_t vg, const char *uuid); /** * Resize physical volume to new_size bytes. * * \memberof pv_t * * NOTE: This function is currently not implemented. * * \param pv * Physical volume handle. * * \param new_size * New size in bytes. * * \return * 0 (success) or -1 (failure). */ int lvm_pv_resize(const pv_t pv, uint64_t new_size); #ifndef _LVM_PERCENT_H /** * This type defines a couple of special percent values. The PERCENT_0 and * PERCENT_100 constants designate *exact* percentages: values are never * rounded to either of these two. */ typedef enum { PERCENT_0 = 0, PERCENT_1 = 1000000, PERCENT_100 = 100 * PERCENT_1, PERCENT_INVALID = -1, PERCENT_MERGE_FAILED = -2 } percent_range_t; typedef int32_t percent_t; #endif /** * Convert a (fixed-point) value obtained from the percent-denominated * *_get_property functions into a floating-point value. */ float lvm_percent_to_float(percent_t v); #ifdef __cplusplus } #endif #endif /* _LIB_LVM2APP_H */ lvm2-2.02.98/liblvm/lvm_base.c0000640000175000017500000000601612037016272014734 0ustar blankblank/* * Copyright (C) 2008,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 "lib.h" #include "toolcontext.h" #include "locking.h" #include "lvm-version.h" #include "metadata-exported.h" #include "lvm2app.h" const char *lvm_library_get_version(void) { return LVM_VERSION; } lvm_t lvm_init(const char *system_dir) { struct cmd_context *cmd; /* FIXME: logging bound to handle */ if (!udev_init_library_context()) stack; /* create context */ /* FIXME: split create_toolcontext */ /* FIXME: make all globals configurable */ cmd = create_toolcontext(0, system_dir, 0, 0); if (!cmd) return NULL; if (stored_errno()) return (lvm_t) cmd; /* * FIXME: if an non memory error occured, return the cmd (maybe some * cleanup needed). */ /* initialization from lvm_run_command */ init_error_message_produced(0); /* FIXME: locking_type config option needed? */ /* initialize locking */ if (!init_locking(-1, cmd, 0)) { /* FIXME: use EAGAIN as error code here */ lvm_quit((lvm_t) cmd); return NULL; } /* * FIXME: Use cmd->cmd_line as audit trail for liblvm calls. Used in * archive() call. Possible example: * cmd_line = "lvm_vg_create: vg1\nlvm_vg_extend vg1 /dev/sda1\n" */ cmd->cmd_line = "liblvm"; return (lvm_t) cmd; } void lvm_quit(lvm_t libh) { destroy_toolcontext((struct cmd_context *)libh); udev_fin_library_context(); } int lvm_config_reload(lvm_t libh) { /* FIXME: re-init locking needed here? */ if (!refresh_toolcontext((struct cmd_context *)libh)) return -1; return 0; } /* * FIXME: submit a patch to document the --config option */ int lvm_config_override(lvm_t libh, const char *config_settings) { struct cmd_context *cmd = (struct cmd_context *)libh; if (override_config_tree_from_string(cmd, config_settings)) return -1; return 0; } int lvm_config_find_bool(lvm_t libh, const char *config_path, int fail) { return find_config_tree_bool((struct cmd_context *)libh, config_path, fail); } int lvm_errno(lvm_t libh) { return stored_errno(); } const char *lvm_errmsg(lvm_t libh) { return stored_errmsg(); } const char *lvm_vgname_from_pvid(lvm_t libh, const char *pvid) { struct cmd_context *cmd = (struct cmd_context *)libh; struct id id; if (!id_read_format(&id, pvid)) { log_error(INTERNAL_ERROR "Unable to convert uuid"); return NULL; } return find_vgname_from_pvid(cmd, (char *)id.uuid); } const char *lvm_vgname_from_device(lvm_t libh, const char *device) { struct cmd_context *cmd = (struct cmd_context *)libh; return find_vgname_from_pvname(cmd, device); } float lvm_percent_to_float(percent_t v) { return percent_to_float(v); } lvm2-2.02.98/liblvm/Makefile.in0000640000175000017500000000365712037016272015055 0ustar blankblank# # Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. # Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved. # # This file is part of LVM2. # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions # of the GNU General Public License v.2. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation, # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA srcdir = @srcdir@ top_srcdir = @top_srcdir@ top_builddir = @top_builddir@ SOURCES =\ lvm_misc.c \ lvm_base.c \ lvm_lv.c \ lvm_pv.c \ lvm_vg.c LIB_NAME = liblvm2app LIB_VERSION = $(LIB_VERSION_APP) ifeq ("@STATIC_LINK@", "yes") LIB_STATIC = $(LIB_NAME).a endif LIB_SHARED = $(LIB_NAME).$(LIB_SUFFIX) CLEAN_TARGETS += liblvm.cflow $(LIB_NAME).a EXPORTED_HEADER = $(srcdir)/lvm2app.h EXPORTED_FN_PREFIX = lvm LDDEPS += $(top_builddir)/lib/liblvm-internal.a include $(top_builddir)/make.tmpl LIBS += $(LVMINTERNAL_LIBS) -ldevmapper ifeq ("@DMEVENTD@", "yes") LIBS += -ldevmapper-event endif .PHONY: install_dynamic install_static install_include install_pkgconfig INSTALL_TYPE = install_dynamic ifeq ("@STATIC_LINK@", "yes") INSTALL_TYPE += install_static endif ifeq ("@PKGCONFIG@", "yes") INSTALL_TYPE += install_pkgconfig endif install: $(INSTALL_TYPE) install_include install_include: $(srcdir)/lvm2app.h $(INSTALL_DATA) -D $< $(includedir)/$( $@ cflow: liblvm.cflow DISTCLEAN_TARGETS += $(LIB_NAME).pc .exported_symbols_generated lvm2-2.02.98/liblvm/liblvm2app.pc.in0000640000175000017500000000037212037016272016000 0ustar blankblankprefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: lvm2app Description: lvm2 application library Version: @LVM_MAJOR@.@LVM_LIBAPI@ Cflags: -I${includedir} Libs: -L${libdir} -llvm2app Requires.private: devmapper lvm2-2.02.98/liblvm/lvm_misc.c0000640000175000017500000000533112037016272014754 0ustar blankblank/* * Copyright (C) 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 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 "properties.h" #include "lvm_misc.h" #include "lvm2app.h" struct dm_list *tag_list_copy(struct dm_pool *p, struct dm_list *tag_list) { struct dm_list *list; lvm_str_list_t *lsl; struct str_list *sl; if (!(list = dm_pool_zalloc(p, sizeof(*list)))) { log_errno(ENOMEM, "Memory allocation fail for dm_list."); return NULL; } dm_list_init(list); dm_list_iterate_items(sl, tag_list) { if (!(lsl = dm_pool_zalloc(p, sizeof(*lsl)))) { log_errno(ENOMEM, "Memory allocation fail for lvm_lv_list."); return NULL; } if (!(lsl->str = dm_pool_strdup(p, sl->str))) { log_errno(ENOMEM, "Memory allocation fail for lvm_lv_list->str."); return NULL; } dm_list_add(list, &lsl->list); } return list; } struct lvm_property_value get_property(const pv_t pv, const vg_t vg, const lv_t lv, const lvseg_t lvseg, const pvseg_t pvseg, const char *name) { struct lvm_property_type prop; struct lvm_property_value v = { 0 }; prop.id = name; if (pv) { if (!pv_get_property(pv, &prop)) return v; } else if (vg) { if (!vg_get_property(vg, &prop)) return v; } else if (lv) { if (!lv_get_property(lv, &prop)) return v; } else if (lvseg) { if (!lvseg_get_property(lvseg, &prop)) return v; } else if (pvseg) { if (!pvseg_get_property(pvseg, &prop)) return v; } else { log_errno(EINVAL, "Invalid NULL handle passed to library function."); return v; } v.is_settable = prop.is_settable; v.is_string = prop.is_string; v.is_integer = prop.is_integer; if (v.is_string) v.value.string = prop.value.string; if (v.is_integer) v.value.integer = prop.value.integer; v.is_valid = 1; return v; } int set_property(const pv_t pv, const vg_t vg, const lv_t lv, const char *name, struct lvm_property_value *v) { struct lvm_property_type prop; prop.id = name; if (v->is_string) prop.value.string = v->value.string; else prop.value.integer = v->value.integer; if (pv) { if (!pv_set_property(pv, &prop)) { v->is_valid = 0; return -1; } } else if (vg) { if (!vg_set_property(vg, &prop)) { v->is_valid = 0; return -1; } } else if (lv) { if (!lv_set_property(lv, &prop)) { v->is_valid = 0; return -1; } } return 0; } lvm2-2.02.98/lib/0000750000175000017500000000000012037016272012255 5ustar blankblanklvm2-2.02.98/lib/device/0000750000175000017500000000000012037016272013514 5ustar blankblanklvm2-2.02.98/lib/device/device.c0000640000175000017500000002617112037016272015127 0ustar blankblank/* * 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 "lvm-types.h" #include "device.h" #include "metadata.h" #include "filter.h" #include "xlate.h" #include /* dirname, basename */ /* See linux/genhd.h and fs/partitions/msdos */ #define PART_MAGIC 0xAA55 #define PART_MAGIC_OFFSET UINT64_C(0x1FE) #define PART_OFFSET UINT64_C(0x1BE) struct partition { uint8_t boot_ind; uint8_t head; uint8_t sector; uint8_t cyl; uint8_t sys_ind; /* partition type */ uint8_t end_head; uint8_t end_sector; uint8_t end_cyl; uint32_t start_sect; uint32_t nr_sects; } __attribute__((packed)); static int _is_partitionable(struct device *dev) { int parts = max_partitions(MAJOR(dev->dev)); /* All MD devices are partitionable via blkext (as of 2.6.28) */ if (MAJOR(dev->dev) == md_major()) return 1; if ((parts <= 1) || (MINOR(dev->dev) % parts)) return 0; return 1; } static int _has_partition_table(struct device *dev) { int ret = 0; unsigned p; struct { uint8_t skip[PART_OFFSET]; struct partition part[4]; uint16_t magic; } __attribute__((packed)) buf; /* sizeof() == SECTOR_SIZE */ if (!dev_read(dev, UINT64_C(0), sizeof(buf), &buf)) return_0; /* FIXME Check for other types of partition table too */ /* Check for msdos partition table */ if (buf.magic == xlate16(PART_MAGIC)) { for (p = 0; p < 4; ++p) { /* Table is invalid if boot indicator not 0 or 0x80 */ if (buf.part[p].boot_ind & 0x7f) { ret = 0; break; } /* Must have at least one non-empty partition */ if (buf.part[p].nr_sects) ret = 1; } } return ret; } int is_partitioned_dev(struct device *dev) { if (!_is_partitionable(dev)) return 0; return _has_partition_table(dev); } #if 0 #include #include #include #include #include #include #include #include #include #include #include int _get_partition_type(struct dev_filter *filter, struct device *d); #define MINOR_PART(dev) (MINOR((dev)->dev) % max_partitions(MINOR((dev)->dev))) int is_extended_partition(struct device *d) { return (MINOR_PART(d) > 4) ? 1 : 0; } struct device *dev_primary(struct dev_mgr *dm, struct device *d) { struct device *ret; ret = dev_by_dev(dm, d->dev - MINOR_PART(dm, d)); /* FIXME: Needs replacing with a 'refresh' */ if (!ret) { init_dev_scan(dm); ret = dev_by_dev(dm, d->dev - MINOR_PART(dm, d)); } return ret; } int partition_type_is_lvm(struct dev_mgr *dm, struct device *d) { int pt; pt = _get_partition_type(dm, d); if (!pt) { if (is_whole_disk(dm, d)) /* FIXME: Overloaded pt=0 in error cases */ return 1; else { log_error ("%s: missing partition table " "on partitioned device", d->name); return 0; } } if (is_whole_disk(dm, d)) { log_error("%s: looks to possess partition table", d->name); return 0; } /* check part type */ if (pt != LVM_PARTITION && pt != LVM_NEW_PARTITION) { log_error("%s: invalid partition type 0x%x " "(must be 0x%x)", d->name, pt, LVM_NEW_PARTITION); return 0; } if (pt == LVM_PARTITION) { log_error ("%s: old LVM partition type found - please change to 0x%x", d->name, LVM_NEW_PARTITION); return 0; } return 1; } int _get_partition_type(struct dev_mgr *dm, struct device *d) { int pv_handle = -1; struct device *primary; ssize_t read_ret; ssize_t bytes_read = 0; char *buffer; unsigned short *s_buffer; struct partition *part; loff_t offset = 0; loff_t extended_offset = 0; int part_sought; int part_found = 0; int first_partition = 1; int extended_partition = 0; int p; if (!(primary = dev_primary(dm, d))) { log_error ("Failed to find main device containing partition %s", d->name); return 0; } if (!(buffer = dm_malloc(SECTOR_SIZE))) { log_error("Failed to allocate partition table buffer"); return 0; } /* Get partition table */ if ((pv_handle = open(primary->name, O_RDONLY)) < 0) { log_error("%s: open failed: %s", primary->name, strerror(errno)); return 0; } s_buffer = (unsigned short *) buffer; part = (struct partition *) (buffer + 0x1be); part_sought = MINOR_PART(dm, d); do { bytes_read = 0; if (llseek(pv_handle, offset * SECTOR_SIZE, SEEK_SET) == -1) { log_error("%s: llseek failed: %s", primary->name, strerror(errno)); return 0; } while ((bytes_read < SECTOR_SIZE) && (read_ret = read(pv_handle, buffer + bytes_read, SECTOR_SIZE - bytes_read)) != -1) bytes_read += read_ret; if (read_ret == -1) { log_error("%s: read failed: %s", primary->name, strerror(errno)); return 0; } if (s_buffer[255] == 0xAA55) { if (is_whole_disk(dm, d)) return -1; } else return 0; extended_partition = 0; /* Loop through primary partitions */ for (p = 0; p < 4; p++) { if (part[p].sys_ind == DOS_EXTENDED_PARTITION || part[p].sys_ind == LINUX_EXTENDED_PARTITION || part[p].sys_ind == WIN98_EXTENDED_PARTITION) { extended_partition = 1; offset = extended_offset + part[p].start_sect; if (extended_offset == 0) extended_offset = part[p].start_sect; if (first_partition == 1) part_found++; } else if (first_partition == 1) { if (p == part_sought) { if (part[p].sys_ind == 0) { /* missing primary? */ return 0; } } else part_found++; } else if (!part[p].sys_ind) part_found++; if (part_sought == part_found) return part[p].sys_ind; } first_partition = 0; } while (extended_partition == 1); return 0; } #endif #ifdef linux int get_primary_dev(const char *sysfs_dir, const struct device *dev, dev_t *result) { char path[PATH_MAX+1]; char temp_path[PATH_MAX+1]; char buffer[64]; struct stat info; FILE *fp; uint32_t pri_maj, pri_min; int size, ret = 0; /* check if dev is a partition */ if (dm_snprintf(path, PATH_MAX, "%s/dev/block/%d:%d/partition", sysfs_dir, (int)MAJOR(dev->dev), (int)MINOR(dev->dev)) < 0) { log_error("dm_snprintf partition failed"); return ret; } if (stat(path, &info) == -1) { if (errno != ENOENT) log_sys_error("stat", path); return ret; } /* * extract parent's path from the partition's symlink, e.g.: * - readlink /sys/dev/block/259:0 = ../../block/md0/md0p1 * - dirname ../../block/md0/md0p1 = ../../block/md0 * - basename ../../block/md0/md0 = md0 * Parent's 'dev' sysfs attribute = /sys/block/md0/dev */ if ((size = readlink(dirname(path), temp_path, PATH_MAX)) < 0) { log_sys_error("readlink", path); return ret; } temp_path[size] = '\0'; if (dm_snprintf(path, PATH_MAX, "%s/block/%s/dev", sysfs_dir, basename(dirname(temp_path))) < 0) { log_error("dm_snprintf dev failed"); return ret; } /* finally, parse 'dev' attribute and create corresponding dev_t */ if (stat(path, &info) == -1) { if (errno == ENOENT) log_error("sysfs file %s does not exist", path); else log_sys_error("stat", path); return ret; } fp = fopen(path, "r"); if (!fp) { log_sys_error("fopen", path); return ret; } if (!fgets(buffer, sizeof(buffer), fp)) { log_sys_error("fgets", path); goto out; } if (sscanf(buffer, "%d:%d", &pri_maj, &pri_min) != 2) { log_error("sysfs file %s not in expected MAJ:MIN format: %s", path, buffer); goto out; } *result = MKDEV((dev_t)pri_maj, pri_min); ret = 1; out: if (fclose(fp)) log_sys_error("fclose", path); return ret; } static unsigned long _dev_topology_attribute(const char *attribute, const char *sysfs_dir, struct device *dev) { static const char sysfs_fmt_str[] = "%s/dev/block/%d:%d/%s"; char path[PATH_MAX+1], buffer[64]; FILE *fp; struct stat info; dev_t uninitialized_var(primary); unsigned long result = 0UL; if (!attribute || !*attribute) return_0; if (!sysfs_dir || !*sysfs_dir) return_0; if (dm_snprintf(path, PATH_MAX, sysfs_fmt_str, sysfs_dir, (int)MAJOR(dev->dev), (int)MINOR(dev->dev), attribute) < 0) { log_error("dm_snprintf %s failed", attribute); return 0; } /* * check if the desired sysfs attribute exists * - if not: either the kernel doesn't have topology support * or the device could be a partition */ if (stat(path, &info) == -1) { if (errno != ENOENT) { log_sys_error("stat", path); return 0; } if (!get_primary_dev(sysfs_dir, dev, &primary)) return 0; /* get attribute from partition's primary device */ if (dm_snprintf(path, PATH_MAX, sysfs_fmt_str, sysfs_dir, (int)MAJOR(primary), (int)MINOR(primary), attribute) < 0) { log_error("primary dm_snprintf %s failed", attribute); return 0; } if (stat(path, &info) == -1) { if (errno != ENOENT) log_sys_error("stat", path); return 0; } } if (!(fp = fopen(path, "r"))) { log_sys_error("fopen", path); return 0; } if (!fgets(buffer, sizeof(buffer), fp)) { log_sys_error("fgets", path); goto out; } if (sscanf(buffer, "%lu", &result) != 1) { log_error("sysfs file %s not in expected format: %s", path, buffer); goto out; } log_very_verbose("Device %s %s is %lu bytes.", dev_name(dev), attribute, result); out: if (fclose(fp)) log_sys_error("fclose", path); return result >> SECTOR_SHIFT; } unsigned long dev_alignment_offset(const char *sysfs_dir, struct device *dev) { return _dev_topology_attribute("alignment_offset", sysfs_dir, dev); } unsigned long dev_minimum_io_size(const char *sysfs_dir, struct device *dev) { return _dev_topology_attribute("queue/minimum_io_size", sysfs_dir, dev); } unsigned long dev_optimal_io_size(const char *sysfs_dir, struct device *dev) { return _dev_topology_attribute("queue/optimal_io_size", sysfs_dir, dev); } unsigned long dev_discard_max_bytes(const char *sysfs_dir, struct device *dev) { return _dev_topology_attribute("queue/discard_max_bytes", sysfs_dir, dev); } unsigned long dev_discard_granularity(const char *sysfs_dir, struct device *dev) { return _dev_topology_attribute("queue/discard_granularity", sysfs_dir, dev); } #else int get_primary_dev(const char *sysfs_dir, struct device *dev, dev_t *result) { return 0; } unsigned long dev_alignment_offset(const char *sysfs_dir, struct device *dev) { return 0UL; } unsigned long dev_minimum_io_size(const char *sysfs_dir, struct device *dev) { return 0UL; } unsigned long dev_optimal_io_size(const char *sysfs_dir, struct device *dev) { return 0UL; } unsigned long dev_discard_max_bytes(const char *sysfs_dir, struct device *dev) { return 0UL; } unsigned long dev_discard_granularity(const char *sysfs_dir, struct device *dev) { return 0UL; } #endif lvm2-2.02.98/lib/device/dev-md.c0000640000175000017500000001711712037016272015044 0ustar blankblank/* * Copyright (C) 2004 Luca Berra * 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 */ #include "lib.h" #include "metadata.h" #include "xlate.h" #include "filter.h" #ifdef linux /* Lifted from because of difficulty including it */ #define MD_SB_MAGIC 0xa92b4efc #define MD_RESERVED_BYTES (64 * 1024ULL) #define MD_RESERVED_SECTORS (MD_RESERVED_BYTES / 512) #define MD_NEW_SIZE_SECTORS(x) ((x & ~(MD_RESERVED_SECTORS - 1)) \ - MD_RESERVED_SECTORS) #define MD_MAX_SYSFS_SIZE 64 static int _dev_has_md_magic(struct device *dev, uint64_t sb_offset) { uint32_t md_magic; /* Version 1 is little endian; version 0.90.0 is machine endian */ if (dev_read(dev, sb_offset, sizeof(uint32_t), &md_magic) && ((md_magic == xlate32(MD_SB_MAGIC)) || (md_magic == MD_SB_MAGIC))) return 1; return 0; } /* * Calculate the position of the superblock. * It is always aligned to a 4K boundary and * depending on minor_version, it can be: * 0: At least 8K, but less than 12K, from end of device * 1: At start of device * 2: 4K from start of device. */ typedef enum { MD_MINOR_VERSION_MIN, MD_MINOR_V0 = MD_MINOR_VERSION_MIN, MD_MINOR_V1, MD_MINOR_V2, MD_MINOR_VERSION_MAX = MD_MINOR_V2 } md_minor_version_t; static uint64_t _v1_sb_offset(uint64_t size, md_minor_version_t minor_version) { uint64_t uninitialized_var(sb_offset); switch(minor_version) { case MD_MINOR_V0: sb_offset = (size - 8 * 2) & ~(4 * 2 - 1ULL); break; case MD_MINOR_V1: sb_offset = 0; break; case MD_MINOR_V2: sb_offset = 4 * 2; break; } sb_offset <<= SECTOR_SHIFT; return sb_offset; } /* * Returns -1 on error */ int dev_is_md(struct device *dev, uint64_t *sb) { int ret = 1; md_minor_version_t minor; uint64_t size, sb_offset; if (!dev_get_size(dev, &size)) { stack; return -1; } if (size < MD_RESERVED_SECTORS * 2) return 0; if (!dev_open_readonly(dev)) { stack; return -1; } /* Check if it is an md component device. */ /* Version 0.90.0 */ sb_offset = MD_NEW_SIZE_SECTORS(size) << SECTOR_SHIFT; if (_dev_has_md_magic(dev, sb_offset)) goto out; minor = MD_MINOR_VERSION_MIN; /* Version 1, try v1.0 -> v1.2 */ do { sb_offset = _v1_sb_offset(size, minor); if (_dev_has_md_magic(dev, sb_offset)) goto out; } while (++minor <= MD_MINOR_VERSION_MAX); ret = 0; out: if (!dev_close(dev)) stack; if (ret && sb) *sb = sb_offset; return ret; } static int _md_sysfs_attribute_snprintf(char *path, size_t size, const char *sysfs_dir, struct device *blkdev, const char *attribute) { struct stat info; dev_t dev = blkdev->dev; int ret = -1; if (!sysfs_dir || !*sysfs_dir) return ret; if (MAJOR(dev) == blkext_major()) { /* lookup parent MD device from blkext partition */ if (!get_primary_dev(sysfs_dir, blkdev, &dev)) return ret; } if (MAJOR(dev) != md_major()) return ret; ret = dm_snprintf(path, size, "%s/dev/block/%d:%d/md/%s", sysfs_dir, (int)MAJOR(dev), (int)MINOR(dev), attribute); if (ret < 0) { log_error("dm_snprintf md %s failed", attribute); return ret; } if (stat(path, &info) == -1) { if (errno != ENOENT) { log_sys_error("stat", path); return ret; } /* old sysfs structure */ ret = dm_snprintf(path, size, "%s/block/md%d/md/%s", sysfs_dir, (int)MINOR(dev), attribute); if (ret < 0) { log_error("dm_snprintf old md %s failed", attribute); return ret; } } return ret; } static int _md_sysfs_attribute_scanf(const char *sysfs_dir, struct device *dev, const char *attribute_name, const char *attribute_fmt, void *attribute_value) { char path[PATH_MAX+1], buffer[MD_MAX_SYSFS_SIZE]; FILE *fp; int ret = 0; if (_md_sysfs_attribute_snprintf(path, PATH_MAX, sysfs_dir, dev, attribute_name) < 0) return ret; if (!(fp = fopen(path, "r"))) { log_sys_error("fopen", path); return ret; } if (!fgets(buffer, sizeof(buffer), fp)) { log_sys_error("fgets", path); goto out; } if ((ret = sscanf(buffer, attribute_fmt, attribute_value)) != 1) { log_error("%s sysfs attr %s not in expected format: %s", dev_name(dev), attribute_name, buffer); goto out; } out: if (fclose(fp)) log_sys_error("fclose", path); return ret; } /* * Retrieve chunk size from md device using sysfs. */ static unsigned long dev_md_chunk_size(const char *sysfs_dir, struct device *dev) { const char *attribute = "chunk_size"; unsigned long chunk_size_bytes = 0UL; if (_md_sysfs_attribute_scanf(sysfs_dir, dev, attribute, "%lu", &chunk_size_bytes) != 1) return 0; log_very_verbose("Device %s %s is %lu bytes.", dev_name(dev), attribute, chunk_size_bytes); return chunk_size_bytes >> SECTOR_SHIFT; } /* * Retrieve level from md device using sysfs. */ static int dev_md_level(const char *sysfs_dir, struct device *dev) { char level_string[MD_MAX_SYSFS_SIZE]; const char *attribute = "level"; int level = -1; if (_md_sysfs_attribute_scanf(sysfs_dir, dev, attribute, "%s", &level_string) != 1) return -1; log_very_verbose("Device %s %s is %s.", dev_name(dev), attribute, level_string); /* We only care about raid - ignore linear/faulty/multipath etc. */ if (sscanf(level_string, "raid%d", &level) != 1) return -1; return level; } /* * Retrieve raid_disks from md device using sysfs. */ static int dev_md_raid_disks(const char *sysfs_dir, struct device *dev) { const char *attribute = "raid_disks"; int raid_disks = 0; if (_md_sysfs_attribute_scanf(sysfs_dir, dev, attribute, "%d", &raid_disks) != 1) return 0; log_very_verbose("Device %s %s is %d.", dev_name(dev), attribute, raid_disks); return raid_disks; } /* * Calculate stripe width of md device using its sysfs files. */ unsigned long dev_md_stripe_width(const char *sysfs_dir, struct device *dev) { unsigned long chunk_size_sectors = 0UL; unsigned long stripe_width_sectors = 0UL; int level, raid_disks, data_disks; chunk_size_sectors = dev_md_chunk_size(sysfs_dir, dev); if (!chunk_size_sectors) return 0; level = dev_md_level(sysfs_dir, dev); if (level < 0) return 0; raid_disks = dev_md_raid_disks(sysfs_dir, dev); if (!raid_disks) return 0; /* The raid level governs the number of data disks. */ switch (level) { case 0: /* striped md does not have any parity disks */ data_disks = raid_disks; break; case 1: case 10: /* mirrored md effectively has 1 data disk */ data_disks = 1; break; case 4: case 5: /* both raid 4 and 5 have a single parity disk */ data_disks = raid_disks - 1; break; case 6: /* raid 6 has 2 parity disks */ data_disks = raid_disks - 2; break; default: log_error("Device %s has an unknown md raid level: %d", dev_name(dev), level); return 0; } stripe_width_sectors = chunk_size_sectors * data_disks; log_very_verbose("Device %s stripe-width is %lu bytes.", dev_name(dev), stripe_width_sectors << SECTOR_SHIFT); return stripe_width_sectors; } #else int dev_is_md(struct device *dev __attribute__((unused)), uint64_t *sb __attribute__((unused))) { return 0; } unsigned long dev_md_stripe_width(const char *sysfs_dir __attribute__((unused)), struct device *dev __attribute__((unused))) { return 0UL; } #endif lvm2-2.02.98/lib/device/dev-swap.c0000640000175000017500000000326612037016272015416 0ustar blankblank/* * 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 "lib.h" #include "metadata.h" #ifdef linux #define MAX_PAGESIZE (64 * 1024) #define SIGNATURE_SIZE 10 static int _swap_detect_signature(const char *buf) { if (memcmp(buf, "SWAP-SPACE", 10) == 0 || memcmp(buf, "SWAPSPACE2", 10) == 0) return 1; if (memcmp(buf, "S1SUSPEND", 9) == 0 || memcmp(buf, "S2SUSPEND", 9) == 0 || memcmp(buf, "ULSUSPEND", 9) == 0 || memcmp(buf, "\xed\xc3\x02\xe9\x98\x56\xe5\x0c", 8) == 0) return 1; return 0; } int dev_is_swap(struct device *dev, uint64_t *signature) { char buf[10]; uint64_t size; unsigned page; int ret = 0; if (!dev_get_size(dev, &size)) { stack; return -1; } if (!dev_open_readonly(dev)) { stack; return -1; } *signature = 0; for (page = 0x1000; page <= MAX_PAGESIZE; page <<= 1) { /* * skip 32k pagesize since this does not seem to be supported */ if (page == 0x8000) continue; if (size < page) break; if (!dev_read(dev, page - SIGNATURE_SIZE, SIGNATURE_SIZE, buf)) { ret = -1; break; } if (_swap_detect_signature(buf)) { *signature = page - SIGNATURE_SIZE; ret = 1; break; } } if (!dev_close(dev)) stack; return ret; } #endif lvm2-2.02.98/lib/device/dev-io.c0000640000175000017500000004163312037016272015053 0ustar blankblank/* * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU 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 "lvm-types.h" #include "device.h" #include "metadata.h" #include "lvmcache.h" #include "memlock.h" #include "locking.h" #include #include #include #include #include #ifdef linux # define u64 uint64_t /* Missing without __KERNEL__ */ # undef WNOHANG /* Avoid redefinition */ # undef WUNTRACED /* Avoid redefinition */ # include /* For block ioctl definitions */ # define BLKSIZE_SHIFT SECTOR_SHIFT # ifndef BLKGETSIZE64 /* fs.h out-of-date */ # define BLKGETSIZE64 _IOR(0x12, 114, size_t) # endif /* BLKGETSIZE64 */ # ifndef BLKDISCARD # define BLKDISCARD _IO(0x12,119) # endif #else # include # define BLKBSZGET DKIOCGETBLOCKSIZE # define BLKSSZGET DKIOCGETBLOCKSIZE # define BLKGETSIZE64 DKIOCGETBLOCKCOUNT # define BLKFLSBUF DKIOCSYNCHRONIZECACHE # define BLKSIZE_SHIFT 0 #endif #ifdef O_DIRECT_SUPPORT # ifndef O_DIRECT # error O_DIRECT support configured but O_DIRECT definition not found in headers # endif #endif static DM_LIST_INIT(_open_devices); /*----------------------------------------------------------------- * The standard io loop that keeps submitting an io until it's * all gone. *---------------------------------------------------------------*/ static int _io(struct device_area *where, char *buffer, int should_write) { int fd = dev_fd(where->dev); ssize_t n = 0; size_t total = 0; if (fd < 0) { log_error("Attempt to read an unopened device (%s).", dev_name(where->dev)); return 0; } /* * Skip all writes in test mode. */ if (should_write && test_mode()) return 1; if (where->size > SSIZE_MAX) { log_error("Read size too large: %" PRIu64, where->size); return 0; } if (lseek(fd, (off_t) where->start, SEEK_SET) < 0) { log_error("%s: lseek %" PRIu64 " failed: %s", dev_name(where->dev), (uint64_t) where->start, strerror(errno)); return 0; } while (total < (size_t) where->size) { do n = should_write ? write(fd, buffer, (size_t) where->size - total) : read(fd, buffer, (size_t) where->size - total); while ((n < 0) && ((errno == EINTR) || (errno == EAGAIN))); if (n < 0) log_error_once("%s: %s failed after %" PRIu64 " of %" PRIu64 " at %" PRIu64 ": %s", dev_name(where->dev), should_write ? "write" : "read", (uint64_t) total, (uint64_t) where->size, (uint64_t) where->start, strerror(errno)); if (n <= 0) break; total += n; buffer += n; } return (total == (size_t) where->size); } /*----------------------------------------------------------------- * LVM2 uses O_DIRECT when performing metadata io, which requires * block size aligned accesses. If any io is not aligned we have * to perform the io via a bounce buffer, obviously this is quite * inefficient. *---------------------------------------------------------------*/ /* * Get the sector size from an _open_ device. */ static int _get_block_size(struct device *dev, unsigned int *size) { const char *name = dev_name(dev); if (dev->block_size == -1) { if (ioctl(dev_fd(dev), BLKBSZGET, &dev->block_size) < 0) { log_sys_error("ioctl BLKBSZGET", name); return 0; } log_debug("%s: block size is %u bytes", name, dev->block_size); } *size = (unsigned int) dev->block_size; return 1; } /* * Widens a region to be an aligned region. */ static void _widen_region(unsigned int block_size, struct device_area *region, struct device_area *result) { uint64_t mask = block_size - 1, delta; memcpy(result, region, sizeof(*result)); /* adjust the start */ delta = result->start & mask; if (delta) { result->start -= delta; result->size += delta; } /* adjust the end */ delta = (result->start + result->size) & mask; if (delta) result->size += block_size - delta; } static int _aligned_io(struct device_area *where, char *buffer, int should_write) { char *bounce, *bounce_buf; unsigned int block_size = 0; uintptr_t mask; struct device_area widened; int r = 0; if (!(where->dev->flags & DEV_REGULAR) && !_get_block_size(where->dev, &block_size)) return_0; if (!block_size) block_size = lvm_getpagesize(); _widen_region(block_size, where, &widened); /* Do we need to use a bounce buffer? */ mask = block_size - 1; if (!memcmp(where, &widened, sizeof(widened)) && !((uintptr_t) buffer & mask)) return _io(where, buffer, should_write); /* Allocate a bounce buffer with an extra block */ if (!(bounce_buf = bounce = dm_malloc((size_t) widened.size + block_size))) { log_error("Bounce buffer malloc failed"); return 0; } /* * Realign start of bounce buffer (using the extra sector) */ if (((uintptr_t) bounce) & mask) bounce = (char *) ((((uintptr_t) bounce) + mask) & ~mask); /* channel the io through the bounce buffer */ if (!_io(&widened, bounce, 0)) { if (!should_write) goto_out; /* FIXME pre-extend the file */ memset(bounce, '\n', widened.size); } if (should_write) { memcpy(bounce + (where->start - widened.start), buffer, (size_t) where->size); /* ... then we write */ if (!(r = _io(&widened, bounce, 1))) stack; goto out; } memcpy(buffer, bounce + (where->start - widened.start), (size_t) where->size); r = 1; out: dm_free(bounce_buf); return r; } static int _dev_get_size_file(const struct device *dev, uint64_t *size) { const char *name = dev_name(dev); struct stat info; if (stat(name, &info)) { log_sys_error("stat", name); return 0; } *size = info.st_size; *size >>= SECTOR_SHIFT; /* Convert to sectors */ log_very_verbose("%s: size is %" PRIu64 " sectors", name, *size); return 1; } static int _dev_get_size_dev(const struct device *dev, uint64_t *size) { int fd; const char *name = dev_name(dev); if ((fd = open(name, O_RDONLY)) < 0) { log_sys_error("open", name); return 0; } if (ioctl(fd, BLKGETSIZE64, size) < 0) { log_sys_error("ioctl BLKGETSIZE64", name); if (close(fd)) log_sys_error("close", name); return 0; } *size >>= BLKSIZE_SHIFT; /* Convert to sectors */ if (close(fd)) log_sys_error("close", name); log_very_verbose("%s: size is %" PRIu64 " sectors", name, *size); return 1; } static int _dev_read_ahead_dev(struct device *dev, uint32_t *read_ahead) { long read_ahead_long; if (dev->read_ahead != -1) { *read_ahead = (uint32_t) dev->read_ahead; return 1; } if (!dev_open_readonly(dev)) return_0; if (ioctl(dev->fd, BLKRAGET, &read_ahead_long) < 0) { log_sys_error("ioctl BLKRAGET", dev_name(dev)); if (!dev_close(dev)) stack; return 0; } *read_ahead = (uint32_t) read_ahead_long; dev->read_ahead = read_ahead_long; log_very_verbose("%s: read_ahead is %u sectors", dev_name(dev), *read_ahead); if (!dev_close(dev)) stack; return 1; } static int _dev_discard_blocks(struct device *dev, uint64_t offset_bytes, uint64_t size_bytes) { uint64_t discard_range[2]; if (!dev_open(dev)) return_0; discard_range[0] = offset_bytes; discard_range[1] = size_bytes; log_debug("Discarding %" PRIu64 " bytes offset %" PRIu64 " bytes on %s.", size_bytes, offset_bytes, dev_name(dev)); if (ioctl(dev->fd, BLKDISCARD, &discard_range) < 0) { log_error("%s: BLKDISCARD ioctl at offset %" PRIu64 " size %" PRIu64 " failed: %s.", dev_name(dev), offset_bytes, size_bytes, strerror(errno)); if (!dev_close(dev)) stack; /* It doesn't matter if discard failed, so return success. */ return 1; } if (!dev_close(dev)) stack; return 1; } /*----------------------------------------------------------------- * Public functions *---------------------------------------------------------------*/ int dev_get_size(const struct device *dev, uint64_t *size) { if (!dev) return 0; if ((dev->flags & DEV_REGULAR)) return _dev_get_size_file(dev, size); else return _dev_get_size_dev(dev, size); } int dev_get_read_ahead(struct device *dev, uint32_t *read_ahead) { if (!dev) return 0; if (dev->flags & DEV_REGULAR) { *read_ahead = 0; return 1; } return _dev_read_ahead_dev(dev, read_ahead); } int dev_discard_blocks(struct device *dev, uint64_t offset_bytes, uint64_t size_bytes) { if (!dev) return 0; if (dev->flags & DEV_REGULAR) return 1; return _dev_discard_blocks(dev, offset_bytes, size_bytes); } /* FIXME Unused int dev_get_sectsize(struct device *dev, uint32_t *size) { int fd; int s; const char *name = dev_name(dev); if ((fd = open(name, O_RDONLY)) < 0) { log_sys_error("open", name); return 0; } if (ioctl(fd, BLKSSZGET, &s) < 0) { log_sys_error("ioctl BLKSSZGET", name); if (close(fd)) log_sys_error("close", name); return 0; } if (close(fd)) log_sys_error("close", name); *size = (uint32_t) s; log_very_verbose("%s: sector size is %" PRIu32 " bytes", name, *size); return 1; } */ void dev_flush(struct device *dev) { if (!(dev->flags & DEV_REGULAR) && ioctl(dev->fd, BLKFLSBUF, 0) >= 0) return; if (fsync(dev->fd) >= 0) return; sync(); } int dev_open_flags(struct device *dev, int flags, int direct, int quiet) { struct stat buf; const char *name; int need_excl = 0, need_rw = 0; if ((flags & O_ACCMODE) == O_RDWR) need_rw = 1; if ((flags & O_EXCL)) need_excl = 1; if (dev->fd >= 0) { if (((dev->flags & DEV_OPENED_RW) || !need_rw) && ((dev->flags & DEV_OPENED_EXCL) || !need_excl)) { dev->open_count++; return 1; } if (dev->open_count && !need_excl) { log_debug("%s already opened read-only. Upgrading " "to read-write.", dev_name(dev)); dev->open_count++; } dev_close_immediate(dev); } if (critical_section()) /* FIXME Make this log_error */ log_verbose("dev_open(%s) called while suspended", dev_name(dev)); if (dev->flags & DEV_REGULAR) name = dev_name(dev); else if (!(name = dev_name_confirmed(dev, quiet))) return_0; #ifdef O_DIRECT_SUPPORT if (direct) { if (!(dev->flags & DEV_O_DIRECT_TESTED)) dev->flags |= DEV_O_DIRECT; if ((dev->flags & DEV_O_DIRECT)) flags |= O_DIRECT; } #endif #ifdef O_NOATIME /* Don't update atime on device inodes */ if (!(dev->flags & DEV_REGULAR)) flags |= O_NOATIME; #endif if ((dev->fd = open(name, flags, 0777)) < 0) { #ifdef O_DIRECT_SUPPORT if (direct && !(dev->flags & DEV_O_DIRECT_TESTED)) { flags &= ~O_DIRECT; if ((dev->fd = open(name, flags, 0777)) >= 0) { dev->flags &= ~DEV_O_DIRECT; log_debug("%s: Not using O_DIRECT", name); goto opened; } } #endif if (quiet) log_sys_debug("open", name); else log_sys_error("open", name); return 0; } #ifdef O_DIRECT_SUPPORT opened: if (direct) dev->flags |= DEV_O_DIRECT_TESTED; #endif dev->open_count++; dev->flags &= ~DEV_ACCESSED_W; if (need_rw) dev->flags |= DEV_OPENED_RW; else dev->flags &= ~DEV_OPENED_RW; if (need_excl) dev->flags |= DEV_OPENED_EXCL; else dev->flags &= ~DEV_OPENED_EXCL; if (!(dev->flags & DEV_REGULAR) && ((fstat(dev->fd, &buf) < 0) || (buf.st_rdev != dev->dev))) { log_error("%s: fstat failed: Has device name changed?", name); dev_close_immediate(dev); return 0; } #ifndef O_DIRECT_SUPPORT if (!(dev->flags & DEV_REGULAR)) dev_flush(dev); #endif if ((flags & O_CREAT) && !(flags & O_TRUNC)) dev->end = lseek(dev->fd, (off_t) 0, SEEK_END); dm_list_add(&_open_devices, &dev->open_list); log_debug("Opened %s %s%s%s", dev_name(dev), dev->flags & DEV_OPENED_RW ? "RW" : "RO", dev->flags & DEV_OPENED_EXCL ? " O_EXCL" : "", dev->flags & DEV_O_DIRECT ? " O_DIRECT" : ""); return 1; } int dev_open_quiet(struct device *dev) { return dev_open_flags(dev, O_RDWR, 1, 1); } int dev_open(struct device *dev) { return dev_open_flags(dev, O_RDWR, 1, 0); } int dev_open_readonly(struct device *dev) { return dev_open_flags(dev, O_RDONLY, 1, 0); } int dev_open_readonly_buffered(struct device *dev) { return dev_open_flags(dev, O_RDONLY, 0, 0); } int dev_open_readonly_quiet(struct device *dev) { return dev_open_flags(dev, O_RDONLY, 1, 1); } int dev_test_excl(struct device *dev) { int flags; int r; flags = vg_write_lock_held() ? O_RDWR : O_RDONLY; flags |= O_EXCL; r = dev_open_flags(dev, flags, 1, 1); if (r) dev_close_immediate(dev); return r; } static void _close(struct device *dev) { if (close(dev->fd)) log_sys_error("close", dev_name(dev)); dev->fd = -1; dev->block_size = -1; dm_list_del(&dev->open_list); log_debug("Closed %s", dev_name(dev)); if (dev->flags & DEV_ALLOCED) { dm_free((void *) dm_list_item(dev->aliases.n, struct str_list)-> str); dm_free(dev->aliases.n); dm_free(dev); } } static int _dev_close(struct device *dev, int immediate) { if (dev->fd < 0) { log_error("Attempt to close device '%s' " "which is not open.", dev_name(dev)); return 0; } #ifndef O_DIRECT_SUPPORT if (dev->flags & DEV_ACCESSED_W) dev_flush(dev); #endif if (dev->open_count > 0) dev->open_count--; if (immediate && dev->open_count) log_debug("%s: Immediate close attempt while still referenced", dev_name(dev)); /* Close unless device is known to belong to a locked VG */ if (immediate || (dev->open_count < 1 && !lvmcache_pvid_is_locked(dev->pvid))) _close(dev); return 1; } int dev_close(struct device *dev) { return _dev_close(dev, 0); } int dev_close_immediate(struct device *dev) { return _dev_close(dev, 1); } void dev_close_all(void) { struct dm_list *doh, *doht; struct device *dev; dm_list_iterate_safe(doh, doht, &_open_devices) { dev = dm_list_struct_base(doh, struct device, open_list); if (dev->open_count < 1) _close(dev); } } static inline int _dev_is_valid(struct device *dev) { return (dev->max_error_count == NO_DEV_ERROR_COUNT_LIMIT || dev->error_count < dev->max_error_count); } static void _dev_inc_error_count(struct device *dev) { if (++dev->error_count == dev->max_error_count) log_warn("WARNING: Error counts reached a limit of %d. " "Device %s was disabled", dev->max_error_count, dev_name(dev)); } int dev_read(struct device *dev, uint64_t offset, size_t len, void *buffer) { struct device_area where; int ret; if (!dev->open_count) return_0; if (!_dev_is_valid(dev)) return 0; where.dev = dev; where.start = offset; where.size = len; // fprintf(stderr, "READ: %s, %lld, %d\n", dev_name(dev), offset, len); ret = _aligned_io(&where, buffer, 0); if (!ret) _dev_inc_error_count(dev); return ret; } /* * Read from 'dev' into 'buf', possibly in 2 distinct regions, denoted * by (offset,len) and (offset2,len2). Thus, the total size of * 'buf' should be len+len2. */ int dev_read_circular(struct device *dev, uint64_t offset, size_t len, uint64_t offset2, size_t len2, char *buf) { if (!dev_read(dev, offset, len, buf)) { log_error("Read from %s failed", dev_name(dev)); return 0; } /* * The second region is optional, and allows for * a circular buffer on the device. */ if (!len2) return 1; if (!dev_read(dev, offset2, len2, buf + len)) { log_error("Circular read from %s failed", dev_name(dev)); return 0; } return 1; } /* FIXME If O_DIRECT can't extend file, dev_extend first; dev_truncate after. * But fails if concurrent processes writing */ /* FIXME pre-extend the file */ int dev_append(struct device *dev, size_t len, char *buffer) { int r; if (!dev->open_count) return_0; r = dev_write(dev, dev->end, len, buffer); dev->end += (uint64_t) len; #ifndef O_DIRECT_SUPPORT dev_flush(dev); #endif return r; } int dev_write(struct device *dev, uint64_t offset, size_t len, void *buffer) { struct device_area where; int ret; if (!dev->open_count) return_0; if (!_dev_is_valid(dev)) return 0; where.dev = dev; where.start = offset; where.size = len; dev->flags |= DEV_ACCESSED_W; ret = _aligned_io(&where, buffer, 1); if (!ret) _dev_inc_error_count(dev); return ret; } int dev_set(struct device *dev, uint64_t offset, size_t len, int value) { size_t s; char buffer[4096] __attribute__((aligned(8))); if (!dev_open(dev)) return_0; if ((offset % SECTOR_SIZE) || (len % SECTOR_SIZE)) log_debug("Wiping %s at %" PRIu64 " length %" PRIsize_t, dev_name(dev), offset, len); else log_debug("Wiping %s at sector %" PRIu64 " length %" PRIsize_t " sectors", dev_name(dev), offset >> SECTOR_SHIFT, len >> SECTOR_SHIFT); memset(buffer, value, sizeof(buffer)); while (1) { s = len > sizeof(buffer) ? sizeof(buffer) : len; if (!dev_write(dev, offset, s, buffer)) break; len -= s; if (!len) break; offset += s; } dev->flags |= DEV_ACCESSED_W; if (!dev_close(dev)) stack; return (len == 0); } lvm2-2.02.98/lib/device/device.h0000640000175000017500000001007712037016272015132 0ustar blankblank/* * 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_DEVICE_H #define _LVM_DEVICE_H #include "uuid.h" #include #define DEV_ACCESSED_W 0x00000001 /* Device written to? */ #define DEV_REGULAR 0x00000002 /* Regular file? */ #define DEV_ALLOCED 0x00000004 /* dm_malloc used */ #define DEV_OPENED_RW 0x00000008 /* Opened RW */ #define DEV_OPENED_EXCL 0x00000010 /* Opened EXCL */ #define DEV_O_DIRECT 0x00000020 /* Use O_DIRECT */ #define DEV_O_DIRECT_TESTED 0x00000040 /* DEV_O_DIRECT is reliable */ /* * All devices in LVM will be represented by one of these. * pointer comparisons are valid. */ struct device { struct dm_list aliases; /* struct str_list from lvm-types.h */ dev_t dev; /* private */ int fd; int open_count; int error_count; int max_error_count; int block_size; int read_ahead; uint32_t flags; uint64_t end; struct dm_list open_list; char pvid[ID_LEN + 1]; char _padding[7]; }; struct device_list { struct dm_list list; struct device *dev; }; struct device_area { struct device *dev; uint64_t start; /* Bytes */ uint64_t size; /* Bytes */ }; /* * All io should use these routines. */ int dev_get_size(const struct device *dev, uint64_t *size); int dev_get_sectsize(struct device *dev, uint32_t *size); int dev_get_read_ahead(struct device *dev, uint32_t *read_ahead); int dev_discard_blocks(struct device *dev, uint64_t offset_bytes, uint64_t size_bytes); /* Use quiet version if device number could change e.g. when opening LV */ int dev_open(struct device *dev); int dev_open_quiet(struct device *dev); int dev_open_flags(struct device *dev, int flags, int direct, int quiet); int dev_open_readonly(struct device *dev); int dev_open_readonly_buffered(struct device *dev); int dev_open_readonly_quiet(struct device *dev); int dev_close(struct device *dev); int dev_close_immediate(struct device *dev); void dev_close_all(void); int dev_test_excl(struct device *dev); int dev_fd(struct device *dev); const char *dev_name(const struct device *dev); int dev_read(struct device *dev, uint64_t offset, size_t len, void *buffer); int dev_read_circular(struct device *dev, uint64_t offset, size_t len, uint64_t offset2, size_t len2, char *buf); int dev_write(struct device *dev, uint64_t offset, size_t len, void *buffer); int dev_append(struct device *dev, size_t len, char *buffer); int dev_set(struct device *dev, uint64_t offset, size_t len, int value); void dev_flush(struct device *dev); struct device *dev_create_file(const char *filename, struct device *dev, struct str_list *alias, int use_malloc); /* Return a valid device name from the alias list; NULL otherwise */ const char *dev_name_confirmed(struct device *dev, int quiet); /* Does device contain md superblock? If so, where? */ int dev_is_md(struct device *dev, uint64_t *sb); int dev_is_swap(struct device *dev, uint64_t *signature); int dev_is_luks(struct device *dev, uint64_t *signature); unsigned long dev_md_stripe_width(const char *sysfs_dir, struct device *dev); int is_partitioned_dev(struct device *dev); int get_primary_dev(const char *sysfs_dir, const struct device *dev, dev_t *result); unsigned long dev_alignment_offset(const char *sysfs_dir, struct device *dev); unsigned long dev_minimum_io_size(const char *sysfs_dir, struct device *dev); unsigned long dev_optimal_io_size(const char *sysfs_dir, struct device *dev); unsigned long dev_discard_max_bytes(const char *sysfs_dir, struct device *dev); unsigned long dev_discard_granularity(const char *sysfs_dir, struct device *dev); #endif lvm2-2.02.98/lib/device/dev-luks.c0000640000175000017500000000173512037016272015421 0ustar blankblank/* * 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 "metadata.h" #define LUKS_SIGNATURE "LUKS\xba\xbe" #define LUKS_SIGNATURE_SIZE 6 int dev_is_luks(struct device *dev, uint64_t *signature) { char buf[LUKS_SIGNATURE_SIZE]; int ret = -1; if (!dev_open_readonly(dev)) { stack; return -1; } *signature = 0; if (!dev_read(dev, 0, LUKS_SIGNATURE_SIZE, buf)) goto_out; ret = memcmp(buf, LUKS_SIGNATURE, LUKS_SIGNATURE_SIZE) ? 0 : 1; out: if (!dev_close(dev)) stack; return ret; } lvm2-2.02.98/lib/device/dev-cache.c0000640000175000017500000005511612037016272015510 0ustar blankblank/* * 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 "dev-cache.h" #include "lvm-types.h" #include "btree.h" #include "filter.h" #include "toolcontext.h" #include #include #include struct dev_iter { struct btree_iter *current; struct dev_filter *filter; }; struct dir_list { struct dm_list list; char dir[0]; }; static struct { struct dm_pool *mem; struct dm_hash_table *names; struct btree *devices; struct dm_regex *preferred_names_matcher; const char *dev_dir; int has_scanned; struct dm_list dirs; struct dm_list files; } _cache; #define _zalloc(x) dm_pool_zalloc(_cache.mem, (x)) #define _free(x) dm_pool_free(_cache.mem, (x)) #define _strdup(x) dm_pool_strdup(_cache.mem, (x)) static int _insert(const char *path, int rec, int check_with_udev_db); /* Setup non-zero members of passed zeroed 'struct device' */ static void _dev_init(struct device *dev, int max_error_count) { dev->block_size = -1; dev->fd = -1; dev->read_ahead = -1; dev->max_error_count = max_error_count; dm_list_init(&dev->aliases); dm_list_init(&dev->open_list); } struct device *dev_create_file(const char *filename, struct device *dev, struct str_list *alias, int use_malloc) { int allocate = !dev; if (allocate) { if (use_malloc) { if (!(dev = dm_zalloc(sizeof(*dev)))) { log_error("struct device allocation failed"); return NULL; } if (!(alias = dm_zalloc(sizeof(*alias)))) { log_error("struct str_list allocation failed"); dm_free(dev); return NULL; } if (!(alias->str = dm_strdup(filename))) { log_error("filename strdup failed"); dm_free(dev); dm_free(alias); return NULL; } } else { if (!(dev = _zalloc(sizeof(*dev)))) { log_error("struct device allocation failed"); return NULL; } if (!(alias = _zalloc(sizeof(*alias)))) { log_error("struct str_list allocation failed"); _free(dev); return NULL; } if (!(alias->str = _strdup(filename))) { log_error("filename strdup failed"); return NULL; } } } else if (!(alias->str = dm_strdup(filename))) { log_error("filename strdup failed"); return NULL; } _dev_init(dev, NO_DEV_ERROR_COUNT_LIMIT); dev->flags = DEV_REGULAR | ((use_malloc) ? DEV_ALLOCED : 0); dm_list_add(&dev->aliases, &alias->list); return dev; } static struct device *_dev_create(dev_t d) { struct device *dev; if (!(dev = _zalloc(sizeof(*dev)))) { log_error("struct device allocation failed"); return NULL; } _dev_init(dev, dev_disable_after_error_count()); dev->dev = d; return dev; } void dev_set_preferred_name(struct str_list *sl, struct device *dev) { /* * Don't interfere with ordering specified in config file. */ if (_cache.preferred_names_matcher) return; log_debug("%s: New preferred name", sl->str); dm_list_del(&sl->list); dm_list_add_h(&dev->aliases, &sl->list); } /* * Check whether path0 or path1 contains the subpath. The path that * *does not* contain the subpath wins (return 0 or 1). If both paths * contain the subpath, return -1. If none of them contains the subpath, * return -2. */ static int _builtin_preference(const char *path0, const char *path1, size_t skip_prefix_count, const char *subpath) { size_t subpath_len; int r0, r1; subpath_len = strlen(subpath); r0 = !strncmp(path0 + skip_prefix_count, subpath, subpath_len); r1 = !strncmp(path1 + skip_prefix_count, subpath, subpath_len); if (!r0 && r1) /* path0 does not have the subpath - it wins */ return 0; else if (r0 && !r1) /* path1 does not have the subpath - it wins */ return 1; else if (r0 && r1) /* both of them have the subpath */ return -1; /* no path has the subpath */ return -2; } static int _apply_builtin_path_preference_rules(const char *path0, const char *path1) { size_t devdir_len; int r; devdir_len = strlen(_cache.dev_dir); if (!strncmp(path0, _cache.dev_dir, devdir_len) && !strncmp(path1, _cache.dev_dir, devdir_len)) { /* * We're trying to achieve the ordering: * /dev/block/ < /dev/dm-* < /dev/disk/ < /dev/mapper/ < anything else */ /* Prefer any other path over /dev/block/ path. */ if ((r = _builtin_preference(path0, path1, devdir_len, "block/")) >= -1) return r; /* Prefer any other path over /dev/dm-* path. */ if ((r = _builtin_preference(path0, path1, devdir_len, "dm-")) >= -1) return r; /* Prefer any other path over /dev/disk/ path. */ if ((r = _builtin_preference(path0, path1, devdir_len, "disk/")) >= -1) return r; /* Prefer any other path over /dev/mapper/ path. */ if ((r = _builtin_preference(path0, path1, 0, dm_dir())) >= -1) return r; } return -1; } /* Return 1 if we prefer path1 else return 0 */ static int _compare_paths(const char *path0, const char *path1) { int slash0 = 0, slash1 = 0; int m0, m1; const char *p; char p0[PATH_MAX], p1[PATH_MAX]; char *s0, *s1; struct stat stat0, stat1; int r; /* * FIXME Better to compare patterns one-at-a-time against all names. */ if (_cache.preferred_names_matcher) { m0 = dm_regex_match(_cache.preferred_names_matcher, path0); m1 = dm_regex_match(_cache.preferred_names_matcher, path1); if (m0 != m1) { if (m0 < 0) return 1; if (m1 < 0) return 0; if (m0 < m1) return 1; if (m1 < m0) return 0; } } /* Apply built-in preference rules first. */ if ((r = _apply_builtin_path_preference_rules(path0, path1)) >= 0) return r; /* Return the path with fewer slashes */ for (p = path0; p++; p = (const char *) strchr(p, '/')) slash0++; for (p = path1; p++; p = (const char *) strchr(p, '/')) slash1++; if (slash0 < slash1) return 0; if (slash1 < slash0) return 1; strncpy(p0, path0, sizeof(p0) - 1); p0[sizeof(p0) - 1] = '\0'; strncpy(p1, path1, sizeof(p1) - 1); p1[sizeof(p1) - 1] = '\0'; s0 = p0 + 1; s1 = p1 + 1; /* * If we reach here, both paths are the same length. * Now skip past identical path components. */ while (*s0 && *s0 == *s1) s0++, s1++; /* We prefer symlinks - they exist for a reason! * So we prefer a shorter path before the first symlink in the name. * FIXME Configuration option to invert this? */ while (s0) { s0 = strchr(s0, '/'); s1 = strchr(s1, '/'); if (s0) { *s0 = '\0'; *s1 = '\0'; } if (lstat(p0, &stat0)) { log_sys_very_verbose("lstat", p0); return 1; } if (lstat(p1, &stat1)) { log_sys_very_verbose("lstat", p1); return 0; } if (S_ISLNK(stat0.st_mode) && !S_ISLNK(stat1.st_mode)) return 0; if (!S_ISLNK(stat0.st_mode) && S_ISLNK(stat1.st_mode)) return 1; if (s0) { *s0++ = '/'; *s1++ = '/'; } } /* ASCII comparison */ if (strcmp(path0, path1) < 0) return 0; else return 1; } static int _add_alias(struct device *dev, const char *path) { struct str_list *sl = _zalloc(sizeof(*sl)); struct str_list *strl; const char *oldpath; int prefer_old = 1; if (!sl) return_0; /* Is name already there? */ dm_list_iterate_items(strl, &dev->aliases) { if (!strcmp(strl->str, path)) { log_debug("%s: Already in device cache", path); return 1; } } sl->str = path; if (!dm_list_empty(&dev->aliases)) { oldpath = dm_list_item(dev->aliases.n, struct str_list)->str; prefer_old = _compare_paths(path, oldpath); log_debug("%s: Aliased to %s in device cache%s", path, oldpath, prefer_old ? "" : " (preferred name)"); } else log_debug("%s: Added to device cache", path); if (prefer_old) dm_list_add(&dev->aliases, &sl->list); else dm_list_add_h(&dev->aliases, &sl->list); return 1; } /* * Either creates a new dev, or adds an alias to * an existing dev. */ static int _insert_dev(const char *path, dev_t d) { struct device *dev; static dev_t loopfile_count = 0; int loopfile = 0; char *path_copy; /* Generate pretend device numbers for loopfiles */ if (!d) { if (dm_hash_lookup(_cache.names, path)) return 1; d = ++loopfile_count; loopfile = 1; } /* is this device already registered ? */ if (!(dev = (struct device *) btree_lookup(_cache.devices, (uint32_t) d))) { /* create new device */ if (loopfile) { if (!(dev = dev_create_file(path, NULL, NULL, 0))) return_0; } else if (!(dev = _dev_create(d))) return_0; if (!(btree_insert(_cache.devices, (uint32_t) d, dev))) { log_error("Couldn't insert device into binary tree."); _free(dev); return 0; } } if (!(path_copy = dm_pool_strdup(_cache.mem, path))) { log_error("Failed to duplicate path string."); return 0; } if (!loopfile && !_add_alias(dev, path_copy)) { log_error("Couldn't add alias to dev cache."); return 0; } if (!dm_hash_insert(_cache.names, path_copy, dev)) { log_error("Couldn't add name to hash in dev cache."); return 0; } return 1; } static char *_join(const char *dir, const char *name) { size_t len = strlen(dir) + strlen(name) + 2; char *r = dm_malloc(len); if (r) snprintf(r, len, "%s/%s", dir, name); return r; } /* * Get rid of extra slashes in the path string. */ static void _collapse_slashes(char *str) { char *ptr; int was_slash = 0; for (ptr = str; *ptr; ptr++) { if (*ptr == '/') { if (was_slash) continue; was_slash = 1; } else was_slash = 0; *str++ = *ptr; } *str = *ptr; } static int _insert_dir(const char *dir) { int n, dirent_count, r = 1; struct dirent **dirent; char *path; dirent_count = scandir(dir, &dirent, NULL, alphasort); if (dirent_count > 0) { for (n = 0; n < dirent_count; n++) { if (dirent[n]->d_name[0] == '.') { free(dirent[n]); continue; } if (!(path = _join(dir, dirent[n]->d_name))) return_0; _collapse_slashes(path); r &= _insert(path, 1, 0); dm_free(path); free(dirent[n]); } free(dirent); } return r; } static int _insert_file(const char *path) { struct stat info; if (stat(path, &info) < 0) { log_sys_very_verbose("stat", path); return 0; } if (!S_ISREG(info.st_mode)) { log_debug("%s: Not a regular file", path); return 0; } if (!_insert_dev(path, 0)) return_0; return 1; } #ifdef UDEV_SYNC_SUPPORT static int _device_in_udev_db(const dev_t d) { struct udev *udev; struct udev_device *udev_device; if (!(udev = udev_get_library_context())) return_0; if ((udev_device = udev_device_new_from_devnum(udev, 'b', d))) { udev_device_unref(udev_device); return 1; } return 0; } static int _insert_udev_dir(struct udev *udev, const char *dir) { struct udev_enumerate *udev_enum = NULL; struct udev_list_entry *device_entry, *symlink_entry; const char *entry_name, *node_name, *symlink_name; struct udev_device *device; int r = 1; if (!(udev_enum = udev_enumerate_new(udev))) goto bad; if (udev_enumerate_add_match_subsystem(udev_enum, "block") || udev_enumerate_scan_devices(udev_enum)) goto bad; /* * Report any missing information as "log_very_verbose" only, do not * report it as a "warning" or "error" - the record could be removed * by the time we ask for more info (node name, symlink name...). * Whatever removes *any* block device in the system (even unrelated * to our operation), we would have a warning/error on output then. * That could be misleading. If there's really any problem with missing * information from udev db, we can still have a look at the verbose log. */ udev_list_entry_foreach(device_entry, udev_enumerate_get_list_entry(udev_enum)) { entry_name = udev_list_entry_get_name(device_entry); if (!(device = udev_device_new_from_syspath(udev, entry_name))) { log_very_verbose("udev failed to return a device for entry %s.", entry_name); continue; } if (!(node_name = udev_device_get_devnode(device))) log_very_verbose("udev failed to return a device node for entry %s.", entry_name); else r &= _insert(node_name, 0, 0); udev_list_entry_foreach(symlink_entry, udev_device_get_devlinks_list_entry(device)) { if (!(symlink_name = udev_list_entry_get_name(symlink_entry))) log_very_verbose("udev failed to return a symlink name for entry %s.", entry_name); else r &= _insert(symlink_name, 0, 0); } udev_device_unref(device); } udev_enumerate_unref(udev_enum); return r; bad: log_error("Failed to enumerate udev device list."); udev_enumerate_unref(udev_enum); return 0; } static void _insert_dirs(struct dm_list *dirs) { struct dir_list *dl; struct udev *udev; int with_udev; with_udev = obtain_device_list_from_udev() && (udev = udev_get_library_context()); dm_list_iterate_items(dl, &_cache.dirs) { if (with_udev) { if (!_insert_udev_dir(udev, dl->dir)) log_debug("%s: Failed to insert devices from " "udev-managed directory to device " "cache fully", dl->dir); } else if (!_insert_dir(dl->dir)) log_debug("%s: Failed to insert devices to " "device cache fully", dl->dir); } } #else /* UDEV_SYNC_SUPPORT */ static int _device_in_udev_db(const dev_t d) { return 0; } static void _insert_dirs(struct dm_list *dirs) { struct dir_list *dl; dm_list_iterate_items(dl, &_cache.dirs) _insert_dir(dl->dir); } #endif /* UDEV_SYNC_SUPPORT */ static int _insert(const char *path, int rec, int check_with_udev_db) { struct stat info; int r = 0; if (stat(path, &info) < 0) { log_sys_very_verbose("stat", path); return 0; } if (check_with_udev_db && !_device_in_udev_db(info.st_rdev)) { log_very_verbose("%s: Not in udev db", path); return 0; } if (S_ISDIR(info.st_mode)) { /* add a directory */ /* check it's not a symbolic link */ if (lstat(path, &info) < 0) { log_sys_very_verbose("lstat", path); return 0; } if (S_ISLNK(info.st_mode)) { log_debug("%s: Symbolic link to directory", path); return 0; } if (rec) r = _insert_dir(path); } else { /* add a device */ if (!S_ISBLK(info.st_mode)) { log_debug("%s: Not a block device", path); return 0; } if (!_insert_dev(path, info.st_rdev)) return_0; r = 1; } return r; } static void _full_scan(int dev_scan) { struct dir_list *dl; if (_cache.has_scanned && !dev_scan) return; _insert_dirs(&_cache.dirs); dm_list_iterate_items(dl, &_cache.files) _insert_file(dl->dir); _cache.has_scanned = 1; init_full_scan_done(1); } int dev_cache_has_scanned(void) { return _cache.has_scanned; } void dev_cache_scan(int do_scan) { if (!do_scan) _cache.has_scanned = 1; else _full_scan(1); } static int _init_preferred_names(struct cmd_context *cmd) { const struct dm_config_node *cn; const struct dm_config_value *v; struct dm_pool *scratch = NULL; const char **regex; unsigned count = 0; int i, r = 0; _cache.preferred_names_matcher = NULL; if (!(cn = find_config_tree_node(cmd, "devices/preferred_names")) || cn->v->type == DM_CFG_EMPTY_ARRAY) { log_very_verbose("devices/preferred_names not found in config file: " "using built-in preferences"); return 1; } for (v = cn->v; v; v = v->next) { if (v->type != DM_CFG_STRING) { log_error("preferred_names patterns must be enclosed in quotes"); return 0; } count++; } if (!(scratch = dm_pool_create("preferred device name matcher", 1024))) return_0; if (!(regex = dm_pool_alloc(scratch, sizeof(*regex) * count))) { log_error("Failed to allocate preferred device name " "pattern list."); goto out; } for (v = cn->v, i = count - 1; v; v = v->next, i--) { if (!(regex[i] = dm_pool_strdup(scratch, v->v.str))) { log_error("Failed to allocate a preferred device name " "pattern."); goto out; } } if (!(_cache.preferred_names_matcher = dm_regex_create(_cache.mem, regex, count))) { log_error("Preferred device name pattern matcher creation failed."); goto out; } r = 1; out: dm_pool_destroy(scratch); return r; } int dev_cache_init(struct cmd_context *cmd) { _cache.names = NULL; _cache.has_scanned = 0; if (!(_cache.mem = dm_pool_create("dev_cache", 10 * 1024))) return_0; if (!(_cache.names = dm_hash_create(128))) { dm_pool_destroy(_cache.mem); _cache.mem = 0; return_0; } if (!(_cache.devices = btree_create(_cache.mem))) { log_error("Couldn't create binary tree for dev-cache."); goto bad; } if (!(_cache.dev_dir = _strdup(cmd->dev_dir))) { log_error("strdup dev_dir failed."); goto bad; } dm_list_init(&_cache.dirs); dm_list_init(&_cache.files); if (!_init_preferred_names(cmd)) goto_bad; return 1; bad: dev_cache_exit(); return 0; } static void _check_closed(struct device *dev) { if (dev->fd >= 0) log_error("Device '%s' has been left open.", dev_name(dev)); } static void _check_for_open_devices(void) { dm_hash_iter(_cache.names, (dm_hash_iterate_fn) _check_closed); } void dev_cache_exit(void) { if (_cache.names) _check_for_open_devices(); if (_cache.preferred_names_matcher) _cache.preferred_names_matcher = NULL; if (_cache.mem) { dm_pool_destroy(_cache.mem); _cache.mem = NULL; } if (_cache.names) { dm_hash_destroy(_cache.names); _cache.names = NULL; } _cache.devices = NULL; _cache.has_scanned = 0; dm_list_init(&_cache.dirs); dm_list_init(&_cache.files); } int dev_cache_add_dir(const char *path) { struct dir_list *dl; struct stat st; if (stat(path, &st)) { log_error("Ignoring %s: %s", path, strerror(errno)); /* But don't fail */ return 1; } if (!S_ISDIR(st.st_mode)) { log_error("Ignoring %s: Not a directory", path); return 1; } if (!(dl = _zalloc(sizeof(*dl) + strlen(path) + 1))) { log_error("dir_list allocation failed"); return 0; } strcpy(dl->dir, path); dm_list_add(&_cache.dirs, &dl->list); return 1; } int dev_cache_add_loopfile(const char *path) { struct dir_list *dl; struct stat st; if (stat(path, &st)) { log_error("Ignoring %s: %s", path, strerror(errno)); /* But don't fail */ return 1; } if (!S_ISREG(st.st_mode)) { log_error("Ignoring %s: Not a regular file", path); return 1; } if (!(dl = _zalloc(sizeof(*dl) + strlen(path) + 1))) { log_error("dir_list allocation failed for file"); return 0; } strcpy(dl->dir, path); dm_list_add(&_cache.files, &dl->list); return 1; } /* Check cached device name is still valid before returning it */ /* This should be a rare occurrence */ /* set quiet if the cache is expected to be out-of-date */ /* FIXME Make rest of code pass/cache struct device instead of dev_name */ const char *dev_name_confirmed(struct device *dev, int quiet) { struct stat buf; const char *name; int r; if ((dev->flags & DEV_REGULAR)) return dev_name(dev); while ((r = stat(name = dm_list_item(dev->aliases.n, struct str_list)->str, &buf)) || (buf.st_rdev != dev->dev)) { if (r < 0) { if (quiet) log_sys_debug("stat", name); else log_sys_error("stat", name); } if (quiet) log_debug("Path %s no longer valid for device(%d,%d)", name, (int) MAJOR(dev->dev), (int) MINOR(dev->dev)); else log_error("Path %s no longer valid for device(%d,%d)", name, (int) MAJOR(dev->dev), (int) MINOR(dev->dev)); /* Remove the incorrect hash entry */ dm_hash_remove(_cache.names, name); /* Leave list alone if there isn't an alternative name */ /* so dev_name will always find something to return. */ /* Otherwise add the name to the correct device. */ if (dm_list_size(&dev->aliases) > 1) { dm_list_del(dev->aliases.n); if (!r) _insert(name, 0, obtain_device_list_from_udev()); continue; } /* Scanning issues this inappropriately sometimes. */ log_debug("Aborting - please provide new pathname for what " "used to be %s", name); return NULL; } return dev_name(dev); } struct device *dev_cache_get(const char *name, struct dev_filter *f) { struct stat buf; struct device *d = (struct device *) dm_hash_lookup(_cache.names, name); if (d && (d->flags & DEV_REGULAR)) return d; /* If the entry's wrong, remove it */ if (d && (stat(name, &buf) || (buf.st_rdev != d->dev))) { dm_hash_remove(_cache.names, name); d = NULL; } if (!d) { _insert(name, 0, obtain_device_list_from_udev()); d = (struct device *) dm_hash_lookup(_cache.names, name); if (!d) { _full_scan(0); d = (struct device *) dm_hash_lookup(_cache.names, name); } } return (d && (!f || (d->flags & DEV_REGULAR) || f->passes_filter(f, d))) ? d : NULL; } static struct device *_dev_cache_seek_devt(dev_t dev) { struct device *d = NULL; struct dm_hash_node *n = dm_hash_get_first(_cache.names); while (n) { d = dm_hash_get_data(_cache.names, n); if (d->dev == dev) return d; n = dm_hash_get_next(_cache.names, n); } return NULL; } /* * TODO This is very inefficient. We probably want a hash table indexed by * major:minor for keys to speed up these lookups. */ struct device *dev_cache_get_by_devt(dev_t dev, struct dev_filter *f) { struct device *d = _dev_cache_seek_devt(dev); if (d && (d->flags & DEV_REGULAR)) return d; if (!d) { _full_scan(0); d = _dev_cache_seek_devt(dev); } return (d && (!f || (d->flags & DEV_REGULAR) || f->passes_filter(f, d))) ? d : NULL; } struct dev_iter *dev_iter_create(struct dev_filter *f, int dev_scan) { struct dev_iter *di = dm_malloc(sizeof(*di)); if (!di) { log_error("dev_iter allocation failed"); return NULL; } if (dev_scan && !trust_cache()) { /* Flag gets reset between each command */ if (!full_scan_done()) { if (f && f->wipe) f->wipe(f); /* Calls _full_scan(1) */ else _full_scan(1); } } else _full_scan(0); di->current = btree_first(_cache.devices); di->filter = f; if (di->filter) di->filter->use_count++; return di; } void dev_iter_destroy(struct dev_iter *iter) { if (iter->filter) iter->filter->use_count--; dm_free(iter); } static struct device *_iter_next(struct dev_iter *iter) { struct device *d = btree_get_data(iter->current); iter->current = btree_next(iter->current); return d; } struct device *dev_iter_get(struct dev_iter *iter) { while (iter->current) { struct device *d = _iter_next(iter); if (!iter->filter || (d->flags & DEV_REGULAR) || iter->filter->passes_filter(iter->filter, d)) return d; } return NULL; } void dev_reset_error_count(struct cmd_context *cmd) { struct dev_iter iter; if (!_cache.devices) return; iter.current = btree_first(_cache.devices); while (iter.current) _iter_next(&iter)->error_count = 0; } int dev_fd(struct device *dev) { return dev->fd; } const char *dev_name(const struct device *dev) { return (dev) ? dm_list_item(dev->aliases.n, struct str_list)->str : "unknown device"; } lvm2-2.02.98/lib/device/dev-cache.h0000640000175000017500000000341412037016272015507 0ustar blankblank/* * 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_DEV_CACHE_H #define _LVM_DEV_CACHE_H #include "device.h" #include "lvm-wrappers.h" /* * predicate for devices. */ struct dev_filter { int (*passes_filter) (struct dev_filter * f, struct device * dev); void (*destroy) (struct dev_filter * f); void (*wipe) (struct dev_filter * f); void *private; unsigned use_count; }; /* * The global device cache. */ struct cmd_context; int dev_cache_init(struct cmd_context *cmd); void dev_cache_exit(void); /* Trigger(1) or avoid(0) a scan */ void dev_cache_scan(int do_scan); int dev_cache_has_scanned(void); int dev_cache_add_dir(const char *path); int dev_cache_add_loopfile(const char *path); __attribute__((nonnull(1))) struct device *dev_cache_get(const char *name, struct dev_filter *f); // TODO struct device *dev_cache_get_by_devt(dev_t device, struct dev_filter *f); void dev_set_preferred_name(struct str_list *sl, struct device *dev); /* * Object for iterating through the cache. */ struct dev_iter; struct dev_iter *dev_iter_create(struct dev_filter *f, int dev_scan); void dev_iter_destroy(struct dev_iter *iter); struct device *dev_iter_get(struct dev_iter *iter); void dev_reset_error_count(struct cmd_context *cmd); #endif lvm2-2.02.98/lib/freeseg/0000750000175000017500000000000012037016272013675 5ustar blankblanklvm2-2.02.98/lib/freeseg/freeseg.c0000640000175000017500000000236312037016272015466 0ustar blankblank/* * 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 "toolcontext.h" #include "segtype.h" static const char *_freeseg_name(const struct lv_segment *seg) { return seg->segtype->name; } static void _freeseg_destroy(struct segment_type *segtype) { dm_free(segtype); } static struct segtype_handler _freeseg_ops = { .name = _freeseg_name, .destroy = _freeseg_destroy, }; struct segment_type *init_free_segtype(struct cmd_context *cmd) { struct segment_type *segtype = dm_zalloc(sizeof(*segtype)); if (!segtype) return_NULL; segtype->cmd = cmd; segtype->ops = &_freeseg_ops; segtype->name = "free"; segtype->private = NULL; segtype->flags = SEG_VIRTUAL | SEG_CANNOT_BE_ZEROED; log_very_verbose("Initialised segtype: %s", segtype->name); return segtype; } lvm2-2.02.98/lib/commands/0000750000175000017500000000000012037016272014056 5ustar blankblanklvm2-2.02.98/lib/commands/toolcontext.c0000640000175000017500000012226512037016272016615 0ustar blankblank/* * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU 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 "toolcontext.h" #include "metadata.h" #include "defaults.h" #include "lvm-string.h" #include "activate.h" #include "filter.h" #include "filter-composite.h" #include "filter-md.h" #include "filter-mpath.h" #include "filter-persistent.h" #include "filter-regex.h" #include "filter-sysfs.h" #include "label.h" #include "lvm-file.h" #include "format-text.h" #include "display.h" #include "memlock.h" #include "str_list.h" #include "segtype.h" #include "lvmcache.h" #include "lvmetad.h" #include "dev-cache.h" #include "archiver.h" #ifdef HAVE_LIBDL #include "sharedlib.h" #endif #ifdef LVM1_INTERNAL #include "format1.h" #endif #ifdef POOL_INTERNAL #include "format_pool.h" #endif #include #include #include #include #include #ifdef linux # include #endif static const size_t linebuffer_size = 4096; static int _get_env_vars(struct cmd_context *cmd) { const char *e; /* Set to "" to avoid using any system directory */ if ((e = getenv("LVM_SYSTEM_DIR"))) { if (dm_snprintf(cmd->system_dir, sizeof(cmd->system_dir), "%s", e) < 0) { log_error("LVM_SYSTEM_DIR environment variable " "is too long."); return 0; } } return 1; } static void _get_sysfs_dir(struct cmd_context *cmd) { static char proc_mounts[PATH_MAX]; static char *split[4], buffer[PATH_MAX + 16]; FILE *fp; char *sys_mnt = NULL; cmd->sysfs_dir[0] = '\0'; if (!*cmd->proc_dir) { log_debug("No proc filesystem found: skipping sysfs detection"); return; } if (dm_snprintf(proc_mounts, sizeof(proc_mounts), "%s/mounts", cmd->proc_dir) < 0) { log_error("Failed to create /proc/mounts string for sysfs detection"); return; } if (!(fp = fopen(proc_mounts, "r"))) { log_sys_error("_get_sysfs_dir fopen", proc_mounts); return; } while (fgets(buffer, sizeof(buffer), fp)) { if (dm_split_words(buffer, 4, 0, split) == 4 && !strcmp(split[2], "sysfs")) { sys_mnt = split[1]; break; } } if (fclose(fp)) log_sys_error("fclose", proc_mounts); if (!sys_mnt) { log_error("Failed to find sysfs mount point"); return; } strncpy(cmd->sysfs_dir, sys_mnt, sizeof(cmd->sysfs_dir)); } static void _init_logging(struct cmd_context *cmd) { int append = 1; time_t t; const char *log_file; char timebuf[26]; /* Syslog */ cmd->default_settings.syslog = find_config_tree_int(cmd, "log/syslog", DEFAULT_SYSLOG); if (cmd->default_settings.syslog != 1) fin_syslog(); if (cmd->default_settings.syslog > 1) init_syslog(cmd->default_settings.syslog); /* Debug level for log file output */ cmd->default_settings.debug = find_config_tree_int(cmd, "log/level", DEFAULT_LOGLEVEL); init_debug(cmd->default_settings.debug); /* * Suppress all non-essential stdout? * -qq can override the default of 0 to 1 later. * Once set to 1, there is no facility to change it back to 0. */ cmd->default_settings.silent = silent_mode() ? : find_config_tree_int(cmd, "log/silent", DEFAULT_SILENT); init_silent(cmd->default_settings.silent); /* Verbose level for tty output */ cmd->default_settings.verbose = find_config_tree_int(cmd, "log/verbose", DEFAULT_VERBOSE); init_verbose(cmd->default_settings.verbose + VERBOSE_BASE_LEVEL); /* Log message formatting */ init_indent(find_config_tree_int(cmd, "log/indent", DEFAULT_INDENT)); init_abort_on_internal_errors(find_config_tree_int(cmd, "global/abort_on_internal_errors", DEFAULT_ABORT_ON_INTERNAL_ERRORS)); cmd->default_settings.msg_prefix = find_config_tree_str_allow_empty(cmd, "log/prefix", DEFAULT_MSG_PREFIX); init_msg_prefix(cmd->default_settings.msg_prefix); cmd->default_settings.cmd_name = find_config_tree_int(cmd, "log/command_names", DEFAULT_CMD_NAME); init_cmd_name(cmd->default_settings.cmd_name); /* Test mode */ cmd->default_settings.test = find_config_tree_int(cmd, "global/test", 0); init_test(cmd->default_settings.test); /* Settings for logging to file */ if (find_config_tree_int(cmd, "log/overwrite", DEFAULT_OVERWRITE)) append = 0; log_file = find_config_tree_str(cmd, "log/file", 0); if (log_file) { release_log_memory(); fin_log(); init_log_file(log_file, append); } log_file = find_config_tree_str(cmd, "log/activate_file", 0); if (log_file) init_log_direct(log_file, append); init_log_while_suspended(find_config_tree_int(cmd, "log/activation", 0)); t = time(NULL); ctime_r(&t, &timebuf[0]); timebuf[24] = '\0'; log_verbose("Logging initialised at %s", timebuf); /* Tell device-mapper about our logging */ #ifdef DEVMAPPER_SUPPORT dm_log_with_errno_init(print_log); #endif reset_log_duplicated(); reset_lvm_errno(1); } #ifdef UDEV_SYNC_SUPPORT /* * Until the DM_UEVENT_GENERATED_FLAG was introduced in kernel patch * 856a6f1dbd8940e72755af145ebcd806408ecedd * some operations could not be performed by udev, requiring our fallback code. */ static int _dm_driver_has_stable_udev_support(void) { char vsn[80]; unsigned maj, min, patchlevel; return driver_version(vsn, sizeof(vsn)) && (sscanf(vsn, "%u.%u.%u", &maj, &min, &patchlevel) == 3) && (maj == 4 ? min >= 18 : maj > 4); } #endif static int _process_config(struct cmd_context *cmd) { mode_t old_umask; const char *read_ahead; struct stat st; const struct dm_config_node *cn; const struct dm_config_value *cv; int64_t pv_min_kb; const char *lvmetad_socket; /* umask */ cmd->default_settings.umask = find_config_tree_int(cmd, "global/umask", DEFAULT_UMASK); if ((old_umask = umask((mode_t) cmd->default_settings.umask)) != (mode_t) cmd->default_settings.umask) log_verbose("Set umask from %04o to %04o", old_umask, cmd->default_settings.umask); /* dev dir */ if (dm_snprintf(cmd->dev_dir, sizeof(cmd->dev_dir), "%s/", find_config_tree_str(cmd, "devices/dir", DEFAULT_DEV_DIR)) < 0) { log_error("Device directory given in config file too long"); return 0; } #ifdef DEVMAPPER_SUPPORT dm_set_dev_dir(cmd->dev_dir); if (!dm_set_uuid_prefix("LVM-")) return_0; #endif /* proc dir */ if (dm_snprintf(cmd->proc_dir, sizeof(cmd->proc_dir), "%s", find_config_tree_str(cmd, "global/proc", DEFAULT_PROC_DIR)) < 0) { log_error("Device directory given in config file too long"); return 0; } if (*cmd->proc_dir && !dir_exists(cmd->proc_dir)) { log_warn("WARNING: proc dir %s not found - some checks will be bypassed", cmd->proc_dir); cmd->proc_dir[0] = '\0'; } /* FIXME Use global value of sysfs_dir everywhere instead cmd->sysfs_dir. */ _get_sysfs_dir(cmd); set_sysfs_dir_path(cmd->sysfs_dir); dm_set_sysfs_dir(cmd->sysfs_dir); /* activation? */ cmd->default_settings.activation = find_config_tree_int(cmd, "global/activation", DEFAULT_ACTIVATION); set_activation(cmd->default_settings.activation); cmd->default_settings.suffix = find_config_tree_int(cmd, "global/suffix", DEFAULT_SUFFIX); if (!(cmd->default_settings.unit_factor = units_to_bytes(find_config_tree_str(cmd, "global/units", DEFAULT_UNITS), &cmd->default_settings.unit_type))) { log_error("Invalid units specification"); return 0; } read_ahead = find_config_tree_str(cmd, "activation/readahead", DEFAULT_READ_AHEAD); if (!strcasecmp(read_ahead, "auto")) cmd->default_settings.read_ahead = DM_READ_AHEAD_AUTO; else if (!strcasecmp(read_ahead, "none")) cmd->default_settings.read_ahead = DM_READ_AHEAD_NONE; else { log_error("Invalid readahead specification"); return 0; } cmd->default_settings.udev_rules = find_config_tree_int(cmd, "activation/udev_rules", DEFAULT_UDEV_RULES); cmd->default_settings.udev_sync = find_config_tree_int(cmd, "activation/udev_sync", DEFAULT_UDEV_SYNC); init_retry_deactivation(find_config_tree_int(cmd, "activation/retry_deactivation", DEFAULT_RETRY_DEACTIVATION)); init_activation_checks(find_config_tree_int(cmd, "activation/checks", DEFAULT_ACTIVATION_CHECKS)); #ifdef UDEV_SYNC_SUPPORT /* * We need udev rules to be applied, otherwise we would end up with no * nodes and symlinks! However, we can disable the synchronization itself * in runtime and still have only udev to create the nodes and symlinks * without any fallback. */ cmd->default_settings.udev_fallback = cmd->default_settings.udev_rules ? find_config_tree_int(cmd, "activation/verify_udev_operations", DEFAULT_VERIFY_UDEV_OPERATIONS) : 1; /* Do not rely fully on udev if the udev support is known to be incomplete. */ if (!cmd->default_settings.udev_fallback && !_dm_driver_has_stable_udev_support()) { log_very_verbose("Kernel driver has incomplete udev support so " "LVM will check and perform some operations itself."); cmd->default_settings.udev_fallback = 1; } #else /* We must use old node/symlink creation code if not compiled with udev support at all! */ cmd->default_settings.udev_fallback = 1; #endif cmd->use_linear_target = find_config_tree_int(cmd, "activation/use_linear_target", DEFAULT_USE_LINEAR_TARGET); cmd->stripe_filler = find_config_tree_str(cmd, "activation/missing_stripe_filler", DEFAULT_STRIPE_FILLER); /* FIXME Missing error code checks from the stats, not log_warn?, notify if setting overridden, delay message/check till it is actually used (eg consider if lvm shell - file could appear later after this check)? */ if (!strcmp(cmd->stripe_filler, "/dev/ioerror") && stat(cmd->stripe_filler, &st)) cmd->stripe_filler = "error"; if (strcmp(cmd->stripe_filler, "error")) { if (stat(cmd->stripe_filler, &st)) { log_warn("WARNING: activation/missing_stripe_filler = \"%s\" " "is invalid,", cmd->stripe_filler); log_warn(" stat failed: %s", strerror(errno)); log_warn("Falling back to \"error\" missing_stripe_filler."); cmd->stripe_filler = "error"; } else if (!S_ISBLK(st.st_mode)) { log_warn("WARNING: activation/missing_stripe_filler = \"%s\" " "is not a block device.", cmd->stripe_filler); log_warn("Falling back to \"error\" missing_stripe_filler."); cmd->stripe_filler = "error"; } } cmd->si_unit_consistency = find_config_tree_int(cmd, "global/si_unit_consistency", DEFAULT_SI_UNIT_CONSISTENCY); if ((cn = find_config_tree_node(cmd, "activation/mlock_filter"))) for (cv = cn->v; cv; cv = cv->next) if ((cv->type != DM_CFG_STRING) || !cv->v.str[0]) log_error("Ignoring invalid activation/mlock_filter entry in config file"); cmd->metadata_read_only = find_config_tree_int(cmd, "global/metadata_read_only", DEFAULT_METADATA_READ_ONLY); pv_min_kb = find_config_tree_int64(cmd, "devices/pv_min_size", DEFAULT_PV_MIN_SIZE_KB); if (pv_min_kb < PV_MIN_SIZE_KB) { log_warn("Ignoring too small pv_min_size %" PRId64 "KB, using default %dKB.", pv_min_kb, PV_MIN_SIZE_KB); pv_min_kb = PV_MIN_SIZE_KB; } /* LVM stores sizes internally in units of 512-byte sectors. */ init_pv_min_size((uint64_t)pv_min_kb * (1024 >> SECTOR_SHIFT)); init_detect_internal_vg_cache_corruption (find_config_tree_int(cmd, "global/detect_internal_vg_cache_corruption", DEFAULT_DETECT_INTERNAL_VG_CACHE_CORRUPTION)); lvmetad_disconnect(); lvmetad_socket = getenv("LVM_LVMETAD_SOCKET"); if (!lvmetad_socket) lvmetad_socket = DEFAULT_RUN_DIR "/lvmetad.socket"; /* TODO? lvmetad_socket = find_config_tree_str(cmd, "lvmetad/socket_path", DEFAULT_RUN_DIR "/lvmetad.socket"); */ lvmetad_set_socket(lvmetad_socket); cn = find_config_tree_node(cmd, "devices/global_filter"); lvmetad_set_token(cn ? cn->v : NULL); lvmetad_set_active(find_config_tree_int(cmd, "global/use_lvmetad", 0)); lvmetad_init(cmd); return 1; } static int _set_tag(struct cmd_context *cmd, const char *tag) { log_very_verbose("Setting host tag: %s", dm_pool_strdup(cmd->libmem, tag)); if (!str_list_add(cmd->libmem, &cmd->tags, tag)) { log_error("_set_tag: str_list_add %s failed", tag); return 0; } return 1; } static int _check_host_filters(struct cmd_context *cmd, const struct dm_config_node *hn, int *passes) { const struct dm_config_node *cn; const struct dm_config_value *cv; *passes = 1; for (cn = hn; cn; cn = cn->sib) { if (!cn->v) continue; if (!strcmp(cn->key, "host_list")) { *passes = 0; if (cn->v->type == DM_CFG_EMPTY_ARRAY) continue; for (cv = cn->v; cv; cv = cv->next) { if (cv->type != DM_CFG_STRING) { log_error("Invalid hostname string " "for tag %s", cn->key); return 0; } if (!strcmp(cv->v.str, cmd->hostname)) { *passes = 1; return 1; } } } if (!strcmp(cn->key, "host_filter")) { log_error("host_filter not supported yet"); return 0; } } return 1; } static int _init_tags(struct cmd_context *cmd, struct dm_config_tree *cft) { const struct dm_config_node *tn, *cn; const char *tag; int passes; if (!(tn = dm_config_find_node(cft->root, "tags")) || !tn->child) return 1; /* NB hosttags 0 when already 1 intentionally does not delete the tag */ if (!cmd->hosttags && dm_config_find_int(cft->root, "tags/hosttags", DEFAULT_HOSTTAGS)) { /* FIXME Strip out invalid chars: only A-Za-z0-9_+.- */ if (!_set_tag(cmd, cmd->hostname)) return_0; cmd->hosttags = 1; } for (cn = tn->child; cn; cn = cn->sib) { if (cn->v) continue; tag = cn->key; if (*tag == '@') tag++; if (!validate_name(tag)) { log_error("Invalid tag in config file: %s", cn->key); return 0; } if (cn->child) { passes = 0; if (!_check_host_filters(cmd, cn->child, &passes)) return_0; if (!passes) continue; } if (!_set_tag(cmd, tag)) return_0; } return 1; } static int _load_config_file(struct cmd_context *cmd, const char *tag) { static char config_file[PATH_MAX] = ""; const char *filler = ""; struct stat info; struct config_tree_list *cfl; if (*tag) filler = "_"; if (dm_snprintf(config_file, sizeof(config_file), "%s/lvm%s%s.conf", cmd->system_dir, filler, tag) < 0) { log_error("LVM_SYSTEM_DIR or tag was too long"); return 0; } if (!(cfl = dm_pool_alloc(cmd->libmem, sizeof(*cfl)))) { log_error("config_tree_list allocation failed"); return 0; } if (!(cfl->cft = config_file_open(config_file, 0))) { log_error("config_tree allocation failed"); return 0; } /* Is there a config file? */ if (stat(config_file, &info) == -1) { if (errno == ENOENT) { dm_list_add(&cmd->config_files, &cfl->list); goto out; } log_sys_error("stat", config_file); config_file_destroy(cfl->cft); return 0; } log_very_verbose("Loading config file: %s", config_file); if (!config_file_read(cfl->cft)) { log_error("Failed to load config file %s", config_file); config_file_destroy(cfl->cft); return 0; } dm_list_add(&cmd->config_files, &cfl->list); out: if (*tag) { if (!_init_tags(cmd, cfl->cft)) return_0; } else /* Use temporary copy of lvm.conf while loading other files */ cmd->cft = cfl->cft; return 1; } /* Find and read first config file */ static int _init_lvm_conf(struct cmd_context *cmd) { /* No config file if LVM_SYSTEM_DIR is empty */ if (!*cmd->system_dir) { if (!(cmd->cft = config_file_open(NULL, 0))) { log_error("Failed to create config tree"); return 0; } return 1; } if (!_load_config_file(cmd, "")) return_0; return 1; } /* Read any additional config files */ static int _init_tag_configs(struct cmd_context *cmd) { struct str_list *sl; /* Tag list may grow while inside this loop */ dm_list_iterate_items(sl, &cmd->tags) { if (!_load_config_file(cmd, sl->str)) return_0; } return 1; } static struct dm_config_tree *_merge_config_files(struct cmd_context *cmd, struct dm_config_tree *cft) { struct config_tree_list *cfl; /* Replace temporary duplicate copy of lvm.conf */ if (cft->root) { if (!(cft = config_file_open(NULL, 0))) { log_error("Failed to create config tree"); return 0; } } dm_list_iterate_items(cfl, &cmd->config_files) { /* Merge all config trees into cmd->cft using merge/tag rules */ if (!merge_config_tree(cmd, cft, cfl->cft)) return_0; } return cft; } static void _destroy_tags(struct cmd_context *cmd) { struct dm_list *slh, *slht; dm_list_iterate_safe(slh, slht, &cmd->tags) { dm_list_del(slh); } } int config_files_changed(struct cmd_context *cmd) { struct config_tree_list *cfl; dm_list_iterate_items(cfl, &cmd->config_files) { if (config_file_changed(cfl->cft)) return 1; } return 0; } /* * Returns cmdline config_tree that overrides all others, if present. */ static struct dm_config_tree *_destroy_tag_configs(struct cmd_context *cmd) { struct config_tree_list *cfl; struct dm_config_tree *cft_cmdline = NULL, *cft; cft = dm_config_remove_cascaded_tree(cmd->cft); if (cft) { cft_cmdline = cmd->cft; cmd->cft = cft; } dm_list_iterate_items(cfl, &cmd->config_files) { if (cfl->cft == cmd->cft) cmd->cft = NULL; config_file_destroy(cfl->cft); } if (cmd->cft) { config_file_destroy(cmd->cft); cmd->cft = NULL; } dm_list_init(&cmd->config_files); return cft_cmdline; } static int _init_dev_cache(struct cmd_context *cmd) { const struct dm_config_node *cn; const struct dm_config_value *cv; size_t len, udev_dir_len = strlen(DM_UDEV_DEV_DIR); int len_diff; int device_list_from_udev; init_dev_disable_after_error_count( find_config_tree_int(cmd, "devices/disable_after_error_count", DEFAULT_DISABLE_AFTER_ERROR_COUNT)); if (!dev_cache_init(cmd)) return_0; device_list_from_udev = udev_is_running() ? find_config_tree_bool(cmd, "devices/obtain_device_list_from_udev", DEFAULT_OBTAIN_DEVICE_LIST_FROM_UDEV) : 0; init_obtain_device_list_from_udev(device_list_from_udev); if (!(cn = find_config_tree_node(cmd, "devices/scan"))) { if (!dev_cache_add_dir("/dev")) { log_error("Failed to add /dev to internal " "device cache"); return 0; } log_verbose("device/scan not in config file: " "Defaulting to /dev"); return 1; } for (cv = cn->v; cv; cv = cv->next) { if (cv->type != DM_CFG_STRING) { log_error("Invalid string in config file: " "devices/scan"); return 0; } if (device_list_from_udev) { len = strlen(cv->v.str); /* * DM_UDEV_DEV_DIR always has '/' at its end. * If the item in the conf does not have it, be sure * to make the right comparison without the '/' char! */ len_diff = len && cv->v.str[len - 1] != '/' ? udev_dir_len - 1 != len : udev_dir_len != len; if (len_diff || strncmp(DM_UDEV_DEV_DIR, cv->v.str, len)) { device_list_from_udev = 0; init_obtain_device_list_from_udev(0); } } if (!dev_cache_add_dir(cv->v.str)) { log_error("Failed to add %s to internal device cache", cv->v.str); return 0; } } if (!(cn = find_config_tree_node(cmd, "devices/loopfiles"))) return 1; for (cv = cn->v; cv; cv = cv->next) { if (cv->type != DM_CFG_STRING) { log_error("Invalid string in config file: " "devices/loopfiles"); return 0; } if (!dev_cache_add_loopfile(cv->v.str)) { log_error("Failed to add loopfile %s to internal " "device cache", cv->v.str); return 0; } } return 1; } #define MAX_FILTERS 5 static struct dev_filter *_init_filter_components(struct cmd_context *cmd) { int nr_filt = 0; const struct dm_config_node *cn; struct dev_filter *filters[MAX_FILTERS] = { 0 }; struct dev_filter *composite; /* * Filters listed in order: top one gets applied first. * Failure to initialise some filters is not fatal. * Update MAX_FILTERS definition above when adding new filters. */ /* * sysfs filter. Only available on 2.6 kernels. Non-critical. * Listed first because it's very efficient at eliminating * unavailable devices. */ if (find_config_tree_bool(cmd, "devices/sysfs_scan", DEFAULT_SYSFS_SCAN)) { if ((filters[nr_filt] = sysfs_filter_create(cmd->sysfs_dir))) nr_filt++; } /* regex filter. Optional. */ if (!(cn = find_config_tree_node(cmd, "devices/filter"))) log_very_verbose("devices/filter not found in config file: " "no regex filter installed"); else if (!(filters[nr_filt] = regex_filter_create(cn->v))) { log_error("Failed to create regex device filter"); goto bad; } else nr_filt++; /* device type filter. Required. */ cn = find_config_tree_node(cmd, "devices/types"); if (!(filters[nr_filt] = lvm_type_filter_create(cmd->proc_dir, cn))) { log_error("Failed to create lvm type filter"); goto bad; } nr_filt++; /* md component filter. Optional, non-critical. */ if (find_config_tree_bool(cmd, "devices/md_component_detection", DEFAULT_MD_COMPONENT_DETECTION)) { init_md_filtering(1); if ((filters[nr_filt] = md_filter_create())) nr_filt++; } /* mpath component filter. Optional, non-critical. */ if (find_config_tree_bool(cmd, "devices/multipath_component_detection", DEFAULT_MULTIPATH_COMPONENT_DETECTION)) { if ((filters[nr_filt] = mpath_filter_create(cmd->sysfs_dir))) nr_filt++; } /* Only build a composite filter if we really need it. */ if (nr_filt == 1) return filters[0]; if (!(composite = composite_filter_create(nr_filt, filters))) goto_bad; return composite; bad: while (--nr_filt >= 0) filters[nr_filt]->destroy(filters[nr_filt]); return NULL; } static int _init_filters(struct cmd_context *cmd, unsigned load_persistent_cache) { static char cache_file[PATH_MAX]; const char *dev_cache = NULL, *cache_dir, *cache_file_prefix; struct dev_filter *f3 = NULL, *f4 = NULL, *toplevel_components[2] = { 0 }; struct stat st; const struct dm_config_node *cn; cmd->dump_filter = 0; if (!(f3 = _init_filter_components(cmd))) goto_bad; init_ignore_suspended_devices(find_config_tree_int(cmd, "devices/ignore_suspended_devices", DEFAULT_IGNORE_SUSPENDED_DEVICES)); /* * If 'cache_dir' or 'cache_file_prefix' is set, ignore 'cache'. */ cache_dir = find_config_tree_str(cmd, "devices/cache_dir", NULL); cache_file_prefix = find_config_tree_str(cmd, "devices/cache_file_prefix", NULL); if (cache_dir || cache_file_prefix) { if (dm_snprintf(cache_file, sizeof(cache_file), "%s%s%s/%s.cache", cache_dir ? "" : cmd->system_dir, cache_dir ? "" : "/", cache_dir ? : DEFAULT_CACHE_SUBDIR, cache_file_prefix ? : DEFAULT_CACHE_FILE_PREFIX) < 0) { log_error("Persistent cache filename too long."); goto bad; } } else if (!(dev_cache = find_config_tree_str(cmd, "devices/cache", NULL)) && (dm_snprintf(cache_file, sizeof(cache_file), "%s/%s/%s.cache", cmd->system_dir, DEFAULT_CACHE_SUBDIR, DEFAULT_CACHE_FILE_PREFIX) < 0)) { log_error("Persistent cache filename too long."); goto bad; } if (!dev_cache) dev_cache = cache_file; if (!(f4 = persistent_filter_create(f3, dev_cache))) { log_verbose("Failed to create persistent device filter."); f3->destroy(f3); return_0; } /* Should we ever dump persistent filter state? */ if (find_config_tree_int(cmd, "devices/write_cache_state", 1)) cmd->dump_filter = 1; if (!*cmd->system_dir) cmd->dump_filter = 0; /* * Only load persistent filter device cache on startup if it is newer * than the config file and this is not a long-lived process. */ if (load_persistent_cache && !cmd->is_long_lived && !stat(dev_cache, &st) && (st.st_ctime > config_file_timestamp(cmd->cft)) && !persistent_filter_load(f4, NULL)) log_verbose("Failed to load existing device cache from %s", dev_cache); if (!(cn = find_config_tree_node(cmd, "devices/global_filter"))) { cmd->filter = f4; } else if (!(cmd->lvmetad_filter = regex_filter_create(cn->v))) goto_bad; else { toplevel_components[0] = cmd->lvmetad_filter; toplevel_components[1] = f4; if (!(cmd->filter = composite_filter_create(2, toplevel_components))) goto_bad; } return 1; bad: if (f3) f3->destroy(f3); if (f4) f4->destroy(f4); if (toplevel_components[0]) toplevel_components[0]->destroy(toplevel_components[0]); return 0; } struct format_type *get_format_by_name(struct cmd_context *cmd, const char *format) { struct format_type *fmt; dm_list_iterate_items(fmt, &cmd->formats) if (!strcasecmp(fmt->name, format) || !strcasecmp(fmt->name + 3, format) || (fmt->alias && !strcasecmp(fmt->alias, format))) return fmt; return NULL; } static int _init_formats(struct cmd_context *cmd) { const char *format; struct format_type *fmt; #ifdef HAVE_LIBDL const struct dm_config_node *cn; #endif #ifdef LVM1_INTERNAL if (!(fmt = init_lvm1_format(cmd))) return 0; fmt->library = NULL; dm_list_add(&cmd->formats, &fmt->list); #endif #ifdef POOL_INTERNAL if (!(fmt = init_pool_format(cmd))) return 0; fmt->library = NULL; dm_list_add(&cmd->formats, &fmt->list); #endif #ifdef HAVE_LIBDL /* Load any formats in shared libs if not static */ if (!is_static() && (cn = find_config_tree_node(cmd, "global/format_libraries"))) { const struct dm_config_value *cv; struct format_type *(*init_format_fn) (struct cmd_context *); void *lib; for (cv = cn->v; cv; cv = cv->next) { if (cv->type != DM_CFG_STRING) { log_error("Invalid string in config file: " "global/format_libraries"); return 0; } if (!(lib = load_shared_library(cmd, cv->v.str, "format", 0))) return_0; if (!(init_format_fn = dlsym(lib, "init_format"))) { log_error("Shared library %s does not contain " "format functions", cv->v.str); dlclose(lib); return 0; } if (!(fmt = init_format_fn(cmd))) { dlclose(lib); return_0; } fmt->library = lib; dm_list_add(&cmd->formats, &fmt->list); } } #endif if (!(fmt = create_text_format(cmd))) return 0; fmt->library = NULL; dm_list_add(&cmd->formats, &fmt->list); cmd->fmt_backup = fmt; format = find_config_tree_str(cmd, "global/format", DEFAULT_FORMAT); dm_list_iterate_items(fmt, &cmd->formats) { if (!strcasecmp(fmt->name, format) || (fmt->alias && !strcasecmp(fmt->alias, format))) { cmd->default_settings.fmt_name = fmt->name; cmd->fmt = fmt; return 1; } } log_error("_init_formats: Default format (%s) not found", format); return 0; } int init_lvmcache_orphans(struct cmd_context *cmd) { struct format_type *fmt; dm_list_iterate_items(fmt, &cmd->formats) if (!lvmcache_add_orphan_vginfo(fmt->orphan_vg_name, fmt)) return_0; return 1; } struct segtype_library { struct cmd_context *cmd; void *lib; const char *libname; }; int lvm_register_segtype(struct segtype_library *seglib, struct segment_type *segtype) { struct segment_type *segtype2; segtype->library = seglib->lib; segtype->cmd = seglib->cmd; dm_list_iterate_items(segtype2, &seglib->cmd->segtypes) { if (strcmp(segtype2->name, segtype->name)) continue; log_error("Duplicate segment type %s: " "unloading shared library %s", segtype->name, seglib->libname); segtype->ops->destroy(segtype); return 0; } dm_list_add(&seglib->cmd->segtypes, &segtype->list); return 1; } static int _init_single_segtype(struct cmd_context *cmd, struct segtype_library *seglib) { struct segment_type *(*init_segtype_fn) (struct cmd_context *); struct segment_type *segtype; if (!(init_segtype_fn = dlsym(seglib->lib, "init_segtype"))) { log_error("Shared library %s does not contain segment type " "functions", seglib->libname); return 0; } if (!(segtype = init_segtype_fn(seglib->cmd))) return_0; return lvm_register_segtype(seglib, segtype); } static int _init_segtypes(struct cmd_context *cmd) { int i; struct segment_type *segtype; struct segtype_library seglib = { .cmd = cmd, .lib = NULL }; struct segment_type *(*init_segtype_array[])(struct cmd_context *cmd) = { init_striped_segtype, init_zero_segtype, init_error_segtype, init_free_segtype, #ifdef SNAPSHOT_INTERNAL init_snapshot_segtype, #endif #ifdef MIRRORED_INTERNAL init_mirrored_segtype, #endif NULL }; #ifdef HAVE_LIBDL const struct dm_config_node *cn; #endif for (i = 0; init_segtype_array[i]; i++) { if (!(segtype = init_segtype_array[i](cmd))) return 0; segtype->library = NULL; dm_list_add(&cmd->segtypes, &segtype->list); } #ifdef REPLICATOR_INTERNAL if (!init_replicator_segtype(cmd, &seglib)) return 0; #endif #ifdef RAID_INTERNAL if (!init_raid_segtypes(cmd, &seglib)) return 0; #endif #ifdef THIN_INTERNAL if (!init_thin_segtypes(cmd, &seglib)) return 0; #endif #ifdef HAVE_LIBDL /* Load any formats in shared libs unless static */ if (!is_static() && (cn = find_config_tree_node(cmd, "global/segment_libraries"))) { const struct dm_config_value *cv; int (*init_multiple_segtypes_fn) (struct cmd_context *, struct segtype_library *); for (cv = cn->v; cv; cv = cv->next) { if (cv->type != DM_CFG_STRING) { log_error("Invalid string in config file: " "global/segment_libraries"); return 0; } seglib.libname = cv->v.str; if (!(seglib.lib = load_shared_library(cmd, seglib.libname, "segment type", 0))) return_0; if ((init_multiple_segtypes_fn = dlsym(seglib.lib, "init_multiple_segtypes"))) { if (dlsym(seglib.lib, "init_segtype")) log_warn("WARNING: Shared lib %s has " "conflicting init fns. Using" " init_multiple_segtypes().", seglib.libname); } else init_multiple_segtypes_fn = _init_single_segtype; if (!init_multiple_segtypes_fn(cmd, &seglib)) { struct dm_list *sgtl, *tmp; log_error("init_multiple_segtypes() failed: " "Unloading shared library %s", seglib.libname); dm_list_iterate_safe(sgtl, tmp, &cmd->segtypes) { segtype = dm_list_item(sgtl, struct segment_type); if (segtype->library == seglib.lib) { dm_list_del(&segtype->list); segtype->ops->destroy(segtype); } } dlclose(seglib.lib); return_0; } } } #endif return 1; } static int _init_hostname(struct cmd_context *cmd) { struct utsname uts; if (uname(&uts)) { log_sys_error("uname", "_init_hostname"); return 0; } if (!(cmd->hostname = dm_pool_strdup(cmd->libmem, uts.nodename))) { log_error("_init_hostname: dm_pool_strdup failed"); return 0; } if (!(cmd->kernel_vsn = dm_pool_strdup(cmd->libmem, uts.release))) { log_error("_init_hostname: dm_pool_strdup kernel_vsn failed"); return 0; } return 1; } static int _init_backup(struct cmd_context *cmd) { static char default_dir[PATH_MAX]; uint32_t days, min; const char *dir; if (!cmd->system_dir[0]) { log_warn("WARNING: Metadata changes will NOT be backed up"); backup_init(cmd, "", 0); archive_init(cmd, "", 0, 0, 0); return 1; } /* set up archiving */ cmd->default_settings.archive = find_config_tree_bool(cmd, "backup/archive", DEFAULT_ARCHIVE_ENABLED); days = (uint32_t) find_config_tree_int(cmd, "backup/retain_days", DEFAULT_ARCHIVE_DAYS); min = (uint32_t) find_config_tree_int(cmd, "backup/retain_min", DEFAULT_ARCHIVE_NUMBER); if (dm_snprintf (default_dir, sizeof(default_dir), "%s/%s", cmd->system_dir, DEFAULT_ARCHIVE_SUBDIR) == -1) { log_error("Couldn't create default archive path '%s/%s'.", cmd->system_dir, DEFAULT_ARCHIVE_SUBDIR); return 0; } dir = find_config_tree_str(cmd, "backup/archive_dir", default_dir); if (!archive_init(cmd, dir, days, min, cmd->default_settings.archive)) { log_debug("archive_init failed."); return 0; } /* set up the backup */ cmd->default_settings.backup = find_config_tree_bool(cmd, "backup/backup", DEFAULT_BACKUP_ENABLED); if (dm_snprintf (default_dir, sizeof(default_dir), "%s/%s", cmd->system_dir, DEFAULT_BACKUP_SUBDIR) == -1) { log_error("Couldn't create default backup path '%s/%s'.", cmd->system_dir, DEFAULT_BACKUP_SUBDIR); return 0; } dir = find_config_tree_str(cmd, "backup/backup_dir", default_dir); if (!backup_init(cmd, dir, cmd->default_settings.backup)) { log_debug("backup_init failed."); return 0; } return 1; } static void _init_rand(struct cmd_context *cmd) { if (read_urandom(&cmd->rand_seed, sizeof(cmd->rand_seed))) { reset_lvm_errno(1); return; } cmd->rand_seed = (unsigned) time(NULL) + (unsigned) getpid(); reset_lvm_errno(1); } static void _init_globals(struct cmd_context *cmd) { init_full_scan_done(0); init_mirror_in_sync(0); } /* * Close and reopen stream on file descriptor fd. */ static int _reopen_stream(FILE *stream, int fd, const char *mode, const char *name, FILE **new_stream) { int fd_copy, new_fd; if ((fd_copy = dup(fd)) < 0) { log_sys_error("dup", name); return 0; } if (fclose(stream)) log_sys_error("fclose", name); if ((new_fd = dup2(fd_copy, fd)) < 0) log_sys_error("dup2", name); else if (new_fd != fd) log_error("dup2(%d, %d) returned %d", fd_copy, fd, new_fd); if (close(fd_copy) < 0) log_sys_error("close", name); if (!(*new_stream = fdopen(fd, mode))) { log_sys_error("fdopen", name); return 0; } return 1; } /* Entry point */ struct cmd_context *create_toolcontext(unsigned is_long_lived, const char *system_dir, unsigned set_buffering, unsigned threaded) { struct cmd_context *cmd; FILE *new_stream; #ifdef M_MMAP_MAX mallopt(M_MMAP_MAX, 0); #endif if (!setlocale(LC_ALL, "")) log_very_verbose("setlocale failed"); #ifdef INTL_PACKAGE bindtextdomain(INTL_PACKAGE, LOCALEDIR); #endif init_syslog(DEFAULT_LOG_FACILITY); if (!(cmd = dm_zalloc(sizeof(*cmd)))) { log_error("Failed to allocate command context"); return NULL; } cmd->is_long_lived = is_long_lived; cmd->threaded = threaded ? 1 : 0; cmd->handles_missing_pvs = 0; cmd->handles_unknown_segments = 0; cmd->independent_metadata_areas = 0; cmd->hosttags = 0; dm_list_init(&cmd->arg_value_groups); dm_list_init(&cmd->formats); dm_list_init(&cmd->segtypes); dm_list_init(&cmd->tags); dm_list_init(&cmd->config_files); label_init(); /* FIXME Make this configurable? */ reset_lvm_errno(1); #ifndef VALGRIND_POOL /* Set in/out stream buffering before glibc */ if (set_buffering) { /* Allocate 2 buffers */ if (!(cmd->linebuffer = dm_malloc(2 * linebuffer_size))) { log_error("Failed to allocate line buffer."); goto out; } if (is_valid_fd(STDIN_FILENO)) { if (!_reopen_stream(stdin, STDIN_FILENO, "r", "stdin", &new_stream)) goto_out; stdin = new_stream; if (setvbuf(stdin, cmd->linebuffer, _IOLBF, linebuffer_size)) { log_sys_error("setvbuf", ""); goto out; } } if (is_valid_fd(STDOUT_FILENO)) { if (!_reopen_stream(stdout, STDOUT_FILENO, "w", "stdout", &new_stream)) goto_out; stdout = new_stream; if (setvbuf(stdout, cmd->linebuffer + linebuffer_size, _IOLBF, linebuffer_size)) { log_sys_error("setvbuf", ""); goto out; } } /* Buffers are used for lines without '\n' */ } else /* Without buffering, must not use stdin/stdout */ init_silent(1); #endif /* * Environment variable LVM_SYSTEM_DIR overrides this below. */ if (system_dir) strncpy(cmd->system_dir, system_dir, sizeof(cmd->system_dir) - 1); else strcpy(cmd->system_dir, DEFAULT_SYS_DIR); if (!_get_env_vars(cmd)) goto_out; /* Create system directory if it doesn't already exist */ if (*cmd->system_dir && !dm_create_dir(cmd->system_dir)) { log_error("Failed to create LVM2 system dir for metadata backups, config " "files and internal cache."); log_error("Set environment variable LVM_SYSTEM_DIR to alternative location " "or empty string."); goto out; } if (!(cmd->libmem = dm_pool_create("library", 4 * 1024))) { log_error("Library memory pool creation failed"); goto out; } if (!_init_lvm_conf(cmd)) goto_out; _init_logging(cmd); if (!_init_hostname(cmd)) goto_out; if (!_init_tags(cmd, cmd->cft)) goto_out; if (!_init_tag_configs(cmd)) goto_out; if (!(cmd->cft = _merge_config_files(cmd, cmd->cft))) goto_out; if (!_process_config(cmd)) goto_out; if (!_init_dev_cache(cmd)) goto_out; if (!_init_filters(cmd, 1)) goto_out; if (!(cmd->mem = dm_pool_create("command", 4 * 1024))) { log_error("Command memory pool creation failed"); goto out; } memlock_init(cmd); if (!_init_formats(cmd)) goto_out; if (!init_lvmcache_orphans(cmd)) goto_out; if (!_init_segtypes(cmd)) goto_out; if (!_init_backup(cmd)) goto_out; _init_rand(cmd); _init_globals(cmd); cmd->default_settings.cache_vgmetadata = 1; cmd->current_settings = cmd->default_settings; cmd->config_valid = 1; out: if (cmd->config_valid != 1) { destroy_toolcontext(cmd); cmd = NULL; } return cmd; } static void _destroy_formats(struct cmd_context *cmd, struct dm_list *formats) { struct dm_list *fmtl, *tmp; struct format_type *fmt; void *lib; dm_list_iterate_safe(fmtl, tmp, formats) { fmt = dm_list_item(fmtl, struct format_type); dm_list_del(&fmt->list); lib = fmt->library; fmt->ops->destroy(fmt); #ifdef HAVE_LIBDL if (lib) dlclose(lib); #endif } cmd->independent_metadata_areas = 0; } static void _destroy_segtypes(struct dm_list *segtypes) { struct dm_list *sgtl, *tmp; struct segment_type *segtype; void *lib; dm_list_iterate_safe(sgtl, tmp, segtypes) { segtype = dm_list_item(sgtl, struct segment_type); dm_list_del(&segtype->list); lib = segtype->library; segtype->ops->destroy(segtype); #ifdef HAVE_LIBDL /* * If no segtypes remain from this library, close it. */ if (lib) { struct segment_type *segtype2; dm_list_iterate_items(segtype2, segtypes) if (segtype2->library == lib) goto skip_dlclose; dlclose(lib); skip_dlclose: ; } #endif } } int refresh_filters(struct cmd_context *cmd) { int r, saved_ignore_suspended_devices = ignore_suspended_devices(); if (cmd->filter) { cmd->filter->destroy(cmd->filter); cmd->filter = NULL; } cmd->lvmetad_filter = NULL; if (!(r = _init_filters(cmd, 0))) stack; /* * During repair code must not reset suspended flag. */ init_ignore_suspended_devices(saved_ignore_suspended_devices); return r; } int refresh_toolcontext(struct cmd_context *cmd) { struct dm_config_tree *cft_cmdline, *cft_tmp; log_verbose("Reloading config files"); /* * Don't update the persistent filter cache as we will * perform a full rescan. */ activation_release(); lvmcache_destroy(cmd, 0); label_exit(); _destroy_segtypes(&cmd->segtypes); _destroy_formats(cmd, &cmd->formats); if (cmd->filter) { cmd->filter->destroy(cmd->filter); cmd->filter = NULL; } dev_cache_exit(); _destroy_tags(cmd); cft_cmdline = _destroy_tag_configs(cmd); cmd->config_valid = 0; cmd->hosttags = 0; if (!_init_lvm_conf(cmd)) return 0; /* Temporary duplicate cft pointer holding lvm.conf - replaced later */ cft_tmp = cmd->cft; if (cft_cmdline) cmd->cft = dm_config_insert_cascaded_tree(cft_cmdline, cft_tmp); /* Uses cmd->cft i.e. cft_cmdline + lvm.conf */ _init_logging(cmd); /* Init tags from lvm.conf. */ if (!_init_tags(cmd, cft_tmp)) return 0; /* Doesn't change cmd->cft */ if (!_init_tag_configs(cmd)) return 0; /* Merge all the tag config files with lvm.conf, returning a * fresh cft pointer in place of cft_tmp. */ if (!(cmd->cft = _merge_config_files(cmd, cft_tmp))) return 0; /* Finally we can make the proper, fully-merged, cmd->cft */ if (cft_cmdline) cmd->cft = dm_config_insert_cascaded_tree(cft_cmdline, cmd->cft); if (!_process_config(cmd)) return 0; if (!_init_dev_cache(cmd)) return 0; if (!_init_filters(cmd, 0)) return 0; if (!_init_formats(cmd)) return 0; if (!init_lvmcache_orphans(cmd)) return 0; if (!_init_segtypes(cmd)) return 0; if (!_init_backup(cmd)) return 0; cmd->config_valid = 1; reset_lvm_errno(1); return 1; } void destroy_toolcontext(struct cmd_context *cmd) { struct dm_config_tree *cft_cmdline; FILE *new_stream; if (cmd->dump_filter) persistent_filter_dump(cmd->filter, 1); archive_exit(cmd); backup_exit(cmd); lvmcache_destroy(cmd, 0); label_exit(); _destroy_segtypes(&cmd->segtypes); _destroy_formats(cmd, &cmd->formats); if (cmd->filter) cmd->filter->destroy(cmd->filter); if (cmd->mem) dm_pool_destroy(cmd->mem); dev_cache_exit(); _destroy_tags(cmd); if ((cft_cmdline = _destroy_tag_configs(cmd))) dm_config_destroy(cft_cmdline); if (cmd->libmem) dm_pool_destroy(cmd->libmem); #ifndef VALGRIND_POOL if (cmd->linebuffer) { /* Reset stream buffering to defaults */ if (is_valid_fd(STDIN_FILENO)) { if (_reopen_stream(stdin, STDIN_FILENO, "r", "stdin", &new_stream)) { stdin = new_stream; setlinebuf(stdin); } else cmd->linebuffer = NULL; /* Leave buffer in place (deliberate leak) */ } if (is_valid_fd(STDOUT_FILENO)) { if (_reopen_stream(stdout, STDOUT_FILENO, "w", "stdout", &new_stream)) { stdout = new_stream; setlinebuf(stdout); } else cmd->linebuffer = NULL; /* Leave buffer in place (deliberate leak) */ } dm_free(cmd->linebuffer); } #endif dm_free(cmd); lvmetad_release_token(); lvmetad_disconnect(); release_log_memory(); activation_exit(); reset_log_duplicated(); fin_log(); fin_syslog(); reset_lvm_errno(0); } lvm2-2.02.98/lib/commands/errors.h0000640000175000017500000000141512037016272015545 0ustar blankblank/* * 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 lvm2-2.02.98/lib/commands/toolcontext.h0000640000175000017500000000734112037016272016617 0ustar blankblank/* * 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 #include /* * Config options that can be changed while commands are processed */ struct config_info { int debug; int verbose; int silent; 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 udev_fallback; 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 dm_config_tree; struct archive_params; struct backup_params; struct arg_values; struct config_tree_list { struct dm_list list; struct dm_config_tree *cft; }; /* 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; char *linebuffer; 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 use_linear_target:1; unsigned partial_activation:1; unsigned si_unit_consistency:1; unsigned metadata_read_only:1; unsigned threaded:1; /* Set if running within a thread e.g. clvmd */ unsigned independent_metadata_areas:1; /* Active formats have MDAs outside PVs */ struct dev_filter *filter; struct dev_filter *lvmetad_filter; int dump_filter; /* Dump filter when exiting? */ struct dm_list config_files; int config_valid; struct dm_config_tree *cft; 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, unsigned set_buffering, unsigned threaded); 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 lvm2-2.02.98/lib/log/0000750000175000017500000000000012037016272013036 5ustar blankblanklvm2-2.02.98/lib/log/log.h0000640000175000017500000000731112037016272013773 0ustar blankblank/* * 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_LOG_H #define _LVM_LOG_H /* * printf()-style macros to use for messages: * * log_error - always print to stderr. * log_print - always print to stdout. Use this instead of printf. * log_verbose - print to stdout if verbose is set (-v) * log_very_verbose - print to stdout if verbose is set twice (-vv) * log_debug - print to stdout if verbose is set three times (-vvv) * * In addition, messages will be logged to file or syslog if they * are more serious than the log level specified with the log/debug_level * parameter in the configuration file. These messages get the file * and line number prepended. 'stack' (without arguments) can be used * to log this information at debug level. * * log_sys_error and log_sys_very_verbose are for errors from system calls * e.g. log_sys_error("stat", filename); * /dev/fd/7: stat failed: No such file or directory * */ #include /* FILE */ #include /* strerror() */ #include #define EUNCLASSIFIED -1 /* Generic error code */ #define _LOG_STDERR 128 /* force things to go to stderr, even if loglevel would make them go to stdout */ #define _LOG_ONCE 256 /* downgrade to NOTICE if this has been already logged */ #define _LOG_DEBUG 7 #define _LOG_INFO 6 #define _LOG_NOTICE 5 #define _LOG_WARN 4 #define _LOG_ERR 3 #define _LOG_FATAL 2 #define INTERNAL_ERROR "Internal error: " #define log_debug(x...) LOG_LINE(_LOG_DEBUG, x) #define log_info(x...) LOG_LINE(_LOG_INFO, x) #define log_notice(x...) LOG_LINE(_LOG_NOTICE, x) #define log_warn(x...) LOG_LINE(_LOG_WARN | _LOG_STDERR, x) #define log_warn_suppress(s, x...) LOG_LINE(s ? _LOG_NOTICE : _LOG_WARN | _LOG_STDERR, x) #define log_err(x...) LOG_LINE_WITH_ERRNO(_LOG_ERR, EUNCLASSIFIED, x) #define log_err_suppress(s, x...) LOG_LINE_WITH_ERRNO(s ? _LOG_NOTICE : _LOG_ERR, EUNCLASSIFIED, x) #define log_err_once(x...) LOG_LINE_WITH_ERRNO(_LOG_ERR | _LOG_ONCE, EUNCLASSIFIED, x) #define log_fatal(x...) LOG_LINE_WITH_ERRNO(_LOG_FATAL, EUNCLASSIFIED, x) #define stack log_debug("") /* Backtrace on error */ #define log_very_verbose(args...) log_info(args) #define log_verbose(args...) log_notice(args) #define log_print(args...) LOG_LINE(_LOG_WARN, args) #define log_print_unless_silent(args...) LOG_LINE(silent_mode() ? _LOG_NOTICE : _LOG_WARN, args) #define log_error(args...) log_err(args) #define log_error_suppress(s, args...) log_err_suppress(s, args) #define log_error_once(args...) log_err_once(args) #define log_errno(args...) LOG_LINE_WITH_ERRNO(_LOG_ERR, args) /* System call equivalents */ #define log_sys_error(x, y) \ log_err("%s: %s failed: %s", y, x, strerror(errno)) #define log_sys_error_suppress(s, x, y) \ log_err_suppress(s, "%s: %s failed: %s", y, x, strerror(errno)) #define log_sys_very_verbose(x, y) \ log_info("%s: %s failed: %s", y, x, strerror(errno)) #define log_sys_debug(x, y) \ log_debug("%s: %s failed: %s", y, x, strerror(errno)) #define return_0 do { stack; return 0; } while (0) #define return_NULL do { stack; return NULL; } while (0) #define goto_out do { stack; goto out; } while (0) #define goto_bad do { stack; goto bad; } while (0) #endif lvm2-2.02.98/lib/log/log.c0000640000175000017500000002134112037016272013765 0ustar blankblank/* * 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 "device.h" #include "memlock.h" #include "defaults.h" #include #include static FILE *_log_file; static struct device _log_dev; static struct str_list _log_dev_alias; static int _syslog = 0; static int _log_to_file = 0; static int _log_direct = 0; static int _log_while_suspended = 0; static int _indent = 1; static int _log_suppress = 0; static char _msg_prefix[30] = " "; static int _already_logging = 0; static int _abort_on_internal_errors = 0; static lvm2_log_fn_t _lvm2_log_fn = NULL; static int _lvm_errno = 0; static int _store_errmsg = 0; static char *_lvm_errmsg = NULL; static size_t _lvm_errmsg_size = 0; static size_t _lvm_errmsg_len = 0; #define MAX_ERRMSG_LEN (512 * 1024) /* Max size of error buffer 512KB */ void init_log_fn(lvm2_log_fn_t log_fn) { if (log_fn) _lvm2_log_fn = log_fn; else _lvm2_log_fn = NULL; } void init_log_file(const char *log_file, int append) { const char *open_mode = append ? "a" : "w"; if (!(_log_file = fopen(log_file, open_mode))) { log_sys_error("fopen", log_file); return; } _log_to_file = 1; } void init_log_direct(const char *log_file, int append) { int open_flags = append ? 0 : O_TRUNC; dev_create_file(log_file, &_log_dev, &_log_dev_alias, 1); if (!dev_open_flags(&_log_dev, O_RDWR | O_CREAT | open_flags, 1, 0)) return; _log_direct = 1; } void init_log_while_suspended(int log_while_suspended) { _log_while_suspended = log_while_suspended; } void init_syslog(int facility) { openlog("lvm", LOG_PID, facility); _syslog = 1; } int log_suppress(int suppress) { int old_suppress = _log_suppress; _log_suppress = suppress; return old_suppress; } void release_log_memory(void) { if (!_log_direct) return; dm_free((char *) _log_dev_alias.str); _log_dev_alias.str = "activate_log file"; } void fin_log(void) { if (_log_direct) { (void) dev_close(&_log_dev); _log_direct = 0; } if (_log_to_file) { if (dm_fclose(_log_file)) { if (errno) fprintf(stderr, "failed to write log file: %s\n", strerror(errno)); else fprintf(stderr, "failed to write log file\n"); } _log_to_file = 0; } } void fin_syslog(void) { if (_syslog) closelog(); _syslog = 0; } void init_msg_prefix(const char *prefix) { strncpy(_msg_prefix, prefix, sizeof(_msg_prefix) - 1); _msg_prefix[sizeof(_msg_prefix) - 1] = '\0'; } void init_indent(int indent) { _indent = indent; } void init_abort_on_internal_errors(int fatal) { _abort_on_internal_errors = fatal; } void reset_lvm_errno(int store_errmsg) { _lvm_errno = 0; if (_lvm_errmsg) { dm_free(_lvm_errmsg); _lvm_errmsg = NULL; _lvm_errmsg_size = _lvm_errmsg_len = 0; } _store_errmsg = store_errmsg; } int stored_errno(void) { return _lvm_errno; } const char *stored_errmsg(void) { return _lvm_errmsg ? : ""; } static struct dm_hash_table *_duplicated = NULL; void reset_log_duplicated(void) { if (_duplicated) { dm_hash_destroy(_duplicated); _duplicated = NULL; } } void print_log(int level, const char *file, int line, int dm_errno, const char *format, ...) { va_list ap; char buf[1024], locn[4096]; int bufused, n; const char *message; const char *trformat; /* Translated format string */ char *newbuf; int use_stderr = level & _LOG_STDERR; int log_once = level & _LOG_ONCE; int fatal_internal_error = 0; size_t msglen; level &= ~(_LOG_STDERR|_LOG_ONCE); if (_abort_on_internal_errors && !strncmp(format, INTERNAL_ERROR, strlen(INTERNAL_ERROR))) { fatal_internal_error = 1; /* Internal errors triggering abort cannot be suppressed. */ _log_suppress = 0; level = _LOG_FATAL; } if (_log_suppress == 2) return; if (level <= _LOG_ERR) init_error_message_produced(1); trformat = _(format); if (dm_errno && !_lvm_errno) _lvm_errno = dm_errno; if (_lvm2_log_fn || (_store_errmsg && (level <= _LOG_ERR)) || log_once) { va_start(ap, format); n = vsnprintf(locn, sizeof(locn) - 1, trformat, ap); va_end(ap); if (n < 0) { fprintf(stderr, _("vsnprintf failed: skipping external " "logging function")); goto log_it; } locn[sizeof(locn) - 1] = '\0'; message = locn; } /* FIXME Avoid pointless use of message buffer when it'll never be read! */ if (_store_errmsg && (level <= _LOG_ERR) && _lvm_errmsg_len < MAX_ERRMSG_LEN) { msglen = strlen(message); if ((_lvm_errmsg_len + msglen + 1) >= _lvm_errmsg_size) { _lvm_errmsg_size = 2 * (_lvm_errmsg_len + msglen + 1); if ((newbuf = dm_realloc(_lvm_errmsg, _lvm_errmsg_size))) _lvm_errmsg = newbuf; else _lvm_errmsg_size = _lvm_errmsg_len; } if (_lvm_errmsg && (_lvm_errmsg_len + msglen + 2) < _lvm_errmsg_size) { /* prepend '\n' and copy with '\0' but do not count in */ if (_lvm_errmsg_len) _lvm_errmsg[_lvm_errmsg_len++] = '\n'; memcpy(_lvm_errmsg + _lvm_errmsg_len, message, msglen + 1); _lvm_errmsg_len += msglen; } } if (log_once) { if (!_duplicated) _duplicated = dm_hash_create(128); if (_duplicated) { if (dm_hash_lookup(_duplicated, message)) level = _LOG_NOTICE; (void) dm_hash_insert(_duplicated, message, (void*)1); } } if (_lvm2_log_fn) { _lvm2_log_fn(level, file, line, 0, message); if (fatal_internal_error) abort(); return; } log_it: if (!_log_suppress) { if (verbose_level() > _LOG_DEBUG) (void) dm_snprintf(locn, sizeof(locn), "#%s:%d ", file, line); else locn[0] = '\0'; va_start(ap, format); switch (level) { case _LOG_DEBUG: if (!strcmp("", format) && verbose_level() <= _LOG_DEBUG) break; if (verbose_level() >= _LOG_DEBUG) { fprintf(stderr, "%s%s%s", locn, log_command_name(), _msg_prefix); if (_indent) fprintf(stderr, " "); vfprintf(stderr, trformat, ap); fputc('\n', stderr); } break; case _LOG_INFO: if (verbose_level() >= _LOG_INFO) { fprintf(stderr, "%s%s%s", locn, log_command_name(), _msg_prefix); if (_indent) fprintf(stderr, " "); vfprintf(stderr, trformat, ap); fputc('\n', stderr); } break; case _LOG_NOTICE: if (verbose_level() >= _LOG_NOTICE) { fprintf(stderr, "%s%s%s", locn, log_command_name(), _msg_prefix); if (_indent) fprintf(stderr, " "); vfprintf(stderr, trformat, ap); fputc('\n', stderr); } break; case _LOG_WARN: if (verbose_level() >= _LOG_WARN) { fprintf(use_stderr ? stderr : stdout, "%s%s", log_command_name(), _msg_prefix); vfprintf(use_stderr ? stderr : stdout, trformat, ap); fputc('\n', use_stderr ? stderr : stdout); } break; case _LOG_ERR: if (verbose_level() >= _LOG_ERR) { fprintf(stderr, "%s%s%s", locn, log_command_name(), _msg_prefix); vfprintf(stderr, trformat, ap); fputc('\n', stderr); } break; case _LOG_FATAL: default: if (verbose_level() >= _LOG_FATAL) { fprintf(stderr, "%s%s%s", locn, log_command_name(), _msg_prefix); vfprintf(stderr, trformat, ap); fputc('\n', stderr); } break; } va_end(ap); } if (fatal_internal_error) abort(); if (level > debug_level()) return; if (_log_to_file && (_log_while_suspended || !critical_section())) { fprintf(_log_file, "%s:%d %s%s", file, line, log_command_name(), _msg_prefix); va_start(ap, format); vfprintf(_log_file, trformat, ap); va_end(ap); fprintf(_log_file, "\n"); fflush(_log_file); } if (_syslog && (_log_while_suspended || !critical_section())) { va_start(ap, format); vsyslog(level, trformat, ap); va_end(ap); } /* FIXME This code is unfinished - pre-extend & condense. */ if (!_already_logging && _log_direct && critical_section()) { _already_logging = 1; memset(&buf, ' ', sizeof(buf)); bufused = 0; if ((n = dm_snprintf(buf, sizeof(buf) - 1, "%s:%d %s%s", file, line, log_command_name(), _msg_prefix)) == -1) goto done; bufused += n; va_start(ap, format); n = vsnprintf(buf + bufused - 1, sizeof(buf) - bufused - 1, trformat, ap); va_end(ap); bufused += n; buf[bufused - 1] = '\n'; done: buf[bufused] = '\n'; buf[sizeof(buf) - 1] = '\n'; /* FIXME real size bufused */ dev_append(&_log_dev, sizeof(buf), buf); _already_logging = 0; } } lvm2-2.02.98/lib/log/lvm-logging.h0000640000175000017500000000354612037016272015442 0ustar blankblank/* * 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_LOGGING_H #define _LVM_LOGGING_H void print_log(int level, const char *file, int line, int dm_errno, const char *format, ...) __attribute__ ((format(printf, 5, 6))); #define LOG_LINE(l, x...) \ print_log(l, __FILE__, __LINE__ , 0, ## x) #define LOG_LINE_WITH_ERRNO(l, e, x...) \ print_log(l, __FILE__, __LINE__ , e, ## x) #include "log.h" typedef void (*lvm2_log_fn_t) (int level, const char *file, int line, int dm_errno, const char *message); void init_log_fn(lvm2_log_fn_t log_fn); void init_indent(int indent); void init_msg_prefix(const char *prefix); void init_log_file(const char *log_file, int append); void init_log_direct(const char *log_file, int append); void init_log_while_suspended(int log_while_suspended); void init_abort_on_internal_errors(int fatal); void fin_log(void); void release_log_memory(void); void reset_log_duplicated(void); void init_syslog(int facility); void fin_syslog(void); int error_message_produced(void); void reset_lvm_errno(int store_errmsg); int stored_errno(void); const char *stored_errmsg(void); /* Suppress messages to stdout/stderr (1) or everywhere (2) */ /* Returns previous setting */ int log_suppress(int suppress); /* Suppress messages to syslog */ void syslog_suppress(int suppress); #endif lvm2-2.02.98/lib/format_pool/0000750000175000017500000000000012037016272014576 5ustar blankblanklvm2-2.02.98/lib/format_pool/.exported_symbols0000640000175000017500000000001412037016272020175 0ustar blankblankinit_format lvm2-2.02.98/lib/format_pool/disk_rep.c0000640000175000017500000002456412037016272016556 0ustar blankblank/* * Copyright (C) 1997-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 */ #include "lib.h" #include "label.h" #include "metadata.h" #include "lvmcache.h" #include "filter.h" #include "xlate.h" #include "disk_rep.h" #include /* FIXME: memcpy might not be portable */ #define CPIN_8(x, y, z) {memcpy((x), (y), (z));} #define CPOUT_8(x, y, z) {memcpy((y), (x), (z));} #define CPIN_16(x, y) {(x) = xlate16_be((y));} #define CPOUT_16(x, y) {(y) = xlate16_be((x));} #define CPIN_32(x, y) {(x) = xlate32_be((y));} #define CPOUT_32(x, y) {(y) = xlate32_be((x));} #define CPIN_64(x, y) {(x) = xlate64_be((y));} #define CPOUT_64(x, y) {(y) = xlate64_be((x));} static int __read_pool_disk(const struct format_type *fmt, struct device *dev, struct dm_pool *mem __attribute__((unused)), struct pool_list *pl, const char *vg_name __attribute__((unused))) { char buf[512] __attribute__((aligned(8))); /* FIXME: Need to check the cache here first */ if (!dev_read(dev, UINT64_C(0), 512, buf)) { log_very_verbose("Failed to read PV data from %s", dev_name(dev)); return 0; } if (!read_pool_label(pl, fmt->labeller, dev, buf, NULL)) return_0; return 1; } static void _add_pl_to_list(struct dm_list *head, struct pool_list *data) { struct pool_list *pl; dm_list_iterate_items(pl, head) { if (id_equal(&data->pv_uuid, &pl->pv_uuid)) { char uuid[ID_LEN + 7] __attribute__((aligned(8))); id_write_format(&pl->pv_uuid, uuid, ID_LEN + 7); if (!dev_subsystem_part_major(data->dev)) { log_very_verbose("Ignoring duplicate PV %s on " "%s", uuid, dev_name(data->dev)); return; } log_very_verbose("Duplicate PV %s - using %s %s", uuid, dev_subsystem_name(data->dev), dev_name(data->dev)); dm_list_del(&pl->list); break; } } dm_list_add(head, &data->list); } int read_pool_label(struct pool_list *pl, struct labeller *l, struct device *dev, char *buf, struct label **label) { struct lvmcache_info *info; struct id pvid; struct id vgid; char uuid[ID_LEN + 7] __attribute__((aligned(8))); struct pool_disk *pd = &pl->pd; pool_label_in(pd, buf); get_pool_pv_uuid(&pvid, pd); id_write_format(&pvid, uuid, ID_LEN + 7); log_debug("Calculated uuid %s for %s", uuid, dev_name(dev)); get_pool_vg_uuid(&vgid, pd); id_write_format(&vgid, uuid, ID_LEN + 7); log_debug("Calculated uuid %s for %s", uuid, pd->pl_pool_name); if (!(info = lvmcache_add(l, (char *) &pvid, dev, pd->pl_pool_name, (char *) &vgid, 0))) return_0; if (label) *label = lvmcache_get_label(info); lvmcache_set_device_size(info, ((uint64_t)xlate32_be(pd->pl_blocks)) << SECTOR_SHIFT); lvmcache_del_mdas(info); lvmcache_make_valid(info); pl->dev = dev; pl->pv = NULL; memcpy(&pl->pv_uuid, &pvid, sizeof(pvid)); return 1; } /** * pool_label_out - copies a pool_label_t into a char buffer * @pl: ptr to a pool_label_t struct * @buf: ptr to raw space where label info will be copied * * This function is important because it takes care of all of * the endian issues when copying to disk. This way, when * machines of different architectures are used, they will * be able to interpret ondisk labels correctly. Always use * this function before writing to disk. */ void pool_label_out(struct pool_disk *pl, void *buf) { struct pool_disk *bufpl = (struct pool_disk *) buf; CPOUT_64(pl->pl_magic, bufpl->pl_magic); CPOUT_64(pl->pl_pool_id, bufpl->pl_pool_id); CPOUT_8(pl->pl_pool_name, bufpl->pl_pool_name, POOL_NAME_SIZE); CPOUT_32(pl->pl_version, bufpl->pl_version); CPOUT_32(pl->pl_subpools, bufpl->pl_subpools); CPOUT_32(pl->pl_sp_id, bufpl->pl_sp_id); CPOUT_32(pl->pl_sp_devs, bufpl->pl_sp_devs); CPOUT_32(pl->pl_sp_devid, bufpl->pl_sp_devid); CPOUT_32(pl->pl_sp_type, bufpl->pl_sp_type); CPOUT_64(pl->pl_blocks, bufpl->pl_blocks); CPOUT_32(pl->pl_striping, bufpl->pl_striping); CPOUT_32(pl->pl_sp_dmepdevs, bufpl->pl_sp_dmepdevs); CPOUT_32(pl->pl_sp_dmepid, bufpl->pl_sp_dmepid); CPOUT_32(pl->pl_sp_weight, bufpl->pl_sp_weight); CPOUT_32(pl->pl_minor, bufpl->pl_minor); CPOUT_32(pl->pl_padding, bufpl->pl_padding); CPOUT_8(pl->pl_reserve, bufpl->pl_reserve, 184); } /** * pool_label_in - copies a char buffer into a pool_label_t * @pl: ptr to a pool_label_t struct * @buf: ptr to raw space where label info is copied from * * This function is important because it takes care of all of * the endian issues when information from disk is about to be * used. This way, when machines of different architectures * are used, they will be able to interpret ondisk labels * correctly. Always use this function before using labels that * were read from disk. */ void pool_label_in(struct pool_disk *pl, void *buf) { struct pool_disk *bufpl = (struct pool_disk *) buf; CPIN_64(pl->pl_magic, bufpl->pl_magic); CPIN_64(pl->pl_pool_id, bufpl->pl_pool_id); CPIN_8(pl->pl_pool_name, bufpl->pl_pool_name, POOL_NAME_SIZE); CPIN_32(pl->pl_version, bufpl->pl_version); CPIN_32(pl->pl_subpools, bufpl->pl_subpools); CPIN_32(pl->pl_sp_id, bufpl->pl_sp_id); CPIN_32(pl->pl_sp_devs, bufpl->pl_sp_devs); CPIN_32(pl->pl_sp_devid, bufpl->pl_sp_devid); CPIN_32(pl->pl_sp_type, bufpl->pl_sp_type); CPIN_64(pl->pl_blocks, bufpl->pl_blocks); CPIN_32(pl->pl_striping, bufpl->pl_striping); CPIN_32(pl->pl_sp_dmepdevs, bufpl->pl_sp_dmepdevs); CPIN_32(pl->pl_sp_dmepid, bufpl->pl_sp_dmepid); CPIN_32(pl->pl_sp_weight, bufpl->pl_sp_weight); CPIN_32(pl->pl_minor, bufpl->pl_minor); CPIN_32(pl->pl_padding, bufpl->pl_padding); CPIN_8(pl->pl_reserve, bufpl->pl_reserve, 184); } static char _calc_char(unsigned int id) { /* * [0-9A-Za-z!#] - 64 printable chars (6-bits) */ if (id < 10) return id + 48; if (id < 36) return (id - 10) + 65; if (id < 62) return (id - 36) + 97; if (id == 62) return '!'; if (id == 63) return '#'; return '%'; } void get_pool_uuid(char *uuid, uint64_t poolid, uint32_t spid, uint32_t devid) { int i; unsigned shifter = 0x003F; assert(ID_LEN == 32); memset(uuid, 0, ID_LEN); strcat(uuid, "POOL0000000000"); /* We grab the entire 64 bits (+2 that get shifted in) */ for (i = 13; i < 24; i++) { uuid[i] = _calc_char(((unsigned) poolid) & shifter); poolid = poolid >> 6; } /* We grab the entire 32 bits (+4 that get shifted in) */ for (i = 24; i < 30; i++) { uuid[i] = _calc_char((unsigned) (spid & shifter)); spid = spid >> 6; } /* * Since we can only have 128 devices, we only worry about the * last 12 bits */ for (i = 30; i < 32; i++) { uuid[i] = _calc_char((unsigned) (devid & shifter)); devid = devid >> 6; } } struct _read_pool_pv_baton { const struct format_type *fmt; struct dm_pool *mem, *tmpmem; struct pool_list *pl; struct dm_list *head; const char *vgname; uint32_t *sp_devs; int sp_count; int failed; int empty; }; static int _read_pool_pv(struct lvmcache_info *info, void *baton) { struct _read_pool_pv_baton *b = baton; b->empty = 0; if (lvmcache_device(info) && !(b->pl = read_pool_disk(b->fmt, lvmcache_device(info), b->mem, b->vgname))) return 0; /* * We need to keep track of the total expected number * of devices per subpool */ if (!b->sp_count) { /* FIXME pl left uninitialised if !info->dev */ if (!b->pl) { log_error(INTERNAL_ERROR "device is missing"); dm_pool_destroy(b->tmpmem); b->failed = 1; return 0; } b->sp_count = b->pl->pd.pl_subpools; if (!(b->sp_devs = dm_pool_zalloc(b->tmpmem, sizeof(uint32_t) * b->sp_count))) { log_error("Unable to allocate %d 32-bit uints", b->sp_count); dm_pool_destroy(b->tmpmem); b->failed = 1; return 0; } } /* * watch out for a pool label with a different subpool * count than the original - give up if it does */ if (b->sp_count != b->pl->pd.pl_subpools) return 0; _add_pl_to_list(b->head, b->pl); if (b->sp_count > b->pl->pd.pl_sp_id && b->sp_devs[b->pl->pd.pl_sp_id] == 0) b->sp_devs[b->pl->pd.pl_sp_id] = b->pl->pd.pl_sp_devs; return 1; } static int _read_vg_pds(struct _read_pool_pv_baton *b, struct lvmcache_vginfo *vginfo, uint32_t *devcount) { uint32_t i; b->sp_count = 0; b->sp_devs = NULL; b->failed = 0; b->pl = NULL; /* FIXME: maybe should return a different error in memory * allocation failure */ if (!(b->tmpmem = dm_pool_create("pool read_vg", 512))) return_0; lvmcache_foreach_pv(vginfo, _read_pool_pv, b); *devcount = 0; for (i = 0; i < b->sp_count; i++) *devcount += b->sp_devs[i]; dm_pool_destroy(b->tmpmem); if (b->pl && *b->pl->pd.pl_pool_name) return 1; return 0; } int read_pool_pds(const struct format_type *fmt, const char *vg_name, struct dm_pool *mem, struct dm_list *pdhead) { struct lvmcache_vginfo *vginfo; uint32_t totaldevs; int full_scan = -1; struct _read_pool_pv_baton baton; baton.vgname = vg_name; baton.mem = mem; baton.fmt = fmt; baton.head = pdhead; baton.empty = 1; do { /* * If the cache scanning doesn't work, this will never work */ if (vg_name && (vginfo = lvmcache_vginfo_from_vgname(vg_name, NULL)) && _read_vg_pds(&baton, vginfo, &totaldevs) && !baton.empty) { /* * If we found all the devices we were expecting, return * success */ if (dm_list_size(pdhead) == totaldevs) return 1; /* * accept partial pool if we've done a full rescan of * the cache */ if (full_scan > 0) return 1; } /* Failed */ dm_list_init(pdhead); full_scan++; if (full_scan > 1) { log_debug("No devices for vg %s found in cache", vg_name); return 0; } lvmcache_label_scan(fmt->cmd, full_scan); } while (1); } struct pool_list *read_pool_disk(const struct format_type *fmt, struct device *dev, struct dm_pool *mem, const char *vg_name) { struct pool_list *pl; if (!dev_open_readonly(dev)) return_NULL; if (!(pl = dm_pool_zalloc(mem, sizeof(*pl)))) { log_error("Unable to allocate pool list structure"); return 0; } if (!__read_pool_disk(fmt, dev, mem, pl, vg_name)) return_NULL; if (!dev_close(dev)) stack; return pl; } lvm2-2.02.98/lib/format_pool/pool_label.h0000640000175000017500000000134112037016272017057 0ustar blankblank/* * Copyright (C) 1997-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_POOL_LABEL_H #define _LVM_POOL_LABEL_H #include "metadata.h" struct labeller *pool_labeller_create(struct format_type *fmt); #endif lvm2-2.02.98/lib/format_pool/import_export.c0000640000175000017500000001513012037016272017656 0ustar blankblank/* * Copyright (C) 1997-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 */ #include "lib.h" #include "label.h" #include "metadata.h" #include "disk_rep.h" #include "sptype_names.h" #include "lv_alloc.h" #include "pv_alloc.h" #include "str_list.h" #include "display.h" #include "segtype.h" #include "toolcontext.h" /* This file contains only imports at the moment... */ int import_pool_vg(struct volume_group *vg, struct dm_pool *mem, struct dm_list *pls) { struct pool_list *pl; dm_list_iterate_items(pl, pls) { vg->extent_count += ((pl->pd.pl_blocks) / POOL_PE_SIZE); vg->free_count = vg->extent_count; if (vg->name) continue; vg->name = dm_pool_strdup(mem, pl->pd.pl_pool_name); get_pool_vg_uuid(&vg->id, &pl->pd); vg->extent_size = POOL_PE_SIZE; vg->status |= LVM_READ | LVM_WRITE | CLUSTERED | SHARED; vg->max_lv = 1; vg->max_pv = POOL_MAX_DEVICES; vg->alloc = ALLOC_NORMAL; } return 1; } int import_pool_lvs(struct volume_group *vg, struct dm_pool *mem, struct dm_list *pls) { struct pool_list *pl; struct logical_volume *lv; if (!(lv = alloc_lv(mem))) return_0; lv->status = 0; lv->alloc = ALLOC_NORMAL; lv->size = 0; lv->name = NULL; lv->le_count = 0; lv->read_ahead = vg->cmd->default_settings.read_ahead; dm_list_iterate_items(pl, pls) { lv->size += pl->pd.pl_blocks; if (lv->name) continue; if (!(lv->name = dm_pool_strdup(mem, pl->pd.pl_pool_name))) return_0; get_pool_lv_uuid(lv->lvid.id, &pl->pd); log_debug("Calculated lv uuid for lv %s: %s", lv->name, lv->lvid.s); lv->status |= VISIBLE_LV | LVM_READ | LVM_WRITE; lv->major = POOL_MAJOR; /* for pool a minor of 0 is dynamic */ if (pl->pd.pl_minor) { lv->status |= FIXED_MINOR; lv->minor = pl->pd.pl_minor + MINOR_OFFSET; } else { lv->minor = -1; } } lv->le_count = lv->size / POOL_PE_SIZE; return link_lv_to_vg(vg, lv); } int import_pool_pvs(const struct format_type *fmt, struct volume_group *vg, struct dm_pool *mem, struct dm_list *pls) { struct pv_list *pvl; struct pool_list *pl; dm_list_iterate_items(pl, pls) { if (!(pvl = dm_pool_zalloc(mem, sizeof(*pvl)))) { log_error("Unable to allocate pv list structure"); return 0; } if (!(pvl->pv = dm_pool_zalloc(mem, sizeof(*pvl->pv)))) { log_error("Unable to allocate pv structure"); return 0; } if (!import_pool_pv(fmt, mem, vg, pvl->pv, pl)) { return 0; } pl->pv = pvl->pv; pvl->mdas = NULL; pvl->pe_ranges = NULL; add_pvl_to_vgs(vg, pvl); } return 1; } int import_pool_pv(const struct format_type *fmt, struct dm_pool *mem, struct volume_group *vg, struct physical_volume *pv, struct pool_list *pl) { struct pool_disk *pd = &pl->pd; memset(pv, 0, sizeof(*pv)); get_pool_pv_uuid(&pv->id, pd); pv->fmt = fmt; pv->dev = pl->dev; if (!(pv->vg_name = dm_pool_strdup(mem, pd->pl_pool_name))) { log_error("Unable to duplicate vg_name string"); return 0; } if (vg != NULL) memcpy(&pv->vgid, &vg->id, sizeof(vg->id)); pv->status = 0; pv->size = pd->pl_blocks; pv->pe_size = POOL_PE_SIZE; pv->pe_start = POOL_PE_START; pv->pe_count = pv->size / POOL_PE_SIZE; pv->pe_alloc_count = 0; pv->pe_align = 0; dm_list_init(&pv->tags); dm_list_init(&pv->segments); if (!alloc_pv_segment_whole_pv(mem, pv)) return_0; return 1; } static const char *_cvt_sptype(uint32_t sptype) { int i; for (i = 0; sptype_names[i].name[0]; i++) { if (sptype == sptype_names[i].label) { break; } } log_debug("Found sptype %X and converted it to %s", sptype, sptype_names[i].name); return sptype_names[i].name; } static int _add_stripe_seg(struct dm_pool *mem, struct user_subpool *usp, struct logical_volume *lv, uint32_t *le_cur) { struct lv_segment *seg; struct segment_type *segtype; unsigned j; uint32_t area_len; if (usp->striping & (usp->striping - 1)) { log_error("Stripe size must be a power of 2"); return 0; } area_len = (usp->devs[0].blocks) / POOL_PE_SIZE; if (!(segtype = get_segtype_from_string(lv->vg->cmd, "striped"))) return_0; if (!(seg = alloc_lv_segment(segtype, lv, *le_cur, area_len * usp->num_devs, 0, usp->striping, NULL, NULL, usp->num_devs, area_len, 0, 0, 0, NULL))) { log_error("Unable to allocate striped lv_segment structure"); return 0; } for (j = 0; j < usp->num_devs; j++) if (!set_lv_segment_area_pv(seg, j, usp->devs[j].pv, 0)) return_0; /* add the subpool type to the segment tag list */ if (!str_list_add(mem, &seg->tags, _cvt_sptype(usp->type))) { log_error("Allocation failed for str_list."); return 0; } dm_list_add(&lv->segments, &seg->list); *le_cur += seg->len; return 1; } static int _add_linear_seg(struct dm_pool *mem, struct user_subpool *usp, struct logical_volume *lv, uint32_t *le_cur) { struct lv_segment *seg; struct segment_type *segtype; unsigned j; uint32_t area_len; if (!(segtype = get_segtype_from_string(lv->vg->cmd, "striped"))) return_0; for (j = 0; j < usp->num_devs; j++) { area_len = (usp->devs[j].blocks) / POOL_PE_SIZE; if (!(seg = alloc_lv_segment(segtype, lv, *le_cur, area_len, 0, usp->striping, NULL, NULL, 1, area_len, POOL_PE_SIZE, 0, 0, NULL))) { log_error("Unable to allocate linear lv_segment " "structure"); return 0; } /* add the subpool type to the segment tag list */ if (!str_list_add(mem, &seg->tags, _cvt_sptype(usp->type))) { log_error("Allocation failed for str_list."); return 0; } if (!set_lv_segment_area_pv(seg, 0, usp->devs[j].pv, 0)) return_0; dm_list_add(&lv->segments, &seg->list); *le_cur += seg->len; } return 1; } int import_pool_segments(struct dm_list *lvs, struct dm_pool *mem, struct user_subpool *usp, int subpools) { struct lv_list *lvl; struct logical_volume *lv; uint32_t le_cur = 0; int i; dm_list_iterate_items(lvl, lvs) { lv = lvl->lv; if (lv->status & SNAPSHOT) continue; for (i = 0; i < subpools; i++) { if (usp[i].striping) { if (!_add_stripe_seg(mem, &usp[i], lv, &le_cur)) return_0; } else { if (!_add_linear_seg(mem, &usp[i], lv, &le_cur)) return_0; } } } return 1; } lvm2-2.02.98/lib/format_pool/sptype_names.h0000640000175000017500000000223512037016272017461 0ustar blankblank/* * Copyright (C) 1997-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 SPTYPE_NAMES_H #define SPTYPE_NAMES_H /* This must be kept up to date with sistina/pool/module/pool_sptypes.h */ /* Generic Labels */ #define SPTYPE_DATA (0x00000000) /* GFS specific labels */ #define SPTYPE_GFS_DATA (0x68011670) #define SPTYPE_GFS_JOURNAL (0x69011670) struct sptype_name { const char *name; uint32_t label; }; static const struct sptype_name sptype_names[] = { {"data", SPTYPE_DATA}, {"gfs_data", SPTYPE_GFS_DATA}, {"gfs_journal", SPTYPE_GFS_JOURNAL}, {"", 0x0} /* This must be the last flag. */ }; #endif lvm2-2.02.98/lib/format_pool/disk_rep.h0000640000175000017500000001316112037016272016552 0ustar blankblank/* * Copyright (C) 1997-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 DISK_REP_FORMAT_POOL_H #define DISK_REP_FORMAT_POOL_H #include "label.h" #include "metadata.h" #define MINOR_OFFSET 65536 /* From NSP.cf */ #define NSPMajorVersion 4 #define NSPMinorVersion 1 #define NSPUpdateLevel 3 /* From pool_std.h */ #define POOL_NAME_SIZE (256) #define POOL_MAGIC 0x011670 #define POOL_MAJOR (121) #define POOL_MAX_DEVICES 128 /* When checking for version matching, the first two numbers ** ** are important for metadata formats, a.k.a pool labels. ** ** All the numbers are important when checking if the user ** ** space tools match up with the kernel module............. */ #define POOL_VERSION (NSPMajorVersion << 16 | \ NSPMinorVersion << 8 | \ NSPUpdateLevel) /* Pool label is at the head of every pool disk partition */ #define SIZEOF_POOL_LABEL (8192) /* in sectors */ #define POOL_PE_SIZE (SIZEOF_POOL_LABEL >> SECTOR_SHIFT) #define POOL_PE_START (SIZEOF_POOL_LABEL >> SECTOR_SHIFT) /* Helper fxns */ #define get_pool_vg_uuid(id, pd) do { get_pool_uuid((char *)(id), \ (pd)->pl_pool_id, 0, 0); \ } while(0) #define get_pool_pv_uuid(id, pd) do { get_pool_uuid((char *)(id), \ (pd)->pl_pool_id, \ (pd)->pl_sp_id, \ (pd)->pl_sp_devid); \ } while(0) #define get_pool_lv_uuid(id, pd) do { get_pool_uuid((char *)&(id)[0], \ (pd)->pl_pool_id, 0, 0); \ get_pool_uuid((char*)&(id)[1], \ (pd)->pl_pool_id, 0, 0); \ } while(0) struct pool_disk; struct pool_list; struct user_subpool; struct user_device; struct pool_disk { uint64_t pl_magic; /* Pool magic number */ uint64_t pl_pool_id; /* Unique pool identifier */ char pl_pool_name[POOL_NAME_SIZE]; /* Name of pool */ uint32_t pl_version; /* Pool version */ uint32_t pl_subpools; /* Number of subpools in this pool */ uint32_t pl_sp_id; /* Subpool number within pool */ uint32_t pl_sp_devs; /* Number of data partitions in this subpool */ uint32_t pl_sp_devid; /* Partition number within subpool */ uint32_t pl_sp_type; /* Partition type */ uint64_t pl_blocks; /* Number of blocks in this partition */ uint32_t pl_striping; /* Striping size within subpool */ /* * If the number of DMEP devices is zero, then the next field ** * ** (pl_sp_dmepid) becomes the subpool ID for redirection. In ** * ** other words, if this subpool does not have the capability ** * ** to do DMEP, then it must specify which subpool will do it ** * ** in it's place */ /* * While the next 3 field are no longer used, they must stay to keep ** * ** backward compatibility........................................... */ uint32_t pl_sp_dmepdevs;/* Number of dmep devices in this subpool */ uint32_t pl_sp_dmepid; /* Dmep device number within subpool */ uint32_t pl_sp_weight; /* if dmep dev, pref to using it */ uint32_t pl_minor; /* the pool minor number */ uint32_t pl_padding; /* reminder - think about alignment */ /* * Even though we're zeroing out 8k at the front of the disk before * writing the label, putting this in */ char pl_reserve[184]; /* bump the structure size out to 512 bytes */ }; struct pool_list { struct dm_list list; struct pool_disk pd; struct physical_volume *pv; struct id pv_uuid; struct device *dev; }; struct user_subpool { uint32_t initialized; uint32_t id; uint32_t striping; uint32_t num_devs; uint32_t type; uint32_t dummy; struct user_device *devs; }; struct user_device { uint32_t initialized; uint32_t sp_id; uint32_t devid; uint32_t dummy; uint64_t blocks; struct physical_volume *pv; }; int read_pool_label(struct pool_list *pl, struct labeller *l, struct device *dev, char *buf, struct label **label); void pool_label_out(struct pool_disk *pl, void *buf); void pool_label_in(struct pool_disk *pl, void *buf); void get_pool_uuid(char *uuid, uint64_t poolid, uint32_t spid, uint32_t devid); int import_pool_vg(struct volume_group *vg, struct dm_pool *mem, struct dm_list *pls); int import_pool_lvs(struct volume_group *vg, struct dm_pool *mem, struct dm_list *pls); int import_pool_pvs(const struct format_type *fmt, struct volume_group *vg, struct dm_pool *mem, struct dm_list *pls); int import_pool_pv(const struct format_type *fmt, struct dm_pool *mem, struct volume_group *vg, struct physical_volume *pv, struct pool_list *pl); int import_pool_segments(struct dm_list *lvs, struct dm_pool *mem, struct user_subpool *usp, int sp_count); int read_pool_pds(const struct format_type *fmt, const char *vgname, struct dm_pool *mem, struct dm_list *head); struct pool_list *read_pool_disk(const struct format_type *fmt, struct device *dev, struct dm_pool *mem, const char *vg_name); #endif /* DISK_REP_POOL_FORMAT_H */ lvm2-2.02.98/lib/format_pool/Makefile.in0000640000175000017500000000152512037016272016647 0ustar blankblank# # Copyright (C) 2003-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@ SOURCES =\ disk_rep.c \ format_pool.c \ import_export.c \ pool_label.c LIB_SHARED = liblvm2formatpool.$(LIB_SUFFIX) LIB_VERSION = $(LIB_VERSION_LVM) include $(top_builddir)/make.tmpl install: install_lvm2_plugin lvm2-2.02.98/lib/format_pool/pool_label.c0000640000175000017500000000470712037016272017063 0ustar blankblank/* * Copyright (C) 1997-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 */ #include "lib.h" #include "label.h" #include "metadata.h" #include "disk_rep.h" #include "pool_label.h" #include #include static void _pool_not_supported(const char *op) { log_error("The '%s' operation is not supported for the pool labeller.", op); } static int _pool_can_handle(struct labeller *l __attribute__((unused)), void *buf, uint64_t sector) { struct pool_disk pd; /* * POOL label must always be in first sector */ if (sector) return 0; pool_label_in(&pd, buf); /* can ignore 8 rightmost bits for ondisk format check */ if ((pd.pl_magic == POOL_MAGIC) && (pd.pl_version >> 8 == POOL_VERSION >> 8)) return 1; return 0; } static int _pool_write(struct label *label __attribute__((unused)), void *buf __attribute__((unused))) { _pool_not_supported("write"); return 0; } static int _pool_read(struct labeller *l, struct device *dev, void *buf, struct label **label) { struct pool_list pl; return read_pool_label(&pl, l, dev, buf, label); } static int _pool_initialise_label(struct labeller *l __attribute__((unused)), struct label *label) { strcpy(label->type, "POOL"); return 1; } static void _pool_destroy_label(struct labeller *l __attribute__((unused)), struct label *label __attribute__((unused))) { } static void _label_pool_destroy(struct labeller *l) { dm_free(l); } struct label_ops _pool_ops = { .can_handle = _pool_can_handle, .write = _pool_write, .read = _pool_read, .verify = _pool_can_handle, .initialise_label = _pool_initialise_label, .destroy_label = _pool_destroy_label, .destroy = _label_pool_destroy, }; struct labeller *pool_labeller_create(struct format_type *fmt) { struct labeller *l; if (!(l = dm_malloc(sizeof(*l)))) { log_error("Couldn't allocate labeller object."); return NULL; } l->ops = &_pool_ops; l->private = (const void *) fmt; return l; } lvm2-2.02.98/lib/format_pool/format_pool.h0000640000175000017500000000153012037016272017270 0ustar blankblank/* * Copyright (C) 2003-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_FORMAT_POOL_H #define _LVM_FORMAT_POOL_H #include "metadata.h" #define FMT_POOL_NAME "pool" #define FMT_POOL_ORPHAN_VG_NAME ORPHAN_VG_NAME(FMT_POOL_NAME) #ifdef POOL_INTERNAL struct format_type *init_pool_format(struct cmd_context *cmd); #endif #endif lvm2-2.02.98/lib/format_pool/format_pool.c0000640000175000017500000002053712037016272017273 0ustar blankblank/* * Copyright (C) 1997-2004 Sistina Software, Inc. All rights reserved. * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU 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 "label.h" #include "metadata.h" #include "limits.h" #include "display.h" #include "toolcontext.h" #include "lvmcache.h" #include "disk_rep.h" #include "format_pool.h" #include "pool_label.h" /* Must be called after pvs are imported */ static struct user_subpool *_build_usp(struct dm_list *pls, struct dm_pool *mem, int *sps) { struct pool_list *pl; struct user_subpool *usp = NULL, *cur_sp = NULL; struct user_device *cur_dev = NULL; /* * FIXME: Need to do some checks here - I'm tempted to add a * user_pool structure and build the entire thing to check against. */ dm_list_iterate_items(pl, pls) { *sps = pl->pd.pl_subpools; if (!usp && (!(usp = dm_pool_zalloc(mem, sizeof(*usp) * (*sps))))) { log_error("Unable to allocate %d subpool structures", *sps); return 0; } if (cur_sp != &usp[pl->pd.pl_sp_id]) { cur_sp = &usp[pl->pd.pl_sp_id]; cur_sp->id = pl->pd.pl_sp_id; cur_sp->striping = pl->pd.pl_striping; cur_sp->num_devs = pl->pd.pl_sp_devs; cur_sp->type = pl->pd.pl_sp_type; cur_sp->initialized = 1; } if (!cur_sp->devs && (!(cur_sp->devs = dm_pool_zalloc(mem, sizeof(*usp->devs) * pl->pd.pl_sp_devs)))) { log_error("Unable to allocate %d pool_device " "structures", pl->pd.pl_sp_devs); return 0; } cur_dev = &cur_sp->devs[pl->pd.pl_sp_devid]; cur_dev->sp_id = cur_sp->id; cur_dev->devid = pl->pd.pl_sp_id; cur_dev->blocks = pl->pd.pl_blocks; cur_dev->pv = pl->pv; cur_dev->initialized = 1; } return usp; } static int _check_usp(const char *vgname, struct user_subpool *usp, int sp_count) { int i; unsigned j; for (i = 0; i < sp_count; i++) { if (!usp[i].initialized) { log_error("Missing subpool %d in pool %s", i, vgname); return 0; } for (j = 0; j < usp[i].num_devs; j++) { if (!usp[i].devs[j].initialized) { log_error("Missing device %u for subpool %d" " in pool %s", j, i, vgname); return 0; } } } return 1; } static struct volume_group *_pool_vg_read(struct format_instance *fid, const char *vg_name, struct metadata_area *mda __attribute__((unused)), int single_device __attribute__((unused))) { struct volume_group *vg; struct user_subpool *usp; int sp_count; DM_LIST_INIT(pds); /* We can safely ignore the mda passed in */ /* Strip dev_dir if present */ if (vg_name) vg_name = strip_dir(vg_name, fid->fmt->cmd->dev_dir); /* Set vg_name through read_pool_pds() */ if (!(vg = alloc_vg("pool_vg_read", fid->fmt->cmd, NULL))) return_NULL; /* Read all the pvs in the vg */ if (!read_pool_pds(fid->fmt, vg_name, vg->vgmem, &pds)) goto_bad; vg_set_fid(vg, fid); /* Setting pool seqno to 1 because the code always did this, * although we don't think it's needed. */ vg->seqno = 1; if (!import_pool_vg(vg, vg->vgmem, &pds)) goto_bad; if (!import_pool_pvs(fid->fmt, vg, vg->vgmem, &pds)) goto_bad; if (!import_pool_lvs(vg, vg->vgmem, &pds)) goto_bad; /* * I need an intermediate subpool structure that contains all the * relevant info for this. Then i can iterate through the subpool * structures for checking, and create the segments */ if (!(usp = _build_usp(&pds, vg->vgmem, &sp_count))) goto_bad; /* * check the subpool structures - we can't handle partial VGs in * the pool format, so this will error out if we're missing PVs */ if (!_check_usp(vg->name, usp, sp_count)) goto_bad; if (!import_pool_segments(&vg->lvs, vg->vgmem, usp, sp_count)) goto_bad; return vg; bad: release_vg(vg); return NULL; } static int _pool_pv_initialise(const struct format_type *fmt __attribute__((unused)), int64_t label_sector __attribute__((unused)), uint64_t pe_start __attribute__((unused)), uint32_t extent_count __attribute__((unused)), uint32_t extent_size __attribute__((unused)), unsigned long data_alignment __attribute__((unused)), unsigned long data_alignment_offset __attribute__((unused)), struct physical_volume *pv __attribute__((unused))) { return 1; } static int _pool_pv_setup(const struct format_type *fmt __attribute__((unused)), struct physical_volume *pv __attribute__((unused)), struct volume_group *vg __attribute__((unused))) { return 1; } static int _pool_pv_read(const struct format_type *fmt, const char *pv_name, struct physical_volume *pv, int scan_label_only __attribute__((unused))) { struct dm_pool *mem = dm_pool_create("pool pv_read", 1024); struct pool_list *pl; struct device *dev; int r = 0; log_very_verbose("Reading physical volume data %s from disk", pv_name); if (!mem) return_0; if (!(dev = dev_cache_get(pv_name, fmt->cmd->filter))) goto_out; /* * I need to read the disk and populate a pv structure here * I'll probably need to abstract some of this later for the * vg_read code */ if (!(pl = read_pool_disk(fmt, dev, mem, NULL))) goto_out; if (!import_pool_pv(fmt, fmt->cmd->mem, NULL, pv, pl)) goto_out; pv->fmt = fmt; r = 1; out: dm_pool_destroy(mem); return r; } /* *INDENT-OFF* */ static struct metadata_area_ops _metadata_format_pool_ops = { .vg_read = _pool_vg_read, }; /* *INDENT-ON* */ static struct format_instance *_pool_create_instance(const struct format_type *fmt, const struct format_instance_ctx *fic) { struct format_instance *fid; struct metadata_area *mda; if (!(fid = alloc_fid(fmt, fic))) return_NULL; /* Define a NULL metadata area */ if (!(mda = dm_pool_zalloc(fid->mem, sizeof(*mda)))) { log_error("Unable to allocate metadata area structure " "for pool format"); goto bad; } mda->ops = &_metadata_format_pool_ops; mda->metadata_locn = NULL; mda->status = 0; dm_list_add(&fid->metadata_areas_in_use, &mda->list); return fid; bad: dm_pool_destroy(fid->mem); return NULL; } static void _pool_destroy_instance(struct format_instance *fid) { if (--fid->ref_count <= 1) dm_pool_destroy(fid->mem); } static void _pool_destroy(struct format_type *fmt) { if (fmt->orphan_vg) free_orphan_vg(fmt->orphan_vg); dm_free(fmt); } /* *INDENT-OFF* */ static struct format_handler _format_pool_ops = { .pv_read = _pool_pv_read, .pv_initialise = _pool_pv_initialise, .pv_setup = _pool_pv_setup, .create_instance = _pool_create_instance, .destroy_instance = _pool_destroy_instance, .destroy = _pool_destroy, }; /* *INDENT-ON */ #ifdef POOL_INTERNAL struct format_type *init_pool_format(struct cmd_context *cmd) #else /* Shared */ struct format_type *init_format(struct cmd_context *cmd); struct format_type *init_format(struct cmd_context *cmd) #endif { struct format_type *fmt = dm_malloc(sizeof(*fmt)); struct format_instance_ctx fic; struct format_instance *fid; if (!fmt) { log_error("Unable to allocate format type structure for pool " "format"); return NULL; } fmt->cmd = cmd; fmt->ops = &_format_pool_ops; fmt->name = FMT_POOL_NAME; fmt->alias = NULL; fmt->orphan_vg_name = FMT_POOL_ORPHAN_VG_NAME; fmt->features = 0; fmt->private = NULL; dm_list_init(&fmt->mda_ops); if (!(fmt->labeller = pool_labeller_create(fmt))) { log_error("Couldn't create pool label handler."); dm_free(fmt); return NULL; } if (!(label_register_handler(FMT_POOL_NAME, fmt->labeller))) { log_error("Couldn't register pool label handler."); fmt->labeller->ops->destroy(fmt->labeller); dm_free(fmt); return NULL; } if (!(fmt->orphan_vg = alloc_vg("pool_orphan", cmd, fmt->orphan_vg_name))) { log_error("Couldn't create pool orphan VG."); dm_free(fmt); return NULL; } fic.type = FMT_INSTANCE_AUX_MDAS; fic.context.vg_ref.vg_name = fmt->orphan_vg_name; fic.context.vg_ref.vg_id = NULL; if (!(fid = _pool_create_instance(fmt, &fic))) { _pool_destroy(fmt); return NULL; } vg_set_fid(fmt->orphan_vg, fid); log_very_verbose("Initialised format: %s", fmt->name); return fmt; } lvm2-2.02.98/lib/error/0000750000175000017500000000000012037016272013406 5ustar blankblanklvm2-2.02.98/lib/error/errseg.c0000640000175000017500000000573712037016272015056 0ustar blankblank/* * 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 "toolcontext.h" #include "segtype.h" #include "display.h" #include "config.h" #include "str_list.h" #include "activate.h" #include "str_list.h" static const char *_errseg_name(const struct lv_segment *seg) { return seg->segtype->name; } static int _errseg_merge_segments(struct lv_segment *seg1, struct lv_segment *seg2) { seg1->len += seg2->len; seg1->area_len += seg2->area_len; return 1; } #ifdef DEVMAPPER_SUPPORT static int _errseg_add_target_line(struct dev_manager *dm __attribute__((unused)), struct dm_pool *mem __attribute__((unused)), struct cmd_context *cmd __attribute__((unused)), void **target_state __attribute__((unused)), struct lv_segment *seg __attribute__((unused)), const struct lv_activate_opts *laopts __attribute__((unused)), struct dm_tree_node *node, uint64_t len, uint32_t *pvmove_mirror_count __attribute__((unused))) { return dm_tree_node_add_error_target(node, len); } static int _errseg_target_present(struct cmd_context *cmd, const struct lv_segment *seg __attribute__((unused)), unsigned *attributes __attribute__((unused))) { static int _errseg_checked = 0; static int _errseg_present = 0; /* Reported truncated in older kernels */ if (!_errseg_checked && (target_present(cmd, "error", 0) || target_present(cmd, "erro", 0))) _errseg_present = 1; _errseg_checked = 1; return _errseg_present; } #endif static int _errseg_modules_needed(struct dm_pool *mem, const struct lv_segment *seg __attribute__((unused)), struct dm_list *modules) { if (!str_list_add(mem, modules, "error")) { log_error("error module string list allocation failed"); return 0; } return 1; } static void _errseg_destroy(struct segment_type *segtype) { dm_free(segtype); } static struct segtype_handler _error_ops = { .name = _errseg_name, .merge_segments = _errseg_merge_segments, #ifdef DEVMAPPER_SUPPORT .add_target_line = _errseg_add_target_line, .target_present = _errseg_target_present, #endif .modules_needed = _errseg_modules_needed, .destroy = _errseg_destroy, }; struct segment_type *init_error_segtype(struct cmd_context *cmd) { struct segment_type *segtype = dm_zalloc(sizeof(*segtype)); if (!segtype) return_NULL; segtype->cmd = cmd; segtype->ops = &_error_ops; segtype->name = "error"; segtype->private = NULL; segtype->flags = SEG_CAN_SPLIT | SEG_VIRTUAL | SEG_CANNOT_BE_ZEROED; log_very_verbose("Initialised segtype: %s", segtype->name); return segtype; } lvm2-2.02.98/lib/replicator/0000750000175000017500000000000012037016272014421 5ustar blankblanklvm2-2.02.98/lib/replicator/.exported_symbols0000640000175000017500000000001512037016272020021 0ustar blankblankinit_segtype lvm2-2.02.98/lib/replicator/replicator.c0000640000175000017500000005272212037016272016742 0ustar blankblank/* * 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 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 "toolcontext.h" #include "metadata.h" #include "segtype.h" #include "text_export.h" #include "activate.h" #include "str_list.h" #ifdef DMEVENTD # include "libdevmapper-event.h" #endif /* Dm kernel module name for replicator */ #define REPLICATOR_MODULE "replicator" #define REPLICATOR_DEV_MODULE "replicator-dev" /* * Macro used as return argument - returns 0. * return is left to be written in the function for better readability. */ #define SEG_LOG_ERROR(t, p...) \ log_error(t " segment %s of logical volume %s.", ## p, \ dm_config_parent_name(sn), seg->lv->name), 0; /* * Replicator target */ static const char *_replicator_name(const struct lv_segment *seg) { return seg->segtype->name; } /* FIXME: missing implementation */ static void _replicator_display(const struct lv_segment *seg) { //const char *size; //uint32_t s; log_print(" Replicator"); if (seg->rlog_lv) log_print(" Replicator volume\t%s", seg->rlog_lv->name); } /* Wrapper for dm_config_get_uint32() with default value */ static uint32_t _get_config_uint32(const struct dm_config_node *cn, const char *path, uint32_t def) { uint32_t t; return dm_config_get_uint32(cn, path, &t) ? t : def; } /* Wrapper for dm_config_get_uint64() with default value */ static uint64_t _get_config_uint64(const struct dm_config_node *cn, const char *path, uint64_t def) { uint64_t t; return dm_config_get_uint64(cn, path, &t) ? t : def; } /* Strings replicator_state_t enum */ static const char _state_txt[NUM_REPLICATOR_STATE][8] = { "passive", "active" }; /* Parse state string */ static replicator_state_t _get_state(const struct dm_config_node *sn, const char *path, replicator_state_t def) { const char *str; unsigned i; if (dm_config_get_str(sn, path, &str)) { for (i = 0; i < sizeof(_state_txt)/sizeof(_state_txt[0]); ++i) if (strcasecmp(str, _state_txt[i]) == 0) return (replicator_state_t) i; log_warn("%s: unknown value '%s', using default '%s' state", path, str, _state_txt[def]); } return def; } /* Strings for replicator_action_t enum */ static const char _op_mode_txt[NUM_DM_REPLICATOR_MODES][8] = { "sync", "warn", "stall", "drop", "fail" }; /* Parse action string */ static dm_replicator_mode_t _get_op_mode(const struct dm_config_node *sn, const char *path, dm_replicator_mode_t def) { const char *str; unsigned i; if (dm_config_get_str(sn, path, &str)) { for (i = 0; i < sizeof(_op_mode_txt)/sizeof(_op_mode_txt[0]); ++i) if (strcasecmp(str, _op_mode_txt[i]) == 0) { log_very_verbose("Setting %s to %s", path, _op_mode_txt[i]); return (dm_replicator_mode_t) i; } log_warn("%s: unknown value '%s', using default '%s' operation mode", path, str, _op_mode_txt[def]); } return def; } static struct replicator_site *_get_site(struct logical_volume *replicator, const char *key) { struct dm_pool *mem = replicator->vg->vgmem; struct replicator_site *rsite; dm_list_iterate_items(rsite, &replicator->rsites) if (strcasecmp(rsite->name, key) == 0) return rsite; if (!(rsite = dm_pool_zalloc(mem, sizeof(*rsite)))) return_NULL; if (!(rsite->name = dm_pool_strdup(mem, key))) return_NULL; rsite->replicator = replicator; dm_list_init(&rsite->rdevices); dm_list_add(&replicator->rsites, &rsite->list); return rsite; } /* Parse replicator site element */ static int _add_site(struct lv_segment *seg, const char *key, const struct dm_config_node *sn) { struct dm_pool *mem = seg->lv->vg->vgmem; const struct dm_config_node *cn; struct replicator_site *rsite; if (!(rsite = _get_site(seg->lv, key))) return_0; if (!dm_config_find_node(sn, "site_index")) return SEG_LOG_ERROR("Mandatory site_index is missing for"); rsite->state = _get_state(sn, "state", REPLICATOR_STATE_PASSIVE); rsite->site_index = _get_config_uint32(sn, "site_index", 0); if (rsite->site_index > seg->rsite_index_highest) return SEG_LOG_ERROR("site_index=%d > highest_site_index=%d for", rsite->site_index, seg->rsite_index_highest); rsite->fall_behind_data = _get_config_uint64(sn, "fall_behind_data", 0); rsite->fall_behind_ios = _get_config_uint32(sn, "fall_behind_ios", 0); rsite->fall_behind_timeout = _get_config_uint32(sn, "fall_behind_timeout", 0); rsite->op_mode = DM_REPLICATOR_SYNC; if (rsite->fall_behind_data || rsite->fall_behind_ios || rsite->fall_behind_timeout) { if (rsite->fall_behind_data && rsite->fall_behind_ios) return SEG_LOG_ERROR("Defined both fall_behind_data " "and fall_behind_ios in"); if (rsite->fall_behind_data && rsite->fall_behind_timeout) return SEG_LOG_ERROR("Defined both fall_behind_data " "and fall_behind_timeout in"); if (rsite->fall_behind_ios && rsite->fall_behind_timeout) return SEG_LOG_ERROR("Defined both fall_behind_ios " "and fall_behind_timeout in"); rsite->op_mode = _get_op_mode(sn, "operation_mode", rsite->op_mode); } if ((cn = dm_config_find_node(sn, "volume_group"))) { if (!cn->v || cn->v->type != DM_CFG_STRING) return SEG_LOG_ERROR("volume_group must be a string in"); if (!(rsite->vg_name = dm_pool_strdup(mem, cn->v->v.str))) return_0; } else if (rsite->site_index != 0) return SEG_LOG_ERROR("volume_group is mandatory for remote site in"); return 1; } /* Import replicator segment */ static int _replicator_text_import(struct lv_segment *seg, const struct dm_config_node *sn, struct dm_hash_table *pv_hash __attribute__((unused))) { const struct dm_config_node *cn; struct logical_volume *rlog_lv; if (!replicator_add_replicator_dev(seg->lv, NULL)) return_0; if (!(cn = dm_config_find_node(sn, "replicator_log")) || !cn->v || cn->v->type != DM_CFG_STRING) return SEG_LOG_ERROR("Replicator log type must be a string in"); if (!(rlog_lv = find_lv(seg->lv->vg, cn->v->v.str))) return SEG_LOG_ERROR("Unknown replicator log %s in", cn->v->v.str); if (!(cn = dm_config_find_node(sn, "replicator_log_type")) || !cn->v || cn->v->type != DM_CFG_STRING) return SEG_LOG_ERROR("Replicator log's type must be a string in"); if (strcasecmp(cn->v->v.str, "ringbuffer")) return SEG_LOG_ERROR("Only ringbuffer replicator log type is supported in"); if (!(seg->rlog_type = dm_pool_strdup(seg->lv->vg->vgmem, cn->v->v.str))) return_0; log_very_verbose("replicator_log = %s", rlog_lv->name); log_very_verbose("replicator_log_type = %s", seg->rlog_type); if (!replicator_add_rlog(seg, rlog_lv)) return_0; seg->rdevice_index_highest = _get_config_uint64(sn, "highest_device_index", 0); seg->rsite_index_highest = _get_config_uint32(sn, "highest_site_index", 0); seg->region_size = _get_config_uint32(sn, "sync_log_size", 0); for (; sn; sn = sn->sib) if (!sn->v) { for (cn = sn->sib; cn; cn = cn->sib) if (!cn->v && (strcasecmp(cn->key ,sn->key) == 0)) return SEG_LOG_ERROR("Detected duplicate site " "name %s in", sn->key); if (!_add_site(seg, sn->key, sn->child)) return_0; } return 1; } /* Export replicator segment */ static int _replicator_text_export(const struct lv_segment *seg, struct formatter *f) { struct replicator_site *rsite; if (!seg->rlog_lv) return_0; outf(f, "replicator_log = \"%s\"", seg->rlog_lv->name); outf(f, "replicator_log_type = \"%s\"", seg->rlog_type); outf(f, "highest_device_index = %" PRIu64, seg->rdevice_index_highest); outf(f, "highest_site_index = %d", seg->rsite_index_highest); if (seg->region_size) outsize(f, (uint64_t)seg->region_size, "sync_log_size = %" PRIu32, seg->region_size); if (!dm_list_empty(&seg->lv->rsites)) outnl(f); dm_list_iterate_items(rsite, &seg->lv->rsites) { outf(f, "%s {", rsite->name); out_inc_indent(f); outf(f, "state = \"%s\"", _state_txt[rsite->state]); outf(f, "site_index = %d", rsite->site_index); /* Only non-default parameters are written */ if (rsite->op_mode != DM_REPLICATOR_SYNC) outf(f, "operation_mode = \"%s\"", _op_mode_txt[rsite->op_mode]); if (rsite->fall_behind_timeout) outfc(f, "# seconds", "fall_behind_timeout = %u", rsite->fall_behind_timeout); if (rsite->fall_behind_ios) outfc(f, "# io operations", "fall_behind_ios = %u", rsite->fall_behind_ios); if (rsite->fall_behind_data) outsize(f, rsite->fall_behind_data, "fall_behind_data = %" PRIu64, rsite->fall_behind_data); if (rsite->state != REPLICATOR_STATE_ACTIVE && rsite->vg_name) outf(f, "volume_group = \"%s\"", rsite->vg_name); out_dec_indent(f); outf(f, "}"); } return 1; } #ifdef DEVMAPPER_SUPPORT static int _replicator_add_target_line(struct dev_manager *dm, struct dm_pool *mem, struct cmd_context *cmd, void **target_state, struct lv_segment *seg, const struct lv_activate_opts *laopts, struct dm_tree_node *node, uint64_t len, uint32_t *pvmove_mirror_count) { const char *rlog_dlid; struct replicator_site *rsite; if (!seg->rlog_lv) return_0; if (!(rlog_dlid = build_dm_uuid(mem, seg->rlog_lv->lvid.s, NULL))) return_0; dm_list_iterate_items(rsite, &seg->lv->rsites) { if (!dm_tree_node_add_replicator_target(node, seg->rlog_lv->size, rlog_dlid, seg->rlog_type, rsite->site_index, rsite->op_mode, rsite->fall_behind_timeout, rsite->fall_behind_data, rsite->fall_behind_ios)) { if (rsite->site_index == 0) { log_error("Failed to add replicator log '%s' " "to replicator '%s'.", rlog_dlid, seg->lv->name); return 0; } // FIXME: } } return 1; } /* FIXME: write something useful for replicator here */ static int _replicator_target_percent(void **target_state, percent_t *percent, struct dm_pool *mem, struct cmd_context *cmd, struct lv_segment *seg, char *params, uint64_t *total_numerator, uint64_t *total_denominator) { return 1; } /* Check for module presence */ static int _replicator_target_present(struct cmd_context *cmd, const struct lv_segment *seg __attribute__((unused)), unsigned *attributes __attribute__((unused))) { static int _checked = 0; static int _present = 0; if (!_checked) { _present = target_present(cmd, REPLICATOR_MODULE, 1); _checked = 1; } return _present; } #endif static int _replicator_modules_needed(struct dm_pool *mem, const struct lv_segment *seg __attribute__((unused)), struct dm_list *modules) { if (!str_list_add(mem, modules, REPLICATOR_MODULE)) return_0; if (!str_list_add(mem, modules, REPLICATOR_DEV_MODULE)) return_0; return 1; } static void _replicator_destroy(struct segment_type *segtype) { dm_free(segtype); } static struct segtype_handler _replicator_ops = { .name = _replicator_name, .display = _replicator_display, .text_import = _replicator_text_import, .text_export = _replicator_text_export, #ifdef DEVMAPPER_SUPPORT .add_target_line = _replicator_add_target_line, .target_percent = _replicator_target_percent, .target_present = _replicator_target_present, #endif .modules_needed = _replicator_modules_needed, .destroy = _replicator_destroy, }; /* * Replicator-dev target */ static void _replicator_dev_display(const struct lv_segment *seg) { //const char *size; //uint32_t s; // FIXME: debug test code for now log_print(" Replicator\t\t%u", seg->area_count); log_print(" Mirror size\t\t%u", seg->area_len); if (seg->log_lv) log_print(" Replicator log volume\t%s", seg->rlog_lv->name); } static int _add_device(struct lv_segment *seg, const char *site_name, const struct dm_config_node *sn, uint64_t devidx) { struct dm_pool *mem = seg->lv->vg->vgmem; struct logical_volume *lv = NULL; struct logical_volume *slog_lv = NULL; struct replicator_site *rsite = _get_site(seg->replicator, site_name); struct replicator_device *rdev; const char *dev_str = NULL; const char *slog_str = NULL; const struct dm_config_node *cn; dm_list_iterate_items(rdev, &rsite->rdevices) if (rdev->replicator_dev == seg) return SEG_LOG_ERROR("Duplicate site found in"); if ((cn = dm_config_find_node(sn, "sync_log"))) { if (!cn->v || !cn->v->v.str) return SEG_LOG_ERROR("Sync log must be a string in"); slog_str = cn->v->v.str; } if (!(cn = dm_config_find_node(sn, "logical_volume")) || !cn->v || !cn->v->v.str) return SEG_LOG_ERROR("Logical volume must be a string in"); dev_str = cn->v->v.str; if (!seg->lv->rdevice) { if (slog_str) return SEG_LOG_ERROR("Sync log %s defined for local " "device in", slog_str); /* Check for device in current VG */ if (!(lv = find_lv(seg->lv->vg, dev_str))) return SEG_LOG_ERROR("Logical volume %s not found in", dev_str); } else { if (!slog_str) return SEG_LOG_ERROR("Sync log is missing for remote " "device in"); /* Check for slog device in current VG */ if (!(slog_lv = find_lv(seg->lv->vg, slog_str))) return SEG_LOG_ERROR("Sync log %s not found in", slog_str); } if (!(rdev = dm_pool_zalloc(mem, sizeof(*rdev)))) return_0; if (!(rdev->name = dm_pool_strdup(mem, dev_str))) return_0; rdev->replicator_dev = seg; rdev->rsite = rsite; rdev->device_index = devidx; if (!seg->lv->rdevice) { if (!replicator_dev_add_rimage(rdev, lv)) return SEG_LOG_ERROR("LV inconsistency found in"); seg->lv->rdevice = rdev; } else { if (!slog_str || !(rdev->slog_name = dm_pool_strdup(mem, slog_str))) return_0; if (!replicator_dev_add_slog(rdev, slog_lv)) return SEG_LOG_ERROR("Sync log inconsistency found in"); } dm_list_add(&rsite->rdevices, &rdev->list);// linked site list return 1; } /* Import replicator segment */ static int _replicator_dev_text_import(struct lv_segment *seg, const struct dm_config_node *sn, struct dm_hash_table *pv_hash __attribute__((unused))) { const struct dm_config_node *cn; struct logical_volume *replicator; uint64_t devidx; if (!(cn = dm_config_find_node(sn, "replicator"))) return SEG_LOG_ERROR("Replicator is missing for"); if (!cn->v || !cn->v->v.str) return SEG_LOG_ERROR("Replicator must be a string for"); if (!(replicator = find_lv(seg->lv->vg, cn->v->v.str))) return SEG_LOG_ERROR("Unknown replicator %s for", cn->v->v.str); if (!replicator_add_replicator_dev(replicator, seg)) return_0; log_very_verbose("replicator=%s", replicator->name); /* Mandatory */ if (!dm_config_find_node(sn, "device_index") || !dm_config_get_uint64(sn, "device_index", &devidx)) return SEG_LOG_ERROR("Could not read 'device_index' for"); /* Read devices from sites */ for (; sn; sn = sn->sib) if (!(sn->v) && !_add_device(seg, sn->key, sn->child, devidx)) return_0; if (!seg->lv->rdevice) return SEG_LOG_ERROR("Replicator device without site in"); seg->rlog_lv = NULL; seg->lv->status |= REPLICATOR; return 1; } /* Export replicator-dev segment */ static int _replicator_dev_text_export(const struct lv_segment *seg, struct formatter *f) { struct replicator_site *rsite; struct replicator_device *rdev; if (!seg->replicator || !seg->lv->rdevice) return_0; outf(f, "replicator = \"%s\"", seg->replicator->name); outf(f, "device_index = %" PRId64, seg->lv->rdevice->device_index); outnl(f); dm_list_iterate_items(rsite, &seg->replicator->rsites) { dm_list_iterate_items(rdev, &rsite->rdevices) { if (rdev->replicator_dev != seg) continue; outf(f, "%s {", rdev->rsite->name); out_inc_indent(f); outf(f, "logical_volume = \"%s\"", rdev->name ? rdev->name : rdev->lv->name); if (rdev->slog) outf(f, "sync_log = \"%s\"", rdev->slog->name); else if (rdev->slog_name) outf(f, "sync_log = \"%s\"", rdev->slog_name); out_dec_indent(f); outf(f, "}"); } } return 1; } #ifdef DEVMAPPER_SUPPORT /* * Add target for passive site matching the device index */ static int _replicator_dev_add_target_line(struct dev_manager *dm, struct dm_pool *mem, struct cmd_context *cmd, void **target_state, struct lv_segment *seg, const struct lv_activate_opts *laopts, struct dm_tree_node *node, uint64_t len, uint32_t *pvmove_mirror_count) { const char *replicator_dlid, *rdev_dlid, *slog_dlid; struct replicator_device *rdev, *rdev_search; struct replicator_site *rsite; uint32_t slog_size; uint32_t slog_flags; if (!lv_is_active_replicator_dev(seg->lv)) { /* Create passive linear mapping */ log_very_verbose("Inactive replicator %s using %s.", seg->lv->name, seg->lv->rdevice->lv->name); if (!add_linear_area_to_dtree(node, seg->lv->size, seg->lv->vg->extent_size, cmd->use_linear_target, seg->lv->vg->name, seg->lv->name)) return_0; if (!(rdev_dlid = build_dm_uuid(mem, seg->lv->rdevice->lv->lvid.s, NULL))) return_0; return dm_tree_node_add_target_area(node, NULL, rdev_dlid, 0); } else if (seg->lv->rdevice->rsite->site_index) { log_error("Active site with site_index != 0 (%s, %d)", seg->lv->rdevice->rsite->name, seg->lv->rdevice->rsite->site_index); return 0; /* Replicator without any active site */ } /* * At this point all devices that have some connection with replicator * must be present in dm_tree */ if (!seg_is_replicator_dev(seg) || !(replicator_dlid = build_dm_uuid(mem, seg->replicator->lvid.s, NULL))) return_0; /* Select remote devices with the same device index */ dm_list_iterate_items(rsite, &seg->replicator->rsites) { if (rsite->site_index == 0) { /* Local slink0 device */ rdev = seg->lv->rdevice; } else { rdev = NULL; dm_list_iterate_items(rdev_search, &rsite->rdevices) { if (rdev_search->replicator_dev == seg) { rdev = rdev_search; break; } } if (!rdev) { log_error(INTERNAL_ERROR "rdev list not found."); return 0; } } if (!rdev->lv || !(rdev_dlid = build_dm_uuid(mem, rdev->lv->lvid.s, NULL))) return_0; slog_dlid = NULL; /* Using either disk or core (in memory) log */ if (rdev->slog) { slog_flags = DM_NOSYNC; slog_size = (uint32_t) rdev->slog->size; if (!(slog_dlid = build_dm_uuid(mem, rdev->slog->lvid.s, NULL))) return_0; } else if (rdev->slog_name && sscanf(rdev->slog_name, "%" PRIu32, &slog_size) == 1) { slog_flags = DM_CORELOG | DM_FORCESYNC; if (slog_size == 0) { log_error("Failed to use empty corelog size " "in replicator '%s'.", rsite->replicator->name); return 0; } } else { slog_flags = DM_CORELOG | DM_FORCESYNC; slog_size = 0; /* NOLOG */ } if (!dm_tree_node_add_replicator_dev_target(node, seg->lv->size, replicator_dlid, seg->lv->rdevice->device_index, rdev_dlid, rsite->site_index, slog_dlid, slog_flags, slog_size)) { return_0; /* FIXME: handle 'state = dropped' in future */ } } return 1; } /* FIXME: write something useful for replicator-dev here */ static int _replicator_dev_target_percent(void **target_state, percent_t *percent, struct dm_pool *mem, struct cmd_context *cmd, struct lv_segment *seg, char *params, uint64_t *total_numerator, uint64_t *total_denominator) { return 1; } /* Check for module presence */ static int _replicator_dev_target_present(struct cmd_context *cmd, const struct lv_segment *seg __attribute__((unused)), unsigned *attributes __attribute__((unused))) { static int _checked = 0; static int _present = 0; if (!_checked) { _present = target_present(cmd, REPLICATOR_DEV_MODULE, 1); _checked = 1; } return _present; } #endif static struct segtype_handler _replicator_dev_ops = { .name = _replicator_name, .display = _replicator_dev_display, .text_import = _replicator_dev_text_import, .text_export = _replicator_dev_text_export, #ifdef DEVMAPPER_SUPPORT .add_target_line = _replicator_dev_add_target_line, .target_percent = _replicator_dev_target_percent, .target_present = _replicator_dev_target_present, #endif .modules_needed = _replicator_modules_needed, .destroy = _replicator_destroy, }; #ifdef REPLICATOR_INTERNAL int init_replicator_segtype(struct cmd_context *cmd, struct segtype_library *seglib) #else /* Shared */ int init_multiple_segtype(struct cmd_context *cmd, struct segtype_library *seglib); int init_multiple_segtype(struct cmd_context *cmd, struct segtype_library *seglib) #endif { struct segment_type *segtype; if (!(segtype = dm_zalloc(sizeof(*segtype)))) return_0; segtype->ops = &_replicator_ops; segtype->name = REPLICATOR_MODULE; segtype->private = NULL; segtype->flags = SEG_REPLICATOR; if (!lvm_register_segtype(seglib, segtype)) /* segtype is already destroyed */ return_0; log_very_verbose("Initialised segtype: " REPLICATOR_MODULE); if (!(segtype = dm_zalloc(sizeof(*segtype)))) return_0; segtype->ops = &_replicator_dev_ops; segtype->name = REPLICATOR_DEV_MODULE; segtype->private = NULL; segtype->flags = SEG_REPLICATOR_DEV; if (!lvm_register_segtype(seglib, segtype)) /* segtype is already destroyed */ return_0; log_very_verbose("Initialised segtype: " REPLICATOR_DEV_MODULE); return 1; } lvm2-2.02.98/lib/replicator/Makefile.in0000640000175000017500000000134112037016272016466 0ustar blankblank# # 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@ SOURCES = replicator.c LIB_SHARED = liblvm2replicator.$(LIB_SUFFIX) LIB_VERSION = $(LIB_VERSION_LVM) include $(top_builddir)/make.tmpl install: install_lib_shared_plugin lvm2-2.02.98/lib/config/0000750000175000017500000000000012037016272013522 5ustar blankblanklvm2-2.02.98/lib/config/config.c0000640000175000017500000002533512037016272015144 0ustar blankblank/* * 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 "config.h" #include "crc.h" #include "device.h" #include "str_list.h" #include "toolcontext.h" #include "lvm-file.h" #include #include #include #include #include struct config_file { time_t timestamp; off_t st_size; char *filename; int exists; int keep_open; struct device *dev; }; /* * public interface */ struct dm_config_tree *config_file_open(const char *filename, int keep_open) { struct dm_config_tree *cft = dm_config_create(); struct config_file *cf; if (!cft) return NULL; cf = dm_pool_zalloc(cft->mem, sizeof(struct config_file)); if (!cf) goto fail; cf->timestamp = 0; cf->exists = 0; cf->keep_open = keep_open; dm_config_set_custom(cft, cf); if (filename && !(cf->filename = dm_pool_strdup(cft->mem, filename))) { log_error("Failed to duplicate filename."); goto fail; } return cft; fail: dm_config_destroy(cft); return NULL; } /* * Doesn't populate filename if the file is empty. */ int config_file_check(struct dm_config_tree *cft, const char **filename, struct stat *info) { struct config_file *cf = dm_config_get_custom(cft); struct stat _info; if (!info) info = &_info; if (stat(cf->filename, info)) { log_sys_error("stat", cf->filename); cf->exists = 0; return 0; } if (!S_ISREG(info->st_mode)) { log_error("%s is not a regular file", cf->filename); cf->exists = 0; return 0; } cf->exists = 1; cf->timestamp = info->st_ctime; cf->st_size = info->st_size; if (info->st_size == 0) log_verbose("%s is empty", cf->filename); else if (filename) *filename = cf->filename; return 1; } /* * Return 1 if config files ought to be reloaded */ int config_file_changed(struct dm_config_tree *cft) { struct config_file *cf = dm_config_get_custom(cft); struct stat info; if (!cf->filename) return 0; if (stat(cf->filename, &info) == -1) { /* Ignore a deleted config file: still use original data */ if (errno == ENOENT) { if (!cf->exists) return 0; log_very_verbose("Config file %s has disappeared!", cf->filename); goto reload; } log_sys_error("stat", cf->filename); log_error("Failed to reload configuration files"); return 0; } if (!S_ISREG(info.st_mode)) { log_error("Configuration file %s is not a regular file", cf->filename); goto reload; } /* Unchanged? */ if (cf->timestamp == info.st_ctime && cf->st_size == info.st_size) return 0; reload: log_verbose("Detected config file change to %s", cf->filename); return 1; } void config_file_destroy(struct dm_config_tree *cft) { struct config_file *cf = dm_config_get_custom(cft); if (cf && cf->dev) if (!dev_close(cf->dev)) stack; dm_config_destroy(cft); } /* * Returns config tree if it was removed. */ struct dm_config_tree *remove_overridden_config_tree(struct cmd_context *cmd) { struct dm_config_tree *old_cft = cmd->cft; struct dm_config_tree *cft = dm_config_remove_cascaded_tree(cmd->cft); if (!cft) return NULL; cmd->cft = cft; return old_cft; } int override_config_tree_from_string(struct cmd_context *cmd, const char *config_settings) { struct dm_config_tree *cft_new; if (!(cft_new = dm_config_from_string(config_settings))) { log_error("Failed to set overridden configuration entries."); return 1; } cmd->cft = dm_config_insert_cascaded_tree(cft_new, cmd->cft); return 0; } int config_file_read_fd(struct dm_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) { char *fb, *fe; int r = 0; int use_mmap = 1; off_t mmap_offset = 0; char *buf = NULL; /* Only use mmap with regular files */ if (!(dev->flags & DEV_REGULAR) || size2) use_mmap = 0; if (use_mmap) { mmap_offset = offset % lvm_getpagesize(); /* memory map the file */ fb = mmap((caddr_t) 0, size + mmap_offset, PROT_READ, MAP_PRIVATE, dev_fd(dev), offset - mmap_offset); if (fb == (caddr_t) (-1)) { log_sys_error("mmap", dev_name(dev)); goto out; } fb = fb + mmap_offset; } else { if (!(buf = dm_malloc(size + size2))) { log_error("Failed to allocate circular buffer."); return 0; } if (!dev_read_circular(dev, (uint64_t) offset, size, (uint64_t) offset2, size2, buf)) { goto out; } fb = buf; } if (checksum_fn && checksum != (checksum_fn(checksum_fn(INITIAL_CRC, (const uint8_t *)fb, size), (const uint8_t *)(fb + size), size2))) { log_error("%s: Checksum error", dev_name(dev)); goto out; } fe = fb + size + size2; if (!dm_config_parse(cft, fb, fe)) goto_out; r = 1; out: if (!use_mmap) dm_free(buf); else { /* unmap the file */ if (munmap(fb - mmap_offset, size + mmap_offset)) { log_sys_error("munmap", dev_name(dev)); r = 0; } } return r; } int config_file_read(struct dm_config_tree *cft) { const char *filename = NULL; struct config_file *cf = dm_config_get_custom(cft); struct stat info; int r; if (!config_file_check(cft, &filename, &info)) return_0; /* Nothing to do. E.g. empty file. */ if (!filename) return 1; if (!cf->dev) { if (!(cf->dev = dev_create_file(filename, NULL, NULL, 1))) return_0; if (!dev_open_readonly_buffered(cf->dev)) return_0; } r = config_file_read_fd(cft, cf->dev, 0, (size_t) info.st_size, 0, 0, (checksum_fn_t) NULL, 0); if (!cf->keep_open) { if (!dev_close(cf->dev)) stack; cf->dev = NULL; } return r; } time_t config_file_timestamp(struct dm_config_tree *cft) { struct config_file *cf = dm_config_get_custom(cft); assert(cf); return cf->timestamp; } const struct dm_config_node *find_config_tree_node(struct cmd_context *cmd, const char *path) { return dm_config_tree_find_node(cmd->cft, path); } const char *find_config_tree_str(struct cmd_context *cmd, const char *path, const char *fail) { return dm_config_tree_find_str(cmd->cft, path, fail); } const char *find_config_tree_str_allow_empty(struct cmd_context *cmd, const char *path, const char *fail) { return dm_config_tree_find_str_allow_empty(cmd->cft, path, fail); } int find_config_tree_int(struct cmd_context *cmd, const char *path, int fail) { return dm_config_tree_find_int(cmd->cft, path, fail); } int64_t find_config_tree_int64(struct cmd_context *cmd, const char *path, int64_t fail) { return dm_config_tree_find_int64(cmd->cft, path, fail); } float find_config_tree_float(struct cmd_context *cmd, const char *path, float fail) { return dm_config_tree_find_float(cmd->cft, path, fail); } int find_config_tree_bool(struct cmd_context *cmd, const char *path, int fail) { return dm_config_tree_find_bool(cmd->cft, path, fail); } /* Insert cn2 after cn1 */ static void _insert_config_node(struct dm_config_node **cn1, struct dm_config_node *cn2) { if (!*cn1) { *cn1 = cn2; cn2->sib = NULL; } else { cn2->sib = (*cn1)->sib; (*cn1)->sib = cn2; } } /* * Merge section cn2 into section cn1 (which has the same name) * overwriting any existing cn1 nodes with matching names. */ static void _merge_section(struct dm_config_node *cn1, struct dm_config_node *cn2) { struct dm_config_node *cn, *nextn, *oldn; struct dm_config_value *cv; for (cn = cn2->child; cn; cn = nextn) { nextn = cn->sib; /* Skip "tags" */ if (!strcmp(cn->key, "tags")) continue; /* Subsection? */ if (!cn->v) /* Ignore - we don't have any of these yet */ continue; /* Not already present? */ if (!(oldn = dm_config_find_node(cn1->child, cn->key))) { _insert_config_node(&cn1->child, cn); continue; } /* Merge certain value lists */ if ((!strcmp(cn1->key, "activation") && !strcmp(cn->key, "volume_list")) || (!strcmp(cn1->key, "devices") && (!strcmp(cn->key, "filter") || !strcmp(cn->key, "types")))) { cv = cn->v; while (cv->next) cv = cv->next; cv->next = oldn->v; } /* Replace values */ oldn->v = cn->v; } } static int _match_host_tags(struct dm_list *tags, const struct dm_config_node *tn) { const struct dm_config_value *tv; const char *str; for (tv = tn->v; tv; tv = tv->next) { if (tv->type != DM_CFG_STRING) continue; str = tv->v.str; if (*str == '@') str++; if (!*str) continue; if (str_list_match_item(tags, str)) return 1; } return 0; } /* Destructively merge a new config tree into an existing one */ int merge_config_tree(struct cmd_context *cmd, struct dm_config_tree *cft, struct dm_config_tree *newdata) { struct dm_config_node *root = cft->root; struct dm_config_node *cn, *nextn, *oldn, *cn2; const struct dm_config_node *tn; for (cn = newdata->root; cn; cn = nextn) { nextn = cn->sib; /* Ignore tags section */ if (!strcmp(cn->key, "tags")) continue; /* If there's a tags node, skip if host tags don't match */ if ((tn = dm_config_find_node(cn->child, "tags"))) { if (!_match_host_tags(&cmd->tags, tn)) continue; } if (!(oldn = dm_config_find_node(root, cn->key))) { _insert_config_node(&cft->root, cn); /* Remove any "tags" nodes */ for (cn2 = cn->child; cn2; cn2 = cn2->sib) { if (!strcmp(cn2->key, "tags")) { cn->child = cn2->sib; continue; } if (cn2->sib && !strcmp(cn2->sib->key, "tags")) { cn2->sib = cn2->sib->sib; continue; } } continue; } _merge_section(oldn, cn); } return 1; } static int _putline_fn(const char *line, void *baton) { FILE *fp = baton; fprintf(fp, "%s\n", line); return 1; }; int config_write(struct dm_config_tree *cft, const char *file, int argc, char **argv) { const struct dm_config_node *cn; int r = 1; FILE *fp = NULL; if (!file) { fp = stdout; file = "stdout"; } else if (!(fp = fopen(file, "w"))) { log_sys_error("open", file); return 0; } log_verbose("Dumping configuration to %s", file); if (!argc) { if (!dm_config_write_node(cft->root, _putline_fn, fp)) { log_error("Failure while writing to %s", file); r = 0; } } else while (argc--) { if ((cn = dm_config_find_node(cft->root, *argv))) { if (!dm_config_write_one_node(cn, _putline_fn, fp)) { log_error("Failure while writing to %s", file); r = 0; } } else { log_error("Configuration node %s not found", *argv); r = 0; } argv++; } if (fp && dm_fclose(fp)) { stack; r = 0; } return r; } lvm2-2.02.98/lib/config/defaults.h0000640000175000017500000001472012037016272015507 0ustar blankblank/* * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU 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_OBTAIN_DEVICE_LIST_FROM_UDEV 1 #define DEFAULT_SYSFS_SCAN 1 #define DEFAULT_MD_COMPONENT_DETECTION 1 #define DEFAULT_MD_CHUNK_ALIGNMENT 1 #define DEFAULT_MULTIPATH_COMPONENT_DETECTION 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_ISSUE_DISCARDS 0 #define DEFAULT_PV_MIN_SIZE_KB 2048 #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_LVDISPLAY_SHOWS_FULL_DEVICE_PATH 0 #define DEFAULT_MIRROR_SEGTYPE "mirror" #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_RAID_FAULT_POLICY "warn" #define DEFAULT_DMEVENTD_RAID_LIB "libdevmapper-event-lvm2raid.so" #define DEFAULT_DMEVENTD_MIRROR_LIB "libdevmapper-event-lvm2mirror.so" #define DEFAULT_DMEVENTD_SNAPSHOT_LIB "libdevmapper-event-lvm2snapshot.so" #define DEFAULT_DMEVENTD_THIN_LIB "libdevmapper-event-lvm2thin.so" #define DEFAULT_DMEVENTD_MONITOR 1 #define DEFAULT_BACKGROUND_POLLING 1 #define DEFAULT_THIN_CHECK_OPTIONS "-q" #define DEFAULT_THIN_POOL_METADATA_REQUIRE_SEPARATE_PVS 0 #define DEFAULT_THIN_POOL_MAX_METADATA_SIZE (16 * 1024 * 1024) /* KB */ #define DEFAULT_THIN_POOL_MIN_METADATA_SIZE 2048 /* KB */ #define DEFAULT_THIN_POOL_OPTIMAL_SIZE (128 * 1024 * 1024) /* KB */ #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 1 #define DEFAULT_VERIFY_UDEV_OPERATIONS 0 #define DEFAULT_RETRY_DEACTIVATION 1 #define DEFAULT_ACTIVATION_CHECKS 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_MIRROR_LOGS_REQUIRE_SEPARATE_PVS 0 #define DEFAULT_MAXIMISE_CLING 1 #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_SILENT 0 #define DEFAULT_LOGLEVEL 0 #define DEFAULT_INDENT 1 #define DEFAULT_ABORT_ON_INTERNAL_ERRORS 0 #define DEFAULT_DETECT_INTERNAL_VG_CACHE_CORRUPTION 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 64 /* KB */ # define DEFAULT_PROCESS_PRIORITY -18 #else # define DEFAULT_ACTIVATION 0 #endif #define DEFAULT_USE_LINEAR_TARGET 1 #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,pool_lv,origin,data_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,pool_lv,origin,data_percent,metadata_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 #define DEFAULT_THIN_POOL_AUTOEXTEND_THRESHOLD 100 #define DEFAULT_THIN_POOL_AUTOEXTEND_PERCENT 20 #endif /* _LVM_DEFAULTS_H */ lvm2-2.02.98/lib/config/config.h0000640000175000017500000000470312037016272015145 0ustar blankblank/* * 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; int override_config_tree_from_string(struct cmd_context *cmd, const char *config_settings); struct dm_config_tree *remove_overridden_config_tree(struct cmd_context *cmd); typedef uint32_t (*checksum_fn_t) (uint32_t initial, const uint8_t *buf, uint32_t size); struct dm_config_tree *config_file_open(const char *filename, int keep_open); int config_file_read_fd(struct dm_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 config_file_read(struct dm_config_tree *cft); int config_write(struct dm_config_tree *cft, const char *file, int argc, char **argv); void config_file_destroy(struct dm_config_tree *cft); time_t config_file_timestamp(struct dm_config_tree *cft); int config_file_changed(struct dm_config_tree *cft); int config_file_check(struct dm_config_tree *cft, const char **filename, struct stat *info); int merge_config_tree(struct cmd_context *cmd, struct dm_config_tree *cft, struct dm_config_tree *newdata); /* * These versions check an override tree, if present, first. */ const struct dm_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); const char *find_config_tree_str_allow_empty(struct cmd_context *cmd, const char *path, const char *fail); int find_config_tree_int(struct cmd_context *cmd, const char *path, int fail); int64_t find_config_tree_int64(struct cmd_context *cmd, const char *path, int64_t fail); float find_config_tree_float(struct cmd_context *cmd, const char *path, float fail); int find_config_tree_bool(struct cmd_context *cmd, const char *path, int fail); #endif lvm2-2.02.98/lib/datastruct/0000750000175000017500000000000012037016272014433 5ustar blankblanklvm2-2.02.98/lib/datastruct/btree.c0000640000175000017500000000471412037016272015707 0ustar blankblank/* * 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 *const *_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 c; } void *btree_lookup(const struct btree *t, uint32_t k) { uint32_t key = _shuffle(k); struct node *p, *const *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 = (struct node **) _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; } lvm2-2.02.98/lib/datastruct/str_list.h0000640000175000017500000000224712037016272016455 0ustar blankblank/* * Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved. * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU 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_STR_LIST_H #define _LVM_STR_LIST_H struct dm_list *str_list_create(struct dm_pool *mem); int str_list_add(struct dm_pool *mem, struct dm_list *sll, const char *str); void str_list_del(struct dm_list *sll, const char *str); int str_list_match_item(const struct dm_list *sll, const char *str); int str_list_match_list(const struct dm_list *sll, const struct dm_list *sll2, const char **tag_matched); int str_list_lists_equal(const struct dm_list *sll, const struct dm_list *sll2); int str_list_dup(struct dm_pool *mem, struct dm_list *sllnew, const struct dm_list *sllold); #endif lvm2-2.02.98/lib/datastruct/btree.h0000640000175000017500000000176312037016272015715 0ustar blankblank/* * 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 lvm2-2.02.98/lib/datastruct/lvm-types.h0000640000175000017500000000154412037016272016551 0ustar blankblank/* * 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 #include /* 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 lvm2-2.02.98/lib/datastruct/str_list.c0000640000175000017500000000507012037016272016445 0ustar blankblank/* * Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved. * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU 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; } void 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); } 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; } lvm2-2.02.98/lib/snapshot/0000750000175000017500000000000012037016272014114 5ustar blankblanklvm2-2.02.98/lib/snapshot/.exported_symbols0000640000175000017500000000001512037016272017514 0ustar blankblankinit_segtype lvm2-2.02.98/lib/snapshot/Makefile.in0000640000175000017500000000143512037016272016165 0ustar blankblank# # 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 srcdir = @srcdir@ top_srcdir = @top_srcdir@ top_builddir = @top_builddir@ SOURCES = snapshot.c LIB_SHARED = liblvm2snapshot.$(LIB_SUFFIX) LIB_VERSION = $(LIB_VERSION_LVM) include $(top_builddir)/make.tmpl install: install_lvm2_plugin lvm2-2.02.98/lib/snapshot/snapshot.c0000640000175000017500000001662312037016272016130 0ustar blankblank/* * Copyright (C) 2003-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 */ #include "lib.h" #include "toolcontext.h" #include "metadata.h" #include "segtype.h" #include "text_export.h" #include "config.h" #include "activate.h" #include "str_list.h" #include "defaults.h" static const char *_snap_name(const struct lv_segment *seg) { return seg->segtype->name; } static const char *_snap_target_name(const struct lv_segment *seg, const struct lv_activate_opts *laopts) { if (!laopts->no_merging && (seg->status & MERGING)) return "snapshot-merge"; return _snap_name(seg); } static int _snap_text_import(struct lv_segment *seg, const struct dm_config_node *sn, struct dm_hash_table *pv_hash __attribute__((unused))) { uint32_t chunk_size; const char *org_name, *cow_name; struct logical_volume *org, *cow; int old_suppress, merge = 0; if (!dm_config_get_uint32(sn, "chunk_size", &chunk_size)) { log_error("Couldn't read chunk size for snapshot."); return 0; } old_suppress = log_suppress(1); if ((cow_name = dm_config_find_str(sn, "merging_store", NULL))) { if (dm_config_find_str(sn, "cow_store", NULL)) { log_suppress(old_suppress); log_error("Both snapshot cow and merging storage were specified."); return 0; } merge = 1; } else if (!(cow_name = dm_config_find_str(sn, "cow_store", NULL))) { log_suppress(old_suppress); log_error("Snapshot cow storage not specified."); return 0; } if (!(org_name = dm_config_find_str(sn, "origin", NULL))) { log_suppress(old_suppress); log_error("Snapshot origin not specified."); return 0; } log_suppress(old_suppress); if (!(cow = find_lv(seg->lv->vg, cow_name))) { log_error("Unknown logical volume specified for " "snapshot cow store."); return 0; } if (!(org = find_lv(seg->lv->vg, org_name))) { log_error("Unknown logical volume specified for " "snapshot origin."); return 0; } init_snapshot_seg(seg, org, cow, chunk_size, merge); return 1; } static int _snap_text_export(const struct lv_segment *seg, struct formatter *f) { outf(f, "chunk_size = %u", seg->chunk_size); outf(f, "origin = \"%s\"", seg->origin->name); if (!(seg->status & MERGING)) outf(f, "cow_store = \"%s\"", seg->cow->name); else outf(f, "merging_store = \"%s\"", seg->cow->name); return 1; } static int _snap_target_status_compatible(const char *type) { return (strcmp(type, "snapshot-merge") == 0); } #ifdef DEVMAPPER_SUPPORT static int _snap_target_percent(void **target_state __attribute__((unused)), percent_t *percent, struct dm_pool *mem __attribute__((unused)), struct cmd_context *cmd __attribute__((unused)), struct lv_segment *seg __attribute__((unused)), char *params, uint64_t *total_numerator, uint64_t *total_denominator) { uint64_t total_sectors, sectors_allocated, metadata_sectors; int r; /* * snapshot target's percent format: * <= 1.7.0: / * >= 1.8.0: / */ r = sscanf(params, "%" PRIu64 "/%" PRIu64 " %" PRIu64, §ors_allocated, &total_sectors, &metadata_sectors); if (r == 2 || r == 3) { *total_numerator += sectors_allocated; *total_denominator += total_sectors; if (r == 3 && sectors_allocated == metadata_sectors) *percent = PERCENT_0; else if (sectors_allocated == total_sectors) *percent = PERCENT_100; else *percent = make_percent(*total_numerator, *total_denominator); } else if (!strcmp(params, "Invalid")) *percent = PERCENT_INVALID; else if (!strcmp(params, "Merge failed")) *percent = PERCENT_MERGE_FAILED; else return 0; return 1; } static int _snap_target_present(struct cmd_context *cmd, const struct lv_segment *seg, unsigned *attributes __attribute__((unused))) { static int _snap_checked = 0; static int _snap_merge_checked = 0; static int _snap_present = 0; static int _snap_merge_present = 0; if (!_snap_checked) { _snap_present = target_present(cmd, "snapshot", 1) && target_present(cmd, "snapshot-origin", 0); _snap_checked = 1; } if (!_snap_merge_checked && seg && (seg->status & MERGING)) { _snap_merge_present = target_present(cmd, "snapshot-merge", 0); _snap_merge_checked = 1; return _snap_present && _snap_merge_present; } return _snap_present; } #ifdef DMEVENTD static const char *_get_snapshot_dso_path(struct cmd_context *cmd) { return get_monitor_dso_path(cmd, find_config_tree_str(cmd, "dmeventd/snapshot_library", DEFAULT_DMEVENTD_SNAPSHOT_LIB)); } /* FIXME Cache this */ static int _target_registered(struct lv_segment *seg, int *pending) { return target_registered_with_dmeventd(seg->lv->vg->cmd, _get_snapshot_dso_path(seg->lv->vg->cmd), seg->cow, pending); } /* FIXME This gets run while suspended and performs banned operations. */ static int _target_set_events(struct lv_segment *seg, int evmask, int set) { /* FIXME Make timeout (10) configurable */ return target_register_events(seg->lv->vg->cmd, _get_snapshot_dso_path(seg->lv->vg->cmd), seg->cow, evmask, set, 10); } static int _target_register_events(struct lv_segment *seg, int events) { return _target_set_events(seg, events, 1); } static int _target_unregister_events(struct lv_segment *seg, int events) { return _target_set_events(seg, events, 0); } #endif /* DMEVENTD */ #endif static int _snap_modules_needed(struct dm_pool *mem, const struct lv_segment *seg __attribute__((unused)), struct dm_list *modules) { if (!str_list_add(mem, modules, "snapshot")) { log_error("snapshot string list allocation failed"); return 0; } return 1; } static void _snap_destroy(struct segment_type *segtype) { dm_free(segtype); } static struct segtype_handler _snapshot_ops = { .name = _snap_name, .target_name = _snap_target_name, .text_import = _snap_text_import, .text_export = _snap_text_export, .target_status_compatible = _snap_target_status_compatible, #ifdef DEVMAPPER_SUPPORT .target_percent = _snap_target_percent, .target_present = _snap_target_present, # ifdef DMEVENTD .target_monitored = _target_registered, .target_monitor_events = _target_register_events, .target_unmonitor_events = _target_unregister_events, # endif /* DMEVENTD */ #endif .modules_needed = _snap_modules_needed, .destroy = _snap_destroy, }; #ifdef SNAPSHOT_INTERNAL struct segment_type *init_snapshot_segtype(struct cmd_context *cmd) #else /* Shared */ struct segment_type *init_segtype(struct cmd_context *cmd); struct segment_type *init_segtype(struct cmd_context *cmd) #endif { struct segment_type *segtype = dm_zalloc(sizeof(*segtype)); if (!segtype) return_NULL; segtype->cmd = cmd; segtype->ops = &_snapshot_ops; segtype->name = "snapshot"; segtype->private = NULL; segtype->flags = SEG_SNAPSHOT; #ifdef DEVMAPPER_SUPPORT # ifdef DMEVENTD if (_get_snapshot_dso_path(cmd)) segtype->flags |= SEG_MONITORED; # endif /* DMEVENTD */ #endif log_very_verbose("Initialised segtype: %s", segtype->name); return segtype; } lvm2-2.02.98/lib/locking/0000750000175000017500000000000012037016272013703 5ustar blankblanklvm2-2.02.98/lib/locking/.exported_symbols0000640000175000017500000000010412037016272017302 0ustar blankblanklocking_init locking_end lock_resource query_resource reset_locking lvm2-2.02.98/lib/locking/file_locking.c0000640000175000017500000002144212037016272016500 0ustar blankblank/* * 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 "locking.h" #include "locking_types.h" #include "activate.h" #include "config.h" #include "defaults.h" #include "lvm-file.h" #include "lvm-string.h" #include "lvmcache.h" #include #include #include #include #include #include struct lock_list { struct dm_list list; int lf; char *res; }; static struct dm_list _lock_list; static char _lock_dir[NAME_LEN]; static int _prioritise_write_locks; static sig_t _oldhandler; static sigset_t _fullsigset, _intsigset; static volatile sig_atomic_t _handler_installed; static void _undo_flock(const char *file, int fd) { struct stat buf1, buf2; log_debug("_undo_flock %s", file); if (!flock(fd, LOCK_NB | LOCK_EX) && !stat(file, &buf1) && !fstat(fd, &buf2) && is_same_inode(buf1, buf2)) if (unlink(file)) log_sys_error("unlink", file); if (close(fd) < 0) log_sys_error("close", file); } static int _release_lock(const char *file, int unlock) { struct lock_list *ll; struct dm_list *llh, *llt; dm_list_iterate_safe(llh, llt, &_lock_list) { ll = dm_list_item(llh, struct lock_list); if (!file || !strcmp(ll->res, file)) { dm_list_del(llh); if (unlock) { log_very_verbose("Unlocking %s", ll->res); if (flock(ll->lf, LOCK_NB | LOCK_UN)) log_sys_error("flock", ll->res); } _undo_flock(ll->res, ll->lf); dm_free(ll->res); dm_free(llh); if (file) return 1; } } return 0; } static void _fin_file_locking(void) { _release_lock(NULL, 1); } static void _reset_file_locking(void) { _release_lock(NULL, 0); } static void _remove_ctrl_c_handler(void) { siginterrupt(SIGINT, 0); if (!_handler_installed) return; _handler_installed = 0; sigprocmask(SIG_SETMASK, &_fullsigset, NULL); if (signal(SIGINT, _oldhandler) == SIG_ERR) log_sys_error("signal", "_remove_ctrl_c_handler"); } static void _trap_ctrl_c(int sig __attribute__((unused))) { _remove_ctrl_c_handler(); log_error("CTRL-c detected: giving up waiting for lock"); } static void _install_ctrl_c_handler(void) { _handler_installed = 1; if ((_oldhandler = signal(SIGINT, _trap_ctrl_c)) == SIG_ERR) { _handler_installed = 0; return; } sigprocmask(SIG_SETMASK, &_intsigset, NULL); siginterrupt(SIGINT, 1); } static int _do_flock(const char *file, int *fd, int operation, uint32_t nonblock) { int r = 1; int old_errno; struct stat buf1, buf2; log_debug("_do_flock %s %c%c", file, operation == LOCK_EX ? 'W' : 'R', nonblock ? ' ' : 'B'); do { if ((*fd > -1) && close(*fd)) log_sys_error("close", file); if ((*fd = open(file, O_CREAT | O_APPEND | O_RDWR, 0777)) < 0) { log_sys_error("open", file); return 0; } if (nonblock) operation |= LOCK_NB; else _install_ctrl_c_handler(); r = flock(*fd, operation); old_errno = errno; if (!nonblock) _remove_ctrl_c_handler(); if (r) { errno = old_errno; log_sys_error("flock", file); if (close(*fd)) log_sys_error("close", file); return 0; } if (!stat(file, &buf1) && !fstat(*fd, &buf2) && is_same_inode(buf1, buf2)) return 1; } while (!nonblock); return_0; } #define AUX_LOCK_SUFFIX ":aux" static int _do_write_priority_flock(const char *file, int *fd, int operation, uint32_t nonblock) { int r, fd_aux = -1; char *file_aux = alloca(strlen(file) + sizeof(AUX_LOCK_SUFFIX)); strcpy(file_aux, file); strcat(file_aux, AUX_LOCK_SUFFIX); if ((r = _do_flock(file_aux, &fd_aux, LOCK_EX, 0))) { if (operation == LOCK_EX) { r = _do_flock(file, fd, operation, nonblock); _undo_flock(file_aux, fd_aux); } else { _undo_flock(file_aux, fd_aux); r = _do_flock(file, fd, operation, nonblock); } } return r; } static int _lock_file(const char *file, uint32_t flags) { int operation; uint32_t nonblock = flags & LCK_NONBLOCK; int r; struct lock_list *ll; char state; switch (flags & LCK_TYPE_MASK) { case LCK_READ: operation = LOCK_SH; state = 'R'; break; case LCK_WRITE: operation = LOCK_EX; state = 'W'; break; case LCK_UNLOCK: return _release_lock(file, 1); default: log_error("Unrecognised lock type: %d", flags & LCK_TYPE_MASK); return 0; } if (!(ll = dm_malloc(sizeof(struct lock_list)))) return_0; if (!(ll->res = dm_strdup(file))) { dm_free(ll); return_0; } ll->lf = -1; log_very_verbose("Locking %s %c%c", ll->res, state, nonblock ? ' ' : 'B'); (void) dm_prepare_selinux_context(file, S_IFREG); if (_prioritise_write_locks) r = _do_write_priority_flock(file, &ll->lf, operation, nonblock); else r = _do_flock(file, &ll->lf, operation, nonblock); (void) dm_prepare_selinux_context(NULL, 0); if (r) dm_list_add(&_lock_list, &ll->list); else { dm_free(ll->res); dm_free(ll); stack; } return r; } static int _file_lock_resource(struct cmd_context *cmd, const char *resource, uint32_t flags) { char lockfile[PATH_MAX]; unsigned origin_only = (flags & LCK_ORIGIN_ONLY) ? 1 : 0; unsigned revert = (flags & LCK_REVERT) ? 1 : 0; switch (flags & LCK_SCOPE_MASK) { case LCK_VG: /* Skip cache refresh for VG_GLOBAL - the caller handles it */ if (strcmp(resource, VG_GLOBAL)) lvmcache_drop_metadata(resource, 0); if (!strcmp(resource, VG_SYNC_NAMES)) fs_unlock(); /* LCK_CACHE does not require a real lock */ if (flags & LCK_CACHE) break; if (is_orphan_vg(resource) || is_global_vg(resource)) { if (dm_snprintf(lockfile, sizeof(lockfile), "%s/P_%s", _lock_dir, resource + 1) < 0) { log_error("Too long locking filename %s/P_%s.", _lock_dir, resource + 1); return 0; } } else if (dm_snprintf(lockfile, sizeof(lockfile), "%s/V_%s", _lock_dir, resource) < 0) { log_error("Too long locking filename %s/V_%s.", _lock_dir, resource); return 0; } if (!_lock_file(lockfile, flags)) return_0; break; case LCK_LV: switch (flags & LCK_TYPE_MASK) { case LCK_UNLOCK: log_very_verbose("Unlocking LV %s%s%s", resource, origin_only ? " without snapshots" : "", revert ? " (reverting)" : ""); if (!lv_resume_if_active(cmd, resource, origin_only, 0, revert)) return 0; break; case LCK_NULL: log_very_verbose("Locking LV %s (NL)", resource); if (!lv_deactivate(cmd, resource)) return 0; break; case LCK_READ: log_very_verbose("Locking LV %s (R)", resource); if (!lv_activate_with_filter(cmd, resource, 0)) return 0; break; case LCK_PREAD: log_very_verbose("Locking LV %s (PR) - ignored", resource); break; case LCK_WRITE: log_very_verbose("Locking LV %s (W)%s", resource, origin_only ? " without snapshots" : ""); if (!lv_suspend_if_active(cmd, resource, origin_only, 0)) return 0; break; case LCK_EXCL: log_very_verbose("Locking LV %s (EX)", resource); if (!lv_activate_with_filter(cmd, resource, 1)) return 0; break; default: break; } break; default: log_error("Unrecognised lock scope: %d", flags & LCK_SCOPE_MASK); return 0; } return 1; } int init_file_locking(struct locking_type *locking, struct cmd_context *cmd, int suppress_messages) { int r; const char *locking_dir; locking->lock_resource = _file_lock_resource; locking->reset_locking = _reset_file_locking; locking->fin_locking = _fin_file_locking; locking->flags = 0; /* Get lockfile directory from config file */ locking_dir = find_config_tree_str(cmd, "global/locking_dir", DEFAULT_LOCK_DIR); if (strlen(locking_dir) >= sizeof(_lock_dir)) { log_error("Path for locking_dir %s is invalid.", locking_dir); return 0; } strcpy(_lock_dir, locking_dir); _prioritise_write_locks = find_config_tree_bool(cmd, "global/prioritise_write_locks", DEFAULT_PRIORITISE_WRITE_LOCKS); (void) dm_prepare_selinux_context(_lock_dir, S_IFDIR); r = dm_create_dir(_lock_dir); (void) dm_prepare_selinux_context(NULL, 0); if (!r) return 0; /* Trap a read-only file system */ if ((access(_lock_dir, R_OK | W_OK | X_OK) == -1) && (errno == EROFS)) return 0; dm_list_init(&_lock_list); if (sigfillset(&_intsigset) || sigfillset(&_fullsigset)) { log_sys_error_suppress(suppress_messages, "sigfillset", "init_file_locking"); return 0; } if (sigdelset(&_intsigset, SIGINT)) { log_sys_error_suppress(suppress_messages, "sigdelset", "init_file_locking"); return 0; } return 1; } lvm2-2.02.98/lib/locking/external_locking.c0000640000175000017500000000574012037016272017406 0ustar blankblank/* * 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 */ #include "lib.h" #include "locking_types.h" #include "defaults.h" #include "sharedlib.h" #include "toolcontext.h" #include "activate.h" #include "locking.h" static void *_locking_lib = NULL; static void (*_reset_fn) (void) = NULL; static void (*_end_fn) (void) = NULL; static int (*_lock_fn) (struct cmd_context * cmd, const char *resource, uint32_t flags) = NULL; static int (*_init_fn) (int type, struct dm_config_tree * cft, uint32_t *flags) = NULL; static int (*_lock_query_fn) (const char *resource, int *mode) = NULL; static int _lock_resource(struct cmd_context *cmd, const char *resource, uint32_t flags) { if (!_lock_fn) return 0; if (!strcmp(resource, VG_SYNC_NAMES)) { /* Hide this lock request from external locking */ fs_unlock(); return 1; } return _lock_fn(cmd, resource, flags); } static void _fin_external_locking(void) { if (_end_fn) _end_fn(); dlclose(_locking_lib); _locking_lib = NULL; _init_fn = NULL; _end_fn = NULL; _lock_fn = NULL; _reset_fn = NULL; } static void _reset_external_locking(void) { if (_reset_fn) _reset_fn(); } int init_external_locking(struct locking_type *locking, struct cmd_context *cmd, int suppress_messages) { const char *libname; if (_locking_lib) { log_error_suppress(suppress_messages, "External locking already initialised"); return 1; } locking->lock_resource = _lock_resource; locking->fin_locking = _fin_external_locking; locking->reset_locking = _reset_external_locking; locking->flags = 0; libname = find_config_tree_str(cmd, "global/locking_library", DEFAULT_LOCKING_LIB); if (!(_locking_lib = load_shared_library(cmd, libname, "locking", 1))) return_0; /* Get the functions we need */ if (!(_init_fn = dlsym(_locking_lib, "locking_init")) || !(_lock_fn = dlsym(_locking_lib, "lock_resource")) || !(_reset_fn = dlsym(_locking_lib, "reset_locking")) || !(_end_fn = dlsym(_locking_lib, "locking_end"))) { log_error_suppress(suppress_messages, "Shared library %s does " "not contain locking functions", libname); dlclose(_locking_lib); _locking_lib = NULL; return 0; } if (!(_lock_query_fn = dlsym(_locking_lib, "query_resource"))) log_warn_suppress(suppress_messages, "WARNING: %s: _query_resource() " "missing: Using inferior activation method.", libname); log_verbose("Loaded external locking library %s", libname); return _init_fn(2, cmd->cft, &locking->flags); } lvm2-2.02.98/lib/locking/locking.h0000640000175000017500000001710612037016272015510 0ustar blankblank/* * 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 */ #ifndef _LVM_LOCKING_H #define _LVM_LOCKING_H #include "uuid.h" #include "config.h" int init_locking(int type, struct cmd_context *cmd, int suppress_messages); void fin_locking(void); void reset_locking(void); int vg_write_lock_held(void); int locking_is_clustered(void); int remote_lock_held(const char *vol, int *exclusive); /* * LCK_VG: * Lock/unlock on-disk volume group data. * Use VG_ORPHANS to lock all orphan PVs. * Use VG_GLOBAL as a global lock and to wipe the internal cache. * char *vol holds volume group name. * Set LCK_CACHE flag when manipulating 'vol' metadata in the internal cache. * (Like commit, revert or invalidate metadata.) * If more than one lock needs to be held simultaneously, they must be * acquired in alphabetical order of 'vol' (to avoid deadlocks), with * VG_ORPHANS last. * * Use VG_SYNC_NAMES to ensure /dev is up-to-date for example, with udev, * by waiting for any asynchronous events issued to have completed. * * LCK_LV: * Lock/unlock an individual logical volume * char *vol holds lvid */ int lock_vol(struct cmd_context *cmd, const char *vol, uint32_t flags); /* * Internal locking representation. * LCK_VG: Uses prefix V_ unless the vol begins with # (i.e. #global or #orphans) * or the LCK_CACHE flag is set when it uses the prefix P_. * If LCK_CACHE is set, we do not take out a real lock. * NB In clustered situations, LCK_CACHE is not propagated directly to remote nodes. * (It can be deduced from lock name.) */ /* * Does the LVM1 driver have this VG active? */ int check_lvm1_vg_inactive(struct cmd_context *cmd, const char *vgname); /* * Lock type - these numbers are the same as VMS and the IBM DLM */ #define LCK_TYPE_MASK 0x00000007U #define LCK_NULL 0x00000000U /* LCK$_NLMODE (Deactivate) */ #define LCK_READ 0x00000001U /* LCK$_CRMODE (Activate) */ /* LCK$_CWMODE */ #define LCK_PREAD 0x00000003U /* LCK$_PRMODE */ #define LCK_WRITE 0x00000004U /* LCK$_PWMODE (Suspend) */ #define LCK_EXCL 0x00000005U /* LCK$_EXMODE (Exclusive) */ #define LCK_UNLOCK 0x00000006U /* This is ours (Resume) */ /* * Lock flags - these numbers are the same as DLM */ #define LCKF_NOQUEUE 0x00000001U /* LKF$_NOQUEUE */ #define LCKF_CONVERT 0x00000004U /* LKF$_CONVERT */ /* * Lock scope */ #define LCK_SCOPE_MASK 0x00000008U #define LCK_VG 0x00000000U #define LCK_LV 0x00000008U /* * Lock bits. * Bottom 8 bits except LCK_LOCAL form args[0] in cluster comms. */ #define LCK_NONBLOCK 0x00000010U /* Don't block waiting for lock? */ #define LCK_HOLD 0x00000020U /* Hold lock when lock_vol returns? */ #define LCK_CLUSTER_VG 0x00000080U /* VG is clustered */ #define LCK_LOCAL 0x00000040U /* Don't propagate to other nodes */ #define LCK_REMOTE 0x00000800U /* Propagate to remote nodes only */ #define LCK_CACHE 0x00000100U /* Operation on cache only using P_ lock */ #define LCK_ORIGIN_ONLY 0x00000200U /* Operation should bypass any snapshots */ #define LCK_REVERT 0x00000400U /* Revert any incomplete change */ /* * Additional lock bits for cluster communication via args[1] */ #define LCK_PARTIAL_MODE 0x01 /* Partial activation? */ #define LCK_MIRROR_NOSYNC_MODE 0x02 /* Mirrors don't require sync */ #define LCK_DMEVENTD_MONITOR_MODE 0x04 /* Register with dmeventd */ /* Not yet used. */ #define LCK_CONVERT 0x08 /* Convert existing lock */ #define LCK_TEST_MODE 0x10 /* Test mode: No activation */ #define LCK_ORIGIN_ONLY_MODE 0x20 /* Same as above */ #define LCK_DMEVENTD_MONITOR_IGNORE 0x40 /* Whether to ignore dmeventd */ #define LCK_REVERT_MODE 0x80 /* Remove inactive tables */ /* * Special cases of VG locks. */ #define VG_ORPHANS "#orphans" #define VG_GLOBAL "#global" #define VG_SYNC_NAMES "#sync_names" /* * Common combinations */ #define LCK_NONE (LCK_VG | LCK_NULL) #define LCK_VG_READ (LCK_VG | LCK_READ | LCK_HOLD) #define LCK_VG_WRITE (LCK_VG | LCK_WRITE | LCK_HOLD) #define LCK_VG_UNLOCK (LCK_VG | LCK_UNLOCK) #define LCK_VG_DROP_CACHE (LCK_VG | LCK_WRITE | LCK_CACHE) /* FIXME: LCK_HOLD abused here */ #define LCK_VG_COMMIT (LCK_VG | LCK_WRITE | LCK_CACHE | LCK_HOLD) #define LCK_VG_REVERT (LCK_VG | LCK_READ | LCK_CACHE | LCK_HOLD) #define LCK_VG_BACKUP (LCK_VG | LCK_CACHE) #define LCK_VG_SYNC (LCK_NONE | LCK_CACHE) #define LCK_VG_SYNC_LOCAL (LCK_NONE | LCK_CACHE | LCK_LOCAL) #define LCK_LV_EXCLUSIVE (LCK_LV | LCK_EXCL) #define LCK_LV_SUSPEND (LCK_LV | LCK_WRITE) #define LCK_LV_RESUME (LCK_LV | LCK_UNLOCK) #define LCK_LV_ACTIVATE (LCK_LV | LCK_READ) #define LCK_LV_DEACTIVATE (LCK_LV | LCK_NULL) #define LCK_MASK (LCK_TYPE_MASK | LCK_SCOPE_MASK) #define LCK_LV_CLUSTERED(lv) \ (vg_is_clustered((lv)->vg) ? LCK_CLUSTER_VG : 0) #define lock_lv_vol(cmd, lv, flags) \ (find_replicator_vgs((lv)) ? \ lock_vol(cmd, (lv)->lvid.s, flags | LCK_LV_CLUSTERED(lv)) : \ 0) #define unlock_vg(cmd, vol) \ do { \ if (is_real_vg(vol)) \ sync_dev_names(cmd); \ (void) lock_vol(cmd, vol, LCK_VG_UNLOCK); \ } while (0) #define unlock_and_release_vg(cmd, vg, vol) \ do { \ unlock_vg(cmd, vol); \ release_vg(vg); \ } while (0) #define resume_lv(cmd, lv) lock_lv_vol(cmd, lv, LCK_LV_RESUME) #define resume_lv_origin(cmd, lv) lock_lv_vol(cmd, lv, LCK_LV_RESUME | LCK_ORIGIN_ONLY) #define revert_lv(cmd, lv) lock_lv_vol(cmd, lv, LCK_LV_RESUME | LCK_REVERT) #define suspend_lv(cmd, lv) lock_lv_vol(cmd, lv, LCK_LV_SUSPEND | LCK_HOLD) #define suspend_lv_origin(cmd, lv) lock_lv_vol(cmd, lv, LCK_LV_SUSPEND | LCK_HOLD | LCK_ORIGIN_ONLY) #define deactivate_lv(cmd, lv) lock_lv_vol(cmd, lv, LCK_LV_DEACTIVATE) #define activate_lv(cmd, lv) lock_lv_vol(cmd, lv, LCK_LV_ACTIVATE | LCK_HOLD) #define activate_lv_excl_local(cmd, lv) \ lock_lv_vol(cmd, lv, LCK_LV_EXCLUSIVE | LCK_HOLD | LCK_LOCAL) #define activate_lv_excl_remote(cmd, lv) \ lock_lv_vol(cmd, lv, LCK_LV_EXCLUSIVE | LCK_HOLD | LCK_REMOTE) struct logical_volume; int activate_lv_excl(struct cmd_context *cmd, struct logical_volume *lv); #define activate_lv_local(cmd, lv) \ lock_lv_vol(cmd, lv, LCK_LV_ACTIVATE | LCK_HOLD | LCK_LOCAL) #define deactivate_lv_local(cmd, lv) \ lock_lv_vol(cmd, lv, LCK_LV_DEACTIVATE | LCK_LOCAL) #define drop_cached_metadata(vg) \ lock_vol((vg)->cmd, (vg)->name, LCK_VG_DROP_CACHE) #define remote_commit_cached_metadata(vg) \ lock_vol((vg)->cmd, (vg)->name, LCK_VG_COMMIT) #define remote_revert_cached_metadata(vg) \ lock_vol((vg)->cmd, (vg)->name, LCK_VG_REVERT) #define remote_backup_metadata(vg) \ lock_vol((vg)->cmd, (vg)->name, LCK_VG_BACKUP) int sync_local_dev_names(struct cmd_context* cmd); int sync_dev_names(struct cmd_context* cmd); /* Process list of LVs */ struct volume_group; int suspend_lvs(struct cmd_context *cmd, struct dm_list *lvs, struct volume_group *vg_to_revert); int resume_lvs(struct cmd_context *cmd, struct dm_list *lvs); int revert_lvs(struct cmd_context *cmd, struct dm_list *lvs); int activate_lvs(struct cmd_context *cmd, struct dm_list *lvs, unsigned exclusive); /* Interrupt handling */ void sigint_clear(void); void sigint_allow(void); void sigint_restore(void); int sigint_caught(void); #endif lvm2-2.02.98/lib/locking/no_locking.c0000640000175000017500000000521612037016272016176 0ustar blankblank/* * 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 "locking.h" #include "locking_types.h" #include "lvm-string.h" #include "activate.h" #include /* * No locking */ static void _no_fin_locking(void) { } static void _no_reset_locking(void) { } static int _no_lock_resource(struct cmd_context *cmd, const char *resource, uint32_t flags) { switch (flags & LCK_SCOPE_MASK) { case LCK_VG: if (!strcmp(resource, VG_SYNC_NAMES)) fs_unlock(); break; case LCK_LV: switch (flags & LCK_TYPE_MASK) { case LCK_NULL: return lv_deactivate(cmd, resource); case LCK_UNLOCK: return lv_resume_if_active(cmd, resource, (flags & LCK_ORIGIN_ONLY) ? 1: 0, 0, (flags & LCK_REVERT) ? 1 : 0); case LCK_READ: return lv_activate_with_filter(cmd, resource, 0); case LCK_WRITE: return lv_suspend_if_active(cmd, resource, (flags & LCK_ORIGIN_ONLY) ? 1 : 0, 0); case LCK_EXCL: return lv_activate_with_filter(cmd, resource, 1); default: break; } break; default: log_error("Unrecognised lock scope: %d", flags & LCK_SCOPE_MASK); return 0; } return 1; } static int _readonly_lock_resource(struct cmd_context *cmd, const char *resource, uint32_t flags) { if ((flags & LCK_TYPE_MASK) == LCK_WRITE && (flags & LCK_SCOPE_MASK) == LCK_VG && !(flags & LCK_CACHE) && strcmp(resource, VG_GLOBAL)) { log_error("Read-only locking type set. " "Write locks are prohibited."); return 0; } return _no_lock_resource(cmd, resource, flags); } int init_no_locking(struct locking_type *locking, struct cmd_context *cmd __attribute__((unused)), int suppress_messages) { locking->lock_resource = _no_lock_resource; locking->reset_locking = _no_reset_locking; locking->fin_locking = _no_fin_locking; locking->flags = LCK_CLUSTERED; return 1; } int init_readonly_locking(struct locking_type *locking, struct cmd_context *cmd __attribute__((unused)), int suppress_messages) { locking->lock_resource = _readonly_lock_resource; locking->reset_locking = _no_reset_locking; locking->fin_locking = _no_fin_locking; locking->flags = 0; return 1; } lvm2-2.02.98/lib/locking/Makefile.in0000640000175000017500000000146712037016272015761 0ustar blankblank# # Copyright (C) 2003-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@ SOURCES = cluster_locking.c LIB_SHARED = liblvm2clusterlock.$(LIB_SUFFIX) LIB_VERSION = $(LIB_VERSION_LVM) include $(top_builddir)/make.tmpl install install_cluster: install_lvm2_plugin lvm2-2.02.98/lib/locking/locking_types.h0000640000175000017500000000330312037016272016726 0ustar blankblank/* * 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 */ #include "metadata.h" #include "config.h" typedef int (*lock_resource_fn) (struct cmd_context * cmd, const char *resource, uint32_t flags); typedef int (*query_resource_fn) (const char *resource, int *mode); typedef void (*fin_lock_fn) (void); typedef void (*reset_lock_fn) (void); #define LCK_PRE_MEMLOCK 0x00000001 /* Is memlock() needed before calls? */ #define LCK_CLUSTERED 0x00000002 struct locking_type { uint32_t flags; lock_resource_fn lock_resource; query_resource_fn query_resource; reset_lock_fn reset_locking; fin_lock_fn fin_locking; }; /* * Locking types */ int init_no_locking(struct locking_type *locking, struct cmd_context *cmd, int suppress_messages); int init_readonly_locking(struct locking_type *locking, struct cmd_context *cmd, int suppress_messages); int init_file_locking(struct locking_type *locking, struct cmd_context *cmd, int suppress_messages); int init_external_locking(struct locking_type *locking, struct cmd_context *cmd, int suppress_messages); int init_cluster_locking(struct locking_type *locking, struct cmd_context *cmd, int suppress_messages); lvm2-2.02.98/lib/locking/cluster_locking.c0000640000175000017500000003556312037016272017253 0ustar blankblank/* * 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 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 */ /* * Locking functions for LVM. * The main purpose of this part of the library is to serialise LVM * management operations across a cluster. */ #include "lib.h" #include "clvm.h" #include "lvm-string.h" #include "locking.h" #include "locking_types.h" #include "toolcontext.h" #include #include #include #include #include #ifndef CLUSTER_LOCKING_INTERNAL int lock_resource(struct cmd_context *cmd, const char *resource, uint32_t flags); int query_resource(const char *resource, int *mode); void locking_end(void); int locking_init(int type, struct dm_config_tree *cf, uint32_t *flags); #endif 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 /* * NOTE: the LVMD uses the socket FD as the client ID, this means * that any client that calls fork() will inherit the context of * it's parent. */ static int _clvmd_sock = -1; /* FIXME Install SIGPIPE handler? */ /* Open connection to the Cluster Manager daemon */ static int _open_local_sock(int suppress_messages) { int local_socket; struct sockaddr_un sockaddr = { .sun_family = AF_UNIX }; if (!dm_strncpy(sockaddr.sun_path, CLVMD_SOCKNAME, sizeof(sockaddr.sun_path))) { log_error("%s: clvmd socket name too long.", CLVMD_SOCKNAME); return -1; } /* Open local socket */ if ((local_socket = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { log_error_suppress(suppress_messages, "Local socket " "creation failed: %s", strerror(errno)); return -1; } if (connect(local_socket,(struct sockaddr *) &sockaddr, sizeof(sockaddr))) { int saved_errno = errno; log_error_suppress(suppress_messages, "connect() failed " "on local socket: %s", strerror(errno)); if (close(local_socket)) stack; errno = saved_errno; return -1; } return local_socket; } /* Send a request and return the status */ static int _send_request(char *inbuf, int inlen, char **retbuf) { char outbuf[PIPE_BUF] __attribute__((aligned(8))); struct clvm_header *outheader = (struct clvm_header *) outbuf; int len; unsigned off; int buflen; int err; /* Send it to CLVMD */ rewrite: if ( (err = write(_clvmd_sock, inbuf, inlen)) != inlen) { if (err == -1 && errno == EINTR) goto rewrite; log_error("Error writing data to clvmd: %s", strerror(errno)); return 0; } /* Get the response */ reread: if ((len = read(_clvmd_sock, outbuf, sizeof(struct clvm_header))) < 0) { if (errno == EINTR) goto reread; log_error("Error reading data from clvmd: %s", strerror(errno)); return 0; } if (len == 0) { log_error("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)) { log_error("cluster request failed: %s", strerror(errno)); return 0; } } return 1; } /* Build the structure header and parse-out wildcard node names */ /* FIXME: Cleanup implicit casts of clvmd_cmd (int, char, uint8_t, etc). */ static void _build_header(struct clvm_header *head, int clvmd_cmd, const char *node, int len) { head->cmd = clvmd_cmd; head->status = 0; head->flags = 0; head->xid = 0; head->clientid = 0; head->arglen = len; /* * Handle special node names. */ if (!node || !strcmp(node, NODE_ALL)) head->node[0] = '\0'; else if (!strcmp(node, NODE_LOCAL)) { head->node[0] = '\0'; head->flags = CLVMD_FLAG_LOCAL; } else if (!strcmp(node, NODE_REMOTE)) { head->node[0] = '\0'; head->flags = CLVMD_FLAG_REMOTE; } else strcpy(head->node, node); } /* * Send a message to a(or all) node(s) in the cluster and wait for replies */ static int _cluster_request(char clvmd_cmd, const char *node, void *data, int len, lvm_response_t ** response, int *num) { char outbuf[sizeof(struct clvm_header) + len + strlen(node) + 1] __attribute__((aligned(8))); 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(0); if (_clvmd_sock == -1) return 0; /* 1 byte is used from struct clvm_header.args[1], so -> len - 1 */ _build_header(head, clvmd_cmd, node, len - 1); memcpy(head->node + strlen(head->node) + 1, data, len); status = _send_request(outbuf, sizeof(struct clvm_header) + strlen(head->node) + len - 1, &retbuf); if (!status) 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); 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: 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; } static int _lock_for_cluster(struct cmd_context *cmd, unsigned char clvmd_cmd, uint32_t flags, const char *name) { int status; int i; char *args; const char *node = ""; int len; int dmeventd_mode; int saved_errno; lvm_response_t *response = NULL; int num_responses; assert(name); len = strlen(name) + 3; args = alloca(len); strcpy(args + 2, name); /* args[0] holds bottom 8 bits except LCK_LOCAL (0x40). */ args[0] = flags & (LCK_SCOPE_MASK | LCK_TYPE_MASK | LCK_NONBLOCK | LCK_HOLD | LCK_CLUSTER_VG); args[1] = 0; if (flags & LCK_ORIGIN_ONLY) args[1] |= LCK_ORIGIN_ONLY_MODE; if (flags & LCK_REVERT) args[1] |= LCK_REVERT_MODE; if (mirror_in_sync()) args[1] |= LCK_MIRROR_NOSYNC_MODE; if (test_mode()) args[1] |= LCK_TEST_MODE; /* * We propagate dmeventd_monitor_mode() to clvmd faithfully, since * dmeventd monitoring is tied to activation which happens inside clvmd * when locking_type = 3. */ dmeventd_mode = dmeventd_monitor_mode(); if (dmeventd_mode == DMEVENTD_MONITOR_IGNORE) args[1] |= LCK_DMEVENTD_MONITOR_IGNORE; if (dmeventd_mode) args[1] |= LCK_DMEVENTD_MONITOR_MODE; if (cmd->partial_activation) args[1] |= LCK_PARTIAL_MODE; /* * VG locks are just that: locks, and have no side effects * so we only need to do them on the local node because all * locks are cluster-wide. * * P_ locks /do/ get distributed across the cluster because they might * have side-effects. * * SYNC_NAMES and VG_BACKUP use the VG name directly without prefix. */ if (clvmd_cmd == CLVMD_CMD_SYNC_NAMES) { if (flags & LCK_LOCAL) node = NODE_LOCAL; } else if (clvmd_cmd != CLVMD_CMD_VG_BACKUP) { if (strncmp(name, "P_", 2) && (clvmd_cmd == CLVMD_CMD_LOCK_VG || (flags & LCK_LOCAL) || !(flags & LCK_CLUSTER_VG))) node = NODE_LOCAL; else if (flags & LCK_REMOTE) node = NODE_REMOTE; } status = _cluster_request(clvmd_cmd, node, args, len, &response, &num_responses); /* If any nodes were down then display them and return an error */ for (i = 0; i < num_responses; i++) { if (response[i].status == EHOSTDOWN) { log_error("clvmd not running on node %s", response[i].node); status = 0; errno = response[i].status; } else if (response[i].status) { log_error("Error locking 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; } /* API entry point for LVM */ #ifdef CLUSTER_LOCKING_INTERNAL static int _lock_resource(struct cmd_context *cmd, const char *resource, uint32_t flags) #else int lock_resource(struct cmd_context *cmd, const char *resource, uint32_t flags) #endif { char lockname[PATH_MAX]; int clvmd_cmd = 0; const char *lock_scope; const char *lock_type = ""; assert(strlen(resource) < sizeof(lockname)); assert(resource); switch (flags & LCK_SCOPE_MASK) { case LCK_VG: if (!strcmp(resource, VG_SYNC_NAMES)) { log_very_verbose("Requesting sync names."); return _lock_for_cluster(cmd, CLVMD_CMD_SYNC_NAMES, flags & ~LCK_HOLD, resource); } if (flags == LCK_VG_BACKUP) { log_very_verbose("Requesting backup of VG metadata for %s", resource); return _lock_for_cluster(cmd, CLVMD_CMD_VG_BACKUP, LCK_CLUSTER_VG, resource); } /* If the VG name is empty then lock the unused PVs */ if (dm_snprintf(lockname, sizeof(lockname), "%c_%s", (is_orphan_vg(resource) || is_global_vg(resource) || (flags & LCK_CACHE)) ? 'P' : 'V', resource) < 0) { log_error("Locking resource %s too long.", resource); return 0; } lock_scope = "VG"; clvmd_cmd = CLVMD_CMD_LOCK_VG; /* * Old clvmd does not expect LCK_HOLD which was already processed * in lock_vol, mask it for compatibility reasons. */ if (flags != LCK_VG_COMMIT && flags != LCK_VG_REVERT) flags &= ~LCK_HOLD; break; case LCK_LV: clvmd_cmd = CLVMD_CMD_LOCK_LV; strcpy(lockname, resource); lock_scope = "LV"; flags &= ~LCK_HOLD; /* Mask off HOLD flag */ break; default: log_error("Unrecognised lock scope: %d", flags & LCK_SCOPE_MASK); return 0; } switch(flags & LCK_TYPE_MASK) { case LCK_UNLOCK: lock_type = "UN"; break; case LCK_NULL: lock_type = "NL"; break; case LCK_READ: lock_type = "CR"; break; case LCK_PREAD: lock_type = "PR"; break; case LCK_WRITE: lock_type = "PW"; break; case LCK_EXCL: lock_type = "EX"; break; default: log_error("Unrecognised lock type: %u", flags & LCK_TYPE_MASK); return 0; } log_very_verbose("Locking %s %s %s (%s%s%s%s%s%s%s%s%s) (0x%x)", lock_scope, lockname, lock_type, lock_scope, flags & LCK_NONBLOCK ? "|NONBLOCK" : "", flags & LCK_HOLD ? "|HOLD" : "", flags & LCK_CLUSTER_VG ? "|CLUSTER" : "", flags & LCK_LOCAL ? "|LOCAL" : "", flags & LCK_REMOTE ? "|REMOTE" : "", flags & LCK_CACHE ? "|CACHE" : "", flags & LCK_ORIGIN_ONLY ? "|ORIGIN_ONLY" : "", flags & LCK_REVERT ? "|REVERT" : "", flags); /* Send a message to the cluster manager */ return _lock_for_cluster(cmd, clvmd_cmd, flags, lockname); } static int decode_lock_type(const char *response) { if (!response) return LCK_NULL; else if (!strcmp(response, "EX")) return LCK_EXCL; else if (!strcmp(response, "CR")) return LCK_READ; else if (!strcmp(response, "PR")) return LCK_PREAD; stack; return 0; } #ifdef CLUSTER_LOCKING_INTERNAL static int _query_resource(const char *resource, int *mode) #else int query_resource(const char *resource, int *mode) #endif { int i, status, len, num_responses, saved_errno; const char *node = ""; char *args; lvm_response_t *response = NULL; saved_errno = errno; len = strlen(resource) + 3; args = alloca(len); strcpy(args + 2, resource); args[0] = 0; args[1] = 0; status = _cluster_request(CLVMD_CMD_LOCK_QUERY, node, args, len, &response, &num_responses); *mode = LCK_NULL; for (i = 0; i < num_responses; i++) { if (response[i].status == EHOSTDOWN) continue; if (!response[i].response[0]) continue; /* * All nodes should use CR, or exactly one node * should hold EX. (PR is obsolete) * If two nodes report different locks, * something is broken - just return more important mode. */ if (decode_lock_type(response[i].response) > *mode) *mode = decode_lock_type(response[i].response); log_debug("Lock held for %s, node %s : %s", resource, response[i].node, response[i].response); } _cluster_free_request(response, num_responses); errno = saved_errno; return status; } #ifdef CLUSTER_LOCKING_INTERNAL static void _locking_end(void) #else void locking_end(void) #endif { if (_clvmd_sock != -1 && close(_clvmd_sock)) stack; _clvmd_sock = -1; } #ifdef CLUSTER_LOCKING_INTERNAL static void _reset_locking(void) #else void reset_locking(void) #endif { if (close(_clvmd_sock)) stack; _clvmd_sock = _open_local_sock(0); if (_clvmd_sock == -1) stack; } #ifdef CLUSTER_LOCKING_INTERNAL int init_cluster_locking(struct locking_type *locking, struct cmd_context *cmd, int suppress_messages) { locking->lock_resource = _lock_resource; locking->query_resource = _query_resource; locking->fin_locking = _locking_end; locking->reset_locking = _reset_locking; locking->flags = LCK_PRE_MEMLOCK | LCK_CLUSTERED; _clvmd_sock = _open_local_sock(suppress_messages); if (_clvmd_sock == -1) return 0; return 1; } #else int locking_init(int type, struct dm_config_tree *cf, uint32_t *flags) { _clvmd_sock = _open_local_sock(0); if (_clvmd_sock == -1) return 0; /* Ask LVM to lock memory before calling us */ *flags |= LCK_PRE_MEMLOCK; *flags |= LCK_CLUSTERED; return 1; } #endif lvm2-2.02.98/lib/locking/locking.c0000640000175000017500000003550012037016272015501 0ustar blankblank/* * 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 "locking.h" #include "locking_types.h" #include "lvm-string.h" #include "activate.h" #include "toolcontext.h" #include "memlock.h" #include "defaults.h" #include "lvmcache.h" #include #include #include #include #include static struct locking_type _locking; static sigset_t _oldset; static int _vg_lock_count = 0; /* Number of locks held */ static int _vg_write_lock_held = 0; /* VG write lock held? */ static int _signals_blocked = 0; static int _blocking_supported = 0; static volatile sig_atomic_t _sigint_caught = 0; static volatile sig_atomic_t _handler_installed; static struct sigaction _oldhandler; static int _oldmasked; typedef enum { LV_NOOP, LV_SUSPEND, LV_RESUME } lv_operation_t; static void _catch_sigint(int unused __attribute__((unused))) { _sigint_caught = 1; } int sigint_caught(void) { return _sigint_caught; } void sigint_clear(void) { _sigint_caught = 0; } /* * Temporarily allow keyboard interrupts to be intercepted and noted; * saves interrupt handler state for sigint_restore(). Users should * use the sigint_caught() predicate to check whether interrupt was * requested and act appropriately. Interrupt flags are never * cleared automatically by this code, but the tools clear the flag * before running each command in lvm_run_command(). All other places * where the flag needs to be cleared need to call sigint_clear(). */ void sigint_allow(void) { struct sigaction handler; sigset_t sigs; /* * Do not overwrite the backed-up handler data - * just increase nesting count. */ if (_handler_installed) { _handler_installed++; return; } /* Grab old sigaction for SIGINT: shall not fail. */ sigaction(SIGINT, NULL, &handler); handler.sa_flags &= ~SA_RESTART; /* Clear restart flag */ handler.sa_handler = _catch_sigint; _handler_installed = 1; /* Override the signal handler: shall not fail. */ sigaction(SIGINT, &handler, &_oldhandler); /* Unmask SIGINT. Remember to mask it again on restore. */ sigprocmask(0, NULL, &sigs); if ((_oldmasked = sigismember(&sigs, SIGINT))) { sigdelset(&sigs, SIGINT); sigprocmask(SIG_SETMASK, &sigs, NULL); } } void sigint_restore(void) { if (!_handler_installed) return; if (_handler_installed > 1) { _handler_installed--; return; } /* Nesting count went down to 0. */ _handler_installed = 0; if (_oldmasked) { sigset_t sigs; sigprocmask(0, NULL, &sigs); sigaddset(&sigs, SIGINT); sigprocmask(SIG_SETMASK, &sigs, NULL); } sigaction(SIGINT, &_oldhandler, NULL); } static void _block_signals(uint32_t flags __attribute__((unused))) { sigset_t set; if (_signals_blocked) return; if (sigfillset(&set)) { log_sys_error("sigfillset", "_block_signals"); return; } if (sigprocmask(SIG_SETMASK, &set, &_oldset)) { log_sys_error("sigprocmask", "_block_signals"); return; } _signals_blocked = 1; } static void _unblock_signals(void) { /* Don't unblock signals while any locks are held */ if (!_signals_blocked || _vg_lock_count) return; if (sigprocmask(SIG_SETMASK, &_oldset, NULL)) { log_sys_error("sigprocmask", "_block_signals"); return; } _signals_blocked = 0; } static void _lock_memory(struct cmd_context *cmd, lv_operation_t lv_op) { if (!(_locking.flags & LCK_PRE_MEMLOCK)) return; if (lv_op == LV_SUSPEND) critical_section_inc(cmd, "locking for suspend"); } static void _unlock_memory(struct cmd_context *cmd, lv_operation_t lv_op) { if (!(_locking.flags & LCK_PRE_MEMLOCK)) return; if (lv_op == LV_RESUME) critical_section_dec(cmd, "unlocking on resume"); } void reset_locking(void) { int was_locked = _vg_lock_count; _vg_lock_count = 0; _vg_write_lock_held = 0; if (_locking.reset_locking) _locking.reset_locking(); if (was_locked) _unblock_signals(); memlock_reset(); } static void _update_vg_lock_count(const char *resource, uint32_t flags) { /* Ignore locks not associated with updating VG metadata */ if ((flags & LCK_SCOPE_MASK) != LCK_VG || (flags & LCK_CACHE) || !strcmp(resource, VG_GLOBAL)) return; if ((flags & LCK_TYPE_MASK) == LCK_UNLOCK) _vg_lock_count--; else _vg_lock_count++; /* We don't bother to reset this until all VG locks are dropped */ if ((flags & LCK_TYPE_MASK) == LCK_WRITE) _vg_write_lock_held = 1; else if (!_vg_lock_count) _vg_write_lock_held = 0; } /* * Select a locking type * type: locking type; if < 0, then read config tree value */ int init_locking(int type, struct cmd_context *cmd, int suppress_messages) { if (getenv("LVM_SUPPRESS_LOCKING_FAILURE_MESSAGES")) suppress_messages = 1; if (type < 0) type = find_config_tree_int(cmd, "global/locking_type", 1); _blocking_supported = find_config_tree_int(cmd, "global/wait_for_locks", DEFAULT_WAIT_FOR_LOCKS); switch (type) { case 0: init_no_locking(&_locking, cmd, suppress_messages); log_warn("WARNING: Locking disabled. Be careful! " "This could corrupt your metadata."); return 1; case 1: log_very_verbose("%sFile-based locking selected.", _blocking_supported ? "" : "Non-blocking "); if (!init_file_locking(&_locking, cmd, suppress_messages)) { log_error_suppress(suppress_messages, "File-based locking initialisation failed."); break; } return 1; #ifdef HAVE_LIBDL case 2: if (!is_static()) { log_very_verbose("External locking selected."); if (init_external_locking(&_locking, cmd, suppress_messages)) return 1; } if (!find_config_tree_int(cmd, "locking/fallback_to_clustered_locking", find_config_tree_int(cmd, "global/fallback_to_clustered_locking", DEFAULT_FALLBACK_TO_CLUSTERED_LOCKING))) { log_error_suppress(suppress_messages, "External locking initialisation failed."); break; } #endif #ifdef CLUSTER_LOCKING_INTERNAL log_very_verbose("Falling back to internal clustered locking."); /* Fall through */ case 3: log_very_verbose("Cluster locking selected."); if (!init_cluster_locking(&_locking, cmd, suppress_messages)) { log_error_suppress(suppress_messages, "Internal cluster locking initialisation failed."); break; } return 1; #endif case 4: log_verbose("Read-only locking selected. " "Only read operations permitted."); if (!init_readonly_locking(&_locking, cmd, suppress_messages)) break; return 1; default: log_error("Unknown locking type requested."); return 0; } if ((type == 2 || type == 3) && find_config_tree_int(cmd, "locking/fallback_to_local_locking", find_config_tree_int(cmd, "global/fallback_to_local_locking", DEFAULT_FALLBACK_TO_LOCAL_LOCKING))) { log_warn_suppress(suppress_messages, "WARNING: Falling back to local file-based locking."); log_warn_suppress(suppress_messages, "Volume Groups with the clustered attribute will " "be inaccessible."); if (init_file_locking(&_locking, cmd, suppress_messages)) return 1; else log_error_suppress(suppress_messages, "File-based locking initialisation failed."); } if (!ignorelockingfailure()) return 0; log_verbose("Locking disabled - only read operations permitted."); init_readonly_locking(&_locking, cmd, suppress_messages); return 1; } void fin_locking(void) { _locking.fin_locking(); } /* * Does the LVM1 driver know of this VG name? */ int check_lvm1_vg_inactive(struct cmd_context *cmd, const char *vgname) { struct stat info; char path[PATH_MAX]; /* We'll allow operations on orphans */ if (!is_real_vg(vgname)) return 1; /* LVM1 is only present in 2.4 kernels. */ if (strncmp(cmd->kernel_vsn, "2.4.", 4)) return 1; if (dm_snprintf(path, sizeof(path), "%s/lvm/VGs/%s", cmd->proc_dir, vgname) < 0) { log_error("LVM1 proc VG pathname too long for %s", vgname); return 0; } if (stat(path, &info) == 0) { log_error("%s exists: Is the original LVM driver using " "this volume group?", path); return 0; } else if (errno != ENOENT && errno != ENOTDIR) { log_sys_error("stat", path); return 0; } return 1; } /* * VG locking is by VG name. * FIXME This should become VG uuid. */ static int _lock_vol(struct cmd_context *cmd, const char *resource, uint32_t flags, lv_operation_t lv_op) { uint32_t lck_type = flags & LCK_TYPE_MASK; uint32_t lck_scope = flags & LCK_SCOPE_MASK; int ret = 0; _block_signals(flags); _lock_memory(cmd, lv_op); assert(resource); if (!*resource) { log_error(INTERNAL_ERROR "Use of P_orphans is deprecated."); return 0; } if ((is_orphan_vg(resource) || is_global_vg(resource)) && (flags & LCK_CACHE)) { log_error(INTERNAL_ERROR "P_%s referenced", resource); return 0; } if (cmd->metadata_read_only && lck_type == LCK_WRITE && strcmp(resource, VG_GLOBAL)) { log_error("Operation prohibited while global/metadata_read_only is set."); return 0; } if ((ret = _locking.lock_resource(cmd, resource, flags))) { if (lck_scope == LCK_VG && !(flags & LCK_CACHE)) { if (lck_type != LCK_UNLOCK) lvmcache_lock_vgname(resource, lck_type == LCK_READ); dev_reset_error_count(cmd); } _update_vg_lock_count(resource, flags); } else stack; /* If unlocking, always remove lock from lvmcache even if operation failed. */ if (lck_scope == LCK_VG && !(flags & LCK_CACHE) && lck_type == LCK_UNLOCK) { lvmcache_unlock_vgname(resource); if (!ret) _update_vg_lock_count(resource, flags); } _unlock_memory(cmd, lv_op); _unblock_signals(); return ret; } int lock_vol(struct cmd_context *cmd, const char *vol, uint32_t flags) { char resource[258] __attribute__((aligned(8))); lv_operation_t lv_op; int lck_type = flags & LCK_TYPE_MASK; switch (flags & (LCK_SCOPE_MASK | LCK_TYPE_MASK)) { case LCK_LV_SUSPEND: lv_op = LV_SUSPEND; break; case LCK_LV_RESUME: lv_op = LV_RESUME; break; default: lv_op = LV_NOOP; } if (flags == LCK_NONE) { log_debug(INTERNAL_ERROR "%s: LCK_NONE lock requested", vol); return 1; } switch (flags & LCK_SCOPE_MASK) { case LCK_VG: if (!_blocking_supported) flags |= LCK_NONBLOCK; /* Global VG_ORPHANS lock covers all orphan formats. */ if (is_orphan_vg(vol)) vol = VG_ORPHANS; /* VG locks alphabetical, ORPHAN lock last */ if ((lck_type != LCK_UNLOCK) && !(flags & LCK_CACHE) && !lvmcache_verify_lock_order(vol)) return_0; /* Lock VG to change on-disk metadata. */ /* If LVM1 driver knows about the VG, it can't be accessed. */ if (!check_lvm1_vg_inactive(cmd, vol)) return_0; break; case LCK_LV: /* All LV locks are non-blocking. */ flags |= LCK_NONBLOCK; break; default: log_error("Unrecognised lock scope: %d", flags & LCK_SCOPE_MASK); return 0; } strncpy(resource, vol, sizeof(resource) - 1); resource[sizeof(resource) - 1] = '\0'; if (!_lock_vol(cmd, resource, flags, lv_op)) return_0; /* * If a real lock was acquired (i.e. not LCK_CACHE), * perform an immediate unlock unless LCK_HOLD was requested. */ if ((lck_type == LCK_NULL) || (lck_type == LCK_UNLOCK) || (flags & (LCK_CACHE | LCK_HOLD))) return 1; if (!_lock_vol(cmd, resource, (flags & ~LCK_TYPE_MASK) | LCK_UNLOCK, lv_op)) return_0; return 1; } /* Unlock list of LVs */ int resume_lvs(struct cmd_context *cmd, struct dm_list *lvs) { struct lv_list *lvl; int r = 1; dm_list_iterate_items(lvl, lvs) if (!resume_lv(cmd, lvl->lv)) { r = 0; stack; } return r; } /* Unlock and revert list of LVs */ int revert_lvs(struct cmd_context *cmd, struct dm_list *lvs) { struct lv_list *lvl; int r = 1; dm_list_iterate_items(lvl, lvs) if (!revert_lv(cmd, lvl->lv)) { r = 0; stack; } return r; } /* * Lock a list of LVs. * On failure to lock any LV, calls vg_revert() if vg_to_revert is set and * then unlocks any LVs on the list already successfully locked. */ int suspend_lvs(struct cmd_context *cmd, struct dm_list *lvs, struct volume_group *vg_to_revert) { struct lv_list *lvl; dm_list_iterate_items(lvl, lvs) { if (!suspend_lv(cmd, lvl->lv)) { log_error("Failed to suspend %s", lvl->lv->name); if (vg_to_revert) vg_revert(vg_to_revert); /* * FIXME Should be * dm_list_uniterate(lvh, lvs, &lvl->list) { * lvl = dm_list_item(lvh, struct lv_list); * but revert would need fixing to use identical tree deps first. */ dm_list_iterate_items(lvl, lvs) if (!revert_lv(cmd, lvl->lv)) stack; return 0; } } return 1; } /* * First try to activate exclusively locally. * Then if the VG is clustered and the LV is not yet active (e.g. due to * an activation filter) try activating on remote nodes. */ int activate_lv_excl(struct cmd_context *cmd, struct logical_volume *lv) { /* Non-clustered VGs are only activated locally. */ if (!vg_is_clustered(lv->vg)) return activate_lv_excl_local(cmd, lv); if (lv_is_active_exclusive_locally(lv)) return 1; if (!activate_lv_excl_local(cmd, lv)) return_0; if (lv_is_active_exclusive(lv)) return 1; /* FIXME Deal with error return codes. */ if (activate_lv_excl_remote(cmd, lv)) stack; return lv_is_active_exclusive(lv); } /* Lock a list of LVs */ int activate_lvs(struct cmd_context *cmd, struct dm_list *lvs, unsigned exclusive) { struct dm_list *lvh; struct lv_list *lvl; dm_list_iterate_items(lvl, lvs) { if (!exclusive && !lv_is_active_exclusive(lvl->lv)) { if (!activate_lv(cmd, lvl->lv)) { log_error("Failed to activate %s", lvl->lv->name); return 0; } } else if (!activate_lv_excl(cmd, lvl->lv)) { log_error("Failed to activate %s", lvl->lv->name); dm_list_uniterate(lvh, lvs, &lvl->list) { lvl = dm_list_item(lvh, struct lv_list); if (!activate_lv(cmd, lvl->lv)) stack; } return 0; } } return 1; } int vg_write_lock_held(void) { return _vg_write_lock_held; } int locking_is_clustered(void) { return (_locking.flags & LCK_CLUSTERED) ? 1 : 0; } int remote_lock_held(const char *vol, int *exclusive) { int mode = LCK_NULL; if (!locking_is_clustered()) return 0; if (!_locking.query_resource) return -1; /* * If an error occured, expect that volume is active */ if (!_locking.query_resource(vol, &mode)) { stack; return 1; } if (exclusive) *exclusive = (mode == LCK_EXCL); return mode == LCK_NULL ? 0 : 1; } int sync_local_dev_names(struct cmd_context* cmd) { memlock_unlock(cmd); return lock_vol(cmd, VG_SYNC_NAMES, LCK_VG_SYNC_LOCAL); } int sync_dev_names(struct cmd_context* cmd) { memlock_unlock(cmd); return lock_vol(cmd, VG_SYNC_NAMES, LCK_VG_SYNC); } lvm2-2.02.98/lib/report/0000750000175000017500000000000012037016272013570 5ustar blankblanklvm2-2.02.98/lib/report/properties.h0000640000175000017500000000325712037016272016145 0ustar blankblank/* * 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 */ #ifndef _LVM_PROPERTIES_H #define _LVM_PROPERTIES_H #include "libdevmapper.h" #include "lvm-types.h" #include "metadata.h" #include "report.h" struct lvm_property_type { unsigned type; const char *id; unsigned is_settable:1; unsigned is_string:1; unsigned is_integer:1; union { const char *string; uint64_t integer; } value; int (*get) (const void *obj, struct lvm_property_type *prop); int (*set) (void *obj, struct lvm_property_type *prop); }; int lvseg_get_property(const struct lv_segment *lvseg, struct lvm_property_type *prop); int lv_get_property(const struct logical_volume *lv, struct lvm_property_type *prop); int vg_get_property(const struct volume_group *vg, struct lvm_property_type *prop); int pvseg_get_property(const struct pv_segment *pvseg, struct lvm_property_type *prop); int pv_get_property(const struct physical_volume *pv, struct lvm_property_type *prop); int lv_set_property(struct logical_volume *lv, struct lvm_property_type *prop); int vg_set_property(struct volume_group *vg, struct lvm_property_type *prop); int pv_set_property(struct physical_volume *pv, struct lvm_property_type *prop); #endif lvm2-2.02.98/lib/report/report.c0000640000175000017500000010006112037016272015246 0ustar blankblank/* * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved. * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU 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 "metadata.h" #include "report.h" #include "toolcontext.h" #include "lvm-string.h" #include "display.h" #include "activate.h" #include "segtype.h" #include "lvmcache.h" #include /* offsetof() */ struct lvm_report_object { struct volume_group *vg; struct logical_volume *lv; struct physical_volume *pv; struct lv_segment *seg; struct pv_segment *pvseg; }; static const uint64_t _minusone64 = UINT64_C(-1); static const int32_t _minusone32 = INT32_C(-1); /* * Data-munging functions to prepare each data type for display and sorting */ static int _string_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { return dm_report_field_string(rh, field, (const char * const *) data); } static int _dev_name_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { const char *name = dev_name(*(const struct device * const *) data); return dm_report_field_string(rh, field, &name); } static int _devices_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { char *str; if (!(str = lvseg_devices(mem, (const struct lv_segment *) data))) return 0; dm_report_field_set_value(field, str, NULL); return 1; } static int _peranges_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { char *str; if (!(str = lvseg_seg_pe_ranges(mem, (const struct lv_segment *) data))) return 0; dm_report_field_set_value(field, str, NULL); return 1; } static int _tags_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { const struct dm_list *tags = (const struct dm_list *) data; char *tags_str; if (!(tags_str = tags_format_and_copy(mem, tags))) return 0; dm_report_field_set_value(field, tags_str, NULL); return 1; } static int _modules_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { const struct logical_volume *lv = (const struct logical_volume *) data; char *modules_str; if (!(modules_str = lv_modules_dup(mem, lv))) return 0; dm_report_field_set_value(field, modules_str, NULL); return 1; } static int _vgfmt_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { const struct volume_group *vg = (const struct volume_group *) data; if (!vg->fid) { dm_report_field_set_value(field, "", NULL); return 1; } return _string_disp(rh, mem, field, &vg->fid->fmt->name, private); } static int _pvfmt_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { const struct physical_volume *pv = (const struct physical_volume *) data; if (!pv->fmt) { dm_report_field_set_value(field, "", NULL); return 1; } return _string_disp(rh, mem, field, &pv->fmt->name, private); } static int _lvkmaj_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { const struct logical_volume *lv = (const struct logical_volume *) data; int major; if ((major = lv_kernel_major(lv)) >= 0) return dm_report_field_int(rh, field, &major); return dm_report_field_int32(rh, field, &_minusone32); } static int _lvkmin_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { const struct logical_volume *lv = (const struct logical_volume *) data; int minor; if ((minor = lv_kernel_minor(lv)) >= 0) return dm_report_field_int(rh, field, &minor); return dm_report_field_int32(rh, field, &_minusone32); } static int _lvstatus_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { const struct logical_volume *lv = (const struct logical_volume *) data; char *repstr; if (!(repstr = lv_attr_dup(mem, lv))) return 0; dm_report_field_set_value(field, repstr, NULL); return 1; } static int _pvstatus_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { const struct physical_volume *pv = (const struct physical_volume *) data; char *repstr; if (!(repstr = pv_attr_dup(mem, pv))) return 0; dm_report_field_set_value(field, repstr, NULL); return 1; } static int _vgstatus_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { const struct volume_group *vg = (const struct volume_group *) data; char *repstr; if (!(repstr = vg_attr_dup(mem, vg))) return 0; dm_report_field_set_value(field, repstr, NULL); return 1; } static int _segtype_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem __attribute__((unused)), struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { const struct lv_segment *seg = (const struct lv_segment *) data; char *name; if (!(name = lvseg_segtype_dup(mem, seg))) { log_error("Failed to get segtype."); return 0; } dm_report_field_set_value(field, name, NULL); return 1; } static int _loglv_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { const struct logical_volume *lv = (const struct logical_volume *) data; const char *name; if ((name = lv_mirror_log_dup(mem, lv))) return dm_report_field_string(rh, field, &name); dm_report_field_set_value(field, "", NULL); return 1; } static int _lvname_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { const struct logical_volume *lv = (const struct logical_volume *) data; char *repstr, *lvname; size_t len; if (lv_is_visible(lv)) return dm_report_field_string(rh, field, &lv->name); len = strlen(lv->name) + 3; if (!(repstr = dm_pool_zalloc(mem, len))) { log_error("dm_pool_alloc failed"); return 0; } if (dm_snprintf(repstr, len, "[%s]", lv->name) < 0) { log_error("lvname snprintf failed"); return 0; } if (!(lvname = dm_pool_strdup(mem, lv->name))) { log_error("dm_pool_strdup failed"); return 0; } dm_report_field_set_value(field, repstr, lvname); return 1; } static int _datalv_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { const struct logical_volume *lv = (const struct logical_volume *) data; if (lv_is_thin_pool(lv)) return _lvname_disp(rh, mem, field, seg_lv(first_seg(lv), 0), private); dm_report_field_set_value(field, "", NULL); return 1; } static int _metadatalv_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { const struct logical_volume *lv = (const struct logical_volume *) data; if (lv_is_thin_pool(lv)) return _lvname_disp(rh, mem, field, first_seg(lv)->metadata_lv, private); dm_report_field_set_value(field, "", NULL); return 1; } static int _poollv_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { const struct logical_volume *lv = (const struct logical_volume *) data; struct lv_segment *seg; if (lv_is_thin_volume(lv)) dm_list_iterate_items(seg, &lv->segments) if (seg_is_thin_volume(seg)) return _lvname_disp(rh, mem, field, seg->pool_lv, private); dm_report_field_set_value(field, "", NULL); return 1; } static int _lvpath_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { const struct logical_volume *lv = (const struct logical_volume *) data; char *repstr; if (!(repstr = lv_path_dup(mem, lv))) return 0; dm_report_field_set_value(field, repstr, NULL); return 1; } static int _origin_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { const struct logical_volume *lv = (const struct logical_volume *) data; if (lv_is_cow(lv)) return _lvname_disp(rh, mem, field, origin_from_cow(lv), private); if (lv_is_thin_volume(lv) && first_seg(lv)->origin) return _lvname_disp(rh, mem, field, first_seg(lv)->origin, private); dm_report_field_set_value(field, "", NULL); return 1; } static int _movepv_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { const struct logical_volume *lv = (const struct logical_volume *) data; const char *name; if (!(name = lv_move_pv_dup(mem, lv))) dm_report_field_set_value(field, "", NULL); else return dm_report_field_string(rh, field, &name); return 1; } static int _convertlv_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { const struct logical_volume *lv = (const struct logical_volume *) data; const char *name = NULL; name = lv_convert_lv_dup(mem, lv); if (name) return dm_report_field_string(rh, field, &name); dm_report_field_set_value(field, "", NULL); return 1; } static int _size32_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { const uint32_t size = *(const uint32_t *) data; const char *disp, *repstr; uint64_t *sortval; if (!*(disp = display_size_units(private, (uint64_t) size))) return_0; if (!(repstr = dm_pool_strdup(mem, disp))) { log_error("dm_pool_strdup failed"); return 0; } if (!(sortval = dm_pool_alloc(mem, sizeof(uint64_t)))) { log_error("dm_pool_alloc failed"); return 0; } *sortval = (uint64_t) size; dm_report_field_set_value(field, repstr, sortval); return 1; } static int _size64_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { const uint64_t size = *(const uint64_t *) data; const char *disp, *repstr; uint64_t *sortval; if (!*(disp = display_size_units(private, size))) return_0; if (!(repstr = dm_pool_strdup(mem, disp))) { log_error("dm_pool_strdup failed"); return 0; } if (!(sortval = dm_pool_alloc(mem, sizeof(uint64_t)))) { log_error("dm_pool_alloc failed"); return 0; } *sortval = size; dm_report_field_set_value(field, repstr, sortval); return 1; } static int _uint32_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { return dm_report_field_uint32(rh, field, data); } static int _int32_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { return dm_report_field_int32(rh, field, data); } static int _lvreadahead_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { const struct logical_volume *lv = (const struct logical_volume *) data; if (lv->read_ahead == DM_READ_AHEAD_AUTO) { dm_report_field_set_value(field, "auto", &_minusone64); return 1; } return _size32_disp(rh, mem, field, &lv->read_ahead, private); } static int _lvkreadahead_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { const struct logical_volume *lv = (const struct logical_volume *) data; uint32_t read_ahead; if ((read_ahead = lv_kernel_read_ahead(lv)) == UINT32_MAX) return dm_report_field_int32(rh, field, &_minusone32); return _size32_disp(rh, mem, field, &read_ahead, private); } static int _vgsize_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { const struct volume_group *vg = (const struct volume_group *) data; uint64_t size; size = (uint64_t) vg_size(vg); return _size64_disp(rh, mem, field, &size, private); } static int _segstart_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { const struct lv_segment *seg = (const struct lv_segment *) data; uint64_t start; start = lvseg_start(seg); return _size64_disp(rh, mem, field, &start, private); } static int _segstartpe_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { const struct lv_segment *seg = (const struct lv_segment *) data; return dm_report_field_uint32(rh, field, &seg->le); } static int _segsize_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { const struct lv_segment *seg = (const struct lv_segment *) data; uint64_t size; size = lvseg_size(seg); return _size64_disp(rh, mem, field, &size, private); } static int _chunksize_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { const struct lv_segment *seg = (const struct lv_segment *) data; uint64_t size; size = lvseg_chunksize(seg); return _size64_disp(rh, mem, field, &size, private); } static int _thinzero_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { const struct lv_segment *seg = (const struct lv_segment *) data; /* Suppress thin count if not thin pool */ if (!seg_is_thin_pool(seg)) { dm_report_field_set_value(field, "", NULL); return 1; } return _uint32_disp(rh, mem, field, &seg->zero_new_blocks, private); } static int _transactionid_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { const struct lv_segment *seg = (const struct lv_segment *) data; /* Suppress thin count if not thin pool */ if (!seg_is_thin_pool(seg)) { dm_report_field_set_value(field, "", NULL); return 1; } return dm_report_field_uint64(rh, field, &seg->transaction_id); } static int _discards_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { const struct lv_segment *seg = (const struct lv_segment *) data; const char *discards_str; if (seg_is_thin_volume(seg)) seg = first_seg(seg->pool_lv); if (seg_is_thin_pool(seg)) { discards_str = get_pool_discards_name(seg->discards); return dm_report_field_string(rh, field, &discards_str); } dm_report_field_set_value(field, "", NULL); return 1; } static int _originsize_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { const struct logical_volume *lv = (const struct logical_volume *) data; uint64_t size; size = lv_origin_size(lv); return _size64_disp(rh, mem, field, &size, private); } static int _pvused_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { const struct physical_volume *pv = (const struct physical_volume *) data; uint64_t used; used = pv_used(pv); return _size64_disp(rh, mem, field, &used, private); } static int _pvfree_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { const struct physical_volume *pv = (const struct physical_volume *) data; uint64_t freespace; freespace = pv_free(pv); return _size64_disp(rh, mem, field, &freespace, private); } static int _pvsize_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { const struct physical_volume *pv = (const struct physical_volume *) data; uint64_t size; size = pv_size_field(pv); return _size64_disp(rh, mem, field, &size, private); } static int _devsize_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { const struct physical_volume *pv = (const struct physical_volume *) data; uint64_t size; size = pv_dev_size(pv); return _size64_disp(rh, mem, field, &size, private); } static int _vgfree_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { const struct volume_group *vg = (const struct volume_group *) data; uint64_t freespace; freespace = (uint64_t) vg_free(vg); return _size64_disp(rh, mem, field, &freespace, private); } static int _uuid_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { char *repstr = NULL; if (!(repstr = id_format_and_copy(mem, data))) return_0; dm_report_field_set_value(field, repstr, NULL); return 1; } static int _pvmdas_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { uint32_t count; const struct physical_volume *pv = (const struct physical_volume *) data; count = pv_mda_count(pv); return _uint32_disp(rh, mem, field, &count, private); } static int _pvmdasused_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { uint32_t count; const struct physical_volume *pv = (const struct physical_volume *) data; count = pv_mda_used_count(pv); return _uint32_disp(rh, mem, field, &count, private); } static int _vgmdas_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { const struct volume_group *vg = (const struct volume_group *) data; uint32_t count; count = vg_mda_count(vg); return _uint32_disp(rh, mem, field, &count, private); } static int _vgmdasused_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { const struct volume_group *vg = (const struct volume_group *) data; uint32_t count; count = vg_mda_used_count(vg); return _uint32_disp(rh, mem, field, &count, private); } static int _vgmdacopies_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { const struct volume_group *vg = (const struct volume_group *) data; uint32_t count; count = vg_mda_copies(vg); if (count == VGMETADATACOPIES_UNMANAGED) { dm_report_field_set_value(field, "unmanaged", &_minusone64); return 1; } return _uint32_disp(rh, mem, field, &count, private); } static int _pvmdafree_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { const struct physical_volume *pv = (const struct physical_volume *) data; uint64_t freespace; freespace = pv_mda_free(pv); return _size64_disp(rh, mem, field, &freespace, private); } static int _pvmdasize_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { const struct physical_volume *pv = (const struct physical_volume *) data; uint64_t min_mda_size; min_mda_size = pv_mda_size(pv); return _size64_disp(rh, mem, field, &min_mda_size, private); } static int _vgmdasize_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { const struct volume_group *vg = (const struct volume_group *) data; uint64_t min_mda_size; min_mda_size = vg_mda_size(vg); return _size64_disp(rh, mem, field, &min_mda_size, private); } static int _vgmdafree_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { const struct volume_group *vg = (const struct volume_group *) data; uint64_t freespace; freespace = vg_mda_free(vg); return _size64_disp(rh, mem, field, &freespace, private); } static int _lvcount_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { const struct volume_group *vg = (const struct volume_group *) data; uint32_t count; count = vg_visible_lvs(vg); return _uint32_disp(rh, mem, field, &count, private); } static int _lvsegcount_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { const struct logical_volume *lv = (const struct logical_volume *) data; uint32_t count; count = dm_list_size(&lv->segments); return _uint32_disp(rh, mem, field, &count, private); } static int _snapcount_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { const struct volume_group *vg = (const struct volume_group *) data; uint32_t count; count = snapshot_count(vg); return _uint32_disp(rh, mem, field, &count, private); } static int _snpercent_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { const struct logical_volume *lv = (const struct logical_volume *) data; struct lvinfo info; percent_t snap_percent; uint64_t *sortval; char *repstr; /* Suppress snapshot percentage if not using driver */ if (!activation()) { dm_report_field_set_value(field, "", NULL); return 1; } if (!(sortval = dm_pool_alloc(mem, sizeof(uint64_t)))) { log_error("dm_pool_alloc failed"); return 0; } if ((!lv_is_cow(lv) && !lv_is_merging_origin(lv)) || !lv_info(lv->vg->cmd, lv, 0, &info, 0, 0) || !info.exists) { *sortval = UINT64_C(0); dm_report_field_set_value(field, "", sortval); return 1; } if (!lv_snapshot_percent(lv, &snap_percent) || (snap_percent == PERCENT_INVALID) || (snap_percent == PERCENT_MERGE_FAILED)) { if (!lv_is_merging_origin(lv)) { *sortval = UINT64_C(100); dm_report_field_set_value(field, "100.00", sortval); } else { /* onactivate merge that hasn't started yet would * otherwise display incorrect snap% in origin */ *sortval = UINT64_C(0); dm_report_field_set_value(field, "", sortval); } return 1; } if (!(repstr = dm_pool_zalloc(mem, 8))) { log_error("dm_pool_alloc failed"); return 0; } if (dm_snprintf(repstr, 7, "%.2f", percent_to_float(snap_percent)) < 0) { log_error("snapshot percentage too large"); return 0; } *sortval = (uint64_t)(snap_percent * 1000.f); dm_report_field_set_value(field, repstr, sortval); return 1; } static int _copypercent_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { const struct logical_volume *lv = (const struct logical_volume *) data; percent_t percent; uint64_t *sortval; char *repstr; if (!(sortval = dm_pool_alloc(mem, sizeof(uint64_t)))) { log_error("dm_pool_alloc failed"); return 0; } if ((!(lv->status & PVMOVE) && !(lv->status & MIRRORED)) || !lv_mirror_percent(lv->vg->cmd, lv, 0, &percent, NULL) || (percent == PERCENT_INVALID)) { *sortval = UINT64_C(0); dm_report_field_set_value(field, "", sortval); return 1; } percent = copy_percent(lv); if (!(repstr = dm_pool_zalloc(mem, 8))) { log_error("dm_pool_alloc failed"); return 0; } if (dm_snprintf(repstr, 7, "%.2f", percent_to_float(percent)) < 0) { log_error("copy percentage too large"); return 0; } *sortval = (uint64_t)(percent * 1000.f); dm_report_field_set_value(field, repstr, sortval); return 1; } static int _dtpercent_disp(int metadata, struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { const struct logical_volume *lv = (const struct logical_volume *) data; struct lvinfo info; percent_t percent; uint64_t *sortval; char *repstr; /* Suppress data percent if not thin pool/volume or not using driver */ if (!lv_info(lv->vg->cmd, lv, 1, &info, 0, 0) || !info.exists) { dm_report_field_set_value(field, "", NULL); return 1; } if (!(sortval = dm_pool_zalloc(mem, sizeof(uint64_t)))) { log_error("Failed to allocate sortval."); return 0; } if (lv_is_thin_pool(lv)) { if (!lv_thin_pool_percent(lv, metadata, &percent)) return_0; } else { /* thin_volume */ if (!lv_thin_percent(lv, 0, &percent)) return_0; } if (!(repstr = dm_pool_alloc(mem, 8))) { log_error("Failed to allocate report buffer."); return 0; } if (dm_snprintf(repstr, 8, "%.2f", percent_to_float(percent)) < 0) { log_error("Data percentage too large."); return 0; } *sortval = (uint64_t)(percent * 1000.f); dm_report_field_set_value(field, repstr, sortval); return 1; } static int _datapercent_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { const struct logical_volume *lv = (const struct logical_volume *) data; if (lv_is_cow(lv)) return _snpercent_disp(rh, mem, field, data, private); if (lv_is_thin_pool(lv) || lv_is_thin_volume(lv)) return _dtpercent_disp(0, rh, mem, field, data, private); dm_report_field_set_value(field, "", NULL); return 1; } static int _metadatapercent_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { const struct logical_volume *lv = (const struct logical_volume *) data; if (lv_is_thin_pool(lv)) return _dtpercent_disp(1, rh, mem, field, data, private); dm_report_field_set_value(field, "", NULL); return 1; } static int _lvmetadatasize_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { const struct logical_volume *lv = (const struct logical_volume *) data; uint64_t size; if (!lv_is_thin_pool(lv)) { dm_report_field_set_value(field, "", NULL); return 1; } size = lv_metadata_size(lv); return _size64_disp(rh, mem, field, &size, private); } static int _thincount_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { const struct lv_segment *seg = (const struct lv_segment *) data; uint32_t count; /* Suppress thin count if not thin pool */ if (!seg_is_thin_pool(seg)) { dm_report_field_set_value(field, "", NULL); return 1; } count = dm_list_size(&seg->lv->segs_using_this_lv); return _uint32_disp(rh, mem, field, &count, private); } static int _lvtime_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { const struct logical_volume *lv = (const struct logical_volume *) data; char *repstr; uint64_t *sortval; if (!(sortval = dm_pool_zalloc(mem, sizeof(uint64_t)))) { log_error("Failed to allocate sortval."); return 0; } *sortval = lv->timestamp; if (!(repstr = lv_time_dup(mem, lv))) return_0; dm_report_field_set_value(field, repstr, sortval); return 1; } static int _lvhost_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { const struct logical_volume *lv = (const struct logical_volume *) data; char *repstr; if (!(repstr = lv_host_dup(mem, lv))) return_0; dm_report_field_set_value(field, repstr, repstr); return 1; } /* Report object types */ /* necessary for displaying something for PVs not belonging to VG */ static struct format_instance _dummy_fid = { .metadata_areas_in_use = { &(_dummy_fid.metadata_areas_in_use), &(_dummy_fid.metadata_areas_in_use) }, .metadata_areas_ignored = { &(_dummy_fid.metadata_areas_ignored), &(_dummy_fid.metadata_areas_ignored) }, }; static struct volume_group _dummy_vg = { .fid = &_dummy_fid, .name = "", .system_id = (char *) "", .pvs = { &(_dummy_vg.pvs), &(_dummy_vg.pvs) }, .lvs = { &(_dummy_vg.lvs), &(_dummy_vg.lvs) }, .tags = { &(_dummy_vg.tags), &(_dummy_vg.tags) }, }; static void *_obj_get_vg(void *obj) { struct volume_group *vg = ((struct lvm_report_object *)obj)->vg; return vg ? vg : &_dummy_vg; } static void *_obj_get_lv(void *obj) { return ((struct lvm_report_object *)obj)->lv; } static void *_obj_get_pv(void *obj) { return ((struct lvm_report_object *)obj)->pv; } static void *_obj_get_seg(void *obj) { return ((struct lvm_report_object *)obj)->seg; } static void *_obj_get_pvseg(void *obj) { return ((struct lvm_report_object *)obj)->pvseg; } static const struct dm_report_object_type _report_types[] = { { VGS, "Volume Group", "vg_", _obj_get_vg }, { LVS, "Logical Volume", "lv_", _obj_get_lv }, { PVS, "Physical Volume", "pv_", _obj_get_pv }, { LABEL, "Physical Volume Label", "pv_", _obj_get_pv }, { SEGS, "Logical Volume Segment", "seg_", _obj_get_seg }, { PVSEGS, "Physical Volume Segment", "pvseg_", _obj_get_pvseg }, { 0, "", "", NULL }, }; /* * Import column definitions */ #define STR DM_REPORT_FIELD_TYPE_STRING #define NUM DM_REPORT_FIELD_TYPE_NUMBER #define FIELD(type, strct, sorttype, head, field, width, func, id, desc, writeable) \ {type, sorttype, offsetof(type_ ## strct, field), width, \ #id, head, &_ ## func ## _disp, desc}, typedef struct physical_volume type_pv; typedef struct logical_volume type_lv; typedef struct volume_group type_vg; typedef struct lv_segment type_seg; typedef struct pv_segment type_pvseg; static const struct dm_report_field_type _fields[] = { #include "columns.h" {0, 0, 0, 0, "", "", NULL, NULL}, }; #undef STR #undef NUM #undef FIELD void *report_init(struct cmd_context *cmd, const char *format, const char *keys, report_type_t *report_type, const char *separator, int aligned, int buffered, int headings, int field_prefixes, int quoted, int columns_as_rows) { uint32_t report_flags = 0; void *rh; if (aligned) report_flags |= DM_REPORT_OUTPUT_ALIGNED; if (buffered) report_flags |= DM_REPORT_OUTPUT_BUFFERED; if (headings) report_flags |= DM_REPORT_OUTPUT_HEADINGS; if (field_prefixes) report_flags |= DM_REPORT_OUTPUT_FIELD_NAME_PREFIX; if (!quoted) report_flags |= DM_REPORT_OUTPUT_FIELD_UNQUOTED; if (columns_as_rows) report_flags |= DM_REPORT_OUTPUT_COLUMNS_AS_ROWS; rh = dm_report_init(report_type, _report_types, _fields, format, separator, report_flags, keys, cmd); if (rh && field_prefixes) dm_report_set_output_field_name_prefix(rh, "lvm2_"); return rh; } /* * Create a row of data for an object */ int report_object(void *handle, struct volume_group *vg, struct logical_volume *lv, struct physical_volume *pv, struct lv_segment *seg, struct pv_segment *pvseg) { struct lvm_report_object obj; /* The two format fields might as well match. */ if (!vg && pv) _dummy_fid.fmt = pv->fmt; obj.vg = vg; obj.lv = lv; obj.pv = pv; obj.seg = seg; obj.pvseg = pvseg; return dm_report_object(handle, &obj); } lvm2-2.02.98/lib/report/properties.c0000640000175000017500000003662512037016272016145 0ustar blankblank/* * Copyright (C) 2010-2012 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU Lesser General Public License v.2.1. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include "libdevmapper.h" #include "properties.h" #include "activate.h" #include "lvm-logging.h" #include "lvm-types.h" #include "metadata.h" #define GET_NUM_PROPERTY_FN(NAME, VALUE, TYPE, VAR) \ static int _ ## NAME ## _get (const void *obj, struct lvm_property_type *prop) \ { \ const struct TYPE *VAR = (const struct TYPE *)obj; \ \ prop->value.integer = VALUE; \ return 1; \ } #define GET_VG_NUM_PROPERTY_FN(NAME, VALUE) \ GET_NUM_PROPERTY_FN(NAME, VALUE, volume_group, vg) #define GET_PV_NUM_PROPERTY_FN(NAME, VALUE) \ GET_NUM_PROPERTY_FN(NAME, VALUE, physical_volume, pv) #define GET_LV_NUM_PROPERTY_FN(NAME, VALUE) \ GET_NUM_PROPERTY_FN(NAME, VALUE, logical_volume, lv) #define GET_LVSEG_NUM_PROPERTY_FN(NAME, VALUE) \ GET_NUM_PROPERTY_FN(NAME, VALUE, lv_segment, lvseg) #define GET_PVSEG_NUM_PROPERTY_FN(NAME, VALUE) \ GET_NUM_PROPERTY_FN(NAME, VALUE, pv_segment, pvseg) #define SET_NUM_PROPERTY_FN(NAME, SETFN, TYPE, VAR) \ static int _ ## NAME ## _set (void *obj, struct lvm_property_type *prop) \ { \ struct TYPE *VAR = (struct TYPE *)obj; \ \ SETFN(VAR, prop->value.integer); \ return 1; \ } #define SET_VG_NUM_PROPERTY_FN(NAME, SETFN) \ SET_NUM_PROPERTY_FN(NAME, SETFN, volume_group, vg) #define SET_PV_NUM_PROPERTY_FN(NAME, SETFN) \ SET_NUM_PROPERTY_FN(NAME, SETFN, physical_volume, pv) #define SET_LV_NUM_PROPERTY_FN(NAME, SETFN) \ SET_NUM_PROPERTY_FN(NAME, SETFN, logical_volume, lv) #define GET_STR_PROPERTY_FN(NAME, VALUE, TYPE, VAR) \ static int _ ## NAME ## _get (const void *obj, struct lvm_property_type *prop) \ { \ const struct TYPE *VAR = (const struct TYPE *)obj; \ \ prop->value.string = (char *)VALUE; \ return 1; \ } #define GET_VG_STR_PROPERTY_FN(NAME, VALUE) \ GET_STR_PROPERTY_FN(NAME, VALUE, volume_group, vg) #define GET_PV_STR_PROPERTY_FN(NAME, VALUE) \ GET_STR_PROPERTY_FN(NAME, VALUE, physical_volume, pv) #define GET_LV_STR_PROPERTY_FN(NAME, VALUE) \ GET_STR_PROPERTY_FN(NAME, VALUE, logical_volume, lv) #define GET_LVSEG_STR_PROPERTY_FN(NAME, VALUE) \ GET_STR_PROPERTY_FN(NAME, VALUE, lv_segment, lvseg) #define GET_PVSEG_STR_PROPERTY_FN(NAME, VALUE) \ GET_STR_PROPERTY_FN(NAME, VALUE, pv_segment, pvseg) static int _not_implemented_get(const void *obj, struct lvm_property_type *prop) { log_errno(ENOSYS, "Function not implemented"); return 0; } static int _not_implemented_set(void *obj, struct lvm_property_type *prop) { log_errno(ENOSYS, "Function not implemented"); return 0; } static percent_t _copy_percent(const struct logical_volume *lv) { percent_t perc; if (!lv_mirror_percent(lv->vg->cmd, lv, 0, &perc, NULL)) perc = PERCENT_INVALID; return perc; } static percent_t _snap_percent(const struct logical_volume *lv) { percent_t perc; if (!lv_is_cow(lv) || !lv_snapshot_percent(lv, &perc)) perc = PERCENT_INVALID; return perc; } static percent_t _data_percent(const struct logical_volume *lv) { percent_t perc; if (lv_is_cow(lv)) return _snap_percent(lv); if (lv_is_thin_volume(lv)) return lv_thin_percent(lv, 0, &perc) ? perc : PERCENT_INVALID; return lv_thin_pool_percent(lv, 0, &perc) ? perc : PERCENT_INVALID; } static percent_t _metadata_percent(const struct logical_volume *lv) { percent_t perc; return lv_thin_pool_percent(lv, 1, &perc) ? perc : PERCENT_INVALID; } /* PV */ GET_PV_STR_PROPERTY_FN(pv_fmt, pv_fmt_dup(pv)) #define _pv_fmt_set _not_implemented_set GET_PV_STR_PROPERTY_FN(pv_uuid, pv_uuid_dup(pv)) #define _pv_uuid_set _not_implemented_set GET_PV_NUM_PROPERTY_FN(dev_size, SECTOR_SIZE * pv_dev_size(pv)) #define _dev_size_set _not_implemented_set GET_PV_STR_PROPERTY_FN(pv_name, pv_name_dup(pv)) #define _pv_name_set _not_implemented_set GET_PV_NUM_PROPERTY_FN(pv_mda_free, SECTOR_SIZE * pv_mda_free(pv)) #define _pv_mda_free_set _not_implemented_set GET_PV_NUM_PROPERTY_FN(pv_mda_size, SECTOR_SIZE * pv_mda_size(pv)) #define _pv_mda_size_set _not_implemented_set GET_PV_NUM_PROPERTY_FN(pe_start, SECTOR_SIZE * pv->pe_start) #define _pe_start_set _not_implemented_set GET_PV_NUM_PROPERTY_FN(pv_size, SECTOR_SIZE * pv_size_field(pv)) #define _pv_size_set _not_implemented_set GET_PV_NUM_PROPERTY_FN(pv_free, SECTOR_SIZE * pv_free(pv)) #define _pv_free_set _not_implemented_set GET_PV_NUM_PROPERTY_FN(pv_used, SECTOR_SIZE * pv_used(pv)) #define _pv_used_set _not_implemented_set GET_PV_STR_PROPERTY_FN(pv_attr, pv_attr_dup(pv->vg->vgmem, pv)) #define _pv_attr_set _not_implemented_set GET_PV_NUM_PROPERTY_FN(pv_pe_count, pv->pe_count) #define _pv_pe_count_set _not_implemented_set GET_PV_NUM_PROPERTY_FN(pv_pe_alloc_count, pv->pe_alloc_count) #define _pv_pe_alloc_count_set _not_implemented_set GET_PV_STR_PROPERTY_FN(pv_tags, pv_tags_dup(pv)) #define _pv_tags_set _not_implemented_set GET_PV_NUM_PROPERTY_FN(pv_mda_count, pv_mda_count(pv)) #define _pv_mda_count_set _not_implemented_set GET_PV_NUM_PROPERTY_FN(pv_mda_used_count, pv_mda_used_count(pv)) #define _pv_mda_used_count_set _not_implemented_set /* LV */ GET_LV_STR_PROPERTY_FN(lv_uuid, lv_uuid_dup(lv)) #define _lv_uuid_set _not_implemented_set GET_LV_STR_PROPERTY_FN(lv_name, lv_name_dup(lv->vg->vgmem, lv)) #define _lv_name_set _not_implemented_set GET_LV_STR_PROPERTY_FN(lv_path, lv_path_dup(lv->vg->vgmem, lv)) #define _lv_path_set _not_implemented_set GET_LV_STR_PROPERTY_FN(lv_attr, lv_attr_dup(lv->vg->vgmem, lv)) #define _lv_attr_set _not_implemented_set GET_LV_NUM_PROPERTY_FN(lv_major, lv->major) #define _lv_major_set _not_implemented_set GET_LV_NUM_PROPERTY_FN(lv_minor, lv->minor) #define _lv_minor_set _not_implemented_set GET_LV_NUM_PROPERTY_FN(lv_read_ahead, lv->read_ahead * SECTOR_SIZE) #define _lv_read_ahead_set _not_implemented_set GET_LV_NUM_PROPERTY_FN(lv_kernel_major, lv_kernel_major(lv)) #define _lv_kernel_major_set _not_implemented_set GET_LV_NUM_PROPERTY_FN(lv_kernel_minor, lv_kernel_minor(lv)) #define _lv_kernel_minor_set _not_implemented_set GET_LV_NUM_PROPERTY_FN(lv_kernel_read_ahead, lv_kernel_read_ahead(lv) * SECTOR_SIZE) #define _lv_kernel_read_ahead_set _not_implemented_set GET_LV_NUM_PROPERTY_FN(lv_size, lv->size * SECTOR_SIZE) #define _lv_size_set _not_implemented_set GET_LV_NUM_PROPERTY_FN(seg_count, dm_list_size(&lv->segments)) #define _seg_count_set _not_implemented_set GET_LV_STR_PROPERTY_FN(origin, lv_origin_dup(lv->vg->vgmem, lv)) #define _origin_set _not_implemented_set GET_LV_NUM_PROPERTY_FN(origin_size, lv_origin_size(lv)) #define _origin_size_set _not_implemented_set GET_LV_NUM_PROPERTY_FN(snap_percent, _snap_percent(lv)) #define _snap_percent_set _not_implemented_set GET_LV_NUM_PROPERTY_FN(copy_percent, _copy_percent(lv)) #define _copy_percent_set _not_implemented_set GET_LV_STR_PROPERTY_FN(move_pv, lv_move_pv_dup(lv->vg->vgmem, lv)) #define _move_pv_set _not_implemented_set GET_LV_STR_PROPERTY_FN(convert_lv, lv_convert_lv_dup(lv->vg->vgmem, lv)) #define _convert_lv_set _not_implemented_set GET_LV_STR_PROPERTY_FN(lv_tags, lv_tags_dup(lv)) #define _lv_tags_set _not_implemented_set GET_LV_STR_PROPERTY_FN(mirror_log, lv_mirror_log_dup(lv->vg->vgmem, lv)) #define _mirror_log_set _not_implemented_set GET_LV_STR_PROPERTY_FN(modules, lv_modules_dup(lv->vg->vgmem, lv)) #define _modules_set _not_implemented_set GET_LV_STR_PROPERTY_FN(data_lv, lv_data_lv_dup(lv->vg->vgmem, lv)) #define _data_lv_set _not_implemented_set GET_LV_STR_PROPERTY_FN(metadata_lv, lv_metadata_lv_dup(lv->vg->vgmem, lv)) #define _metadata_lv_set _not_implemented_set GET_LV_STR_PROPERTY_FN(pool_lv, lv_pool_lv_dup(lv->vg->vgmem, lv)) #define _pool_lv_set _not_implemented_set GET_LV_NUM_PROPERTY_FN(data_percent, _data_percent(lv)) #define _data_percent_set _not_implemented_set GET_LV_NUM_PROPERTY_FN(metadata_percent, _metadata_percent(lv)) #define _metadata_percent_set _not_implemented_set GET_LV_NUM_PROPERTY_FN(lv_metadata_size, lv_metadata_size(lv) * SECTOR_SIZE) #define _lv_metadata_size_set _not_implemented_set GET_LV_STR_PROPERTY_FN(lv_time, lv_time_dup(lv->vg->vgmem, lv)) #define _lv_time_set _not_implemented_set GET_LV_STR_PROPERTY_FN(lv_host, lv_host_dup(lv->vg->vgmem, lv)) #define _lv_host_set _not_implemented_set /* VG */ GET_VG_STR_PROPERTY_FN(vg_fmt, vg_fmt_dup(vg)) #define _vg_fmt_set _not_implemented_set GET_VG_STR_PROPERTY_FN(vg_uuid, vg_uuid_dup(vg)) #define _vg_uuid_set _not_implemented_set GET_VG_STR_PROPERTY_FN(vg_name, vg_name_dup(vg)) #define _vg_name_set _not_implemented_set GET_VG_STR_PROPERTY_FN(vg_attr, vg_attr_dup(vg->vgmem, vg)) #define _vg_attr_set _not_implemented_set GET_VG_NUM_PROPERTY_FN(vg_size, (SECTOR_SIZE * vg_size(vg))) #define _vg_size_set _not_implemented_set GET_VG_NUM_PROPERTY_FN(vg_free, (SECTOR_SIZE * vg_free(vg))) #define _vg_free_set _not_implemented_set GET_VG_STR_PROPERTY_FN(vg_sysid, vg_system_id_dup(vg)) #define _vg_sysid_set _not_implemented_set GET_VG_NUM_PROPERTY_FN(vg_extent_size, vg->extent_size) #define _vg_extent_size_set _not_implemented_set GET_VG_NUM_PROPERTY_FN(vg_extent_count, vg->extent_count) #define _vg_extent_count_set _not_implemented_set GET_VG_NUM_PROPERTY_FN(vg_free_count, vg->free_count) #define _vg_free_count_set _not_implemented_set GET_VG_NUM_PROPERTY_FN(max_lv, vg->max_lv) #define _max_lv_set _not_implemented_set GET_VG_NUM_PROPERTY_FN(max_pv, vg->max_pv) #define _max_pv_set _not_implemented_set GET_VG_NUM_PROPERTY_FN(pv_count, vg->pv_count) #define _pv_count_set _not_implemented_set GET_VG_NUM_PROPERTY_FN(lv_count, (vg_visible_lvs(vg))) #define _lv_count_set _not_implemented_set GET_VG_NUM_PROPERTY_FN(snap_count, (snapshot_count(vg))) #define _snap_count_set _not_implemented_set GET_VG_NUM_PROPERTY_FN(vg_seqno, vg->seqno) #define _vg_seqno_set _not_implemented_set GET_VG_STR_PROPERTY_FN(vg_tags, vg_tags_dup(vg)) #define _vg_tags_set _not_implemented_set GET_VG_NUM_PROPERTY_FN(vg_mda_count, (vg_mda_count(vg))) #define _vg_mda_count_set _not_implemented_set GET_VG_NUM_PROPERTY_FN(vg_mda_used_count, (vg_mda_used_count(vg))) #define _vg_mda_used_count_set _not_implemented_set GET_VG_NUM_PROPERTY_FN(vg_mda_free, (SECTOR_SIZE * vg_mda_free(vg))) #define _vg_mda_free_set _not_implemented_set GET_VG_NUM_PROPERTY_FN(vg_mda_size, (SECTOR_SIZE * vg_mda_size(vg))) #define _vg_mda_size_set _not_implemented_set GET_VG_NUM_PROPERTY_FN(vg_mda_copies, (vg_mda_copies(vg))) SET_VG_NUM_PROPERTY_FN(vg_mda_copies, vg_set_mda_copies) /* LVSEG */ GET_LVSEG_STR_PROPERTY_FN(segtype, lvseg_segtype_dup(lvseg->lv->vg->vgmem, lvseg)) #define _segtype_set _not_implemented_set GET_LVSEG_NUM_PROPERTY_FN(stripes, lvseg->area_count) #define _stripes_set _not_implemented_set GET_LVSEG_NUM_PROPERTY_FN(stripesize, lvseg->stripe_size) #define _stripesize_set _not_implemented_set GET_LVSEG_NUM_PROPERTY_FN(stripe_size, lvseg->stripe_size) #define _stripe_size_set _not_implemented_set GET_LVSEG_NUM_PROPERTY_FN(regionsize, lvseg->region_size) #define _regionsize_set _not_implemented_set GET_LVSEG_NUM_PROPERTY_FN(region_size, lvseg->region_size) #define _region_size_set _not_implemented_set GET_LVSEG_NUM_PROPERTY_FN(chunksize, lvseg_chunksize(lvseg)) #define _chunksize_set _not_implemented_set GET_LVSEG_NUM_PROPERTY_FN(chunk_size, lvseg_chunksize(lvseg)) #define _chunk_size_set _not_implemented_set GET_LVSEG_NUM_PROPERTY_FN(thin_count, dm_list_size(&lvseg->lv->segs_using_this_lv)) #define _thin_count_set _not_implemented_set GET_LVSEG_NUM_PROPERTY_FN(zero, lvseg->zero_new_blocks) #define _zero_set _not_implemented_set GET_LVSEG_NUM_PROPERTY_FN(transaction_id, lvseg->transaction_id) #define _transaction_id_set _not_implemented_set GET_LVSEG_NUM_PROPERTY_FN(discards, lvseg->discards) #define _discards_set _not_implemented_set GET_LVSEG_NUM_PROPERTY_FN(seg_start, lvseg_start(lvseg)) #define _seg_start_set _not_implemented_set GET_LVSEG_NUM_PROPERTY_FN(seg_start_pe, lvseg->le) #define _seg_start_pe_set _not_implemented_set GET_LVSEG_NUM_PROPERTY_FN(seg_size, (SECTOR_SIZE * lvseg_size(lvseg))) #define _seg_size_set _not_implemented_set GET_LVSEG_STR_PROPERTY_FN(seg_tags, lvseg_tags_dup(lvseg)) #define _seg_tags_set _not_implemented_set GET_LVSEG_STR_PROPERTY_FN(seg_pe_ranges, lvseg_seg_pe_ranges(lvseg->lv->vg->vgmem, lvseg)) #define _seg_pe_ranges_set _not_implemented_set GET_LVSEG_STR_PROPERTY_FN(devices, lvseg_devices(lvseg->lv->vg->vgmem, lvseg)) #define _devices_set _not_implemented_set /* PVSEG */ GET_PVSEG_NUM_PROPERTY_FN(pvseg_start, pvseg->pe) #define _pvseg_start_set _not_implemented_set GET_PVSEG_NUM_PROPERTY_FN(pvseg_size, pvseg->len) #define _pvseg_size_set _not_implemented_set #define STR DM_REPORT_FIELD_TYPE_STRING #define NUM DM_REPORT_FIELD_TYPE_NUMBER #define FIELD(type, strct, sorttype, head, field, width, fn, id, desc, settable) \ { type, #id, settable, sorttype == STR, sorttype == NUM, { .integer = 0 }, _ ## id ## _get, _ ## id ## _set }, struct lvm_property_type _properties[] = { #include "columns.h" { 0, "", 0, 0, 0, { .integer = 0 }, _not_implemented_get, _not_implemented_set }, }; #undef STR #undef NUM #undef FIELD static int _get_property(const void *obj, struct lvm_property_type *prop, unsigned type) { struct lvm_property_type *p; p = _properties; while (p->id[0]) { if (!strcmp(p->id, prop->id)) break; p++; } if (!p->id[0]) { log_errno(EINVAL, "Invalid property name %s", prop->id); return 0; } if (!(p->type & type)) { log_errno(EINVAL, "Property name %s does not match type %d", prop->id, p->type); return 0; } *prop = *p; if (!p->get(obj, prop)) { return 0; } return 1; } static int _set_property(void *obj, struct lvm_property_type *prop, unsigned type) { struct lvm_property_type *p; p = _properties; while (p->id[0]) { if (!strcmp(p->id, prop->id)) break; p++; } if (!p->id[0]) { log_errno(EINVAL, "Invalid property name %s", prop->id); return 0; } if (!p->is_settable) { log_errno(EINVAL, "Unable to set read-only property %s", prop->id); return 0; } if (!(p->type & type)) { log_errno(EINVAL, "Property name %s does not match type %d", prop->id, p->type); return 0; } if (p->is_string) p->value.string = prop->value.string; else p->value.integer = prop->value.integer; if (!p->set(obj, p)) { return 0; } return 1; } int lvseg_get_property(const struct lv_segment *lvseg, struct lvm_property_type *prop) { return _get_property(lvseg, prop, SEGS); } int lv_get_property(const struct logical_volume *lv, struct lvm_property_type *prop) { return _get_property(lv, prop, LVS); } int vg_get_property(const struct volume_group *vg, struct lvm_property_type *prop) { return _get_property(vg, prop, VGS); } int pvseg_get_property(const struct pv_segment *pvseg, struct lvm_property_type *prop) { return _get_property(pvseg, prop, PVSEGS); } int pv_get_property(const struct physical_volume *pv, struct lvm_property_type *prop) { return _get_property(pv, prop, PVS | LABEL); } int lv_set_property(struct logical_volume *lv, struct lvm_property_type *prop) { return _set_property(lv, prop, LVS); } int vg_set_property(struct volume_group *vg, struct lvm_property_type *prop) { return _set_property(vg, prop, VGS); } int pv_set_property(struct physical_volume *pv, struct lvm_property_type *prop) { return _set_property(pv, prop, PVS | LABEL); } lvm2-2.02.98/lib/report/report.h0000640000175000017500000000256212037016272015262 0ustar blankblank/* * 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 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_REPORT_H #define _LVM_REPORT_H #include "metadata-exported.h" typedef enum { LVS = 1, PVS = 2, VGS = 4, SEGS = 8, PVSEGS = 16, LABEL = 32 } report_type_t; struct field; struct report_handle; typedef int (*field_report_fn) (struct report_handle * dh, struct field * field, const void *data); void *report_init(struct cmd_context *cmd, const char *format, const char *keys, report_type_t *report_type, const char *separator, int aligned, int buffered, int headings, int field_prefixes, int quoted, int columns_as_rows); void report_free(void *handle); int report_object(void *handle, struct volume_group *vg, struct logical_volume *lv, struct physical_volume *pv, struct lv_segment *seg, struct pv_segment *pvseg); int report_output(void *handle); #endif lvm2-2.02.98/lib/report/columns.h0000640000175000017500000003100412037016272015420 0ustar blankblank/* * 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 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 defines the fields (columns) for the reporting commands * (pvs/vgs/lvs). */ /* * The 'FIELD' macro arguments are defined as follows: * 1. report_type. An enum value that selects a specific * struct dm_report_object_type in the _report_types array. The value is * used to select the containing base object address (see *obj_get* * functions) for any data values of any field in the report. * 2. Containing struct. The structure that either contains the field data * as a member or should be used to obtain the field data. The containing * struct should match the base object of the report_type. * 3. Field type. This must be either 'STR' or 'NUM'. * 4. Report heading. This is the field heading that is displayed by the * reporting commands. * 5. Data value pointer. This argument is always a member of the * containing struct. It may point directly to the data value (for example, * lv_uuid - see _uuid_disp()) or may be used to derive the data value (for * example, seg_count - see _lvsegcount_disp()). In the FIELD macro * definition, it is used in an offset calculation to derive the offset to * the data value from the containing struct base address. Note that in some * cases, the argument is the first member of the struct, in which case the * data value pointer points to the start of the struct itself (for example, * 'lvid' field of struct 'lv'). * 6. Minimum display width. This is the minimum width used to display * the field value, typically matching the width of the column heading. * 7. Display function identifier. Used to derive the full name of the * function that displays this field. Derivation is done by appending '_' * then prepending this argument to '_disp'. For example, if this argument * is 'uuid', the display function is _uuid_disp(). Adding a new field may * require defining a new display function (for example _myfieldname_disp()), * or re-use of an existing one (for example, _uint32_disp()). * 8. Unique format identifier / field id. This name must be unique and is * used to select fields via '-o' in the reporting commands (pvs/vgs/lvs). * The string used to specify the field - the 'id' member of * struct dm_report_field_type. * 9. Description of field. This is a brief (ideally <= 52 chars) description * of the field used in the reporting commands. * 10. Flags. * FIELD_MODIFIABLE. A '_set' function exists to change the field's value. * The function name is derived in a similar way to item 7 above. */ #define FIELD_MODIFIABLE 0x00000001 /* *INDENT-OFF* */ FIELD(LVS, lv, STR, "LV UUID", lvid.id[1], 38, uuid, lv_uuid, "Unique identifier.", 0) FIELD(LVS, lv, STR, "LV", lvid, 4, lvname, lv_name, "Name. LVs created for internal use are enclosed in brackets.", 0) FIELD(LVS, lv, STR, "Path", lvid, 4, lvpath, lv_path, "Full pathname for LV.", 0) FIELD(LVS, lv, STR, "Attr", lvid, 4, lvstatus, lv_attr, "Various attributes - see man page.", 0) FIELD(LVS, lv, NUM, "Maj", major, 3, int32, lv_major, "Persistent major number or -1 if not persistent.", 0) FIELD(LVS, lv, NUM, "Min", minor, 3, int32, lv_minor, "Persistent minor number or -1 if not persistent.", 0) FIELD(LVS, lv, NUM, "Rahead", lvid, 6, lvreadahead, lv_read_ahead, "Read ahead setting in current units.", 0) FIELD(LVS, lv, STR, "KMaj", lvid, 4, lvkmaj, lv_kernel_major, "Currently assigned major number or -1 if LV is not active.", 0) FIELD(LVS, lv, STR, "KMin", lvid, 4, lvkmin, lv_kernel_minor, "Currently assigned minor number or -1 if LV is not active.", 0) FIELD(LVS, lv, NUM, "KRahead", lvid, 7, lvkreadahead, lv_kernel_read_ahead, "Currently-in-use read ahead setting in current units.", 0) FIELD(LVS, lv, NUM, "LSize", size, 5, size64, lv_size, "Size of LV in current units.", 0) FIELD(LVS, lv, NUM, "MSize", lvid, 6, lvmetadatasize, lv_metadata_size, "For thin pools, the size of the LV that holds the metadata.", 0) FIELD(LVS, lv, NUM, "#Seg", lvid, 4, lvsegcount, seg_count, "Number of segments in LV.", 0) FIELD(LVS, lv, STR, "Origin", lvid, 6, origin, origin, "For snapshots, the origin device of this LV.", 0) FIELD(LVS, lv, NUM, "OSize", lvid, 5, originsize, origin_size, "For snapshots, the size of the origin device of this LV.", 0) FIELD(LVS, lv, NUM, "Data%", lvid, 6, datapercent, data_percent, "For snapshot and thin pools and volumes, the percentage full if LV is active.", 0) FIELD(LVS, lv, NUM, "Snap%", lvid, 6, snpercent, snap_percent, "For snapshots, the percentage full if LV is active.", 0) FIELD(LVS, lv, NUM, "Meta%", lvid, 6, metadatapercent, metadata_percent, "For thin pools, the percentage of metadata full if LV is active.", 0) FIELD(LVS, lv, NUM, "Copy%", lvid, 6, copypercent, copy_percent, "For mirrors and pvmove, current percentage in-sync.", 0) FIELD(LVS, lv, STR, "Move", lvid, 4, movepv, move_pv, "For pvmove, Source PV of temporary LV created by pvmove.", 0) FIELD(LVS, lv, STR, "Convert", lvid, 7, convertlv, convert_lv, "For lvconvert, Name of temporary LV created by lvconvert.", 0) FIELD(LVS, lv, STR, "Log", lvid, 3, loglv, mirror_log, "For mirrors, the LV holding the synchronisation log.", 0) FIELD(LVS, lv, STR, "Data", lvid, 4, datalv, data_lv, "For thin pools, the LV holding the associated data.", 0) FIELD(LVS, lv, STR, "Meta", lvid, 4, metadatalv, metadata_lv, "For thin pools, the LV holding the associated metadata.", 0) FIELD(LVS, lv, STR, "Pool", lvid, 4, poollv, pool_lv, "For thin volumes, the thin pool LV for this volume.", 0) FIELD(LVS, lv, STR, "LV Tags", tags, 7, tags, lv_tags, "Tags, if any.", 0) FIELD(LVS, lv, STR, "Time", lvid, 26, lvtime, lv_time, "Creation time of the LV, if known", 0) FIELD(LVS, lv, STR, "Host", lvid, 10, lvhost, lv_host, "Creation host of the LV, if known.", 0) FIELD(LVS, lv, STR, "Modules", lvid, 7, modules, modules, "Kernel device-mapper modules required for this LV.", 0) FIELD(LABEL, pv, STR, "Fmt", id, 3, pvfmt, pv_fmt, "Type of metadata.", 0) FIELD(LABEL, pv, STR, "PV UUID", id, 38, uuid, pv_uuid, "Unique identifier.", 0) FIELD(LABEL, pv, NUM, "DevSize", id, 7, devsize, dev_size, "Size of underlying device in current units.", 0) FIELD(LABEL, pv, STR, "PV", dev, 10, dev_name, pv_name, "Name.", 0) FIELD(LABEL, pv, NUM, "PMdaFree", id, 9, pvmdafree, pv_mda_free, "Free metadata area space on this device in current units.", 0) FIELD(LABEL, pv, NUM, "PMdaSize", id, 9, pvmdasize, pv_mda_size, "Size of smallest metadata area on this device in current units.", 0) FIELD(PVS, pv, NUM, "1st PE", pe_start, 7, size64, pe_start, "Offset to the start of data on the underlying device.", 0) FIELD(PVS, pv, NUM, "PSize", id, 5, pvsize, pv_size, "Size of PV in current units.", 0) FIELD(PVS, pv, NUM, "PFree", id, 5, pvfree, pv_free, "Total amount of unallocated space in current units.", 0) FIELD(PVS, pv, NUM, "Used", id, 4, pvused, pv_used, "Total amount of allocated space in current units.", 0) FIELD(PVS, pv, STR, "Attr", id, 4, pvstatus, pv_attr, "Various attributes - see man page.", 0) FIELD(PVS, pv, NUM, "PE", pe_count, 3, uint32, pv_pe_count, "Total number of Physical Extents.", 0) FIELD(PVS, pv, NUM, "Alloc", pe_alloc_count, 5, uint32, pv_pe_alloc_count, "Total number of allocated Physical Extents.", 0) FIELD(PVS, pv, STR, "PV Tags", tags, 7, tags, pv_tags, "Tags, if any.", 0) FIELD(PVS, pv, NUM, "#PMda", id, 5, pvmdas, pv_mda_count, "Number of metadata areas on this device.", 0) FIELD(PVS, pv, NUM, "#PMdaUse", id, 8, pvmdasused, pv_mda_used_count, "Number of metadata areas in use on this device.", 0) FIELD(VGS, vg, STR, "Fmt", cmd, 3, vgfmt, vg_fmt, "Type of metadata.", 0) FIELD(VGS, vg, STR, "VG UUID", id, 38, uuid, vg_uuid, "Unique identifier.", 0) FIELD(VGS, vg, STR, "VG", name, 4, string, vg_name, "Name.", 0) FIELD(VGS, vg, STR, "Attr", cmd, 5, vgstatus, vg_attr, "Various attributes - see man page.", 0) FIELD(VGS, vg, NUM, "VSize", cmd, 5, vgsize, vg_size, "Total size of VG in current units.", 0) FIELD(VGS, vg, NUM, "VFree", cmd, 5, vgfree, vg_free, "Total amount of free space in current units.", 0) FIELD(VGS, vg, STR, "SYS ID", system_id, 6, string, vg_sysid, "System ID indicating when and where it was created.", 0) FIELD(VGS, vg, NUM, "Ext", extent_size, 3, size32, vg_extent_size, "Size of Physical Extents in current units.", 0) FIELD(VGS, vg, NUM, "#Ext", extent_count, 4, uint32, vg_extent_count, "Total number of Physical Extents.", 0) FIELD(VGS, vg, NUM, "Free", free_count, 4, uint32, vg_free_count, "Total number of unallocated Physical Extents.", 0) FIELD(VGS, vg, NUM, "MaxLV", max_lv, 5, uint32, max_lv, "Maximum number of LVs allowed in VG or 0 if unlimited.", 0) FIELD(VGS, vg, NUM, "MaxPV", max_pv, 5, uint32, max_pv, "Maximum number of PVs allowed in VG or 0 if unlimited.", 0) FIELD(VGS, vg, NUM, "#PV", pv_count, 3, uint32, pv_count, "Number of PVs.", 0) FIELD(VGS, vg, NUM, "#LV", cmd, 3, lvcount, lv_count, "Number of LVs.", 0) FIELD(VGS, vg, NUM, "#SN", cmd, 3, snapcount, snap_count, "Number of snapshots.", 0) FIELD(VGS, vg, NUM, "Seq", seqno, 3, uint32, vg_seqno, "Revision number of internal metadata. Incremented whenever it changes.", 0) FIELD(VGS, vg, STR, "VG Tags", tags, 7, tags, vg_tags, "Tags, if any.", 0) FIELD(VGS, vg, NUM, "#VMda", cmd, 5, vgmdas, vg_mda_count, "Number of metadata areas on this VG.", 0) FIELD(VGS, vg, NUM, "#VMdaUse", cmd, 8, vgmdasused, vg_mda_used_count, "Number of metadata areas in use on this VG.", 0) FIELD(VGS, vg, NUM, "VMdaFree", cmd, 9, vgmdafree, vg_mda_free, "Free metadata area space for this VG in current units.", 0) FIELD(VGS, vg, NUM, "VMdaSize", cmd, 9, vgmdasize, vg_mda_size, "Size of smallest metadata area for this VG in current units.", 0) FIELD(VGS, vg, NUM, "#VMdaCps", cmd, 8, vgmdacopies, vg_mda_copies, "Target number of in use metadata areas in the VG.", 1) FIELD(SEGS, seg, STR, "Type", list, 4, segtype, segtype, "Type of LV segment.", 0) FIELD(SEGS, seg, NUM, "#Str", area_count, 4, uint32, stripes, "Number of stripes or mirror legs.", 0) FIELD(SEGS, seg, NUM, "Stripe", stripe_size, 6, size32, stripesize, "For stripes, amount of data placed on one device before switching to the next.", 0) FIELD(SEGS, seg, NUM, "Stripe", stripe_size, 6, size32, stripe_size, "For stripes, amount of data placed on one device before switching to the next.", 0) FIELD(SEGS, seg, NUM, "Region", region_size, 6, size32, regionsize, "For mirrors, the unit of data copied when synchronising devices.", 0) FIELD(SEGS, seg, NUM, "Region", region_size, 6, size32, region_size, "For mirrors, the unit of data copied when synchronising devices.", 0) FIELD(SEGS, seg, NUM, "Chunk", list, 5, chunksize, chunksize, "For snapshots, the unit of data used when tracking changes.", 0) FIELD(SEGS, seg, NUM, "Chunk", list, 5, chunksize, chunk_size, "For snapshots, the unit of data used when tracking changes.", 0) FIELD(SEGS, seg, NUM, "#Thins", list, 4, thincount, thin_count, "For thin pools, the number of thin volumes in this pool.", 0) FIELD(SEGS, seg, NUM, "Discards", list, 8, discards, discards, "For thin pools, how discards are handled.", 0) FIELD(SEGS, seg, NUM, "Zero", list, 4, thinzero, zero, "For thin pools, if zeroing is enabled.", 0) FIELD(SEGS, seg, NUM, "TransId", list, 4, transactionid, transaction_id, "For thin pools, the transaction id.", 0) FIELD(SEGS, seg, NUM, "Start", list, 5, segstart, seg_start, "Offset within the LV to the start of the segment in current units.", 0) FIELD(SEGS, seg, NUM, "Start", list, 5, segstartpe, seg_start_pe, "Offset within the LV to the start of the segment in physical extents.", 0) FIELD(SEGS, seg, NUM, "SSize", list, 5, segsize, seg_size, "Size of segment in current units.", 0) FIELD(SEGS, seg, STR, "Seg Tags", tags, 8, tags, seg_tags, "Tags, if any.", 0) FIELD(SEGS, seg, STR, "PE Ranges", list, 9, peranges, seg_pe_ranges, "Ranges of Physical Extents of underlying devices in command line format.", 0) FIELD(SEGS, seg, STR, "Devices", list, 7, devices, devices, "Underlying devices used with starting extent numbers.", 0) FIELD(PVSEGS, pvseg, NUM, "Start", pe, 5, uint32, pvseg_start, "Physical Extent number of start of segment.", 0) FIELD(PVSEGS, pvseg, NUM, "SSize", len, 5, uint32, pvseg_size, "Number of extents in segment.", 0) /* *INDENT-ON* */ lvm2-2.02.98/lib/mirror/0000750000175000017500000000000012037016272013567 5ustar blankblanklvm2-2.02.98/lib/mirror/.exported_symbols0000640000175000017500000000001512037016272017167 0ustar blankblankinit_segtype lvm2-2.02.98/lib/mirror/Makefile.in0000640000175000017500000000143312037016272015636 0ustar blankblank# # Copyright (C) 2003-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@ SOURCES = mirrored.c LIB_SHARED = liblvm2mirror.$(LIB_SUFFIX) LIB_VERSION = $(LIB_VERSION_LVM) include $(top_builddir)/make.tmpl install: install_lvm2_plugin lvm2-2.02.98/lib/mirror/mirrored.c0000640000175000017500000004262112037016272015564 0ustar blankblank/* * Copyright (C) 2003-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 "toolcontext.h" #include "metadata.h" #include "segtype.h" #include "display.h" #include "text_export.h" #include "text_import.h" #include "config.h" #include "defaults.h" #include "lvm-string.h" #include "targets.h" #include "activate.h" #include "str_list.h" #include enum { MIRR_DISABLED, MIRR_RUNNING, MIRR_COMPLETED }; struct mirror_state { uint32_t default_region_size; }; static const char *_mirrored_name(const struct lv_segment *seg) { return seg->segtype->name; } static void _mirrored_display(const struct lv_segment *seg) { const char *size; uint32_t s; log_print(" Mirrors\t\t%u", seg->area_count); log_print(" Mirror size\t\t%u", seg->area_len); if (seg->log_lv) log_print(" Mirror log volume\t%s", seg->log_lv->name); if (seg->region_size) { size = display_size(seg->lv->vg->cmd, (uint64_t) seg->region_size); log_print(" Mirror region size\t%s", size); } log_print(" Mirror original:"); display_stripe(seg, 0, " "); log_print(" Mirror destinations:"); for (s = 1; s < seg->area_count; s++) display_stripe(seg, s, " "); log_print(" "); } static int _mirrored_text_import_area_count(const struct dm_config_node *sn, uint32_t *area_count) { if (!dm_config_get_uint32(sn, "mirror_count", area_count)) { log_error("Couldn't read 'mirror_count' for " "segment '%s'.", dm_config_parent_name(sn)); return 0; } return 1; } static int _mirrored_text_import(struct lv_segment *seg, const struct dm_config_node *sn, struct dm_hash_table *pv_hash) { const struct dm_config_value *cv; const char *logname = NULL; if (dm_config_has_node(sn, "extents_moved")) { if (dm_config_get_uint32(sn, "extents_moved", &seg->extents_copied)) seg->status |= PVMOVE; else { log_error("Couldn't read 'extents_moved' for " "segment %s of logical volume %s.", dm_config_parent_name(sn), seg->lv->name); return 0; } } if (dm_config_has_node(sn, "region_size")) { if (!dm_config_get_uint32(sn, "region_size", &seg->region_size)) { log_error("Couldn't read 'region_size' for " "segment %s of logical volume %s.", dm_config_parent_name(sn), seg->lv->name); return 0; } } if (dm_config_get_str(sn, "mirror_log", &logname)) { if (!(seg->log_lv = find_lv(seg->lv->vg, logname))) { log_error("Unrecognised mirror log in " "segment %s of logical volume %s.", dm_config_parent_name(sn), seg->lv->name); return 0; } seg->log_lv->status |= MIRROR_LOG; } if (logname && !seg->region_size) { log_error("Missing region size for mirror log for " "segment %s of logical volume %s.", dm_config_parent_name(sn), seg->lv->name); return 0; } if (!dm_config_get_list(sn, "mirrors", &cv)) { log_error("Couldn't find mirrors array for " "segment %s of logical volume %s.", dm_config_parent_name(sn), seg->lv->name); return 0; } return text_import_areas(seg, sn, cv, pv_hash, MIRROR_IMAGE); } static int _mirrored_text_export(const struct lv_segment *seg, struct formatter *f) { outf(f, "mirror_count = %u", seg->area_count); if (seg->status & PVMOVE) outsize(f, (uint64_t) seg->extents_copied * seg->lv->vg->extent_size, "extents_moved = %" PRIu32, seg->extents_copied); if (seg->log_lv) outf(f, "mirror_log = \"%s\"", seg->log_lv->name); if (seg->region_size) outf(f, "region_size = %" PRIu32, seg->region_size); return out_areas(f, seg, "mirror"); } #ifdef DEVMAPPER_SUPPORT static int _block_on_error_available = 0; static unsigned _mirror_attributes = 0; static struct mirror_state *_mirrored_init_target(struct dm_pool *mem, struct cmd_context *cmd) { struct mirror_state *mirr_state; if (!(mirr_state = dm_pool_alloc(mem, sizeof(*mirr_state)))) { log_error("struct mirr_state allocation failed"); return NULL; } mirr_state->default_region_size = 2 * find_config_tree_int(cmd, "activation/mirror_region_size", DEFAULT_MIRROR_REGION_SIZE); return mirr_state; } static int _mirrored_target_percent(void **target_state, percent_t *percent, struct dm_pool *mem, struct cmd_context *cmd, struct lv_segment *seg, char *params, uint64_t *total_numerator, uint64_t *total_denominator) { uint64_t numerator, denominator; unsigned mirror_count, m; int used; char *pos = params; if (!*target_state) *target_state = _mirrored_init_target(mem, cmd); /* Status line: <#mirrors> (maj:min)+ / */ log_debug("Mirror status: %s", params); if (sscanf(pos, "%u %n", &mirror_count, &used) != 1) { log_error("Failure parsing mirror status mirror count: %s", params); return 0; } pos += used; for (m = 0; m < mirror_count; m++) { if (sscanf(pos, "%*x:%*x %n", &used) != 0) { log_error("Failure parsing mirror status devices: %s", params); return 0; } pos += used; } if (sscanf(pos, "%" PRIu64 "/%" PRIu64 "%n", &numerator, &denominator, &used) != 2) { log_error("Failure parsing mirror status fraction: %s", params); return 0; } pos += used; *total_numerator += numerator; *total_denominator += denominator; if (seg) seg->extents_copied = seg->area_len * numerator / denominator; *percent = make_percent(numerator, denominator); return 1; } static int _mirrored_transient_status(struct lv_segment *seg, char *params) { unsigned i, j; struct logical_volume *lv = seg->lv; struct lvinfo info; char *p = NULL; char **args, **log_args; struct logical_volume **images; struct logical_volume *log; unsigned num_devs, log_argc; int failed = 0; char *status; log_very_verbose("Mirrored transient status: \"%s\"", params); /* number of devices */ if (!dm_split_words(params, 1, 0, &p)) return_0; if (!(num_devs = (unsigned) atoi(p))) return_0; p += strlen(p) + 1; if (num_devs > DEFAULT_MIRROR_MAX_IMAGES) { log_error("Unexpectedly many (%d) mirror images in %s.", num_devs, lv->name); return 0; } args = alloca((num_devs + 5) * sizeof(char *)); images = alloca(num_devs * sizeof(struct logical_volume *)); /* FIXME: dm_split_words() should return unsigned */ if ((unsigned)dm_split_words(p, num_devs + 4, 0, args) < num_devs + 4) return_0; log_argc = (unsigned) atoi(args[3 + num_devs]); if (log_argc > 16) { log_error("Unexpectedly many (%d) log arguments in %s.", log_argc, lv->name); return 0; } log_args = alloca(log_argc * sizeof(char *)); if ((unsigned)dm_split_words(args[3 + num_devs] + strlen(args[3 + num_devs]) + 1, log_argc, 0, log_args) < log_argc) return_0; if (num_devs != seg->area_count) { log_error("Active mirror has a wrong number of mirror images!"); log_error("Metadata says %d, kernel says %d.", seg->area_count, num_devs); return 0; } if (!strcmp(log_args[0], "disk")) { char buf[32]; log = first_seg(lv)->log_lv; if (!lv_info(lv->vg->cmd, log, 0, &info, 0, 0)) { log_error("Check for existence of mirror log %s failed.", log->name); return 0; } log_debug("Found mirror log at %d:%d", info.major, info.minor); sprintf(buf, "%d:%d", info.major, info.minor); if (strcmp(buf, log_args[1])) { log_error("Mirror log mismatch. Metadata says %s, kernel says %s.", buf, log_args[1]); return 0; } log_very_verbose("Status of log (%s): %s", buf, log_args[2]); if (log_args[2][0] != 'A') { log->status |= PARTIAL_LV; ++failed; } } for (i = 0; i < num_devs; ++i) images[i] = NULL; for (i = 0; i < seg->area_count; ++i) { char buf[32]; if (!lv_info(lv->vg->cmd, seg_lv(seg, i), 0, &info, 0, 0)) { log_error("Check for existence of mirror image %s failed.", seg_lv(seg, i)->name); return 0; } log_debug("Found mirror image at %d:%d", info.major, info.minor); sprintf(buf, "%d:%d", info.major, info.minor); for (j = 0; j < num_devs; ++j) { if (!strcmp(buf, args[j])) { log_debug("Match: metadata image %d matches kernel image %d", i, j); images[j] = seg_lv(seg, i); } } } status = args[2 + num_devs]; for (i = 0; i < num_devs; ++i) { if (!images[i]) { log_error("Failed to find image %d (%s).", i, args[i]); return 0; } log_very_verbose("Status of image %d: %c", i, status[i]); if (status[i] != 'A') { images[i]->status |= PARTIAL_LV; ++failed; } } /* update PARTIAL_LV flags across the VG */ if (failed) vg_mark_partial_lvs(lv->vg, 0); return 1; } static int _add_log(struct dm_pool *mem, struct lv_segment *seg, const struct lv_activate_opts *laopts, struct dm_tree_node *node, uint32_t area_count, uint32_t region_size) { unsigned clustered = 0; char *log_dlid = NULL; uint32_t log_flags = 0; /* * Use clustered mirror log for non-exclusive activation * in clustered VG. */ if (!laopts->exclusive && vg_is_clustered(seg->lv->vg)) clustered = 1; if (seg->log_lv) { /* If disk log, use its UUID */ if (!(log_dlid = build_dm_uuid(mem, seg->log_lv->lvid.s, NULL))) { log_error("Failed to build uuid for log LV %s.", seg->log_lv->name); return 0; } } else { /* If core log, use mirror's UUID and set DM_CORELOG flag */ if (!(log_dlid = build_dm_uuid(mem, seg->lv->lvid.s, NULL))) { log_error("Failed to build uuid for mirror LV %s.", seg->lv->name); return 0; } log_flags |= DM_CORELOG; } if (mirror_in_sync() && !(seg->status & PVMOVE)) log_flags |= DM_NOSYNC; if (_block_on_error_available && !(seg->status & PVMOVE)) log_flags |= DM_BLOCK_ON_ERROR; return dm_tree_node_add_mirror_target_log(node, region_size, clustered, log_dlid, area_count, log_flags); } static int _mirrored_add_target_line(struct dev_manager *dm, struct dm_pool *mem, struct cmd_context *cmd, void **target_state, struct lv_segment *seg, const struct lv_activate_opts *laopts, struct dm_tree_node *node, uint64_t len, uint32_t *pvmove_mirror_count) { struct mirror_state *mirr_state; uint32_t area_count = seg->area_count; unsigned start_area = 0u; int mirror_status = MIRR_RUNNING; uint32_t region_size; int r; if (!*target_state && !(*target_state = _mirrored_init_target(mem, cmd))) return_0; mirr_state = *target_state; /* * Mirror segment could have only 1 area temporarily * if the segment is under conversion. */ if (seg->area_count == 1) mirror_status = MIRR_DISABLED; /* * For pvmove, only have one mirror segment RUNNING at once. * Segments before this are COMPLETED and use 2nd area. * Segments after this are DISABLED and use 1st area. */ if (seg->status & PVMOVE) { if (seg->extents_copied == seg->area_len) { mirror_status = MIRR_COMPLETED; start_area = 1; } else if ((*pvmove_mirror_count)++) { mirror_status = MIRR_DISABLED; area_count = 1; } /* else MIRR_RUNNING */ } if (mirror_status != MIRR_RUNNING) { if (!add_linear_area_to_dtree(node, len, seg->lv->vg->extent_size, cmd->use_linear_target, seg->lv->vg->name, seg->lv->name)) return_0; goto done; } if (!(seg->status & PVMOVE)) { if (!seg->region_size) { log_error("Missing region size for mirror segment."); return 0; } region_size = seg->region_size; } else region_size = adjusted_mirror_region_size(seg->lv->vg->extent_size, seg->area_len, mirr_state->default_region_size); if (!dm_tree_node_add_mirror_target(node, len)) return_0; if ((r = _add_log(mem, seg, laopts, node, area_count, region_size)) <= 0) { stack; return r; } done: return add_areas_line(dm, seg, node, start_area, area_count); } static int _mirrored_target_present(struct cmd_context *cmd, const struct lv_segment *seg, unsigned *attributes) { static int _mirrored_checked = 0; static int _mirrored_present = 0; uint32_t maj, min, patchlevel; unsigned maj2, min2, patchlevel2; char vsn[80]; struct utsname uts; unsigned kmaj, kmin, krel; if (!_mirrored_checked) { _mirrored_present = target_present(cmd, "mirror", 1); /* * block_on_error available as "block_on_error" log * argument with mirror target >= 1.1 and <= 1.11 * or with 1.0 in RHEL4U3 driver >= 4.5 * * block_on_error available as "handle_errors" mirror * argument with mirror target >= 1.12. * * libdm-deptree.c is smart enough to handle the differences * between block_on_error and handle_errors for all * mirror target versions >= 1.1 */ /* FIXME Move this into libdevmapper */ if (target_version("mirror", &maj, &min, &patchlevel) && maj == 1 && ((min >= 1) || (min == 0 && driver_version(vsn, sizeof(vsn)) && sscanf(vsn, "%u.%u.%u", &maj2, &min2, &patchlevel2) == 3 && maj2 == 4 && min2 == 5 && patchlevel2 == 0))) /* RHEL4U3 */ _block_on_error_available = 1; } /* * Check only for modules if atttributes requested and no previous check. * FIXME: Fails incorrectly if cmirror was built into kernel. */ if (attributes) { if (!_mirror_attributes) { /* * The dm-log-userspace module was added to the * 2.6.31 kernel. */ if (!uname(&uts) && (sscanf(uts.release, "%u.%u.%u", &kmaj, &kmin, &krel) == 3) && KERNEL_VERSION(kmaj, kmin, krel) < KERNEL_VERSION(2, 6, 31)) { if (module_present(cmd, "log-clustered")) _mirror_attributes |= MIRROR_LOG_CLUSTERED; } else if (module_present(cmd, "log-userspace")) _mirror_attributes |= MIRROR_LOG_CLUSTERED; if (!(_mirror_attributes & MIRROR_LOG_CLUSTERED)) log_verbose("Cluster mirror log module is not available"); /* * The cluster mirror log daemon must be running, * otherwise, the kernel module will fail to make * contact. */ #ifdef CMIRRORD_PIDFILE if (!dm_daemon_is_running(CMIRRORD_PIDFILE)) { log_verbose("Cluster mirror log daemon is not running"); _mirror_attributes &= ~MIRROR_LOG_CLUSTERED; } #else log_verbose("Cluster mirror log daemon not included in build"); _mirror_attributes &= ~MIRROR_LOG_CLUSTERED; #endif } *attributes = _mirror_attributes; } _mirrored_checked = 1; return _mirrored_present; } #ifdef DMEVENTD static const char *_get_mirror_dso_path(struct cmd_context *cmd) { return get_monitor_dso_path(cmd, find_config_tree_str(cmd, "dmeventd/mirror_library", DEFAULT_DMEVENTD_MIRROR_LIB)); } /* FIXME Cache this */ static int _target_registered(struct lv_segment *seg, int *pending) { return target_registered_with_dmeventd(seg->lv->vg->cmd, _get_mirror_dso_path(seg->lv->vg->cmd), seg->lv, pending); } /* FIXME This gets run while suspended and performs banned operations. */ static int _target_set_events(struct lv_segment *seg, int evmask, int set) { return target_register_events(seg->lv->vg->cmd, _get_mirror_dso_path(seg->lv->vg->cmd), seg->lv, evmask, set, 0); } static int _target_monitor_events(struct lv_segment *seg, int events) { return _target_set_events(seg, events, 1); } static int _target_unmonitor_events(struct lv_segment *seg, int events) { return _target_set_events(seg, events, 0); } #endif /* DMEVENTD */ #endif /* DEVMAPPER_SUPPORT */ static int _mirrored_modules_needed(struct dm_pool *mem, const struct lv_segment *seg, struct dm_list *modules) { if (seg->log_lv && !list_segment_modules(mem, first_seg(seg->log_lv), modules)) return_0; if (vg_is_clustered(seg->lv->vg) && !str_list_add(mem, modules, "clog")) { log_error("cluster log string list allocation failed"); return 0; } if (!str_list_add(mem, modules, "mirror")) { log_error("mirror string list allocation failed"); return 0; } return 1; } static void _mirrored_destroy(struct segment_type *segtype) { dm_free(segtype); } static struct segtype_handler _mirrored_ops = { .name = _mirrored_name, .display = _mirrored_display, .text_import_area_count = _mirrored_text_import_area_count, .text_import = _mirrored_text_import, .text_export = _mirrored_text_export, #ifdef DEVMAPPER_SUPPORT .add_target_line = _mirrored_add_target_line, .target_percent = _mirrored_target_percent, .target_present = _mirrored_target_present, .check_transient_status = _mirrored_transient_status, # ifdef DMEVENTD .target_monitored = _target_registered, .target_monitor_events = _target_monitor_events, .target_unmonitor_events = _target_unmonitor_events, # endif /* DMEVENTD */ #endif .modules_needed = _mirrored_modules_needed, .destroy = _mirrored_destroy, }; #ifdef MIRRORED_INTERNAL struct segment_type *init_mirrored_segtype(struct cmd_context *cmd) #else /* Shared */ struct segment_type *init_segtype(struct cmd_context *cmd); struct segment_type *init_segtype(struct cmd_context *cmd) #endif { struct segment_type *segtype = dm_zalloc(sizeof(*segtype)); if (!segtype) return_NULL; segtype->cmd = cmd; segtype->ops = &_mirrored_ops; segtype->name = "mirror"; segtype->private = NULL; segtype->flags = SEG_AREAS_MIRRORED; #ifdef DEVMAPPER_SUPPORT # ifdef DMEVENTD if (_get_mirror_dso_path(cmd)) segtype->flags |= SEG_MONITORED; # endif /* DMEVENTD */ #endif log_very_verbose("Initialised segtype: %s", segtype->name); return segtype; } lvm2-2.02.98/lib/filters/0000750000175000017500000000000012037016272013725 5ustar blankblanklvm2-2.02.98/lib/filters/filter-mpath.c0000640000175000017500000001040512037016272016466 0ustar blankblank/* * Copyright (C) 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 "filter.h" #include "filter-mpath.h" #include "activate.h" #ifdef linux #include #define MPATH_PREFIX "mpath-" static const char *get_sysfs_name(struct device *dev) { const char *name; if (!(name = strrchr(dev_name(dev), '/'))) { log_error("Cannot find '/' in device name."); return NULL; } name++; if (!*name) { log_error("Device name is not valid."); return NULL; } return name; } static int get_sysfs_string(const char *path, char *buffer, int max_size) { FILE *fp; int r = 0; if (!(fp = fopen(path, "r"))) { log_sys_error("fopen", path); return 0; } if (!fgets(buffer, max_size, fp)) log_sys_error("fgets", path); else r = 1; if (fclose(fp)) log_sys_error("fclose", path); return r; } static int get_sysfs_get_major_minor(const char *sysfs_dir, const char *kname, int *major, int *minor) { char path[PATH_MAX], buffer[64]; if (dm_snprintf(path, sizeof(path), "%s/block/%s/dev", sysfs_dir, kname) < 0) { log_error("Sysfs path string is too long."); return 0; } if (!get_sysfs_string(path, buffer, sizeof(buffer))) return_0; if (sscanf(buffer, "%d:%d", major, minor) != 2) { log_error("Failed to parse major minor from %s", buffer); return 0; } return 1; } static int get_parent_mpath(const char *dir, char *name, int max_size) { struct dirent *d; DIR *dr; int r = 0; if (!(dr = opendir(dir))) { log_sys_error("opendir", dir); return 0; } *name = '\0'; while ((d = readdir(dr))) { if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) continue; /* There should be only one holder if it is multipath */ if (*name) { r = 0; break; } strncpy(name, d->d_name, max_size); r = 1; } if (closedir(dr)) log_sys_error("closedir", dir); return r; } static int dev_is_mpath(struct dev_filter *f, struct device *dev) { const char *name; char path[PATH_MAX+1]; char parent_name[PATH_MAX+1]; struct stat info; const char *sysfs_dir = f->private; int major, minor; /* Limit this filter only to SCSI devices */ if (!major_is_scsi_device(MAJOR(dev->dev))) return 0; if (!(name = get_sysfs_name(dev))) return_0; if (dm_snprintf(path, PATH_MAX, "%s/block/%s/holders", sysfs_dir, name) < 0) { log_error("Sysfs path to check mpath is too long."); return 0; } /* also will filter out partitions */ if (stat(path, &info)) return 0; if (!S_ISDIR(info.st_mode)) { log_error("Path %s is not a directory.", path); return 0; } if (!get_parent_mpath(path, parent_name, PATH_MAX)) return 0; if (!get_sysfs_get_major_minor(sysfs_dir, parent_name, &major, &minor)) return_0; if (major != dm_major()) { log_error("mpath major %d is not dm major %d.", major, dm_major()); return 0; } return lvm_dm_prefix_check(major, minor, MPATH_PREFIX); } static int _ignore_mpath(struct dev_filter *f, struct device *dev) { if (dev_is_mpath(f, dev) == 1) { log_debug("%s: Skipping mpath component device", dev_name(dev)); return 0; } return 1; } static void _destroy(struct dev_filter *f) { if (f->use_count) log_error(INTERNAL_ERROR "Destroying mpath filter while in use %u times.", f->use_count); dm_free(f->private); dm_free(f); } struct dev_filter *mpath_filter_create(const char *sysfs_dir) { struct dev_filter *f; if (!*sysfs_dir) { log_verbose("No proc filesystem found: skipping multipath filter"); return NULL; } if (!(f = dm_zalloc(sizeof(*f)))) { log_error("mpath filter allocation failed"); return NULL; } f->passes_filter = _ignore_mpath; f->destroy = _destroy; f->use_count = 0; if (!(f->private = dm_strdup(sysfs_dir))) { log_error("Cannot duplicate sysfs dir."); dm_free(f); return NULL; } return f; } #else struct dev_filter *mpath_filter_create(const char *sysfs_dir __attribute__((unused))) { return NULL; } #endif lvm2-2.02.98/lib/filters/filter-persistent.c0000640000175000017500000002110312037016272017552 0ustar blankblank/* * 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 "config.h" #include "dev-cache.h" #include "filter.h" #include "filter-persistent.h" #include "lvm-file.h" #include "lvm-string.h" #include "activate.h" #include #include #include struct pfilter { char *file; struct dm_hash_table *devices; struct dev_filter *real; time_t ctime; }; /* * The hash table holds one of these two states * against each entry. */ #define PF_BAD_DEVICE ((void *) 1) #define PF_GOOD_DEVICE ((void *) 2) static int _init_hash(struct pfilter *pf) { if (pf->devices) dm_hash_destroy(pf->devices); if (!(pf->devices = dm_hash_create(128))) return_0; return 1; } static void _persistent_filter_wipe(struct dev_filter *f) { struct pfilter *pf = (struct pfilter *) f->private; log_verbose("Wiping cache of LVM-capable devices"); dm_hash_wipe(pf->devices); /* Trigger complete device scan */ dev_cache_scan(1); } static int _read_array(struct pfilter *pf, struct dm_config_tree *cft, const char *path, void *data) { const struct dm_config_node *cn; const struct dm_config_value *cv; if (!(cn = dm_config_find_node(cft->root, path))) { log_very_verbose("Couldn't find %s array in '%s'", path, pf->file); return 0; } /* * iterate through the array, adding * devices as we go. */ for (cv = cn->v; cv; cv = cv->next) { if (cv->type != DM_CFG_STRING) { log_verbose("Devices array contains a value " "which is not a string ... ignoring"); continue; } if (!dm_hash_insert(pf->devices, cv->v.str, data)) log_verbose("Couldn't add '%s' to filter ... ignoring", cv->v.str); /* Populate dev_cache ourselves */ dev_cache_get(cv->v.str, NULL); } return 1; } int persistent_filter_load(struct dev_filter *f, struct dm_config_tree **cft_out) { struct pfilter *pf = (struct pfilter *) f->private; struct dm_config_tree *cft; struct stat info; int r = 0; if (obtain_device_list_from_udev()) { if (!stat(pf->file, &info)) { log_very_verbose("Obtaining device list from " "udev. Removing obolete %s.", pf->file); if (unlink(pf->file) < 0 && errno != EROFS) log_sys_error("unlink", pf->file); } return 1; } if (!stat(pf->file, &info)) pf->ctime = info.st_ctime; else { log_very_verbose("%s: stat failed: %s", pf->file, strerror(errno)); return_0; } if (!(cft = config_file_open(pf->file, 1))) return_0; if (!config_file_read(cft)) goto_out; _read_array(pf, cft, "persistent_filter_cache/valid_devices", PF_GOOD_DEVICE); /* We don't gain anything by holding invalid devices */ /* _read_array(pf, cft, "persistent_filter_cache/invalid_devices", PF_BAD_DEVICE); */ /* Did we find anything? */ if (dm_hash_get_num_entries(pf->devices)) { /* We populated dev_cache ourselves */ dev_cache_scan(0); r = 1; } log_very_verbose("Loaded persistent filter cache from %s", pf->file); out: if (r && cft_out) *cft_out = cft; else config_file_destroy(cft); return r; } static void _write_array(struct pfilter *pf, FILE *fp, const char *path, void *data) { void *d; int first = 1; char buf[2 * PATH_MAX]; struct dm_hash_node *n; for (n = dm_hash_get_first(pf->devices); n; n = dm_hash_get_next(pf->devices, n)) { d = dm_hash_get_data(pf->devices, n); if (d != data) continue; if (!first) fprintf(fp, ",\n"); else { fprintf(fp, "\t%s=[\n", path); first = 0; } dm_escape_double_quotes(buf, dm_hash_get_key(pf->devices, n)); fprintf(fp, "\t\t\"%s\"", buf); } if (!first) fprintf(fp, "\n\t]\n"); } int persistent_filter_dump(struct dev_filter *f, int merge_existing) { struct pfilter *pf; char *tmp_file; struct stat info, info2; struct dm_config_tree *cft = NULL; FILE *fp; int lockfd; int r = 0; if (obtain_device_list_from_udev()) return 1; if (!f) return_0; pf = (struct pfilter *) f->private; if (!dm_hash_get_num_entries(pf->devices)) { log_very_verbose("Internal persistent device cache empty " "- not writing to %s", pf->file); return 0; } if (!dev_cache_has_scanned()) { log_very_verbose("Device cache incomplete - not writing " "to %s", pf->file); return 0; } log_very_verbose("Dumping persistent device cache to %s", pf->file); while (1) { if ((lockfd = fcntl_lock_file(pf->file, F_WRLCK, 0)) < 0) return_0; /* * Ensure we locked the file we expected */ if (fstat(lockfd, &info)) { log_sys_error("fstat", pf->file); goto out; } if (stat(pf->file, &info2)) { log_sys_error("stat", pf->file); goto out; } if (is_same_inode(info, info2)) break; fcntl_unlock_file(lockfd); } /* * If file contents changed since we loaded it, merge new contents */ if (merge_existing && info.st_ctime != pf->ctime) /* Keep cft open to avoid losing lock */ persistent_filter_load(f, &cft); tmp_file = alloca(strlen(pf->file) + 5); sprintf(tmp_file, "%s.tmp", pf->file); if (!(fp = fopen(tmp_file, "w"))) { /* EACCES has been reported over NFS */ if (errno != EROFS && errno != EACCES) log_sys_error("fopen", tmp_file); goto out; } fprintf(fp, "# This file is automatically maintained by lvm.\n\n"); fprintf(fp, "persistent_filter_cache {\n"); _write_array(pf, fp, "valid_devices", PF_GOOD_DEVICE); /* We don't gain anything by remembering invalid devices */ /* _write_array(pf, fp, "invalid_devices", PF_BAD_DEVICE); */ fprintf(fp, "}\n"); if (lvm_fclose(fp, tmp_file)) goto_out; if (rename(tmp_file, pf->file)) log_error("%s: rename to %s failed: %s", tmp_file, pf->file, strerror(errno)); r = 1; out: fcntl_unlock_file(lockfd); if (cft) config_file_destroy(cft); return r; } static int _lookup_p(struct dev_filter *f, struct device *dev) { struct pfilter *pf = (struct pfilter *) f->private; void *l = dm_hash_lookup(pf->devices, dev_name(dev)); struct str_list *sl; /* Cached BAD? */ if (l == PF_BAD_DEVICE) { log_debug("%s: Skipping (cached)", dev_name(dev)); return 0; } /* Test dm devices every time, so cache them as GOOD. */ if (MAJOR(dev->dev) == dm_major()) { if (!l) dm_list_iterate_items(sl, &dev->aliases) if (!dm_hash_insert(pf->devices, sl->str, PF_GOOD_DEVICE)) { log_error("Failed to hash device to filter."); return 0; } if (!device_is_usable(dev)) { log_debug("%s: Skipping unusable device", dev_name(dev)); return 0; } return pf->real->passes_filter(pf->real, dev); } /* Uncached */ if (!l) { l = pf->real->passes_filter(pf->real, dev) ? PF_GOOD_DEVICE : PF_BAD_DEVICE; dm_list_iterate_items(sl, &dev->aliases) if (!dm_hash_insert(pf->devices, sl->str, l)) { log_error("Failed to hash alias to filter."); return 0; } } return (l == PF_BAD_DEVICE) ? 0 : 1; } static void _persistent_destroy(struct dev_filter *f) { struct pfilter *pf = (struct pfilter *) f->private; if (f->use_count) log_error(INTERNAL_ERROR "Destroying persistent filter while in use %u times.", f->use_count); dm_hash_destroy(pf->devices); dm_free(pf->file); pf->real->destroy(pf->real); dm_free(pf); dm_free(f); } struct dev_filter *persistent_filter_create(struct dev_filter *real, const char *file) { struct pfilter *pf; struct dev_filter *f = NULL; struct stat info; if (!(pf = dm_zalloc(sizeof(*pf)))) { log_error("Allocation of persistent filter failed."); return NULL; } if (!(pf->file = dm_strdup(file))) { log_error("Filename duplication for persistent filter failed."); goto bad; } pf->real = real; if (!(_init_hash(pf))) { log_error("Couldn't create hash table for persistent filter."); goto bad; } if (!(f = dm_zalloc(sizeof(*f)))) { log_error("Allocation of device filter for persistent filter failed."); goto bad; } /* Only merge cache file before dumping it if it changed externally. */ if (!stat(pf->file, &info)) pf->ctime = info.st_ctime; f->passes_filter = _lookup_p; f->destroy = _persistent_destroy; f->use_count = 0; f->private = pf; f->wipe = _persistent_filter_wipe; return f; bad: dm_free(pf->file); if (pf->devices) dm_hash_destroy(pf->devices); dm_free(pf); dm_free(f); return NULL; } lvm2-2.02.98/lib/filters/filter-regex.c0000640000175000017500000001030512037016272016466 0ustar blankblank/* * 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 "filter-regex.h" #include "device.h" struct rfilter { struct dm_pool *mem; dm_bitset_t accept; struct dm_regex *engine; }; static int _extract_pattern(struct dm_pool *mem, const char *pat, char **regex, dm_bitset_t accept, int ix) { char sep, *r, *ptr; /* * is this an accept or reject pattern */ switch (*pat) { case 'a': dm_bit_set(accept, ix); break; case 'r': dm_bit_clear(accept, ix); break; default: log_info("pattern must begin with 'a' or 'r'"); return 0; } pat++; /* * get the separator */ switch (*pat) { case '(': sep = ')'; break; case '[': sep = ']'; break; case '{': sep = '}'; break; default: sep = *pat; } pat++; /* * copy the regex */ if (!(r = dm_pool_strdup(mem, pat))) return_0; /* * trim the trailing character, having checked it's sep. */ ptr = r + strlen(r) - 1; if (*ptr != sep) { log_info("invalid separator at end of regex"); return 0; } *ptr = '\0'; regex[ix] = r; return 1; } static int _build_matcher(struct rfilter *rf, const struct dm_config_value *val) { struct dm_pool *scratch; const struct dm_config_value *v; char **regex; unsigned count = 0; int i, r = 0; if (!(scratch = dm_pool_create("filter dm_regex", 1024))) return_0; /* * count how many patterns we have. */ for (v = val; v; v = v->next) { if (v->type != DM_CFG_STRING) { log_error("Filter patterns must be enclosed in quotes."); goto out; } count++; } /* Allocate space for them */ if (!(regex = dm_pool_alloc(scratch, sizeof(*regex) * count))) { log_error("Failed to allocate regex."); goto out; } /* Create the accept/reject bitset */ if (!(rf->accept = dm_bitset_create(rf->mem, count))) { log_error("Failed to create bitset."); goto out; } /* * fill the array back to front because we * want the opposite precedence to what * the matcher gives. */ for (v = val, i = count - 1; v; v = v->next, i--) if (!_extract_pattern(scratch, v->v.str, regex, rf->accept, i)) { log_error("Invalid filter pattern \"%s\".", v->v.str); goto out; } /* * build the matcher. */ if (!(rf->engine = dm_regex_create(rf->mem, (const char * const*) regex, count))) goto_out; r = 1; out: dm_pool_destroy(scratch); return r; } static int _accept_p(struct dev_filter *f, struct device *dev) { int m, first = 1, rejected = 0; struct rfilter *rf = (struct rfilter *) f->private; struct str_list *sl; dm_list_iterate_items(sl, &dev->aliases) { m = dm_regex_match(rf->engine, sl->str); if (m >= 0) { if (dm_bit(rf->accept, m)) { if (!first) dev_set_preferred_name(sl, dev); return 1; } rejected = 1; } first = 0; } if (rejected) log_debug("%s: Skipping (regex)", dev_name(dev)); /* * pass everything that doesn't match * anything. */ return !rejected; } static void _regex_destroy(struct dev_filter *f) { struct rfilter *rf = (struct rfilter *) f->private; if (f->use_count) log_error(INTERNAL_ERROR "Destroying regex filter while in use %u times.", f->use_count); dm_pool_destroy(rf->mem); } struct dev_filter *regex_filter_create(const struct dm_config_value *patterns) { struct dm_pool *mem = dm_pool_create("filter regex", 10 * 1024); struct rfilter *rf; struct dev_filter *f; if (!mem) return_NULL; if (!(rf = dm_pool_alloc(mem, sizeof(*rf)))) goto_bad; rf->mem = mem; if (!_build_matcher(rf, patterns)) goto_bad; if (!(f = dm_pool_zalloc(mem, sizeof(*f)))) goto_bad; f->passes_filter = _accept_p; f->destroy = _regex_destroy; f->use_count = 0; f->private = rf; return f; bad: dm_pool_destroy(mem); return NULL; } lvm2-2.02.98/lib/filters/filter.c0000640000175000017500000001764012037016272015367 0ustar blankblank/* * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU 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 "dev-cache.h" #include "filter.h" #include "lvm-string.h" #include "config.h" #include "metadata.h" #include "activate.h" #include #include #include #include #include #include "device-types.h" #define NUMBER_OF_MAJORS 4096 #define PARTITION_SCSI_DEVICE (1 << 0) static struct { int max_partitions; /* 0 means LVM won't use this major number. */ int flags; } _partitions[NUMBER_OF_MAJORS]; static int _md_major = -1; static int _blkext_major = -1; static int _drbd_major = -1; static int _device_mapper_major = -1; static int _emcpower_major = -1; int dm_major(void) { return _device_mapper_major; } int md_major(void) { return _md_major; } int blkext_major(void) { return _blkext_major; } int dev_subsystem_part_major(const struct device *dev) { dev_t primary_dev; if (MAJOR(dev->dev) == _md_major) return 1; if (MAJOR(dev->dev) == _drbd_major) return 1; if (MAJOR(dev->dev) == _emcpower_major) return 1; if ((MAJOR(dev->dev) == _blkext_major) && (get_primary_dev(sysfs_dir_path(), dev, &primary_dev)) && (MAJOR(primary_dev) == _md_major)) return 1; return 0; } const char *dev_subsystem_name(const struct device *dev) { if (MAJOR(dev->dev) == _md_major) return "MD"; if (MAJOR(dev->dev) == _drbd_major) return "DRBD"; if (MAJOR(dev->dev) == _emcpower_major) return "EMCPOWER"; if (MAJOR(dev->dev) == _blkext_major) return "BLKEXT"; return ""; } static int _passes_lvm_type_device_filter(struct dev_filter *f __attribute__((unused)), struct device *dev) { const char *name = dev_name(dev); int ret = 0; uint64_t size; /* Is this a recognised device type? */ if (!_partitions[MAJOR(dev->dev)].max_partitions) { log_debug("%s: Skipping: Unrecognised LVM device type %" PRIu64, name, (uint64_t) MAJOR(dev->dev)); return 0; } /* Check it's accessible */ if (!dev_open_readonly_quiet(dev)) { log_debug("%s: Skipping: open failed", name); return 0; } /* Check it's not too small */ if (!dev_get_size(dev, &size)) { log_debug("%s: Skipping: dev_get_size failed", name); goto out; } if (size < pv_min_size()) { log_debug("%s: Skipping: Too small to hold a PV", name); goto out; } if (is_partitioned_dev(dev)) { log_debug("%s: Skipping: Partition table signature found", name); goto out; } ret = 1; out: if (!dev_close(dev)) stack; return ret; } static int _scan_proc_dev(const char *proc, const struct dm_config_node *cn) { char line[80]; char proc_devices[PATH_MAX]; FILE *pd = NULL; int i, j = 0; int line_maj = 0; int blocksection = 0; size_t dev_len = 0; const struct dm_config_value *cv; const char *name; char *nl; if (!*proc) { log_verbose("No proc filesystem found: using all block device " "types"); for (i = 0; i < NUMBER_OF_MAJORS; i++) _partitions[i].max_partitions = 1; return 1; } /* All types unrecognised initially */ memset(_partitions, 0, sizeof(_partitions)); if (dm_snprintf(proc_devices, sizeof(proc_devices), "%s/devices", proc) < 0) { log_error("Failed to create /proc/devices string"); return 0; } if (!(pd = fopen(proc_devices, "r"))) { log_sys_error("fopen", proc_devices); return 0; } while (fgets(line, sizeof(line), pd) != NULL) { i = 0; while (line[i] == ' ') i++; /* If it's not a number it may be name of section */ line_maj = atoi(((char *) (line + i))); if (line_maj < 0 || line_maj >= NUMBER_OF_MAJORS) { /* * Device numbers shown in /proc/devices are actually direct * numbers passed to registering function, however the kernel * uses only 12 bits, so use just 12 bits for major. */ if ((nl = strchr(line, '\n'))) *nl = '\0'; log_warn("WARNING: /proc/devices line: %s, replacing major with %d.", line, line_maj & (NUMBER_OF_MAJORS - 1)); line_maj &= (NUMBER_OF_MAJORS - 1); } if (!line_maj) { blocksection = (line[i] == 'B') ? 1 : 0; continue; } /* We only want block devices ... */ if (!blocksection) continue; /* Find the start of the device major name */ while (line[i] != ' ' && line[i] != '\0') i++; while (line[i] == ' ') i++; /* Look for md device */ if (!strncmp("md", line + i, 2) && isspace(*(line + i + 2))) _md_major = line_maj; /* Look for blkext device */ if (!strncmp("blkext", line + i, 6) && isspace(*(line + i + 6))) _blkext_major = line_maj; /* Look for drbd device */ if (!strncmp("drbd", line + i, 4) && isspace(*(line + i + 4))) _drbd_major = line_maj; /* Look for EMC powerpath */ if (!strncmp("emcpower", line + i, 8) && isspace(*(line + i + 8))) _emcpower_major = line_maj; /* Look for device-mapper device */ /* FIXME Cope with multiple majors */ if (!strncmp("device-mapper", line + i, 13) && isspace(*(line + i + 13))) _device_mapper_major = line_maj; /* Major is SCSI device */ if (!strncmp("sd", line + i, 2) && isspace(*(line + i + 2))) _partitions[line_maj].flags |= PARTITION_SCSI_DEVICE; /* Go through the valid device names and if there is a match store max number of partitions */ for (j = 0; _device_info[j].name[0]; j++) { dev_len = strlen(_device_info[j].name); if (dev_len <= strlen(line + i) && !strncmp(_device_info[j].name, line + i, dev_len) && (line_maj < NUMBER_OF_MAJORS)) { _partitions[line_maj].max_partitions = _device_info[j].max_partitions; break; } } if (!cn) continue; /* Check devices/types for local variations */ for (cv = cn->v; cv; cv = cv->next) { if (cv->type != DM_CFG_STRING) { log_error("Expecting string in devices/types " "in config file"); if (fclose(pd)) log_sys_error("fclose", proc_devices); return 0; } dev_len = strlen(cv->v.str); name = cv->v.str; cv = cv->next; if (!cv || cv->type != DM_CFG_INT) { log_error("Max partition count missing for %s " "in devices/types in config file", name); if (fclose(pd)) log_sys_error("fclose", proc_devices); return 0; } if (!cv->v.i) { log_error("Zero partition count invalid for " "%s in devices/types in config file", name); if (fclose(pd)) log_sys_error("fclose", proc_devices); return 0; } if (dev_len <= strlen(line + i) && !strncmp(name, line + i, dev_len) && (line_maj < NUMBER_OF_MAJORS)) { _partitions[line_maj].max_partitions = cv->v.i; break; } } } if (fclose(pd)) log_sys_error("fclose", proc_devices); return 1; } int max_partitions(int major) { if (major >= NUMBER_OF_MAJORS) return 0; return _partitions[major].max_partitions; } int major_is_scsi_device(int major) { if (major >= NUMBER_OF_MAJORS) return 0; return (_partitions[major].flags & PARTITION_SCSI_DEVICE) ? 1 : 0; } static void _lvm_type_filter_destroy(struct dev_filter *f) { if (f->use_count) log_error(INTERNAL_ERROR "Destroying lvm_type filter while in use %u times.", f->use_count); dm_free(f); } struct dev_filter *lvm_type_filter_create(const char *proc, const struct dm_config_node *cn) { struct dev_filter *f; if (!(f = dm_zalloc(sizeof(struct dev_filter)))) { log_error("LVM type filter allocation failed"); return NULL; } f->passes_filter = _passes_lvm_type_device_filter; f->destroy = _lvm_type_filter_destroy; f->use_count = 0; f->private = NULL; if (!_scan_proc_dev(proc, cn)) { dm_free(f); return_NULL; } return f; } lvm2-2.02.98/lib/filters/filter-sysfs.h0000640000175000017500000000126012037016272016530 0ustar blankblank/* * 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_FILTER_SYSFS_H #define _LVM_FILTER_SYSFS_H #include "config.h" #include "dev-cache.h" struct dev_filter *sysfs_filter_create(const char *sysfs_dir); #endif lvm2-2.02.98/lib/filters/device-types.h0000640000175000017500000000432212037016272016501 0ustar blankblank/* * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU 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 */ typedef struct { const char name[15]; const int8_t max_partitions; } device_info_t; /* * Devices are only checked for partition tables if their minor number * is a multiple of the number corresponding to their type below * i.e. this gives the granularity of whole-device minor numbers. * Use 1 if the device is not partitionable. * * The list can be supplemented with devices/types in the config file. */ static const device_info_t _device_info[] = { {"ide", 64}, /* IDE disk */ {"sd", 16}, /* SCSI disk */ {"md", 1}, /* Multiple Disk driver (SoftRAID) */ {"mdp", 1}, /* Partitionable MD */ {"loop", 1}, /* Loop device */ {"dasd", 4}, /* DASD disk (IBM S/390, zSeries) */ {"dac960", 8}, /* DAC960 */ {"nbd", 16}, /* Network Block Device */ {"ida", 16}, /* Compaq SMART2 */ {"cciss", 16}, /* Compaq CCISS array */ {"ubd", 16}, /* User-mode virtual block device */ {"ataraid", 16}, /* ATA Raid */ {"drbd", 16}, /* Distributed Replicated Block Device */ {"emcpower", 16}, /* EMC Powerpath */ {"power2", 16}, /* EMC Powerpath */ {"i2o_block", 16}, /* i2o Block Disk */ {"iseries/vd", 8}, /* iSeries disks */ {"gnbd", 1}, /* Network block device */ {"ramdisk", 1}, /* RAM disk */ {"aoe", 16}, /* ATA over Ethernet */ {"device-mapper", 1}, /* Other mapped devices */ {"xvd", 16}, /* Xen virtual block device */ {"vdisk", 8}, /* SUN's LDOM virtual block device */ {"ps3disk", 16}, /* PlayStation 3 internal disk */ {"virtblk", 8}, /* VirtIO disk */ {"mmc", 16}, /* MMC block device */ {"blkext", 1}, /* Extended device partitions */ {"fio", 16}, /* Fusion */ {"mtip32xx", 16}, /* Micron PCIe SSDs */ {"", 0} }; lvm2-2.02.98/lib/filters/filter-composite.h0000640000175000017500000000137612037016272017373 0ustar blankblank/* * 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_FILTER_COMPOSITE_H #define _LVM_FILTER_COMPOSITE_H #include "dev-cache.h" struct dev_filter *composite_filter_create(int n, struct dev_filter **filters); #endif lvm2-2.02.98/lib/filters/filter-composite.c0000640000175000017500000000361012037016272017357 0ustar blankblank/* * Copyright (C) 2001-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 */ #include "lib.h" #include "filter-composite.h" #include static int _and_p(struct dev_filter *f, struct device *dev) { struct dev_filter **filters = (struct dev_filter **) f->private; while (*filters) { if (!(*filters)->passes_filter(*filters, dev)) return 0; filters++; } log_debug("Using %s", dev_name(dev)); return 1; } static void _composite_destroy(struct dev_filter *f) { struct dev_filter **filters = (struct dev_filter **) f->private; if (f->use_count) log_error(INTERNAL_ERROR "Destroying composite filter while in use %u times.", f->use_count); while (*filters) { (*filters)->destroy(*filters); filters++; } dm_free(f->private); dm_free(f); } struct dev_filter *composite_filter_create(int n, struct dev_filter **filters) { struct dev_filter **filters_copy, *cft; if (!filters) return_NULL; if (!(filters_copy = dm_malloc(sizeof(*filters) * (n + 1)))) { log_error("composite filters allocation failed"); return NULL; } memcpy(filters_copy, filters, sizeof(*filters) * n); filters_copy[n] = NULL; if (!(cft = dm_zalloc(sizeof(*cft)))) { log_error("compsoite filters allocation failed"); dm_free(filters_copy); return NULL; } cft->passes_filter = _and_p; cft->destroy = _composite_destroy; cft->use_count = 0; cft->private = filters_copy; return cft; } lvm2-2.02.98/lib/filters/filter-md.h0000640000175000017500000000115312037016272015762 0ustar blankblank/* * Copyright (C) 2004 Luca Berra * * 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_FILTER_MD_H #define _LVM_FILTER_MD_H #include "dev-cache.h" struct dev_filter *md_filter_create(void); #endif lvm2-2.02.98/lib/filters/filter-mpath.h0000640000175000017500000000123512037016272016474 0ustar blankblank/* * Copyright (C) 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 */ #ifndef _LVM_FILTER_MPATH_H #define _LVM_FILTER_MPATH_H #include "dev-cache.h" struct dev_filter *mpath_filter_create(const char *sysfs_dir); #endif lvm2-2.02.98/lib/filters/filter-persistent.h0000640000175000017500000000165512037016272017571 0ustar blankblank/* * Copyright (C) 2001-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_FILTER_PERSISTENT_H #define _LVM_FILTER_PERSISTENT_H #include "dev-cache.h" struct dev_filter *persistent_filter_create(struct dev_filter *f, const char *file); int persistent_filter_load(struct dev_filter *f, struct dm_config_tree **cft_out); int persistent_filter_dump(struct dev_filter *f, int merge_existing); #endif lvm2-2.02.98/lib/filters/filter-sysfs.c0000640000175000017500000001601412037016272016526 0ustar blankblank/* * 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 "filter-sysfs.h" #ifdef linux #include static int _locate_sysfs_blocks(const char *sysfs_dir, char *path, size_t len, unsigned *sysfs_depth) { struct stat info; /* * unified classification directory for all kernel subsystems * * /sys/subsystem/block/devices * |-- sda -> ../../../devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda * |-- sda1 -> ../../../devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1 * `-- sr0 -> ../../../devices/pci0000:00/0000:00:1f.2/host1/target1:0:0/1:0:0:0/block/sr0 * */ if (dm_snprintf(path, len, "%s/%s", sysfs_dir, "subsystem/block/devices") >= 0) { if (!stat(path, &info)) { *sysfs_depth = 0; return 1; } } /* * block subsystem as a class * * /sys/class/block * |-- sda -> ../../devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda * |-- sda1 -> ../../devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1 * `-- sr0 -> ../../devices/pci0000:00/0000:00:1f.2/host1/target1:0:0/1:0:0:0/block/sr0 * */ if (dm_snprintf(path, len, "%s/%s", sysfs_dir, "class/block") >= 0) { if (!stat(path, &info)) { *sysfs_depth = 0; return 1; } } /* * old block subsystem layout with nested directories * * /sys/block/ * |-- sda * | |-- capability * | |-- dev * ... * | |-- sda1 * | | |-- dev * ... * | * `-- sr0 * |-- capability * |-- dev * ... * */ if (dm_snprintf(path, len, "%s/%s", sysfs_dir, "block") >= 0) { if (!stat(path, &info)) { *sysfs_depth = 1; return 1; } } return 0; } /*---------------------------------------------------------------- * We need to store a set of dev_t. *--------------------------------------------------------------*/ struct entry { struct entry *next; dev_t dev; }; #define SET_BUCKETS 64 struct dev_set { struct dm_pool *mem; const char *sys_block; unsigned sysfs_depth; int initialised; struct entry *slots[SET_BUCKETS]; }; static struct dev_set *_dev_set_create(struct dm_pool *mem, const char *sys_block, unsigned sysfs_depth) { struct dev_set *ds; if (!(ds = dm_pool_zalloc(mem, sizeof(*ds)))) return NULL; ds->mem = mem; if (!(ds->sys_block = dm_pool_strdup(mem, sys_block))) return NULL; ds->sysfs_depth = sysfs_depth; ds->initialised = 0; return ds; } static unsigned _hash_dev(dev_t dev) { return (major(dev) ^ minor(dev)) & (SET_BUCKETS - 1); } /* * Doesn't check that the set already contains dev. */ static int _set_insert(struct dev_set *ds, dev_t dev) { struct entry *e; unsigned h = _hash_dev(dev); if (!(e = dm_pool_alloc(ds->mem, sizeof(*e)))) return 0; e->next = ds->slots[h]; e->dev = dev; ds->slots[h] = e; return 1; } static int _set_lookup(struct dev_set *ds, dev_t dev) { unsigned h = _hash_dev(dev); struct entry *e; for (e = ds->slots[h]; e; e = e->next) if (e->dev == dev) return 1; return 0; } /*---------------------------------------------------------------- * filter methods *--------------------------------------------------------------*/ static int _parse_dev(const char *file, FILE *fp, dev_t *result) { unsigned major, minor; char buffer[64]; if (!fgets(buffer, sizeof(buffer), fp)) { log_error("Empty sysfs device file: %s", file); return 0; } if (sscanf(buffer, "%u:%u", &major, &minor) != 2) { log_info("sysfs device file not correct format"); return 0; } *result = makedev(major, minor); return 1; } static int _read_dev(const char *file, dev_t *result) { int r; FILE *fp; if (!(fp = fopen(file, "r"))) { log_sys_error("fopen", file); return 0; } r = _parse_dev(file, fp, result); if (fclose(fp)) log_sys_error("fclose", file); return r; } /* * Recurse through sysfs directories, inserting any devs found. */ static int _read_devs(struct dev_set *ds, const char *dir, unsigned sysfs_depth) { struct dirent *d; DIR *dr; struct stat info; char path[PATH_MAX]; char file[PATH_MAX]; dev_t dev = { 0 }; int r = 1; if (!(dr = opendir(dir))) { log_sys_error("opendir", dir); return 0; } while ((d = readdir(dr))) { if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) continue; if (dm_snprintf(path, sizeof(path), "%s/%s", dir, d->d_name) < 0) { log_error("sysfs path name too long: %s in %s", d->d_name, dir); continue; } /* devices have a "dev" file */ if (dm_snprintf(file, sizeof(file), "%s/dev", path) < 0) { log_error("sysfs path name too long: %s in %s", d->d_name, dir); continue; } if (!stat(file, &info)) { /* recurse if we found a device and expect subdirs */ if (sysfs_depth) _read_devs(ds, path, sysfs_depth - 1); /* add the device we have found */ if (_read_dev(file, &dev)) _set_insert(ds, dev); } } if (closedir(dr)) log_sys_error("closedir", dir); return r; } static int _init_devs(struct dev_set *ds) { if (!_read_devs(ds, ds->sys_block, ds->sysfs_depth)) { ds->initialised = -1; return 0; } ds->initialised = 1; return 1; } static int _accept_p(struct dev_filter *f, struct device *dev) { struct dev_set *ds = (struct dev_set *) f->private; if (!ds->initialised) _init_devs(ds); /* Pass through if initialisation failed */ if (ds->initialised != 1) return 1; if (!_set_lookup(ds, dev->dev)) { log_debug("%s: Skipping (sysfs)", dev_name(dev)); return 0; } else return 1; } static void _destroy(struct dev_filter *f) { struct dev_set *ds = (struct dev_set *) f->private; if (f->use_count) log_error(INTERNAL_ERROR "Destroying sysfs filter while in use %u times.", f->use_count); dm_pool_destroy(ds->mem); } struct dev_filter *sysfs_filter_create(const char *sysfs_dir) { char sys_block[PATH_MAX]; unsigned sysfs_depth; struct dm_pool *mem; struct dev_set *ds; struct dev_filter *f; if (!*sysfs_dir) { log_verbose("No proc filesystem found: skipping sysfs filter"); return NULL; } if (!_locate_sysfs_blocks(sysfs_dir, sys_block, sizeof(sys_block), &sysfs_depth)) return NULL; if (!(mem = dm_pool_create("sysfs", 256))) { log_error("sysfs pool creation failed"); return NULL; } if (!(ds = _dev_set_create(mem, sys_block, sysfs_depth))) { log_error("sysfs dev_set creation failed"); goto bad; } if (!(f = dm_pool_zalloc(mem, sizeof(*f)))) goto_bad; f->passes_filter = _accept_p; f->destroy = _destroy; f->use_count = 0; f->private = ds; return f; bad: dm_pool_destroy(mem); return NULL; } #else struct dev_filter *sysfs_filter_create(const char *sysfs_dir __attribute__((unused))) { return NULL; } #endif lvm2-2.02.98/lib/filters/filter-regex.h0000640000175000017500000000174312037016272016501 0ustar blankblank/* * 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_FILTER_REGEX_H #define _LVM_FILTER_REGEX_H #include "config.h" #include "dev-cache.h" /* * patterns must be an array of strings of the form: * [ra], eg, * r/cdrom/ - reject cdroms * a|loop/[0-4]| - accept loops 0 to 4 * r|.*| - reject everything else */ struct dev_filter *regex_filter_create(const struct dm_config_value *patterns); #endif lvm2-2.02.98/lib/filters/filter-md.c0000640000175000017500000000277512037016272015770 0ustar blankblank/* * Copyright (C) 2004 Luca Berra * 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 */ #include "lib.h" #include "filter-md.h" #ifdef linux static int _ignore_md(struct dev_filter *f __attribute__((unused)), struct device *dev) { int ret; if (!md_filtering()) return 1; ret = dev_is_md(dev, NULL); if (ret == 1) { log_debug("%s: Skipping md component device", dev_name(dev)); return 0; } if (ret < 0) { log_debug("%s: Skipping: error in md component detection", dev_name(dev)); return 0; } return 1; } static void _destroy(struct dev_filter *f) { if (f->use_count) log_error(INTERNAL_ERROR "Destroying md filter while in use %u times.", f->use_count); dm_free(f); } struct dev_filter *md_filter_create(void) { struct dev_filter *f; if (!(f = dm_zalloc(sizeof(*f)))) { log_error("md filter allocation failed"); return NULL; } f->passes_filter = _ignore_md; f->destroy = _destroy; f->use_count = 0; f->private = NULL; return f; } #else struct dev_filter *md_filter_create(void) { return NULL; } #endif lvm2-2.02.98/lib/filters/filter.h0000640000175000017500000000247512037016272015374 0ustar blankblank/* * 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_FILTER_H #define _LVM_FILTER_H #include "config.h" #include #ifdef linux # define MAJOR(dev) ((dev & 0xfff00) >> 8) # define MINOR(dev) ((dev & 0xff) | ((dev >> 12) & 0xfff00)) # define MKDEV(ma,mi) ((mi & 0xff) | (ma << 8) | ((mi & ~0xff) << 12)) #else # define MAJOR(x) major((x)) # define MINOR(x) minor((x)) # define MKDEV(x,y) makedev((x),(y)) #endif struct dev_filter *lvm_type_filter_create(const char *proc, const struct dm_config_node *cn); int dm_major(void); int md_major(void); int blkext_major(void); int max_partitions(int major); int major_is_scsi_device(int major); int dev_subsystem_part_major(const struct device *dev); const char *dev_subsystem_name(const struct device *dev); #endif lvm2-2.02.98/lib/format_text/0000750000175000017500000000000012037016272014611 5ustar blankblanklvm2-2.02.98/lib/format_text/import_vsn1.c0000640000175000017500000005365412037016272017254 0ustar blankblank/* * 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 "metadata.h" #include "import-export.h" #include "display.h" #include "toolcontext.h" #include "lvmcache.h" #include "lvmetad.h" #include "lv_alloc.h" #include "pv_alloc.h" #include "segtype.h" #include "text_import.h" #include "defaults.h" typedef int (*section_fn) (struct format_instance * fid, struct volume_group * vg, const struct dm_config_node * pvn, const struct dm_config_node * vgn, struct dm_hash_table * pv_hash, struct dm_hash_table * lv_hash, unsigned *scan_done_once, unsigned report_missing_devices); #define _read_int32(root, path, result) \ dm_config_get_uint32(root, path, (uint32_t *) result) #define _read_uint32(root, path, result) \ dm_config_get_uint32(root, path, result) #define _read_uint64(root, path, result) \ dm_config_get_uint64(root, path, result) /* * Logs an attempt to read an invalid format file. */ static void _invalid_format(const char *str) { log_error("Can't process text format file - %s.", str); } /* * Checks that the config file contains vg metadata, and that it * we recognise the version number, */ static int _vsn1_check_version(const struct dm_config_tree *cft) { const struct dm_config_node *cn; const struct dm_config_value *cv; // TODO if this is pvscan --cache, we want this check back. if (lvmetad_active()) return 1; /* * Check the contents field. */ if (!(cn = dm_config_find_node(cft->root, CONTENTS_FIELD))) { _invalid_format("missing contents field"); return 0; } cv = cn->v; if (!cv || cv->type != DM_CFG_STRING || strcmp(cv->v.str, CONTENTS_VALUE)) { _invalid_format("unrecognised contents field"); return 0; } /* * Check the version number. */ if (!(cn = dm_config_find_node(cft->root, FORMAT_VERSION_FIELD))) { _invalid_format("missing version number"); return 0; } cv = cn->v; if (!cv || cv->type != DM_CFG_INT || cv->v.i != FORMAT_VERSION_VALUE) { _invalid_format("unrecognised version number"); return 0; } return 1; } static int _is_converting(struct logical_volume *lv) { struct lv_segment *seg; if (lv->status & MIRRORED) { seg = first_seg(lv); /* Can't use is_temporary_mirror() because the metadata for * seg_lv may not be read in and flags may not be set yet. */ if (seg_type(seg, 0) == AREA_LV && strstr(seg_lv(seg, 0)->name, MIRROR_SYNC_LAYER)) return 1; } return 0; } static int _read_id(struct id *id, const struct dm_config_node *cn, const char *path) { const char *uuid; if (!dm_config_get_str(cn, path, &uuid)) { log_error("Couldn't find uuid."); return 0; } if (!id_read_format(id, uuid)) { log_error("Invalid uuid."); return 0; } return 1; } static int _read_flag_config(const struct dm_config_node *n, uint64_t *status, int type) { const struct dm_config_value *cv; *status = 0; if (!dm_config_get_list(n, "status", &cv)) { log_error("Could not find status flags."); return 0; } if (!(read_flags(status, type | STATUS_FLAG, cv))) { log_error("Could not read status flags."); return 0; } if (dm_config_get_list(n, "flags", &cv)) { if (!(read_flags(status, type, cv))) { log_error("Could not read flags."); return 0; } } return 1; } static int _read_pv(struct format_instance *fid, struct volume_group *vg, const struct dm_config_node *pvn, const struct dm_config_node *vgn __attribute__((unused)), struct dm_hash_table *pv_hash, struct dm_hash_table *lv_hash __attribute__((unused)), unsigned *scan_done_once, unsigned report_missing_devices) { struct dm_pool *mem = vg->vgmem; struct physical_volume *pv; struct pv_list *pvl; const struct dm_config_value *cv; uint64_t size; if (!(pvl = dm_pool_zalloc(mem, sizeof(*pvl))) || !(pvl->pv = dm_pool_zalloc(mem, sizeof(*pvl->pv)))) return_0; pv = pvl->pv; /* * Add the pv to the pv hash for quick lookup when we read * the lv segments. */ if (!dm_hash_insert(pv_hash, pvn->key, pv)) return_0; if (!(pvn = pvn->child)) { log_error("Empty pv section."); return 0; } if (!_read_id(&pv->id, pvn, "id")) { log_error("Couldn't read uuid for physical volume."); return 0; } pv->is_labelled = 1; /* All format_text PVs are labelled. */ /* * Convert the uuid into a device. */ if (!(pv->dev = lvmcache_device_from_pvid(fid->fmt->cmd, &pv->id, scan_done_once, &pv->label_sector))) { char buffer[64] __attribute__((aligned(8))); if (!id_write_format(&pv->id, buffer, sizeof(buffer))) buffer[0] = '\0'; if (report_missing_devices) log_error_once("Couldn't find device with uuid %s.", buffer); else log_very_verbose("Couldn't find device with uuid %s.", buffer); } if (!(pv->vg_name = dm_pool_strdup(mem, vg->name))) return_0; memcpy(&pv->vgid, &vg->id, sizeof(vg->id)); if (!_read_flag_config(pvn, &pv->status, PV_FLAGS)) { log_error("Couldn't read status flags for physical volume."); return 0; } /* TODO is the !lvmetad_active() too coarse here? */ if (!pv->dev && !lvmetad_active()) pv->status |= MISSING_PV; /* Late addition */ if (dm_config_has_node(pvn, "dev_size") && !_read_uint64(pvn, "dev_size", &pv->size)) { log_error("Couldn't read dev size for physical volume."); return 0; } if (!_read_uint64(pvn, "pe_start", &pv->pe_start)) { log_error("Couldn't read extent size for physical volume."); return 0; } if (!_read_int32(pvn, "pe_count", &pv->pe_count)) { log_error("Couldn't find extent count (pe_count) for " "physical volume."); return 0; } dm_list_init(&pv->tags); dm_list_init(&pv->segments); /* Optional tags */ if (dm_config_get_list(pvn, "tags", &cv) && !(read_tags(mem, &pv->tags, cv))) { log_error("Couldn't read tags for physical volume %s in %s.", pv_dev_name(pv), vg->name); return 0; } pv->pe_size = vg->extent_size; pv->pe_alloc_count = 0; pv->pe_align = 0; pv->fmt = fid->fmt; /* Fix up pv size if missing or impossibly large */ if ((!pv->size || pv->size > (1ULL << 62)) && pv->dev) { if (!dev_get_size(pv->dev, &pv->size)) { log_error("%s: Couldn't get size.", pv_dev_name(pv)); return 0; } log_verbose("Fixing up missing size (%s) " "for PV %s", display_size(fid->fmt->cmd, pv->size), pv_dev_name(pv)); size = pv->pe_count * (uint64_t) vg->extent_size + pv->pe_start; if (size > pv->size) log_warn("WARNING: Physical Volume %s is too large " "for underlying device", pv_dev_name(pv)); } if (!alloc_pv_segment_whole_pv(mem, pv)) return_0; vg->extent_count += pv->pe_count; vg->free_count += pv->pe_count; add_pvl_to_vgs(vg, pvl); return 1; } static void _insert_segment(struct logical_volume *lv, struct lv_segment *seg) { struct lv_segment *comp; dm_list_iterate_items(comp, &lv->segments) { if (comp->le > seg->le) { dm_list_add(&comp->list, &seg->list); return; } } lv->le_count += seg->len; dm_list_add(&lv->segments, &seg->list); } static int _read_segment(struct logical_volume *lv, const struct dm_config_node *sn, struct dm_hash_table *pv_hash) { struct dm_pool *mem = lv->vg->vgmem; uint32_t area_count = 0u; struct lv_segment *seg; const struct dm_config_node *sn_child = sn->child; const struct dm_config_value *cv; uint32_t start_extent, extent_count; struct segment_type *segtype; const char *segtype_str; if (!sn_child) { log_error("Empty segment section."); return 0; } if (!_read_int32(sn_child, "start_extent", &start_extent)) { log_error("Couldn't read 'start_extent' for segment '%s' " "of logical volume %s.", sn->key, lv->name); return 0; } if (!_read_int32(sn_child, "extent_count", &extent_count)) { log_error("Couldn't read 'extent_count' for segment '%s' " "of logical volume %s.", sn->key, lv->name); return 0; } segtype_str = "striped"; if (!dm_config_get_str(sn_child, "type", &segtype_str)) { log_error("Segment type must be a string."); return 0; } if (!(segtype = get_segtype_from_string(lv->vg->cmd, segtype_str))) return_0; if (segtype->ops->text_import_area_count && !segtype->ops->text_import_area_count(sn_child, &area_count)) return_0; if (!(seg = alloc_lv_segment(segtype, lv, start_extent, extent_count, 0, 0, NULL, NULL, area_count, extent_count, 0, 0, 0, NULL))) { log_error("Segment allocation failed"); return 0; } if (seg->segtype->ops->text_import && !seg->segtype->ops->text_import(seg, sn_child, pv_hash)) return_0; /* Optional tags */ if (dm_config_get_list(sn_child, "tags", &cv) && !(read_tags(mem, &seg->tags, cv))) { log_error("Couldn't read tags for a segment of %s/%s.", lv->vg->name, lv->name); return 0; } /* * Insert into correct part of segment list. */ _insert_segment(lv, seg); if (seg_is_mirrored(seg)) lv->status |= MIRRORED; if (seg_is_raid(seg)) lv->status |= RAID; if (seg_is_virtual(seg)) lv->status |= VIRTUAL; if (!seg_is_raid(seg) && _is_converting(lv)) lv->status |= CONVERTING; return 1; } int text_import_areas(struct lv_segment *seg, const struct dm_config_node *sn, const struct dm_config_value *cv, struct dm_hash_table *pv_hash, uint64_t status) { unsigned int s; struct logical_volume *lv1; struct physical_volume *pv; const char *seg_name = dm_config_parent_name(sn); if (!seg->area_count) { log_error("Zero areas not allowed for segment %s", seg_name); return 0; } for (s = 0; cv && s < seg->area_count; s++, cv = cv->next) { /* first we read the pv */ if (cv->type != DM_CFG_STRING) { log_error("Bad volume name in areas array for segment %s.", seg_name); return 0; } if (!cv->next) { log_error("Missing offset in areas array for segment %s.", seg_name); return 0; } if (cv->next->type != DM_CFG_INT) { log_error("Bad offset in areas array for segment %s.", seg_name); return 0; } /* FIXME Cope if LV not yet read in */ if ((pv = dm_hash_lookup(pv_hash, cv->v.str))) { if (!set_lv_segment_area_pv(seg, s, pv, (uint32_t) cv->next->v.i)) return_0; } else if ((lv1 = find_lv(seg->lv->vg, cv->v.str))) { if (!set_lv_segment_area_lv(seg, s, lv1, (uint32_t) cv->next->v.i, status)) return_0; } else { log_error("Couldn't find volume '%s' " "for segment '%s'.", cv->v.str ? : "NULL", seg_name); return 0; } cv = cv->next; } /* * Check we read the correct number of stripes. */ if (cv || (s < seg->area_count)) { log_error("Incorrect number of areas in area array " "for segment '%s'.", seg_name); return 0; } return 1; } static int _read_segments(struct logical_volume *lv, const struct dm_config_node *lvn, struct dm_hash_table *pv_hash) { const struct dm_config_node *sn; int count = 0, seg_count; for (sn = lvn; sn; sn = sn->sib) { /* * All sub-sections are assumed to be segments. */ if (!sn->v) { if (!_read_segment(lv, sn, pv_hash)) return_0; count++; } /* FIXME Remove this restriction */ if ((lv->status & SNAPSHOT) && count > 1) { log_error("Only one segment permitted for snapshot"); return 0; } } if (!_read_int32(lvn, "segment_count", &seg_count)) { log_error("Couldn't read segment count for logical volume %s.", lv->name); return 0; } if (seg_count != count) { log_error("segment_count and actual number of segments " "disagree for logical volume %s.", lv->name); return 0; } /* * Check there are no gaps or overlaps in the lv. */ if (!check_lv_segments(lv, 0)) return_0; /* * Merge segments in case someones been editing things by hand. */ if (!lv_merge_segments(lv)) return_0; return 1; } static int _read_lvnames(struct format_instance *fid __attribute__((unused)), struct volume_group *vg, const struct dm_config_node *lvn, const struct dm_config_node *vgn __attribute__((unused)), struct dm_hash_table *pv_hash __attribute__((unused)), struct dm_hash_table *lv_hash, unsigned *scan_done_once __attribute__((unused)), unsigned report_missing_devices __attribute__((unused))) { struct dm_pool *mem = vg->vgmem; struct logical_volume *lv; const char *lv_alloc; const struct dm_config_value *cv; const char *hostname; uint64_t timestamp = 0; if (!(lv = alloc_lv(mem))) return_0; if (!(lv->name = dm_pool_strdup(mem, lvn->key))) return_0; if (!(lvn = lvn->child)) { log_error("Empty logical volume section."); return 0; } if (!_read_flag_config(lvn, &lv->status, LV_FLAGS)) { log_error("Couldn't read status flags for logical volume %s.", lv->name); return 0; } if (dm_config_has_node(lvn, "creation_time")) { if (!_read_uint64(lvn, "creation_time", ×tamp)) { log_error("Invalid creation_time for logical volume %s.", lv->name); return 0; } if (!dm_config_get_str(lvn, "creation_host", &hostname)) { log_error("Couldn't read creation_host for logical volume %s.", lv->name); return 0; } } else if (dm_config_has_node(lvn, "creation_host")) { log_error("Missing creation_time for logical volume %s.", lv->name); return 0; } lv->alloc = ALLOC_INHERIT; if (dm_config_get_str(lvn, "allocation_policy", &lv_alloc)) { lv->alloc = get_alloc_from_string(lv_alloc); if (lv->alloc == ALLOC_INVALID) { log_warn("WARNING: Ignoring unrecognised allocation policy %s for LV %s", lv_alloc, lv->name); lv->alloc = ALLOC_INHERIT; } } if (!_read_int32(lvn, "read_ahead", &lv->read_ahead)) /* If not present, choice of auto or none is configurable */ lv->read_ahead = vg->cmd->default_settings.read_ahead; else { switch (lv->read_ahead) { case 0: lv->read_ahead = DM_READ_AHEAD_AUTO; break; case (uint32_t) -1: lv->read_ahead = DM_READ_AHEAD_NONE; break; default: ; } } /* Optional tags */ if (dm_config_get_list(lvn, "tags", &cv) && !(read_tags(mem, &lv->tags, cv))) { log_error("Couldn't read tags for logical volume %s/%s.", vg->name, lv->name); return 0; } if (!dm_hash_insert(lv_hash, lv->name, lv)) return_0; if (!link_lv_to_vg(vg, lv)) return_0; if (timestamp && !lv_set_creation(lv, hostname, timestamp)) return_0; return 1; } static int _read_lvsegs(struct format_instance *fid __attribute__((unused)), struct volume_group *vg, const struct dm_config_node *lvn, const struct dm_config_node *vgn __attribute__((unused)), struct dm_hash_table *pv_hash, struct dm_hash_table *lv_hash, unsigned *scan_done_once __attribute__((unused)), unsigned report_missing_devices __attribute__((unused))) { struct logical_volume *lv; if (!(lv = dm_hash_lookup(lv_hash, lvn->key))) { log_error("Lost logical volume reference %s", lvn->key); return 0; } if (!(lvn = lvn->child)) { log_error("Empty logical volume section."); return 0; } /* FIXME: read full lvid */ if (!_read_id(&lv->lvid.id[1], lvn, "id")) { log_error("Couldn't read uuid for logical volume %s.", lv->name); return 0; } memcpy(&lv->lvid.id[0], &lv->vg->id, sizeof(lv->lvid.id[0])); if (!_read_segments(lv, lvn, pv_hash)) return_0; lv->size = (uint64_t) lv->le_count * (uint64_t) vg->extent_size; lv->minor = -1; if ((lv->status & FIXED_MINOR) && !_read_int32(lvn, "minor", &lv->minor)) { log_error("Couldn't read minor number for logical " "volume %s.", lv->name); return 0; } lv->major = -1; if ((lv->status & FIXED_MINOR) && !_read_int32(lvn, "major", &lv->major)) { log_error("Couldn't read major number for logical " "volume %s.", lv->name); } return 1; } static int _read_sections(struct format_instance *fid, const char *section, section_fn fn, struct volume_group *vg, const struct dm_config_node *vgn, struct dm_hash_table *pv_hash, struct dm_hash_table *lv_hash, int optional, unsigned *scan_done_once) { const struct dm_config_node *n; /* Only report missing devices when doing a scan */ unsigned report_missing_devices = scan_done_once ? !*scan_done_once : 1; if (!dm_config_get_section(vgn, section, &n)) { if (!optional) { log_error("Couldn't find section '%s'.", section); return 0; } return 1; } for (n = n->child; n; n = n->sib) { if (!fn(fid, vg, n, vgn, pv_hash, lv_hash, scan_done_once, report_missing_devices)) return_0; } return 1; } static struct volume_group *_read_vg(struct format_instance *fid, const struct dm_config_tree *cft, unsigned use_cached_pvs) { const struct dm_config_node *vgn; const struct dm_config_value *cv; const char *str; struct volume_group *vg; struct dm_hash_table *pv_hash = NULL, *lv_hash = NULL; unsigned scan_done_once = use_cached_pvs; /* skip any top-level values */ for (vgn = cft->root; (vgn && vgn->v); vgn = vgn->sib) ; if (!vgn) { log_error("Couldn't find volume group in file."); return NULL; } if (!(vg = alloc_vg("read_vg", fid->fmt->cmd, vgn->key))) return_NULL; if (!(vg->system_id = dm_pool_zalloc(vg->vgmem, NAME_LEN + 1))) goto_bad; /* * The pv hash memorises the pv section names -> pv * structures. */ if (!(pv_hash = dm_hash_create(64))) { log_error("Couldn't create pv hash table."); goto bad; } /* * The lv hash memorises the lv section names -> lv * structures. */ if (!(lv_hash = dm_hash_create(1024))) { log_error("Couldn't create lv hash table."); goto bad; } vgn = vgn->child; if (dm_config_get_str(vgn, "system_id", &str)) { strncpy(vg->system_id, str, NAME_LEN); } if (!_read_id(&vg->id, vgn, "id")) { log_error("Couldn't read uuid for volume group %s.", vg->name); goto bad; } if (!_read_int32(vgn, "seqno", &vg->seqno)) { log_error("Couldn't read 'seqno' for volume group %s.", vg->name); goto bad; } if (!_read_flag_config(vgn, &vg->status, VG_FLAGS)) { log_error("Error reading flags of volume group %s.", vg->name); goto bad; } if (!_read_int32(vgn, "extent_size", &vg->extent_size)) { log_error("Couldn't read extent size for volume group %s.", vg->name); goto bad; } /* * 'extent_count' and 'free_count' get filled in * implicitly when reading in the pv's and lv's. */ if (!_read_int32(vgn, "max_lv", &vg->max_lv)) { log_error("Couldn't read 'max_lv' for volume group %s.", vg->name); goto bad; } if (!_read_int32(vgn, "max_pv", &vg->max_pv)) { log_error("Couldn't read 'max_pv' for volume group %s.", vg->name); goto bad; } if (dm_config_get_str(vgn, "allocation_policy", &str)) { vg->alloc = get_alloc_from_string(str); if (vg->alloc == ALLOC_INVALID) { log_warn("WARNING: Ignoring unrecognised allocation policy %s for VG %s", str, vg->name); vg->alloc = ALLOC_NORMAL; } } if (!_read_uint32(vgn, "metadata_copies", &vg->mda_copies)) { vg->mda_copies = DEFAULT_VGMETADATACOPIES; } if (!_read_sections(fid, "physical_volumes", _read_pv, vg, vgn, pv_hash, lv_hash, 0, &scan_done_once)) { log_error("Couldn't find all physical volumes for volume " "group %s.", vg->name); goto bad; } /* Optional tags */ if (dm_config_get_list(vgn, "tags", &cv) && !(read_tags(vg->vgmem, &vg->tags, cv))) { log_error("Couldn't read tags for volume group %s.", vg->name); goto bad; } if (!_read_sections(fid, "logical_volumes", _read_lvnames, vg, vgn, pv_hash, lv_hash, 1, NULL)) { log_error("Couldn't read all logical volume names for volume " "group %s.", vg->name); goto bad; } if (!_read_sections(fid, "logical_volumes", _read_lvsegs, vg, vgn, pv_hash, lv_hash, 1, NULL)) { log_error("Couldn't read all logical volumes for " "volume group %s.", vg->name); goto bad; } if (!fixup_imported_mirrors(vg)) { log_error("Failed to fixup mirror pointers after import for " "volume group %s.", vg->name); goto bad; } dm_hash_destroy(pv_hash); dm_hash_destroy(lv_hash); /* FIXME Determine format type from file contents */ /* eg Set to instance of fmt1 here if reading a format1 backup? */ vg_set_fid(vg, fid); /* * Finished. */ return vg; bad: if (pv_hash) dm_hash_destroy(pv_hash); if (lv_hash) dm_hash_destroy(lv_hash); release_vg(vg); return NULL; } static void _read_desc(struct dm_pool *mem, const struct dm_config_tree *cft, time_t *when, char **desc) { const char *d; unsigned int u = 0u; int old_suppress; old_suppress = log_suppress(1); d = dm_config_find_str_allow_empty(cft->root, "description", ""); log_suppress(old_suppress); *desc = dm_pool_strdup(mem, d); (void) dm_config_get_uint32(cft->root, "creation_time", &u); *when = u; } static const char *_read_vgname(const struct format_type *fmt, const struct dm_config_tree *cft, struct id *vgid, uint64_t *vgstatus, char **creation_host) { const struct dm_config_node *vgn; struct dm_pool *mem = fmt->cmd->mem; char *vgname; int old_suppress; old_suppress = log_suppress(2); *creation_host = dm_pool_strdup(mem, dm_config_find_str_allow_empty(cft->root, "creation_host", "")); log_suppress(old_suppress); /* skip any top-level values */ for (vgn = cft->root; (vgn && vgn->v); vgn = vgn->sib) ; if (!vgn) { log_error("Couldn't find volume group in file."); return 0; } if (!(vgname = dm_pool_strdup(mem, vgn->key))) return_0; vgn = vgn->child; if (!_read_id(vgid, vgn, "id")) { log_error("Couldn't read uuid for volume group %s.", vgname); return 0; } if (!_read_flag_config(vgn, vgstatus, VG_FLAGS)) { log_error("Couldn't find status flags for volume group %s.", vgname); return 0; } return vgname; } static struct text_vg_version_ops _vsn1_ops = { .check_version = _vsn1_check_version, .read_vg = _read_vg, .read_desc = _read_desc, .read_vgname = _read_vgname, }; struct text_vg_version_ops *text_vg_vsn1_init(void) { return &_vsn1_ops; } lvm2-2.02.98/lib/format_text/tags.c0000640000175000017500000000345012037016272015716 0ustar blankblank/* * 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 "metadata.h" #include "import-export.h" #include "str_list.h" #include "lvm-string.h" char *alloc_printed_tags(struct dm_list *tags) { struct str_list *sl; int first = 1; size_t size = 0; char *buffer, *buf; dm_list_iterate_items(sl, tags) /* '"' + tag + '"' + ',' + ' ' */ size += strlen(sl->str) + 4; /* '[' + ']' + '\0' */ size += 3; if (!(buffer = buf = dm_malloc(size))) { log_error("Could not allocate memory for tag list buffer."); return NULL; } if (!emit_to_buffer(&buf, &size, "[")) goto_bad; dm_list_iterate_items(sl, tags) { if (!first) { if (!emit_to_buffer(&buf, &size, ", ")) goto_bad; } else first = 0; if (!emit_to_buffer(&buf, &size, "\"%s\"", sl->str)) goto_bad; } if (!emit_to_buffer(&buf, &size, "]")) goto_bad; return buffer; bad: dm_free(buffer); return_NULL; } int read_tags(struct dm_pool *mem, struct dm_list *tags, const struct dm_config_value *cv) { if (cv->type == DM_CFG_EMPTY_ARRAY) return 1; while (cv) { if (cv->type != DM_CFG_STRING) { log_error("Found a tag that is not a string"); return 0; } if (!str_list_add(mem, tags, dm_pool_strdup(mem, cv->v.str))) return_0; cv = cv->next; } return 1; } lvm2-2.02.98/lib/format_text/archiver.c0000640000175000017500000002531612037016272016570 0ustar blankblank/* * 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 "archiver.h" #include "format-text.h" #include "lvm-string.h" #include "lvmcache.h" #include "toolcontext.h" #include "locking.h" #include struct archive_params { int enabled; char *dir; unsigned int keep_days; unsigned int keep_number; }; struct backup_params { int enabled; char *dir; }; int archive_init(struct cmd_context *cmd, const char *dir, unsigned int keep_days, unsigned int keep_min, int enabled) { archive_exit(cmd); if (!(cmd->archive_params = dm_pool_zalloc(cmd->libmem, sizeof(*cmd->archive_params)))) { log_error("archive_params alloc failed"); return 0; } cmd->archive_params->dir = NULL; if (!*dir) return 1; if (!(cmd->archive_params->dir = dm_strdup(dir))) { log_error("Couldn't copy archive directory name."); return 0; } cmd->archive_params->keep_days = keep_days; cmd->archive_params->keep_number = keep_min; archive_enable(cmd, enabled); return 1; } void archive_exit(struct cmd_context *cmd) { if (!cmd->archive_params) return; dm_free(cmd->archive_params->dir); memset(cmd->archive_params, 0, sizeof(*cmd->archive_params)); } void archive_enable(struct cmd_context *cmd, int flag) { cmd->archive_params->enabled = flag; } static char *_build_desc(struct dm_pool *mem, const char *line, int before) { size_t len = strlen(line) + 32; char *buffer; if (!(buffer = dm_pool_alloc(mem, len))) { log_error("Failed to allocate desc."); return NULL; } if (dm_snprintf(buffer, len, "Created %s executing '%s'", before ? "*before*" : "*after*", line) < 0) { log_error("Failed to build desc."); return NULL; } return buffer; } static int __archive(struct volume_group *vg) { char *desc; if (!(desc = _build_desc(vg->cmd->mem, vg->cmd->cmd_line, 1))) return_0; return archive_vg(vg, vg->cmd->archive_params->dir, desc, vg->cmd->archive_params->keep_days, vg->cmd->archive_params->keep_number); } int archive(struct volume_group *vg) { if (!vg->cmd->archive_params->enabled || !vg->cmd->archive_params->dir) return 1; if (test_mode()) { log_verbose("Test mode: Skipping archiving of volume group."); return 1; } if (!dm_create_dir(vg->cmd->archive_params->dir)) return 0; /* Trap a read-only file system */ if ((access(vg->cmd->archive_params->dir, R_OK | W_OK | X_OK) == -1) && (errno == EROFS)) return 0; log_verbose("Archiving volume group \"%s\" metadata (seqno %u).", vg->name, vg->seqno); if (!__archive(vg)) { log_error("Volume group \"%s\" metadata archive failed.", vg->name); return 0; } return 1; } int archive_display(struct cmd_context *cmd, const char *vg_name) { int r1, r2; r1 = archive_list(cmd, cmd->archive_params->dir, vg_name); r2 = backup_list(cmd, cmd->backup_params->dir, vg_name); return r1 && r2; } int archive_display_file(struct cmd_context *cmd, const char *file) { int r; r = archive_list_file(cmd, file); return r; } int backup_init(struct cmd_context *cmd, const char *dir, int enabled) { backup_exit(cmd); if (!(cmd->backup_params = dm_pool_zalloc(cmd->libmem, sizeof(*cmd->backup_params)))) { log_error("backup_params alloc failed"); return 0; } cmd->backup_params->dir = NULL; if (!*dir) return 1; if (!(cmd->backup_params->dir = dm_strdup(dir))) { log_error("Couldn't copy backup directory name."); return 0; } backup_enable(cmd, enabled); return 1; } void backup_exit(struct cmd_context *cmd) { if (!cmd->backup_params) return; dm_free(cmd->backup_params->dir); memset(cmd->backup_params, 0, sizeof(*cmd->backup_params)); } void backup_enable(struct cmd_context *cmd, int flag) { cmd->backup_params->enabled = flag; } static int __backup(struct volume_group *vg) { char name[PATH_MAX]; char *desc; if (!(desc = _build_desc(vg->cmd->mem, vg->cmd->cmd_line, 0))) return_0; if (dm_snprintf(name, sizeof(name), "%s/%s", vg->cmd->backup_params->dir, vg->name) < 0) { log_error("Failed to generate volume group metadata backup " "filename."); return 0; } return backup_to_file(name, desc, vg); } int backup_locally(struct volume_group *vg) { if (!vg->cmd->backup_params->enabled || !vg->cmd->backup_params->dir) { log_warn("WARNING: This metadata update is NOT backed up"); return 1; } if (test_mode()) { log_verbose("Test mode: Skipping backup of volume group."); return 1; } if (!dm_create_dir(vg->cmd->backup_params->dir)) return 0; /* Trap a read-only file system */ if ((access(vg->cmd->backup_params->dir, R_OK | W_OK | X_OK) == -1) && (errno == EROFS)) return 0; if (!__backup(vg)) { log_error("Backup of volume group %s metadata failed.", vg->name); return 0; } return 1; } int backup(struct volume_group *vg) { if (vg_is_clustered(vg)) if (!remote_backup_metadata(vg)) stack; return backup_locally(vg); } int backup_remove(struct cmd_context *cmd, const char *vg_name) { char path[PATH_MAX]; if (dm_snprintf(path, sizeof(path), "%s/%s", cmd->backup_params->dir, vg_name) < 0) { log_error("Failed to generate backup filename (for removal)."); return 0; } /* * Let this fail silently. */ if (unlink(path)) log_sys_debug("unlink", path); return 1; } struct volume_group *backup_read_vg(struct cmd_context *cmd, const char *vg_name, const char *file) { struct volume_group *vg = NULL; struct format_instance *tf; struct format_instance_ctx fic; struct text_context tc = {.path_live = file, .path_edit = NULL, .desc = cmd->cmd_line}; struct metadata_area *mda; fic.type = FMT_INSTANCE_PRIVATE_MDAS; fic.context.private = &tc; if (!(tf = cmd->fmt_backup->ops->create_instance(cmd->fmt_backup, &fic))) { log_error("Couldn't create text format object."); return NULL; } dm_list_iterate_items(mda, &tf->metadata_areas_in_use) { if (!(vg = mda->ops->vg_read(tf, vg_name, mda, 0))) stack; break; } if (!vg) tf->fmt->ops->destroy_instance(tf); return vg; } /* ORPHAN and VG locks held before calling this */ int backup_restore_vg(struct cmd_context *cmd, struct volume_group *vg) { struct pv_list *pvl; struct format_instance *fid; struct format_instance_ctx fic; uint32_t tmp; /* * FIXME: Check that the PVs referenced in the backup are * not members of other existing VGs. */ /* Attempt to write out using currently active format */ fic.type = FMT_INSTANCE_AUX_MDAS; fic.context.vg_ref.vg_name = vg->name; fic.context.vg_ref.vg_id = NULL; if (!(fid = cmd->fmt->ops->create_instance(cmd->fmt, &fic))) { log_error("Failed to allocate format instance"); return 0; } vg_set_fid(vg, fid); /* * Setting vg->old_name to a blank value will explicitly * disable any attempt to check VG name in existing metadata. */ vg->old_name = dm_pool_strdup(vg->vgmem, ""); /* Add any metadata areas on the PVs */ dm_list_iterate_items(pvl, &vg->pvs) { tmp = vg->extent_size; vg->extent_size = 0; if (!vg->fid->fmt->ops->pv_setup(vg->fid->fmt, pvl->pv, vg)) { log_error("Format-specific setup for %s failed", pv_dev_name(pvl->pv)); return 0; } vg->extent_size = tmp; } if (!vg_write(vg) || !vg_commit(vg)) return_0; return 1; } /* ORPHAN and VG locks held before calling this */ int backup_restore_from_file(struct cmd_context *cmd, const char *vg_name, const char *file) { struct volume_group *vg; int missing_pvs, r = 0; const struct lv_list *lvl; /* * Read in the volume group from the text file. */ if (!(vg = backup_read_vg(cmd, vg_name, file))) return_0; /* FIXME: Restore support is missing for now */ dm_list_iterate_items(lvl, &vg->lvs) if (lv_is_thin_type(lvl->lv)) { log_error("Cannot restore Volume Group %s with " "thin logical volumes. " "(not yet supported).", vg->name); r = 0; goto out; } missing_pvs = vg_missing_pv_count(vg); if (missing_pvs == 0) r = backup_restore_vg(cmd, vg); else log_error("Cannot restore Volume Group %s with %i PVs " "marked as missing.", vg->name, missing_pvs); out: release_vg(vg); return r; } int backup_restore(struct cmd_context *cmd, const char *vg_name) { char path[PATH_MAX]; if (dm_snprintf(path, sizeof(path), "%s/%s", cmd->backup_params->dir, vg_name) < 0) { log_error("Failed to generate backup filename (for restore)."); return 0; } return backup_restore_from_file(cmd, vg_name, path); } int backup_to_file(const char *file, const char *desc, struct volume_group *vg) { int r = 0; struct format_instance *tf; struct format_instance_ctx fic; struct text_context tc = {.path_live = file, .path_edit = NULL, .desc = desc}; struct metadata_area *mda; struct cmd_context *cmd; cmd = vg->cmd; log_verbose("Creating volume group backup \"%s\" (seqno %u).", file, vg->seqno); fic.type = FMT_INSTANCE_PRIVATE_MDAS; fic.context.private = &tc; if (!(tf = cmd->fmt_backup->ops->create_instance(cmd->fmt_backup, &fic))) { log_error("Couldn't create backup object."); return 0; } if (!dm_list_size(&tf->metadata_areas_in_use)) { log_error(INTERNAL_ERROR "No in use metadata areas to write."); tf->fmt->ops->destroy_instance(tf); return 0; } /* Write and commit the metadata area */ dm_list_iterate_items(mda, &tf->metadata_areas_in_use) { if (!(r = mda->ops->vg_write(tf, vg, mda))) { stack; continue; } if (mda->ops->vg_commit && !(r = mda->ops->vg_commit(tf, vg, mda))) { stack; } } tf->fmt->ops->destroy_instance(tf); return r; } /* * Update backup (and archive) if they're out-of-date or don't exist. */ void check_current_backup(struct volume_group *vg) { char path[PATH_MAX]; struct volume_group *vg_backup; int old_suppress; if (vg_is_exported(vg)) return; if (dm_snprintf(path, sizeof(path), "%s/%s", vg->cmd->backup_params->dir, vg->name) < 0) { log_debug("Failed to generate backup filename."); return; } old_suppress = log_suppress(1); /* Up-to-date backup exists? */ if ((vg_backup = backup_read_vg(vg->cmd, vg->name, path)) && (vg->seqno == vg_backup->seqno) && (id_equal(&vg->id, &vg_backup->id))) { log_suppress(old_suppress); release_vg(vg_backup); return; } log_suppress(old_suppress); if (vg_backup) { if (!archive(vg_backup)) stack; release_vg(vg_backup); } if (!archive(vg)) stack; if (!backup_locally(vg)) stack; } lvm2-2.02.98/lib/format_text/format-text.c0000640000175000017500000017655012037016272017246 0ustar blankblank/* * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU 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 "format-text.h" #include "import-export.h" #include "device.h" #include "lvm-file.h" #include "config.h" #include "display.h" #include "toolcontext.h" #include "lvm-string.h" #include "uuid.h" #include "layout.h" #include "crc.h" #include "xlate.h" #include "label.h" #include "lvmcache.h" #include "lvmetad.h" #include #include #include #include #include static struct format_instance *_text_create_text_instance(const struct format_type *fmt, const struct format_instance_ctx *fic); struct text_fid_context { char *raw_metadata_buf; uint32_t raw_metadata_buf_size; }; struct dir_list { struct dm_list list; char dir[0]; }; struct raw_list { struct dm_list list; struct device_area dev_area; }; int rlocn_is_ignored(const struct raw_locn *rlocn) { return (rlocn->flags & RAW_LOCN_IGNORED ? 1 : 0); } void rlocn_set_ignored(struct raw_locn *rlocn, unsigned mda_ignored) { if (mda_ignored) rlocn->flags |= RAW_LOCN_IGNORED; else rlocn->flags &= ~RAW_LOCN_IGNORED; } /* * NOTE: Currently there can be only one vg per text file. */ static int _text_vg_setup(struct format_instance *fid __attribute__((unused)), struct volume_group *vg) { if (vg->extent_size & (vg->extent_size - 1)) { log_error("Extent size must be power of 2"); return 0; } return 1; } static uint64_t _mda_free_sectors_raw(struct metadata_area *mda) { struct mda_context *mdac = (struct mda_context *) mda->metadata_locn; return mdac->free_sectors; } static uint64_t _mda_total_sectors_raw(struct metadata_area *mda) { struct mda_context *mdac = (struct mda_context *) mda->metadata_locn; return mdac->area.size >> SECTOR_SHIFT; } /* * Check if metadata area belongs to vg */ static int _mda_in_vg_raw(struct format_instance *fid __attribute__((unused)), struct volume_group *vg, struct metadata_area *mda) { struct mda_context *mdac = (struct mda_context *) mda->metadata_locn; struct pv_list *pvl; dm_list_iterate_items(pvl, &vg->pvs) if (pvl->pv->dev == mdac->area.dev) return 1; return 0; } static unsigned _mda_locns_match_raw(struct metadata_area *mda1, struct metadata_area *mda2) { struct mda_context *mda1c = (struct mda_context *) mda1->metadata_locn; struct mda_context *mda2c = (struct mda_context *) mda2->metadata_locn; if ((mda1c->area.dev == mda2c->area.dev) && (mda1c->area.start == mda2c->area.start) && (mda1c->area.size == mda2c->area.size)) return 1; return 0; } static struct device *_mda_get_device_raw(struct metadata_area *mda) { struct mda_context *mdac = (struct mda_context *) mda->metadata_locn; return mdac->area.dev; } /* * For circular region between region_start and region_start + region_size, * back up one SECTOR_SIZE from 'region_ptr' and return the value. * This allows reverse traversal through text metadata area to find old * metadata. * * Parameters: * region_start: start of the region (bytes) * region_size: size of the region (bytes) * region_ptr: pointer within the region (bytes) * NOTE: region_start <= region_ptr <= region_start + region_size */ static uint64_t _get_prev_sector_circular(uint64_t region_start, uint64_t region_size, uint64_t region_ptr) { if (region_ptr >= region_start + SECTOR_SIZE) return region_ptr - SECTOR_SIZE; else return (region_start + region_size - SECTOR_SIZE); } /* * Analyze a metadata area for old metadata records in the circular buffer. * This function just looks through and makes a first pass at the data in * the sectors for particular things. * FIXME: do something with each metadata area (try to extract vg, write * raw data to file, etc) */ static int _pv_analyze_mda_raw (const struct format_type * fmt, struct metadata_area *mda) { struct mda_header *mdah; struct raw_locn *rlocn; uint64_t area_start; uint64_t area_size; uint64_t prev_sector, prev_sector2; uint64_t latest_mrec_offset; uint64_t offset; uint64_t offset2; size_t size; size_t size2; char *buf=NULL; struct device_area *area; struct mda_context *mdac; int r=0; mdac = (struct mda_context *) mda->metadata_locn; log_print("Found text metadata area: offset=%" PRIu64 ", size=%" PRIu64, mdac->area.start, mdac->area.size); area = &mdac->area; if (!dev_open_readonly(area->dev)) return_0; if (!(mdah = raw_read_mda_header(fmt, area))) goto_out; rlocn = mdah->raw_locns; /* * The device area includes the metadata header as well as the * records, so remove the metadata header from the start and size */ area_start = area->start + MDA_HEADER_SIZE; area_size = area->size - MDA_HEADER_SIZE; latest_mrec_offset = rlocn->offset + area->start; /* * Start searching at rlocn (point of live metadata) and go * backwards. */ prev_sector = _get_prev_sector_circular(area_start, area_size, latest_mrec_offset); offset = prev_sector; size = SECTOR_SIZE; offset2 = size2 = 0; while (prev_sector != latest_mrec_offset) { prev_sector2 = prev_sector; prev_sector = _get_prev_sector_circular(area_start, area_size, prev_sector); if (prev_sector > prev_sector2) goto_out; /* * FIXME: for some reason, the whole metadata region from * area->start to area->start+area->size is not used. * Only ~32KB seems to contain valid metadata records * (LVM2 format - format_text). As a result, I end up with * "dm_config_maybe_section" returning true when there's no valid * metadata in a sector (sectors with all nulls). */ if (!(buf = dm_malloc(size + size2))) goto_out; if (!dev_read_circular(area->dev, offset, size, offset2, size2, buf)) goto_out; /* * FIXME: We could add more sophisticated metadata detection */ if (dm_config_maybe_section(buf, size + size2)) { /* FIXME: Validate region, pull out timestamp?, etc */ /* FIXME: Do something with this region */ log_verbose ("Found LVM2 metadata record at " "offset=%"PRIu64", size=%"PRIsize_t", " "offset2=%"PRIu64" size2=%"PRIsize_t, offset, size, offset2, size2); offset = prev_sector; size = SECTOR_SIZE; offset2 = size2 = 0; } else { /* * Not a complete metadata record, assume we have * metadata and just increase the size and offset. * Start the second region if the previous sector is * wrapping around towards the end of the disk. */ if (prev_sector > offset) { offset2 = prev_sector; size2 += SECTOR_SIZE; } else { offset = prev_sector; size += SECTOR_SIZE; } } dm_free(buf); buf = NULL; } r = 1; out: if (buf) dm_free(buf); if (!dev_close(area->dev)) stack; return r; } static int _text_lv_setup(struct format_instance *fid __attribute__((unused)), struct logical_volume *lv) { /******** FIXME Any LV size restriction? uint64_t max_size = UINT_MAX; if (lv->size > max_size) { char *dummy = display_size(max_size); log_error("logical volumes cannot be larger than %s", dummy); dm_free(dummy); return 0; } */ if (!*lv->lvid.s && !lvid_create(&lv->lvid, &lv->vg->id)) { log_error("Random lvid creation failed for %s/%s.", lv->vg->name, lv->name); return 0; } return 1; } static void _xlate_mdah(struct mda_header *mdah) { struct raw_locn *rl; mdah->version = xlate32(mdah->version); mdah->start = xlate64(mdah->start); mdah->size = xlate64(mdah->size); rl = &mdah->raw_locns[0]; while (rl->offset) { rl->checksum = xlate32(rl->checksum); rl->offset = xlate64(rl->offset); rl->size = xlate64(rl->size); rl++; } } struct mda_header *raw_read_mda_header(const struct format_type *fmt, struct device_area *dev_area) { struct mda_header *mdah; if (!(mdah = dm_pool_alloc(fmt->cmd->mem, MDA_HEADER_SIZE))) { log_error("struct mda_header allocation failed"); return NULL; } if (!dev_read(dev_area->dev, dev_area->start, MDA_HEADER_SIZE, mdah)) goto_bad; if (mdah->checksum_xl != xlate32(calc_crc(INITIAL_CRC, (uint8_t *)mdah->magic, MDA_HEADER_SIZE - sizeof(mdah->checksum_xl)))) { log_error("Incorrect metadata area header checksum on %s" " at offset %"PRIu64, dev_name(dev_area->dev), dev_area->start); goto bad; } _xlate_mdah(mdah); if (strncmp((char *)mdah->magic, FMTT_MAGIC, sizeof(mdah->magic))) { log_error("Wrong magic number in metadata area header on %s" " at offset %"PRIu64, dev_name(dev_area->dev), dev_area->start); goto bad; } if (mdah->version != FMTT_VERSION) { log_error("Incompatible metadata area header version: %d on %s" " at offset %"PRIu64, mdah->version, dev_name(dev_area->dev), dev_area->start); goto bad; } if (mdah->start != dev_area->start) { log_error("Incorrect start sector in metadata area header: %" PRIu64" on %s at offset %"PRIu64, mdah->start, dev_name(dev_area->dev), dev_area->start); goto bad; } return mdah; bad: dm_pool_free(fmt->cmd->mem, mdah); return NULL; } static int _raw_write_mda_header(const struct format_type *fmt, struct device *dev, uint64_t start_byte, struct mda_header *mdah) { strncpy((char *)mdah->magic, FMTT_MAGIC, sizeof(mdah->magic)); mdah->version = FMTT_VERSION; mdah->start = start_byte; _xlate_mdah(mdah); mdah->checksum_xl = xlate32(calc_crc(INITIAL_CRC, (uint8_t *)mdah->magic, MDA_HEADER_SIZE - sizeof(mdah->checksum_xl))); if (!dev_write(dev, start_byte, MDA_HEADER_SIZE, mdah)) return_0; return 1; } static struct raw_locn *_find_vg_rlocn(struct device_area *dev_area, struct mda_header *mdah, const char *vgname, int *precommitted) { size_t len; char vgnamebuf[NAME_LEN + 2] __attribute__((aligned(8))); struct raw_locn *rlocn, *rlocn_precommitted; struct lvmcache_info *info; rlocn = mdah->raw_locns; /* Slot 0 */ rlocn_precommitted = rlocn + 1; /* Slot 1 */ /* Should we use precommitted metadata? */ if (*precommitted && rlocn_precommitted->size && (rlocn_precommitted->offset != rlocn->offset)) { rlocn = rlocn_precommitted; } else *precommitted = 0; /* Do not check non-existent metadata. */ if (!rlocn->offset && !rlocn->size) return NULL; /* * Don't try to check existing metadata * if given vgname is an empty string. */ if (!*vgname) return rlocn; /* FIXME Loop through rlocns two-at-a-time. List null-terminated. */ /* FIXME Ignore if checksum incorrect!!! */ if (!dev_read(dev_area->dev, dev_area->start + rlocn->offset, sizeof(vgnamebuf), vgnamebuf)) goto_bad; if (!strncmp(vgnamebuf, vgname, len = strlen(vgname)) && (isspace(vgnamebuf[len]) || vgnamebuf[len] == '{')) return rlocn; else log_debug("Volume group name found in metadata does " "not match expected name %s.", vgname); bad: if ((info = lvmcache_info_from_pvid(dev_area->dev->pvid, 0))) lvmcache_update_vgname_and_id(info, FMT_TEXT_ORPHAN_VG_NAME, FMT_TEXT_ORPHAN_VG_NAME, 0, NULL); return NULL; } /* * Determine offset for uncommitted metadata */ static uint64_t _next_rlocn_offset(struct raw_locn *rlocn, struct mda_header *mdah) { if (!rlocn) /* Find an empty slot */ /* FIXME Assume only one VG per mdah for now */ return MDA_HEADER_SIZE; /* Start of free space - round up to next sector; circular */ return ((rlocn->offset + rlocn->size + (SECTOR_SIZE - rlocn->size % SECTOR_SIZE) - MDA_HEADER_SIZE) % (mdah->size - MDA_HEADER_SIZE)) + MDA_HEADER_SIZE; } static int _raw_holds_vgname(struct format_instance *fid, struct device_area *dev_area, const char *vgname) { int r = 0; int noprecommit = 0; struct mda_header *mdah; if (!dev_open_readonly(dev_area->dev)) return_0; if (!(mdah = raw_read_mda_header(fid->fmt, dev_area))) return_0; if (_find_vg_rlocn(dev_area, mdah, vgname, &noprecommit)) r = 1; if (!dev_close(dev_area->dev)) stack; return r; } static struct volume_group *_vg_read_raw_area(struct format_instance *fid, const char *vgname, struct device_area *area, int precommitted, int single_device) { struct volume_group *vg = NULL; struct raw_locn *rlocn; struct mda_header *mdah; time_t when; char *desc; uint32_t wrap = 0; if (!(mdah = raw_read_mda_header(fid->fmt, area))) goto_out; if (!(rlocn = _find_vg_rlocn(area, mdah, vgname, &precommitted))) { log_debug("VG %s not found on %s", vgname, dev_name(area->dev)); goto out; } if (rlocn->offset + rlocn->size > mdah->size) wrap = (uint32_t) ((rlocn->offset + rlocn->size) - mdah->size); if (wrap > rlocn->offset) { log_error("VG %s metadata too large for circular buffer", vgname); goto out; } /* FIXME 64-bit */ if (!(vg = text_vg_import_fd(fid, NULL, single_device, area->dev, (off_t) (area->start + rlocn->offset), (uint32_t) (rlocn->size - wrap), (off_t) (area->start + MDA_HEADER_SIZE), wrap, calc_crc, rlocn->checksum, &when, &desc))) goto_out; log_debug("Read %s %smetadata (%u) from %s at %" PRIu64 " size %" PRIu64, vg->name, precommitted ? "pre-commit " : "", vg->seqno, dev_name(area->dev), area->start + rlocn->offset, rlocn->size); if (precommitted) vg->status |= PRECOMMITTED; out: return vg; } static struct volume_group *_vg_read_raw(struct format_instance *fid, const char *vgname, struct metadata_area *mda, int single_device) { struct mda_context *mdac = (struct mda_context *) mda->metadata_locn; struct volume_group *vg; if (!dev_open_readonly(mdac->area.dev)) return_NULL; vg = _vg_read_raw_area(fid, vgname, &mdac->area, 0, single_device); if (!dev_close(mdac->area.dev)) stack; return vg; } static struct volume_group *_vg_read_precommit_raw(struct format_instance *fid, const char *vgname, struct metadata_area *mda) { struct mda_context *mdac = (struct mda_context *) mda->metadata_locn; struct volume_group *vg; if (!dev_open_readonly(mdac->area.dev)) return_NULL; vg = _vg_read_raw_area(fid, vgname, &mdac->area, 1, 0); if (!dev_close(mdac->area.dev)) stack; return vg; } static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg, struct metadata_area *mda) { struct mda_context *mdac = (struct mda_context *) mda->metadata_locn; struct text_fid_context *fidtc = (struct text_fid_context *) fid->private; struct raw_locn *rlocn; struct mda_header *mdah; struct pv_list *pvl; int r = 0; uint64_t new_wrap = 0, old_wrap = 0, new_end; int found = 0; int noprecommit = 0; /* Ignore any mda on a PV outside the VG. vgsplit relies on this */ dm_list_iterate_items(pvl, &vg->pvs) { if (pvl->pv->dev == mdac->area.dev) { found = 1; break; } } if (!found) return 1; if (!dev_open(mdac->area.dev)) return_0; if (!(mdah = raw_read_mda_header(fid->fmt, &mdac->area))) goto_out; rlocn = _find_vg_rlocn(&mdac->area, mdah, vg->old_name ? vg->old_name : vg->name, &noprecommit); mdac->rlocn.offset = _next_rlocn_offset(rlocn, mdah); if (!fidtc->raw_metadata_buf && !(fidtc->raw_metadata_buf_size = text_vg_export_raw(vg, "", &fidtc->raw_metadata_buf))) { log_error("VG %s metadata writing failed", vg->name); goto out; } mdac->rlocn.size = fidtc->raw_metadata_buf_size; if (mdac->rlocn.offset + mdac->rlocn.size > mdah->size) new_wrap = (mdac->rlocn.offset + mdac->rlocn.size) - mdah->size; if (rlocn && (rlocn->offset + rlocn->size > mdah->size)) old_wrap = (rlocn->offset + rlocn->size) - mdah->size; new_end = new_wrap ? new_wrap + MDA_HEADER_SIZE : mdac->rlocn.offset + mdac->rlocn.size; if ((new_wrap && old_wrap) || (rlocn && (new_wrap || old_wrap) && (new_end > rlocn->offset)) || (mdac->rlocn.size >= mdah->size)) { log_error("VG %s metadata too large for circular buffer", vg->name); goto out; } log_debug("Writing %s metadata to %s at %" PRIu64 " len %" PRIu64, vg->name, dev_name(mdac->area.dev), mdac->area.start + mdac->rlocn.offset, mdac->rlocn.size - new_wrap); /* Write text out, circularly */ if (!dev_write(mdac->area.dev, mdac->area.start + mdac->rlocn.offset, (size_t) (mdac->rlocn.size - new_wrap), fidtc->raw_metadata_buf)) goto_out; if (new_wrap) { log_debug("Writing metadata to %s at %" PRIu64 " len %" PRIu64, dev_name(mdac->area.dev), mdac->area.start + MDA_HEADER_SIZE, new_wrap); if (!dev_write(mdac->area.dev, mdac->area.start + MDA_HEADER_SIZE, (size_t) new_wrap, fidtc->raw_metadata_buf + mdac->rlocn.size - new_wrap)) goto_out; } mdac->rlocn.checksum = calc_crc(INITIAL_CRC, (uint8_t *)fidtc->raw_metadata_buf, (uint32_t) (mdac->rlocn.size - new_wrap)); if (new_wrap) mdac->rlocn.checksum = calc_crc(mdac->rlocn.checksum, (uint8_t *)fidtc->raw_metadata_buf + mdac->rlocn.size - new_wrap, (uint32_t) new_wrap); r = 1; out: if (!r) { if (!dev_close(mdac->area.dev)) stack; if (fidtc->raw_metadata_buf) { dm_free(fidtc->raw_metadata_buf); fidtc->raw_metadata_buf = NULL; } } return r; } static int _vg_commit_raw_rlocn(struct format_instance *fid, struct volume_group *vg, struct metadata_area *mda, int precommit) { struct mda_context *mdac = (struct mda_context *) mda->metadata_locn; struct text_fid_context *fidtc = (struct text_fid_context *) fid->private; struct mda_header *mdah; struct raw_locn *rlocn; struct pv_list *pvl; int r = 0; int found = 0; int noprecommit = 0; /* Ignore any mda on a PV outside the VG. vgsplit relies on this */ dm_list_iterate_items(pvl, &vg->pvs) { if (pvl->pv->dev == mdac->area.dev) { found = 1; break; } } if (!found) return 1; if (!(mdah = raw_read_mda_header(fid->fmt, &mdac->area))) goto_out; if (!(rlocn = _find_vg_rlocn(&mdac->area, mdah, vg->old_name ? vg->old_name : vg->name, &noprecommit))) { mdah->raw_locns[0].offset = 0; mdah->raw_locns[0].size = 0; mdah->raw_locns[0].checksum = 0; mdah->raw_locns[1].offset = 0; mdah->raw_locns[1].size = 0; mdah->raw_locns[1].checksum = 0; mdah->raw_locns[2].offset = 0; mdah->raw_locns[2].size = 0; mdah->raw_locns[2].checksum = 0; rlocn = &mdah->raw_locns[0]; } if (precommit) rlocn++; else { /* If not precommitting, wipe the precommitted rlocn */ mdah->raw_locns[1].offset = 0; mdah->raw_locns[1].size = 0; mdah->raw_locns[1].checksum = 0; } /* Is there new metadata to commit? */ if (mdac->rlocn.size) { rlocn->offset = mdac->rlocn.offset; rlocn->size = mdac->rlocn.size; rlocn->checksum = mdac->rlocn.checksum; log_debug("%sCommitting %s metadata (%u) to %s header at %" PRIu64, precommit ? "Pre-" : "", vg->name, vg->seqno, dev_name(mdac->area.dev), mdac->area.start); } else log_debug("Wiping pre-committed %s metadata from %s " "header at %" PRIu64, vg->name, dev_name(mdac->area.dev), mdac->area.start); rlocn_set_ignored(mdah->raw_locns, mda_is_ignored(mda)); if (!_raw_write_mda_header(fid->fmt, mdac->area.dev, mdac->area.start, mdah)) { dm_pool_free(fid->fmt->cmd->mem, mdah); log_error("Failed to write metadata area header"); goto out; } r = 1; out: if (!precommit) { if (!dev_close(mdac->area.dev)) stack; if (fidtc->raw_metadata_buf) { dm_free(fidtc->raw_metadata_buf); fidtc->raw_metadata_buf = NULL; } } return r; } static int _vg_commit_raw(struct format_instance *fid, struct volume_group *vg, struct metadata_area *mda) { return _vg_commit_raw_rlocn(fid, vg, mda, 0); } static int _vg_precommit_raw(struct format_instance *fid, struct volume_group *vg, struct metadata_area *mda) { return _vg_commit_raw_rlocn(fid, vg, mda, 1); } /* Close metadata area devices */ static int _vg_revert_raw(struct format_instance *fid, struct volume_group *vg, struct metadata_area *mda) { struct mda_context *mdac = (struct mda_context *) mda->metadata_locn; struct pv_list *pvl; int found = 0; /* Ignore any mda on a PV outside the VG. vgsplit relies on this */ dm_list_iterate_items(pvl, &vg->pvs) { if (pvl->pv->dev == mdac->area.dev) { found = 1; break; } } if (!found) return 1; /* Wipe pre-committed metadata */ mdac->rlocn.size = 0; return _vg_commit_raw_rlocn(fid, vg, mda, 0); } static int _vg_remove_raw(struct format_instance *fid, struct volume_group *vg, struct metadata_area *mda) { struct mda_context *mdac = (struct mda_context *) mda->metadata_locn; struct mda_header *mdah; struct raw_locn *rlocn; int r = 0; int noprecommit = 0; if (!dev_open(mdac->area.dev)) return_0; if (!(mdah = raw_read_mda_header(fid->fmt, &mdac->area))) goto_out; if (!(rlocn = _find_vg_rlocn(&mdac->area, mdah, vg->name, &noprecommit))) { rlocn = &mdah->raw_locns[0]; mdah->raw_locns[1].offset = 0; } rlocn->offset = 0; rlocn->size = 0; rlocn->checksum = 0; rlocn_set_ignored(mdah->raw_locns, mda_is_ignored(mda)); if (!_raw_write_mda_header(fid->fmt, mdac->area.dev, mdac->area.start, mdah)) { dm_pool_free(fid->fmt->cmd->mem, mdah); log_error("Failed to write metadata area header"); goto out; } r = 1; out: if (!dev_close(mdac->area.dev)) stack; return r; } static struct volume_group *_vg_read_file_name(struct format_instance *fid, const char *vgname, const char *read_path) { struct volume_group *vg; time_t when; char *desc; if (!(vg = text_vg_import_file(fid, read_path, &when, &desc))) return_NULL; /* * Currently you can only have a single volume group per * text file (this restriction may remain). We need to * check that it contains the correct volume group. */ if (vgname && strcmp(vgname, vg->name)) { release_vg(vg); log_error("'%s' does not contain volume group '%s'.", read_path, vgname); return NULL; } else log_debug("Read volume group %s from %s", vg->name, read_path); return vg; } static struct volume_group *_vg_read_file(struct format_instance *fid, const char *vgname, struct metadata_area *mda, int single_device __attribute__((unused))) { struct text_context *tc = (struct text_context *) mda->metadata_locn; return _vg_read_file_name(fid, vgname, tc->path_live); } static struct volume_group *_vg_read_precommit_file(struct format_instance *fid, const char *vgname, struct metadata_area *mda) { struct text_context *tc = (struct text_context *) mda->metadata_locn; struct volume_group *vg; if ((vg = _vg_read_file_name(fid, vgname, tc->path_edit))) vg->status |= PRECOMMITTED; else vg = _vg_read_file_name(fid, vgname, tc->path_live); return vg; } static int _vg_write_file(struct format_instance *fid __attribute__((unused)), struct volume_group *vg, struct metadata_area *mda) { struct text_context *tc = (struct text_context *) mda->metadata_locn; FILE *fp; int fd; char *slash; char temp_file[PATH_MAX], temp_dir[PATH_MAX]; slash = strrchr(tc->path_edit, '/'); if (slash == 0) strcpy(temp_dir, "."); else if (slash - tc->path_edit < PATH_MAX) { strncpy(temp_dir, tc->path_edit, (size_t) (slash - tc->path_edit)); temp_dir[slash - tc->path_edit] = '\0'; } else { log_error("Text format failed to determine directory."); return 0; } if (!create_temp_name(temp_dir, temp_file, sizeof(temp_file), &fd, &vg->cmd->rand_seed)) { log_error("Couldn't create temporary text file name."); return 0; } if (!(fp = fdopen(fd, "w"))) { log_sys_error("fdopen", temp_file); if (close(fd)) log_sys_error("fclose", temp_file); return 0; } log_debug("Writing %s metadata to %s", vg->name, temp_file); if (!text_vg_export_file(vg, tc->desc, fp)) { log_error("Failed to write metadata to %s.", temp_file); if (fclose(fp)) log_sys_error("fclose", temp_file); return 0; } if (fsync(fd) && (errno != EROFS) && (errno != EINVAL)) { log_sys_error("fsync", tc->path_edit); if (fclose(fp)) log_sys_error("fclose", tc->path_edit); return 0; } if (lvm_fclose(fp, tc->path_edit)) return_0; if (rename(temp_file, tc->path_edit)) { log_debug("Renaming %s to %s", temp_file, tc->path_edit); log_error("%s: rename to %s failed: %s", temp_file, tc->path_edit, strerror(errno)); return 0; } return 1; } static int _vg_commit_file_backup(struct format_instance *fid __attribute__((unused)), struct volume_group *vg, struct metadata_area *mda) { struct text_context *tc = (struct text_context *) mda->metadata_locn; if (test_mode()) { log_verbose("Test mode: Skipping committing %s metadata (%u)", vg->name, vg->seqno); if (unlink(tc->path_edit)) { log_debug("Unlinking %s", tc->path_edit); log_sys_error("unlink", tc->path_edit); return 0; } } else { log_debug("Committing %s metadata (%u)", vg->name, vg->seqno); log_debug("Renaming %s to %s", tc->path_edit, tc->path_live); if (rename(tc->path_edit, tc->path_live)) { log_error("%s: rename to %s failed: %s", tc->path_edit, tc->path_live, strerror(errno)); return 0; } } sync_dir(tc->path_edit); return 1; } static int _vg_commit_file(struct format_instance *fid, struct volume_group *vg, struct metadata_area *mda) { struct text_context *tc = (struct text_context *) mda->metadata_locn; const char *slash; char new_name[PATH_MAX]; size_t len; if (!_vg_commit_file_backup(fid, vg, mda)) return 0; /* vgrename? */ if ((slash = strrchr(tc->path_live, '/'))) slash = slash + 1; else slash = tc->path_live; if (strcmp(slash, vg->name)) { len = slash - tc->path_live; strncpy(new_name, tc->path_live, len); strcpy(new_name + len, vg->name); log_debug("Renaming %s to %s", tc->path_live, new_name); if (test_mode()) log_verbose("Test mode: Skipping rename"); else { if (rename(tc->path_live, new_name)) { log_error("%s: rename to %s failed: %s", tc->path_live, new_name, strerror(errno)); sync_dir(new_name); return 0; } } } return 1; } static int _vg_remove_file(struct format_instance *fid __attribute__((unused)), struct volume_group *vg __attribute__((unused)), struct metadata_area *mda) { struct text_context *tc = (struct text_context *) mda->metadata_locn; if (path_exists(tc->path_edit) && unlink(tc->path_edit)) { log_sys_error("unlink", tc->path_edit); return 0; } if (path_exists(tc->path_live) && unlink(tc->path_live)) { log_sys_error("unlink", tc->path_live); return 0; } sync_dir(tc->path_live); return 1; } static int _scan_file(const struct format_type *fmt, const char *vgname) { struct dirent *dirent; struct dir_list *dl; struct dm_list *dir_list; char *tmp; DIR *d; struct volume_group *vg; struct format_instance *fid; struct format_instance_ctx fic; char path[PATH_MAX]; char *scanned_vgname; dir_list = &((struct mda_lists *) fmt->private)->dirs; dm_list_iterate_items(dl, dir_list) { if (!(d = opendir(dl->dir))) { log_sys_error("opendir", dl->dir); continue; } while ((dirent = readdir(d))) if (strcmp(dirent->d_name, ".") && strcmp(dirent->d_name, "..") && (!(tmp = strstr(dirent->d_name, ".tmp")) || tmp != dirent->d_name + strlen(dirent->d_name) - 4)) { scanned_vgname = dirent->d_name; /* If vgname supplied, only scan that one VG */ if (vgname && strcmp(vgname, scanned_vgname)) continue; if (dm_snprintf(path, PATH_MAX, "%s/%s", dl->dir, scanned_vgname) < 0) { log_error("Name too long %s/%s", dl->dir, scanned_vgname); break; } /* FIXME stat file to see if it's changed */ /* FIXME: Check this fid is OK! */ fic.type = FMT_INSTANCE_PRIVATE_MDAS; fic.context.private = NULL; fid = _text_create_text_instance(fmt, &fic); if ((vg = _vg_read_file_name(fid, scanned_vgname, path))) { /* FIXME Store creation host in vg */ lvmcache_update_vg(vg, 0); release_vg(vg); } } if (closedir(d)) log_sys_error("closedir", dl->dir); } return 1; } const char *vgname_from_mda(const struct format_type *fmt, struct mda_header *mdah, struct device_area *dev_area, struct id *vgid, uint64_t *vgstatus, char **creation_host, uint64_t *mda_free_sectors) { struct raw_locn *rlocn; uint32_t wrap = 0; const char *vgname = NULL; unsigned int len = 0; char buf[NAME_LEN + 1] __attribute__((aligned(8))); char uuid[64] __attribute__((aligned(8))); uint64_t buffer_size, current_usage; if (mda_free_sectors) *mda_free_sectors = ((dev_area->size - MDA_HEADER_SIZE) / 2) >> SECTOR_SHIFT; if (!mdah) { log_error(INTERNAL_ERROR "vgname_from_mda called with NULL pointer for mda_header"); goto_out; } /* FIXME Cope with returning a list */ rlocn = mdah->raw_locns; /* * If no valid offset, do not try to search for vgname */ if (!rlocn->offset) goto out; /* Do quick check for a vgname */ if (!dev_read(dev_area->dev, dev_area->start + rlocn->offset, NAME_LEN, buf)) goto_out; while (buf[len] && !isspace(buf[len]) && buf[len] != '{' && len < (NAME_LEN - 1)) len++; buf[len] = '\0'; /* Ignore this entry if the characters aren't permissible */ if (!validate_name(buf)) goto_out; /* We found a VG - now check the metadata */ if (rlocn->offset + rlocn->size > mdah->size) wrap = (uint32_t) ((rlocn->offset + rlocn->size) - mdah->size); if (wrap > rlocn->offset) { log_error("%s: metadata too large for circular buffer", dev_name(dev_area->dev)); goto out; } /* FIXME 64-bit */ if (!(vgname = text_vgname_import(fmt, dev_area->dev, (off_t) (dev_area->start + rlocn->offset), (uint32_t) (rlocn->size - wrap), (off_t) (dev_area->start + MDA_HEADER_SIZE), wrap, calc_crc, rlocn->checksum, vgid, vgstatus, creation_host))) goto_out; /* Ignore this entry if the characters aren't permissible */ if (!validate_name(vgname)) { vgname = NULL; goto_out; } if (!id_write_format(vgid, uuid, sizeof(uuid))) { vgname = NULL; goto_out; } log_debug("%s: Found metadata at %" PRIu64 " size %" PRIu64 " (in area at %" PRIu64 " size %" PRIu64 ") for %s (%s)", dev_name(dev_area->dev), dev_area->start + rlocn->offset, rlocn->size, dev_area->start, dev_area->size, vgname, uuid); if (mda_free_sectors) { current_usage = (rlocn->size + SECTOR_SIZE - UINT64_C(1)) - (rlocn->size + SECTOR_SIZE - UINT64_C(1)) % SECTOR_SIZE; buffer_size = mdah->size - MDA_HEADER_SIZE; if (current_usage * 2 >= buffer_size) *mda_free_sectors = UINT64_C(0); else *mda_free_sectors = ((buffer_size - 2 * current_usage) / 2) >> SECTOR_SHIFT; } out: return vgname; } static int _scan_raw(const struct format_type *fmt, const char *vgname __attribute__((unused))) { struct raw_list *rl; struct dm_list *raw_list; const char *scanned_vgname; struct volume_group *vg; struct format_instance fid; struct id vgid; uint64_t vgstatus; struct mda_header *mdah; raw_list = &((struct mda_lists *) fmt->private)->raws; fid.fmt = fmt; dm_list_init(&fid.metadata_areas_in_use); dm_list_init(&fid.metadata_areas_ignored); dm_list_iterate_items(rl, raw_list) { /* FIXME We're reading mdah twice here... */ if (!dev_open_readonly(rl->dev_area.dev)) { stack; continue; } if (!(mdah = raw_read_mda_header(fmt, &rl->dev_area))) { stack; goto close_dev; } if ((scanned_vgname = vgname_from_mda(fmt, mdah, &rl->dev_area, &vgid, &vgstatus, NULL, NULL))) { vg = _vg_read_raw_area(&fid, scanned_vgname, &rl->dev_area, 0, 0); if (vg) lvmcache_update_vg(vg, 0); } close_dev: if (!dev_close(rl->dev_area.dev)) stack; } return 1; } static int _text_scan(const struct format_type *fmt, const char *vgname) { return (_scan_file(fmt, vgname) & _scan_raw(fmt, vgname)); } struct _write_single_mda_baton { const struct format_type *fmt; struct physical_volume *pv; }; static int _write_single_mda(struct metadata_area *mda, void *baton) { struct _write_single_mda_baton *p = baton; struct mda_context *mdac; char buf[MDA_HEADER_SIZE] __attribute__((aligned(8))) = { 0 }; struct mda_header *mdah = (struct mda_header *) buf; mdac = mda->metadata_locn; mdah->size = mdac->area.size; rlocn_set_ignored(mdah->raw_locns, mda_is_ignored(mda)); if (!_raw_write_mda_header(p->fmt, mdac->area.dev, mdac->area.start, mdah)) { if (!dev_close(p->pv->dev)) stack; return_0; } return 1; } /* Only for orphans */ static int _text_pv_write(const struct format_type *fmt, struct physical_volume *pv) { struct format_instance *fid = pv->fid; const char *pvid = (const char *) (*pv->old_id.uuid ? &pv->old_id : &pv->id); struct label *label; struct lvmcache_info *info; struct mda_context *mdac; struct metadata_area *mda; struct _write_single_mda_baton baton; unsigned mda_index; /* Add a new cache entry with PV info or update existing one. */ if (!(info = lvmcache_add(fmt->labeller, (const char *) &pv->id, pv->dev, pv->vg_name, NULL, 0))) return_0; label = lvmcache_get_label(info); label->sector = pv->label_sector; lvmcache_update_pv(info, pv, fmt); /* Flush all cached metadata areas, we will reenter new/modified ones. */ lvmcache_del_mdas(info); /* * Add all new or modified metadata areas for this PV stored in * its format instance. If this PV is not part of a VG yet, * pv->fid will be used. Otherwise pv->vg->fid will be used. * The fid_get_mda_indexed fn can handle that transparently, * just pass the right format_instance in. */ for (mda_index = 0; mda_index < FMT_TEXT_MAX_MDAS_PER_PV; mda_index++) { if (!(mda = fid_get_mda_indexed(fid, pvid, ID_LEN, mda_index))) continue; mdac = (struct mda_context *) mda->metadata_locn; log_debug("Creating metadata area on %s at sector %" PRIu64 " size %" PRIu64 " sectors", dev_name(mdac->area.dev), mdac->area.start >> SECTOR_SHIFT, mdac->area.size >> SECTOR_SHIFT); // if fmt is not the same as info->fmt we are in trouble lvmcache_add_mda(info, mdac->area.dev, mdac->area.start, mdac->area.size, mda_is_ignored(mda)); } /* * FIXME: Allow writing zero offset/size data area to disk. * This requires defining a special value since we can't * write offset/size that is 0/0 - this is already reserved * as a delimiter in data/metadata area area list in PV header * (needs exploring compatibility with older lvm2). */ /* * We can't actually write pe_start = 0 (a data area offset) * in PV header now. We need to replace this value here. This can * happen with vgcfgrestore with redefined pe_start or * pvcreate --restorefile. However, we can can have this value in * metadata which will override the value in the PV header. */ if (!lvmcache_update_das(info, pv)) return_0; if (!dev_open(pv->dev)) return_0; baton.pv = pv; baton.fmt = fmt; if (!lvmcache_foreach_mda(info, _write_single_mda, &baton)) return_0; if (!label_write(pv->dev, label)) { stack; if (!dev_close(pv->dev)) stack; return 0; } /* * FIXME: We should probably use the format instance's metadata * areas for label_write and only if it's successful, * update the cache afterwards? */ if (!dev_close(pv->dev)) return_0; return 1; } static int _add_raw(struct dm_list *raw_list, struct device_area *dev_area) { struct raw_list *rl; /* Already present? */ dm_list_iterate_items(rl, raw_list) { /* FIXME Check size/overlap consistency too */ if (rl->dev_area.dev == dev_area->dev && rl->dev_area.start == dev_area->start) return 1; } if (!(rl = dm_malloc(sizeof(struct raw_list)))) { log_error("_add_raw allocation failed"); return 0; } memcpy(&rl->dev_area, dev_area, sizeof(*dev_area)); dm_list_add(raw_list, &rl->list); return 1; } /* * Copy constructor for a metadata_locn. */ static void *_metadata_locn_copy_raw(struct dm_pool *mem, void *metadata_locn) { struct mda_context *mdac, *mdac_new; mdac = (struct mda_context *) metadata_locn; if (!(mdac_new = dm_pool_alloc(mem, sizeof(*mdac_new)))) { log_error("mda_context allocation failed"); return NULL; } memcpy(mdac_new, mdac, sizeof(*mdac)); return mdac_new; } /* * Return a string description of the metadata location. */ static const char *_metadata_locn_name_raw(void *metadata_locn) { struct mda_context *mdac = (struct mda_context *) metadata_locn; return dev_name(mdac->area.dev); } static uint64_t _metadata_locn_offset_raw(void *metadata_locn) { struct mda_context *mdac = (struct mda_context *) metadata_locn; return mdac->area.start; } static int _text_pv_read(const struct format_type *fmt, const char *pv_name, struct physical_volume *pv, int scan_label_only) { struct lvmcache_info *info; struct device *dev; if (!(dev = dev_cache_get(pv_name, fmt->cmd->filter))) return_0; if (lvmetad_active()) { info = lvmcache_info_from_pvid(dev->pvid, 0); if (!info && !lvmetad_pv_lookup_by_dev(fmt->cmd, dev, NULL)) return 0; info = lvmcache_info_from_pvid(dev->pvid, 0); } else { struct label *label; if (!(label_read(dev, &label, UINT64_C(0)))) return_0; info = label->info; } if (!info) return_0; if (!lvmcache_populate_pv_fields(info, pv, scan_label_only)) return 0; return 1; } static int _text_pv_initialise(const struct format_type *fmt, const int64_t label_sector, uint64_t pe_start, uint32_t extent_count, uint32_t extent_size, unsigned long data_alignment, unsigned long data_alignment_offset, struct physical_volume *pv) { /* * Try to keep the value of PE start set to a firm value if requested. * This is usefull when restoring existing PE start value (backups etc.). */ if (pe_start != PV_PE_START_CALC) pv->pe_start = pe_start; if (!data_alignment) data_alignment = find_config_tree_int(pv->fmt->cmd, "devices/data_alignment", 0) * 2; if (set_pe_align(pv, data_alignment) != data_alignment && data_alignment) { log_error("%s: invalid data alignment of " "%lu sectors (requested %lu sectors)", pv_dev_name(pv), pv->pe_align, data_alignment); return 0; } if (set_pe_align_offset(pv, data_alignment_offset) != data_alignment_offset && data_alignment_offset) { log_error("%s: invalid data alignment offset of " "%lu sectors (requested %lu sectors)", pv_dev_name(pv), pv->pe_align_offset, data_alignment_offset); return 0; } if (pv->pe_align < pv->pe_align_offset) { log_error("%s: pe_align (%lu sectors) must not be less " "than pe_align_offset (%lu sectors)", pv_dev_name(pv), pv->pe_align, pv->pe_align_offset); return 0; } if (pe_start == PV_PE_START_CALC && pv->pe_start < pv->pe_align) pv->pe_start = pv->pe_align; if (extent_size) pv->pe_size = extent_size; if (extent_count) pv->pe_count = extent_count; if ((pv->pe_start + pv->pe_count * pv->pe_size - 1) > (pv->size << SECTOR_SHIFT)) { log_error("Physical extents end beyond end of device %s.", pv_dev_name(pv)); return 0; } if (label_sector != -1) pv->label_sector = label_sector; return 1; } static void _text_destroy_instance(struct format_instance *fid) { if (--fid->ref_count <= 1) { if (fid->metadata_areas_index) dm_hash_destroy(fid->metadata_areas_index); dm_pool_destroy(fid->mem); } } static void _free_dirs(struct dm_list *dir_list) { struct dm_list *dl, *tmp; dm_list_iterate_safe(dl, tmp, dir_list) { dm_list_del(dl); dm_free(dl); } } static void _free_raws(struct dm_list *raw_list) { struct dm_list *rl, *tmp; dm_list_iterate_safe(rl, tmp, raw_list) { dm_list_del(rl); dm_free(rl); } } static void _text_destroy(struct format_type *fmt) { if (fmt->orphan_vg) free_orphan_vg(fmt->orphan_vg); if (fmt->private) { _free_dirs(&((struct mda_lists *) fmt->private)->dirs); _free_raws(&((struct mda_lists *) fmt->private)->raws); dm_free(fmt->private); } dm_free(fmt); } static struct metadata_area_ops _metadata_text_file_ops = { .vg_read = _vg_read_file, .vg_read_precommit = _vg_read_precommit_file, .vg_write = _vg_write_file, .vg_remove = _vg_remove_file, .vg_commit = _vg_commit_file }; static struct metadata_area_ops _metadata_text_file_backup_ops = { .vg_read = _vg_read_file, .vg_write = _vg_write_file, .vg_remove = _vg_remove_file, .vg_commit = _vg_commit_file_backup }; static int _mda_export_text_raw(struct metadata_area *mda, struct dm_config_tree *cft, struct dm_config_node *parent); static int _mda_import_text_raw(struct lvmcache_info *info, const struct dm_config_node *cn); static struct metadata_area_ops _metadata_text_raw_ops = { .vg_read = _vg_read_raw, .vg_read_precommit = _vg_read_precommit_raw, .vg_write = _vg_write_raw, .vg_remove = _vg_remove_raw, .vg_precommit = _vg_precommit_raw, .vg_commit = _vg_commit_raw, .vg_revert = _vg_revert_raw, .mda_metadata_locn_copy = _metadata_locn_copy_raw, .mda_metadata_locn_name = _metadata_locn_name_raw, .mda_metadata_locn_offset = _metadata_locn_offset_raw, .mda_free_sectors = _mda_free_sectors_raw, .mda_total_sectors = _mda_total_sectors_raw, .mda_in_vg = _mda_in_vg_raw, .pv_analyze_mda = _pv_analyze_mda_raw, .mda_locns_match = _mda_locns_match_raw, .mda_get_device = _mda_get_device_raw, .mda_export_text = _mda_export_text_raw, .mda_import_text = _mda_import_text_raw }; static int _mda_export_text_raw(struct metadata_area *mda, struct dm_config_tree *cft, struct dm_config_node *parent) { struct mda_context *mdc = (struct mda_context *) mda->metadata_locn; return config_make_nodes(cft, parent, NULL, "ignore = %" PRId64, (int64_t) mda_is_ignored(mda), "start = %" PRId64, (int64_t) mdc->area.start, "size = %" PRId64, (int64_t) mdc->area.size, "free_sectors = %" PRId64, (int64_t) mdc->free_sectors, NULL) ? 1 : 0; } static int _mda_import_text_raw(struct lvmcache_info *info, const struct dm_config_node *cn) { struct device *device; uint64_t offset; uint64_t size; int ignore; if (!cn->child) return 0; cn = cn->child; device = lvmcache_device(info); size = dm_config_find_int(cn, "size", 0); if (!device || !size) return 0; offset = dm_config_find_int(cn, "start", 0); ignore = dm_config_find_int(cn, "ignore", 0); lvmcache_add_mda(info, device, offset, size, ignore); return 1; } static int _text_pv_setup(const struct format_type *fmt, struct physical_volume *pv, struct volume_group *vg) { struct format_instance *fid = pv->fid; const char *pvid = (const char *) (*pv->old_id.uuid ? &pv->old_id : &pv->id); struct lvmcache_info *info; unsigned mda_index; struct metadata_area *pv_mda, *pv_mda_copy; struct mda_context *pv_mdac; uint64_t pe_count; uint64_t size_reduction = 0; /* If PV has its own format instance, add mdas from pv->fid to vg->fid. */ if (pv->fid != vg->fid) { for (mda_index = 0; mda_index < FMT_TEXT_MAX_MDAS_PER_PV; mda_index++) { if (!(pv_mda = fid_get_mda_indexed(fid, pvid, ID_LEN, mda_index))) continue; /* Be sure it's not already in VG's format instance! */ if (!fid_get_mda_indexed(vg->fid, pvid, ID_LEN, mda_index)) { if (!(pv_mda_copy = mda_copy(vg->fid->mem, pv_mda))) return_0; fid_add_mda(vg->fid, pv_mda_copy, pvid, ID_LEN, mda_index); } } } /* * Otherwise, if the PV is already a part of the VG (pv->fid == vg->fid), * reread PV mda information from the cache and add it to vg->fid. */ else { if (!pv->dev || !(info = lvmcache_info_from_pvid(pv->dev->pvid, 0))) { log_error("PV %s missing from cache", pv_dev_name(pv)); return 0; } if (!lvmcache_check_format(info, fmt)) return_0; if (!lvmcache_fid_add_mdas_pv(info, fid)) return_0; } /* If there's the 2nd mda, we need to reduce * usable size for further pe_count calculation! */ if ((pv_mda = fid_get_mda_indexed(fid, pvid, ID_LEN, 1)) && (pv_mdac = pv_mda->metadata_locn)) size_reduction = pv_mdac->area.size >> SECTOR_SHIFT; /* From now on, VG format instance will be used. */ pv_set_fid(pv, vg->fid); /* FIXME Cope with genuine pe_count 0 */ /* If missing, estimate pv->size from file-based metadata */ if (!pv->size && pv->pe_count) pv->size = pv->pe_count * (uint64_t) vg->extent_size + pv->pe_start + size_reduction; /* Recalculate number of extents that will fit */ if (!pv->pe_count && vg->extent_size) { pe_count = (pv->size - pv->pe_start - size_reduction) / vg->extent_size; if (pe_count > UINT32_MAX) { log_error("PV %s too large for extent size %s.", pv_dev_name(pv), display_size(vg->cmd, (uint64_t) vg->extent_size)); return 0; } pv->pe_count = (uint32_t) pe_count; } /* Unlike LVM1, we don't store this outside a VG */ /* FIXME Default from config file? vgextend cmdline flag? */ pv->status |= ALLOCATABLE_PV; return 1; } static void *_create_text_context(struct dm_pool *mem, struct text_context *tc) { struct text_context *new_tc; const char *path; char *tmp; if (!tc) return NULL; path = tc->path_live; if ((tmp = strstr(path, ".tmp")) && (tmp == path + strlen(path) - 4)) { log_error("%s: Volume group filename may not end in .tmp", path); return NULL; } if (!(new_tc = dm_pool_alloc(mem, sizeof(*new_tc)))) return_NULL; if (!(new_tc->path_live = dm_pool_strdup(mem, path))) goto_bad; /* If path_edit not defined, create one from path_live with .tmp suffix. */ if (!tc->path_edit) { if (!(tmp = dm_pool_alloc(mem, strlen(path) + 5))) goto_bad; sprintf(tmp, "%s.tmp", path); new_tc->path_edit = tmp; } else if (!(new_tc->path_edit = dm_pool_strdup(mem, tc->path_edit))) goto_bad; if (!(new_tc->desc = tc->desc ? dm_pool_strdup(mem, tc->desc) : dm_pool_strdup(mem, ""))) goto_bad; return (void *) new_tc; bad: dm_pool_free(mem, new_tc); log_error("Couldn't allocate text format context object."); return NULL; } static int _create_vg_text_instance(struct format_instance *fid, const struct format_instance_ctx *fic) { static char path[PATH_MAX]; uint32_t type = fic->type; struct text_fid_context *fidtc; struct metadata_area *mda; struct mda_context *mdac; struct dir_list *dl; struct raw_list *rl; struct dm_list *dir_list, *raw_list; struct text_context tc; struct lvmcache_vginfo *vginfo; const char *vg_name, *vg_id; if (!(fidtc = (struct text_fid_context *) dm_pool_zalloc(fid->mem, sizeof(*fidtc)))) { log_error("Couldn't allocate text_fid_context."); return 0; } fidtc->raw_metadata_buf = NULL; fid->private = (void *) fidtc; if (type & FMT_INSTANCE_PRIVATE_MDAS) { if (!(mda = dm_pool_zalloc(fid->mem, sizeof(*mda)))) return_0; mda->ops = &_metadata_text_file_backup_ops; mda->metadata_locn = _create_text_context(fid->mem, fic->context.private); mda->status = 0; fid->metadata_areas_index = NULL; fid_add_mda(fid, mda, NULL, 0, 0); } else { vg_name = fic->context.vg_ref.vg_name; vg_id = fic->context.vg_ref.vg_id; if (!(fid->metadata_areas_index = dm_hash_create(128))) { log_error("Couldn't create metadata index for format " "instance of VG %s.", vg_name); return 0; } if (type & FMT_INSTANCE_AUX_MDAS) { dir_list = &((struct mda_lists *) fid->fmt->private)->dirs; dm_list_iterate_items(dl, dir_list) { if (dm_snprintf(path, PATH_MAX, "%s/%s", dl->dir, vg_name) < 0) { log_error("Name too long %s/%s", dl->dir, vg_name); return 0; } if (!(mda = dm_pool_zalloc(fid->mem, sizeof(*mda)))) return_0; mda->ops = &_metadata_text_file_ops; tc.path_live = path; tc.path_edit = tc.desc = NULL; mda->metadata_locn = _create_text_context(fid->mem, &tc); mda->status = 0; fid_add_mda(fid, mda, NULL, 0, 0); } raw_list = &((struct mda_lists *) fid->fmt->private)->raws; dm_list_iterate_items(rl, raw_list) { /* FIXME Cache this; rescan below if some missing */ if (!_raw_holds_vgname(fid, &rl->dev_area, vg_name)) continue; if (!(mda = dm_pool_zalloc(fid->mem, sizeof(*mda)))) return_0; if (!(mdac = dm_pool_zalloc(fid->mem, sizeof(*mdac)))) return_0; mda->metadata_locn = mdac; /* FIXME Allow multiple dev_areas inside area */ memcpy(&mdac->area, &rl->dev_area, sizeof(mdac->area)); mda->ops = &_metadata_text_raw_ops; mda->status = 0; /* FIXME MISTAKE? mda->metadata_locn = context; */ fid_add_mda(fid, mda, NULL, 0, 0); } } if (type & FMT_INSTANCE_MDAS) { /* Scan PVs in VG for any further MDAs */ lvmcache_label_scan(fid->fmt->cmd, 0); if (!(vginfo = lvmcache_vginfo_from_vgname(vg_name, vg_id))) goto_out; if (!lvmcache_fid_add_mdas_vg(vginfo, fid)) goto_out; } /* FIXME Check raw metadata area count - rescan if required */ } out: return 1; } static int _add_metadata_area_to_pv(struct physical_volume *pv, unsigned mda_index, uint64_t mda_start, uint64_t mda_size, unsigned mda_ignored) { struct metadata_area *mda; struct mda_context *mdac; struct mda_lists *mda_lists = (struct mda_lists *) pv->fmt->private; if (mda_index >= FMT_TEXT_MAX_MDAS_PER_PV) { log_error(INTERNAL_ERROR "can't add metadata area with " "index %u to PV %s. Metadata " "layout not supported by %s format.", mda_index, dev_name(pv->dev), pv->fmt->name); } if (!(mda = dm_pool_zalloc(pv->fid->mem, sizeof(struct metadata_area)))) { log_error("struct metadata_area allocation failed"); return 0; } if (!(mdac = dm_pool_zalloc(pv->fid->mem, sizeof(struct mda_context)))) { log_error("struct mda_context allocation failed"); dm_free(mda); return 0; } mda->ops = mda_lists->raw_ops; mda->metadata_locn = mdac; mda->status = 0; mdac->area.dev = pv->dev; mdac->area.start = mda_start; mdac->area.size = mda_size; mdac->free_sectors = UINT64_C(0); memset(&mdac->rlocn, 0, sizeof(mdac->rlocn)); mda_set_ignored(mda, mda_ignored); fid_add_mda(pv->fid, mda, (char *) &pv->id, ID_LEN, mda_index); return 1; } static int _text_pv_remove_metadata_area(const struct format_type *fmt, struct physical_volume *pv, unsigned mda_index); static int _text_pv_add_metadata_area(const struct format_type *fmt, struct physical_volume *pv, int pe_start_locked, unsigned mda_index, uint64_t mda_size, unsigned mda_ignored) { struct format_instance *fid = pv->fid; const char *pvid = (const char *) (*pv->old_id.uuid ? &pv->old_id : &pv->id); uint64_t pe_start, pe_end; uint64_t alignment, alignment_offset; uint64_t disk_size; uint64_t mda_start; uint64_t adjustment, limit, tmp_mda_size; uint64_t wipe_size = 8 << SECTOR_SHIFT; size_t page_size = lvm_getpagesize(); struct metadata_area *mda; struct mda_context *mdac; const char *limit_name; int limit_applied = 0; if (mda_index >= FMT_TEXT_MAX_MDAS_PER_PV) { log_error(INTERNAL_ERROR "invalid index of value %u used " "while trying to add metadata area on PV %s. " "Metadata layout not supported by %s format.", mda_index, pv_dev_name(pv), fmt->name); return 0; } pe_start = pv->pe_start << SECTOR_SHIFT; alignment = pv->pe_align << SECTOR_SHIFT; alignment_offset = pv->pe_align_offset << SECTOR_SHIFT; disk_size = pv->size << SECTOR_SHIFT; mda_size = mda_size << SECTOR_SHIFT; if (fid_get_mda_indexed(fid, pvid, ID_LEN, mda_index)) { if (!_text_pv_remove_metadata_area(fmt, pv, mda_index)) { log_error(INTERNAL_ERROR "metadata area with index %u already " "exists on PV %s and removal failed.", mda_index, pv_dev_name(pv)); return 0; } } /* First metadata area at the start of the device. */ if (mda_index == 0) { /* * Try to fit MDA0 end within given pe_start limit if its value * is locked. If it's not locked, count with any existing MDA1. * If there's no MDA1, just use disk size as the limit. */ if (pe_start_locked) { limit = pe_start; limit_name = "pe_start"; } else if ((mda = fid_get_mda_indexed(fid, pvid, ID_LEN, 1)) && (mdac = mda->metadata_locn)) { limit = mdac->area.start; limit_name = "MDA1 start"; } else { limit = disk_size; limit_name = "disk size"; } if (limit > disk_size) goto bad; mda_start = LABEL_SCAN_SIZE; /* Align MDA0 start with page size if possible. */ if (limit - mda_start >= MDA_SIZE_MIN) { if ((adjustment = mda_start % page_size)) mda_start += (page_size - adjustment); } /* Align MDA0 end position with given alignment if possible. */ if (alignment && (adjustment = (mda_start + mda_size) % alignment)) { tmp_mda_size = mda_size + alignment - adjustment; if (mda_start + tmp_mda_size <= limit) mda_size = tmp_mda_size; } /* Align MDA0 end position with given alignment offset if possible. */ if (alignment_offset && (((mda_start + mda_size) % alignment) == 0)) { tmp_mda_size = mda_size + alignment_offset; if (mda_start + tmp_mda_size <= limit) mda_size = tmp_mda_size; } if (mda_start + mda_size > limit) { /* * Try to decrease the MDA0 size with twice the * alignment and then align with given alignment. * If pe_start is locked, skip this type of * alignment since it would be useless. * Check first whether we can apply that! */ if (!pe_start_locked && ((limit - mda_start) > alignment * 2)) { mda_size = limit - mda_start - alignment * 2; if ((adjustment = (mda_start + mda_size) % alignment)) mda_size += (alignment - adjustment); /* Still too much? Then there's nothing else to do. */ if (mda_start + mda_size > limit) goto bad; } /* Otherwise, give up and take any usable space. */ /* FIXME: We should probably check for some minimum MDA size here. */ else mda_size = limit - mda_start; limit_applied = 1; } /* * If PV's pe_start is not locked, update pe_start value with the * start of the area that follows the MDA0 we've just calculated. */ if (!pe_start_locked) { pe_start = mda_start + mda_size; pv->pe_start = pe_start >> SECTOR_SHIFT; } } /* Second metadata area at the end of the device. */ else { /* * Try to fit MDA1 start within given pe_end or pe_start limit * if defined or locked. If pe_start is not defined yet, count * with any existing MDA0. If MDA0 does not exist, just use * LABEL_SCAN_SIZE. */ pe_end = pv->pe_count ? (pv->pe_start + pv->pe_count * pv->pe_size - 1) << SECTOR_SHIFT : 0; if (pe_start || pe_start_locked) { limit = pe_end ? pe_end : pe_start; limit_name = pe_end ? "pe_end" : "pe_start"; } else if ((mda = fid_get_mda_indexed(fid, pvid, ID_LEN, 0)) && (mdac = mda->metadata_locn)) { limit = mdac->area.start + mdac->area.size; limit_name = "MDA0 end"; } else { limit = LABEL_SCAN_SIZE; limit_name = "label scan size"; } if (limit > disk_size) goto bad; if (mda_size > disk_size) { mda_size = disk_size - limit; limit_applied = 1; } mda_start = disk_size - mda_size; /* If MDA1 size is too big, just take any usable space. */ if (disk_size - mda_size < limit) { mda_size = disk_size - limit; mda_start = disk_size - mda_size; limit_applied = 1; } /* Otherwise, try to align MDA1 start if possible. */ else if (alignment && (adjustment = mda_start % alignment)) { tmp_mda_size = mda_size + adjustment; if (tmp_mda_size < disk_size && disk_size - tmp_mda_size >= limit) { mda_size = tmp_mda_size; mda_start = disk_size - mda_size; } } /* * If PV's pe_end not set yet, set it to the end of the * area that precedes the MDA1 we've just calculated. * FIXME: do we need to set this? Isn't it always set before? */ /*if (!pe_end) { pe_end = mda_start; pv->pe_end = pe_end >> SECTOR_SHIFT; }*/ } if (limit_applied) log_very_verbose("Using limited metadata area size on %s " "with value %" PRIu64 " (limited by %s of " "%" PRIu64 ").", pv_dev_name(pv), mda_size, limit_name, limit); if (mda_size) { /* Wipe metadata area with zeroes. */ if (!dev_set((struct device *) pv->dev, mda_start, (size_t) ((mda_size > wipe_size) ? wipe_size : mda_size), 0)) { log_error("Failed to wipe new metadata area " "at the %s of the %s", mda_index ? "end" : "start", pv_dev_name(pv)); return 0; } /* Finally, add new metadata area to PV's format instance. */ if (!_add_metadata_area_to_pv(pv, mda_index, mda_start, mda_size, mda_ignored)) return_0; } return 1; bad: log_error("Not enough space available for metadata area " "with index %u on PV %s.", mda_index, pv_dev_name(pv)); return 0; } static int _remove_metadata_area_from_pv(struct physical_volume *pv, unsigned mda_index) { if (mda_index >= FMT_TEXT_MAX_MDAS_PER_PV) { log_error(INTERNAL_ERROR "can't remove metadata area with " "index %u from PV %s. Metadata " "layou not supported by %s format.", mda_index, dev_name(pv->dev), pv->fmt->name); return 0; } return fid_remove_mda(pv->fid, NULL, (const char *) &pv->id, ID_LEN, mda_index); } static int _text_pv_remove_metadata_area(const struct format_type *fmt, struct physical_volume *pv, unsigned mda_index) { return _remove_metadata_area_from_pv(pv, mda_index); } static int _text_pv_resize(const struct format_type *fmt, struct physical_volume *pv, struct volume_group *vg, uint64_t size) { struct format_instance *fid = pv->fid; const char *pvid = (const char *) (*pv->old_id.uuid ? &pv->old_id : &pv->id); struct metadata_area *mda; struct mda_context *mdac; uint64_t size_reduction; uint64_t mda_size; unsigned mda_ignored; /* * First, set the new size and update the cache and reset pe_count. * (pe_count must be reset otherwise it would be considered as * a limiting factor while moving the mda!) */ pv->size = size; pv->pe_count = 0; /* If there's an mda at the end, move it to a new position. */ if ((mda = fid_get_mda_indexed(fid, pvid, ID_LEN, 1)) && (mdac = mda->metadata_locn)) { /* FIXME: Maybe MDA0 size would be better? */ mda_size = mdac->area.size >> SECTOR_SHIFT; mda_ignored = mda_is_ignored(mda); if (!_text_pv_remove_metadata_area(fmt, pv, 1) || !_text_pv_add_metadata_area(fmt, pv, 1, 1, mda_size, mda_ignored)) { log_error("Failed to move metadata area with index 1 " "while resizing PV %s.", pv_dev_name(pv)); return 0; } } /* If there's a VG, reduce size by counting in pe_start and metadata areas. */ if (vg) { size_reduction = pv_pe_start(pv); if ((mda = fid_get_mda_indexed(fid, pvid, ID_LEN, 1)) && (mdac = mda->metadata_locn)) size_reduction += mdac->area.size >> SECTOR_SHIFT; pv->size -= size_reduction; } return 1; } static struct format_instance *_text_create_text_instance(const struct format_type *fmt, const struct format_instance_ctx *fic) { struct format_instance *fid; if (!(fid = alloc_fid(fmt, fic))) return_NULL; if (_create_vg_text_instance(fid, fic)) return fid; dm_pool_destroy(fid->mem); return NULL; } static struct format_handler _text_handler = { .scan = _text_scan, .pv_read = _text_pv_read, .pv_initialise = _text_pv_initialise, .pv_setup = _text_pv_setup, .pv_add_metadata_area = _text_pv_add_metadata_area, .pv_remove_metadata_area = _text_pv_remove_metadata_area, .pv_resize = _text_pv_resize, .pv_write = _text_pv_write, .vg_setup = _text_vg_setup, .lv_setup = _text_lv_setup, .create_instance = _text_create_text_instance, .destroy_instance = _text_destroy_instance, .destroy = _text_destroy }; static int _add_dir(const char *dir, struct dm_list *dir_list) { struct dir_list *dl; if (dm_create_dir(dir)) { if (!(dl = dm_malloc(sizeof(struct dm_list) + strlen(dir) + 1))) { log_error("_add_dir allocation failed"); return 0; } log_very_verbose("Adding text format metadata dir: %s", dir); strcpy(dl->dir, dir); dm_list_add(dir_list, &dl->list); return 1; } return 0; } static int _get_config_disk_area(struct cmd_context *cmd, const struct dm_config_node *cn, struct dm_list *raw_list) { struct device_area dev_area; const char *id_str; struct id id; if (!(cn = cn->child)) { log_error("Empty metadata disk_area section of config file"); return 0; } if (!dm_config_get_uint64(cn, "start_sector", &dev_area.start)) { log_error("Missing start_sector in metadata disk_area section " "of config file"); return 0; } dev_area.start <<= SECTOR_SHIFT; if (!dm_config_get_uint64(cn, "size", &dev_area.size)) { log_error("Missing size in metadata disk_area section " "of config file"); return 0; } dev_area.size <<= SECTOR_SHIFT; if (!dm_config_get_str(cn, "id", &id_str)) { log_error("Missing uuid in metadata disk_area section " "of config file"); return 0; } if (!id_read_format(&id, id_str)) { log_error("Invalid uuid in metadata disk_area section " "of config file: %s", id_str); return 0; } if (!(dev_area.dev = lvmcache_device_from_pvid(cmd, &id, NULL, NULL))) { char buffer[64] __attribute__((aligned(8))); if (!id_write_format(&id, buffer, sizeof(buffer))) log_error("Couldn't find device."); else log_error("Couldn't find device with uuid '%s'.", buffer); return 0; } return _add_raw(raw_list, &dev_area); } struct format_type *create_text_format(struct cmd_context *cmd) { struct format_instance_ctx fic; struct format_instance *fid; struct format_type *fmt; const struct dm_config_node *cn; const struct dm_config_value *cv; struct mda_lists *mda_lists; if (!(fmt = dm_malloc(sizeof(*fmt)))) { log_error("Failed to allocate text format type structure."); return NULL; } fmt->cmd = cmd; fmt->ops = &_text_handler; fmt->name = FMT_TEXT_NAME; fmt->alias = FMT_TEXT_ALIAS; fmt->orphan_vg_name = ORPHAN_VG_NAME(FMT_TEXT_NAME); fmt->features = FMT_SEGMENTS | FMT_MDAS | FMT_TAGS | FMT_PRECOMMIT | FMT_UNLIMITED_VOLS | FMT_RESIZE_PV | FMT_UNLIMITED_STRIPESIZE; if (!(mda_lists = dm_malloc(sizeof(struct mda_lists)))) { log_error("Failed to allocate dir_list"); dm_free(fmt); return NULL; } dm_list_init(&mda_lists->dirs); dm_list_init(&mda_lists->raws); mda_lists->file_ops = &_metadata_text_file_ops; mda_lists->raw_ops = &_metadata_text_raw_ops; fmt->private = (void *) mda_lists; dm_list_init(&fmt->mda_ops); dm_list_add(&fmt->mda_ops, &_metadata_text_raw_ops.list); if (!(fmt->labeller = text_labeller_create(fmt))) { log_error("Couldn't create text label handler."); goto bad; } if (!(label_register_handler(FMT_TEXT_NAME, fmt->labeller))) { log_error("Couldn't register text label handler."); fmt->labeller->ops->destroy(fmt->labeller); goto bad; } if ((cn = find_config_tree_node(cmd, "metadata/dirs"))) { for (cv = cn->v; cv; cv = cv->next) { if (cv->type != DM_CFG_STRING) { log_error("Invalid string in config file: " "metadata/dirs"); goto bad; } if (!_add_dir(cv->v.str, &mda_lists->dirs)) { log_error("Failed to add %s to text format " "metadata directory list ", cv->v.str); goto bad; } cmd->independent_metadata_areas = 1; } } if ((cn = find_config_tree_node(cmd, "metadata/disk_areas"))) { for (cn = cn->child; cn; cn = cn->sib) { if (!_get_config_disk_area(cmd, cn, &mda_lists->raws)) goto_bad; cmd->independent_metadata_areas = 1; } } if (!(fmt->orphan_vg = alloc_vg("text_orphan", cmd, fmt->orphan_vg_name))) goto_bad; fic.type = FMT_INSTANCE_AUX_MDAS; fic.context.vg_ref.vg_name = fmt->orphan_vg_name; fic.context.vg_ref.vg_id = NULL; if (!(fid = _text_create_text_instance(fmt, &fic))) goto_bad; vg_set_fid(fmt->orphan_vg, fid); log_very_verbose("Initialised format: %s", fmt->name); return fmt; bad: _text_destroy(fmt); return NULL; } lvm2-2.02.98/lib/format_text/layout.h0000640000175000017500000000565412037016272016312 0ustar blankblank/* * Copyright (C) 2001-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_TEXT_LAYOUT_H #define _LVM_TEXT_LAYOUT_H #include "config.h" #include "lvm-types.h" #include "metadata.h" #include "uuid.h" /* disk_locn and data_area_list are defined in format-text.h */ /* Fields with the suffix _xl should be xlate'd wherever they appear */ /* On disk */ struct pv_header { int8_t pv_uuid[ID_LEN]; /* This size can be overridden if PV belongs to a VG */ uint64_t device_size_xl; /* Bytes */ /* NULL-terminated list of data areas followed by */ /* NULL-terminated list of metadata area headers */ struct disk_locn disk_areas_xl[0]; /* Two lists */ } __attribute__ ((packed)); /* * Ignore this raw location. This allows us to * ignored metadata areas easily, and thus balance * metadata across VGs with many PVs. */ #define RAW_LOCN_IGNORED 0x00000001 /* On disk */ struct raw_locn { uint64_t offset; /* Offset in bytes to start sector */ uint64_t size; /* Bytes */ uint32_t checksum; uint32_t flags; } __attribute__ ((packed)); int rlocn_is_ignored(const struct raw_locn *rlocn); void rlocn_set_ignored(struct raw_locn *rlocn, unsigned mda_ignored); /* On disk */ /* Structure size limited to one sector */ struct mda_header { uint32_t checksum_xl; /* Checksum of rest of mda_header */ int8_t magic[16]; /* To aid scans for metadata */ uint32_t version; uint64_t start; /* Absolute start byte of mda_header */ uint64_t size; /* Size of metadata area */ struct raw_locn raw_locns[0]; /* NULL-terminated list */ } __attribute__ ((packed)); struct mda_header *raw_read_mda_header(const struct format_type *fmt, struct device_area *dev_area); struct mda_lists { struct dm_list dirs; struct dm_list raws; struct metadata_area_ops *file_ops; struct metadata_area_ops *raw_ops; }; struct mda_context { struct device_area area; uint64_t free_sectors; struct raw_locn rlocn; /* Store inbetween write and commit */ }; /* FIXME Convert this at runtime */ #define FMTT_MAGIC "\040\114\126\115\062\040\170\133\065\101\045\162\060\116\052\076" #define FMTT_VERSION 1 #define MDA_HEADER_SIZE 512 #define LVM2_LABEL "LVM2 001" #define MDA_SIZE_MIN (8 * (unsigned) lvm_getpagesize()) const char *vgname_from_mda(const struct format_type *fmt, struct mda_header *mdah, struct device_area *dev_area, struct id *vgid, uint64_t *vgstatus, char **creation_host, uint64_t *mda_free_sectors); #endif lvm2-2.02.98/lib/format_text/import-export.h0000640000175000017500000000576512037016272017631 0ustar blankblank/* * Copyright (C) 2001-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_TEXT_IMPORT_EXPORT_H #define _LVM_TEXT_IMPORT_EXPORT_H #include "config.h" #include "lvm-types.h" #include "metadata.h" #include /* * Constants to identify files this code can parse. */ #define CONTENTS_FIELD "contents" #define CONTENTS_VALUE "Text Format Volume Group" #define FORMAT_VERSION_FIELD "version" #define FORMAT_VERSION_VALUE 1 /* * VGs, PVs and LVs all have status bitsets, we gather together * common code for reading and writing them. */ enum { COMPATIBLE_FLAG = 0x0, VG_FLAGS, PV_FLAGS, LV_FLAGS, STATUS_FLAG = 0x8, }; struct text_vg_version_ops { int (*check_version) (const struct dm_config_tree * cf); struct volume_group *(*read_vg) (struct format_instance * fid, const struct dm_config_tree *cf, unsigned use_cached_pvs); void (*read_desc) (struct dm_pool * mem, const struct dm_config_tree *cf, time_t *when, char **desc); const char *(*read_vgname) (const struct format_type *fmt, const struct dm_config_tree *cft, struct id *vgid, uint64_t *vgstatus, char **creation_host); }; struct text_vg_version_ops *text_vg_vsn1_init(void); int print_flags(uint64_t status, int type, char *buffer, size_t size); int read_flags(uint64_t *status, int type, const struct dm_config_value *cv); char *alloc_printed_tags(struct dm_list *tags); int read_tags(struct dm_pool *mem, struct dm_list *tags, const struct dm_config_value *cv); int text_vg_export_file(struct volume_group *vg, const char *desc, FILE *fp); size_t text_vg_export_raw(struct volume_group *vg, const char *desc, char **buf); struct volume_group *text_vg_import_file(struct format_instance *fid, const char *file, time_t *when, char **desc); struct volume_group *text_vg_import_fd(struct format_instance *fid, const char *file, int single_device, struct device *dev, off_t offset, uint32_t size, off_t offset2, uint32_t size2, checksum_fn_t checksum_fn, uint32_t checksum, time_t *when, char **desc); const char *text_vgname_import(const struct format_type *fmt, struct device *dev, off_t offset, uint32_t size, off_t offset2, uint32_t size2, checksum_fn_t checksum_fn, uint32_t checksum, struct id *vgid, uint64_t *vgstatus, char **creation_host); #endif lvm2-2.02.98/lib/format_text/import.c0000640000175000017500000000770612037016272016302 0ustar blankblank/* * 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 */ #include "lib.h" #include "metadata.h" #include "import-export.h" /* FIXME Use tidier inclusion method */ static struct text_vg_version_ops *(_text_vsn_list[2]); static int _text_import_initialised = 0; static void _init_text_import(void) { if (_text_import_initialised) return; _text_vsn_list[0] = text_vg_vsn1_init(); _text_vsn_list[1] = NULL; _text_import_initialised = 1; } const char *text_vgname_import(const struct format_type *fmt, struct device *dev, off_t offset, uint32_t size, off_t offset2, uint32_t size2, checksum_fn_t checksum_fn, uint32_t checksum, struct id *vgid, uint64_t *vgstatus, char **creation_host) { struct dm_config_tree *cft; struct text_vg_version_ops **vsn; const char *vgname = NULL; _init_text_import(); if (!(cft = config_file_open(NULL, 0))) return_NULL; if ((!dev && !config_file_read(cft)) || (dev && !config_file_read_fd(cft, dev, offset, size, offset2, size2, checksum_fn, checksum))) goto_out; /* * Find a set of version functions that can read this file */ for (vsn = &_text_vsn_list[0]; *vsn; vsn++) { if (!(*vsn)->check_version(cft)) continue; if (!(vgname = (*vsn)->read_vgname(fmt, cft, vgid, vgstatus, creation_host))) goto_out; break; } out: config_file_destroy(cft); return vgname; } struct volume_group *text_vg_import_fd(struct format_instance *fid, const char *file, int single_device, struct device *dev, off_t offset, uint32_t size, off_t offset2, uint32_t size2, checksum_fn_t checksum_fn, uint32_t checksum, time_t *when, char **desc) { struct volume_group *vg = NULL; struct dm_config_tree *cft; struct text_vg_version_ops **vsn; _init_text_import(); *desc = NULL; *when = 0; if (!(cft = config_file_open(file, 0))) return_NULL; if ((!dev && !config_file_read(cft)) || (dev && !config_file_read_fd(cft, dev, offset, size, offset2, size2, checksum_fn, checksum))) { log_error("Couldn't read volume group metadata."); goto out; } /* * Find a set of version functions that can read this file */ for (vsn = &_text_vsn_list[0]; *vsn; vsn++) { if (!(*vsn)->check_version(cft)) continue; if (!(vg = (*vsn)->read_vg(fid, cft, single_device))) goto_out; (*vsn)->read_desc(vg->vgmem, cft, when, desc); break; } out: config_file_destroy(cft); return vg; } struct volume_group *text_vg_import_file(struct format_instance *fid, const char *file, time_t *when, char **desc) { return text_vg_import_fd(fid, file, 0, NULL, (off_t)0, 0, (off_t)0, 0, NULL, 0, when, desc); } struct volume_group *import_vg_from_config_tree(const struct dm_config_tree *cft, struct format_instance *fid) { struct volume_group *vg = NULL; struct text_vg_version_ops **vsn; int vg_missing; _init_text_import(); for (vsn = &_text_vsn_list[0]; *vsn; vsn++) { if (!(*vsn)->check_version(cft)) continue; /* * The only path to this point uses cached vgmetadata, * so it can use cached PV state too. */ if (!(vg = (*vsn)->read_vg(fid, cft, 1))) stack; else if ((vg_missing = vg_missing_pv_count(vg))) { log_verbose("There are %d physical volumes missing.", vg_missing); vg_mark_partial_lvs(vg, 1); /* FIXME: move this code inside read_vg() */ } break; } return vg; } lvm2-2.02.98/lib/format_text/flags.c0000640000175000017500000001061312037016272016053 0ustar blankblank/* * Copyright (C) 2001-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 */ #include "lib.h" #include "metadata.h" #include "import-export.h" #include "lvm-string.h" /* * Bitsets held in the 'status' flags get * converted into arrays of strings. */ struct flag { const uint64_t mask; const char *description; int kind; }; static const struct flag _vg_flags[] = { {EXPORTED_VG, "EXPORTED", STATUS_FLAG}, {RESIZEABLE_VG, "RESIZEABLE", STATUS_FLAG}, {PVMOVE, "PVMOVE", STATUS_FLAG}, {LVM_READ, "READ", STATUS_FLAG}, {LVM_WRITE, "WRITE", STATUS_FLAG}, {CLUSTERED, "CLUSTERED", STATUS_FLAG}, {SHARED, "SHARED", STATUS_FLAG}, {PARTIAL_VG, NULL, 0}, {PRECOMMITTED, NULL, 0}, {0, NULL, 0} }; static const struct flag _pv_flags[] = { {ALLOCATABLE_PV, "ALLOCATABLE", STATUS_FLAG}, {EXPORTED_VG, "EXPORTED", STATUS_FLAG}, {MISSING_PV, "MISSING", COMPATIBLE_FLAG}, {UNLABELLED_PV, NULL, 0}, {0, NULL, 0} }; static const struct flag _lv_flags[] = { {LVM_READ, "READ", STATUS_FLAG}, {LVM_WRITE, "WRITE", STATUS_FLAG}, {FIXED_MINOR, "FIXED_MINOR", STATUS_FLAG}, {VISIBLE_LV, "VISIBLE", STATUS_FLAG}, {PVMOVE, "PVMOVE", STATUS_FLAG}, {LOCKED, "LOCKED", STATUS_FLAG}, {LV_NOTSYNCED, "NOTSYNCED", STATUS_FLAG}, {LV_REBUILD, "REBUILD", STATUS_FLAG}, {RAID, NULL, 0}, {RAID_META, NULL, 0}, {RAID_IMAGE, NULL, 0}, {MIRROR_IMAGE, NULL, 0}, {MIRROR_LOG, NULL, 0}, {MIRRORED, NULL, 0}, {VIRTUAL, NULL, 0}, {SNAPSHOT, NULL, 0}, {MERGING, NULL, 0}, {CONVERTING, NULL, 0}, {PARTIAL_LV, NULL, 0}, {POSTORDER_FLAG, NULL, 0}, {VIRTUAL_ORIGIN, NULL, 0}, {REPLICATOR, NULL, 0}, {REPLICATOR_LOG, NULL, 0}, {THIN_VOLUME, NULL, 0}, {THIN_POOL, NULL, 0}, {THIN_POOL_DATA, NULL, 0}, {THIN_POOL_METADATA, NULL, 0}, {0, NULL, 0} }; static const struct flag *_get_flags(int type) { switch (type & ~STATUS_FLAG) { case VG_FLAGS: return _vg_flags; case PV_FLAGS: return _pv_flags; case LV_FLAGS: return _lv_flags; } log_error("Unknown flag set requested."); return NULL; } /* * Converts a bitset to an array of string values, * using one of the tables defined at the top of * the file. */ int print_flags(uint64_t status, int type, char *buffer, size_t size) { int f, first = 1; const struct flag *flags; if (!(flags = _get_flags(type))) return_0; if (!emit_to_buffer(&buffer, &size, "[")) return 0; for (f = 0; flags[f].mask; f++) { if (status & flags[f].mask) { status &= ~flags[f].mask; if ((type & STATUS_FLAG) != flags[f].kind) continue; /* Internal-only flag? */ if (!flags[f].description) continue; if (!first) { if (!emit_to_buffer(&buffer, &size, ", ")) return 0; } else first = 0; if (!emit_to_buffer(&buffer, &size, "\"%s\"", flags[f].description)) return 0; } } if (!emit_to_buffer(&buffer, &size, "]")) return 0; if (status) log_error("Metadata inconsistency: Not all flags successfully " "exported."); return 1; } int read_flags(uint64_t *status, int type, const struct dm_config_value *cv) { int f; uint64_t s = UINT64_C(0); const struct flag *flags; if (!(flags = _get_flags(type))) return_0; if (cv->type == DM_CFG_EMPTY_ARRAY) goto out; while (cv) { if (cv->type != DM_CFG_STRING) { log_error("Status value is not a string."); return 0; } for (f = 0; flags[f].description; f++) if (!strcmp(flags[f].description, cv->v.str)) { s |= flags[f].mask; break; } if (type == VG_FLAGS && !strcmp(cv->v.str, "PARTIAL")) { /* * Exception: We no longer write this flag out, but it * might be encountered in old backup files, so restore * it in that case. It is never part of live metadata * though, so only vgcfgrestore needs to be concerned * by this case. */ s |= PARTIAL_VG; } else if (!flags[f].description && (type & STATUS_FLAG)) { log_error("Unknown status flag '%s'.", cv->v.str); return 0; } cv = cv->next; } out: *status |= s; return 1; } lvm2-2.02.98/lib/format_text/text_export.h0000640000175000017500000000343112037016272017351 0ustar blankblank/* * 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 */ #ifndef _LVM_TEXT_EXPORT_H #define _LVM_TEXT_EXPORT_H #define outsize(args...) do {if (!out_size(args)) return_0;} while (0) #define outhint(args...) do {if (!out_hint(args)) return_0;} while (0) #define outfc(args...) do {if (!out_text_with_comment(args)) return_0;} while (0) #define outf(args...) do {if (!out_text(args)) return_0;} while (0) #define outnl(f) do {if (!out_newline(f)) return_0;} while (0) struct formatter; struct lv_segment; struct dm_config_node; int out_size(struct formatter *f, uint64_t size, const char *fmt, ...) __attribute__ ((format(printf, 3, 4))); int out_hint(struct formatter *f, const char *fmt, ...) __attribute__ ((format(printf, 2, 3))); int out_text(struct formatter *f, const char *fmt, ...) __attribute__ ((format(printf, 2, 3))); int out_config_node(struct formatter *f, const struct dm_config_node *cn); int out_areas(struct formatter *f, const struct lv_segment *seg, const char *type); int out_text_with_comment(struct formatter *f, const char* comment, const char *fmt, ...) __attribute__ ((format(printf, 3, 4))); void out_inc_indent(struct formatter *f); void out_dec_indent(struct formatter *f); int out_newline(struct formatter *f); #endif lvm2-2.02.98/lib/format_text/text_label.c0000640000175000017500000002434512037016272017111 0ustar blankblank/* * 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 */ #include "lib.h" #include "format-text.h" #include "layout.h" #include "label.h" #include "xlate.h" #include "lvmcache.h" #include #include static int _text_can_handle(struct labeller *l __attribute__((unused)), void *buf, uint64_t sector __attribute__((unused))) { struct label_header *lh = (struct label_header *) buf; if (!strncmp((char *)lh->type, LVM2_LABEL, sizeof(lh->type))) return 1; return 0; } struct _da_setup_baton { struct disk_locn *pvh_dlocn_xl; struct device *dev; }; static int _da_setup(struct disk_locn *da, void *baton) { struct _da_setup_baton *p = baton; p->pvh_dlocn_xl->offset = xlate64(da->offset); p->pvh_dlocn_xl->size = xlate64(da->size); p->pvh_dlocn_xl++; return 1; } static int _mda_setup(struct metadata_area *mda, void *baton) { struct _da_setup_baton *p = baton; struct mda_context *mdac = (struct mda_context *) mda->metadata_locn; if (mdac->area.dev != p->dev) return 1; p->pvh_dlocn_xl->offset = xlate64(mdac->area.start); p->pvh_dlocn_xl->size = xlate64(mdac->area.size); p->pvh_dlocn_xl++; return 1; } static int _text_write(struct label *label, void *buf) { struct label_header *lh = (struct label_header *) buf; struct pv_header *pvhdr; struct lvmcache_info *info; struct _da_setup_baton baton; char buffer[64] __attribute__((aligned(8))); int da1, mda1, mda2; /* FIXME Move to where label is created */ strncpy(label->type, LVM2_LABEL, sizeof(label->type)); strncpy((char *)lh->type, label->type, sizeof(label->type)); pvhdr = (struct pv_header *) ((char *) buf + xlate32(lh->offset_xl)); info = (struct lvmcache_info *) label->info; pvhdr->device_size_xl = xlate64(lvmcache_device_size(info)); memcpy(pvhdr->pv_uuid, &lvmcache_device(info)->pvid, sizeof(struct id)); if (!id_write_format((const struct id *)pvhdr->pv_uuid, buffer, sizeof(buffer))) { stack; buffer[0] = '\0'; } baton.dev = lvmcache_device(info); /* List of data areas (holding PEs) */ baton.pvh_dlocn_xl = &pvhdr->disk_areas_xl[0]; lvmcache_foreach_da(info, _da_setup, &baton); /* NULL-termination */ baton.pvh_dlocn_xl->offset = xlate64(UINT64_C(0)); baton.pvh_dlocn_xl->size = xlate64(UINT64_C(0)); baton.pvh_dlocn_xl++; /* List of metadata area header locations */ lvmcache_foreach_mda(info, _mda_setup, &baton); /* NULL-termination */ baton.pvh_dlocn_xl->offset = xlate64(UINT64_C(0)); baton.pvh_dlocn_xl->size = xlate64(UINT64_C(0)); /* Create debug message with da and mda locations */ if (xlate64(pvhdr->disk_areas_xl[0].offset) || xlate64(pvhdr->disk_areas_xl[0].size)) da1 = 0; else da1 = -1; mda1 = da1 + 2; mda2 = mda1 + 1; if (!xlate64(pvhdr->disk_areas_xl[mda1].offset) && !xlate64(pvhdr->disk_areas_xl[mda1].size)) mda1 = mda2 = 0; else if (!xlate64(pvhdr->disk_areas_xl[mda2].offset) && !xlate64(pvhdr->disk_areas_xl[mda2].size)) mda2 = 0; log_debug("%s: Preparing PV label header %s size %" PRIu64 " with" "%s%.*" PRIu64 "%s%.*" PRIu64 "%s" "%s%.*" PRIu64 "%s%.*" PRIu64 "%s" "%s%.*" PRIu64 "%s%.*" PRIu64 "%s", dev_name(lvmcache_device(info)), buffer, lvmcache_device_size(info), (da1 > -1) ? " da1 (" : "", (da1 > -1) ? 1 : 0, (da1 > -1) ? xlate64(pvhdr->disk_areas_xl[da1].offset) >> SECTOR_SHIFT : 0, (da1 > -1) ? "s, " : "", (da1 > -1) ? 1 : 0, (da1 > -1) ? xlate64(pvhdr->disk_areas_xl[da1].size) >> SECTOR_SHIFT : 0, (da1 > -1) ? "s)" : "", mda1 ? " mda1 (" : "", mda1 ? 1 : 0, mda1 ? xlate64(pvhdr->disk_areas_xl[mda1].offset) >> SECTOR_SHIFT : 0, mda1 ? "s, " : "", mda1 ? 1 : 0, mda1 ? xlate64(pvhdr->disk_areas_xl[mda1].size) >> SECTOR_SHIFT : 0, mda1 ? "s)" : "", mda2 ? " mda2 (" : "", mda2 ? 1 : 0, mda2 ? xlate64(pvhdr->disk_areas_xl[mda2].offset) >> SECTOR_SHIFT : 0, mda2 ? "s, " : "", mda2 ? 1 : 0, mda2 ? xlate64(pvhdr->disk_areas_xl[mda2].size) >> SECTOR_SHIFT : 0, mda2 ? "s)" : ""); if (da1 < 0) { log_error(INTERNAL_ERROR "%s label header currently requires " "a data area.", dev_name(lvmcache_device(info))); return 0; } return 1; } int add_da(struct dm_pool *mem, struct dm_list *das, uint64_t start, uint64_t size) { struct data_area_list *dal; if (!mem) { if (!(dal = dm_malloc(sizeof(*dal)))) { log_error("struct data_area_list allocation failed"); return 0; } } else { if (!(dal = dm_pool_alloc(mem, sizeof(*dal)))) { log_error("struct data_area_list allocation failed"); return 0; } } dal->disk_locn.offset = start; dal->disk_locn.size = size; dm_list_add(das, &dal->list); return 1; } void del_das(struct dm_list *das) { struct dm_list *dah, *tmp; struct data_area_list *da; dm_list_iterate_safe(dah, tmp, das) { da = dm_list_item(dah, struct data_area_list); dm_list_del(&da->list); dm_free(da); } } /* FIXME: refactor this function with other mda constructor code */ int add_mda(const struct format_type *fmt, struct dm_pool *mem, struct dm_list *mdas, struct device *dev, uint64_t start, uint64_t size, unsigned ignored) { /* FIXME List size restricted by pv_header SECTOR_SIZE */ struct metadata_area *mdal; struct mda_lists *mda_lists = (struct mda_lists *) fmt->private; struct mda_context *mdac; if (!mem) { if (!(mdal = dm_malloc(sizeof(struct metadata_area)))) { log_error("struct mda_list allocation failed"); return 0; } if (!(mdac = dm_malloc(sizeof(struct mda_context)))) { log_error("struct mda_context allocation failed"); dm_free(mdal); return 0; } } else { if (!(mdal = dm_pool_alloc(mem, sizeof(struct metadata_area)))) { log_error("struct mda_list allocation failed"); return 0; } if (!(mdac = dm_pool_alloc(mem, sizeof(struct mda_context)))) { log_error("struct mda_context allocation failed"); return 0; } } mdal->ops = mda_lists->raw_ops; mdal->metadata_locn = mdac; mdal->status = 0; mdac->area.dev = dev; mdac->area.start = start; mdac->area.size = size; mdac->free_sectors = UINT64_C(0); memset(&mdac->rlocn, 0, sizeof(mdac->rlocn)); mda_set_ignored(mdal, ignored); dm_list_add(mdas, &mdal->list); return 1; } void del_mdas(struct dm_list *mdas) { struct dm_list *mdah, *tmp; struct metadata_area *mda; dm_list_iterate_safe(mdah, tmp, mdas) { mda = dm_list_item(mdah, struct metadata_area); dm_free(mda->metadata_locn); dm_list_del(&mda->list); dm_free(mda); } } static int _text_initialise_label(struct labeller *l __attribute__((unused)), struct label *label) { strncpy(label->type, LVM2_LABEL, sizeof(label->type)); return 1; } struct _update_mda_baton { struct lvmcache_info *info; struct label *label; }; static int _update_mda(struct metadata_area *mda, void *baton) { struct _update_mda_baton *p = baton; const struct format_type *fmt = p->label->labeller->private; // Oh dear. struct mda_context *mdac = (struct mda_context *) mda->metadata_locn; struct mda_header *mdah; const char *vgname = NULL; struct id vgid; uint64_t vgstatus; char *creation_host; if (!dev_open_readonly(mdac->area.dev)) { mda_set_ignored(mda, 1); stack; return 1; } if (!(mdah = raw_read_mda_header(fmt, &mdac->area))) { stack; goto close_dev; } mda_set_ignored(mda, rlocn_is_ignored(mdah->raw_locns)); if (mda_is_ignored(mda)) { log_debug("Ignoring mda on device %s at offset %"PRIu64, dev_name(mdac->area.dev), mdac->area.start); if (!dev_close(mdac->area.dev)) stack; return 1; } if ((vgname = vgname_from_mda(fmt, mdah, &mdac->area, &vgid, &vgstatus, &creation_host, &mdac->free_sectors)) && !lvmcache_update_vgname_and_id(p->info, vgname, (char *) &vgid, vgstatus, creation_host)) { if (!dev_close(mdac->area.dev)) stack; return_0; } close_dev: if (!dev_close(mdac->area.dev)) stack; return 1; } static int _text_read(struct labeller *l, struct device *dev, void *buf, struct label **label) { struct label_header *lh = (struct label_header *) buf; struct pv_header *pvhdr; struct lvmcache_info *info; struct disk_locn *dlocn_xl; uint64_t offset; struct _update_mda_baton baton; pvhdr = (struct pv_header *) ((char *) buf + xlate32(lh->offset_xl)); if (!(info = lvmcache_add(l, (char *)pvhdr->pv_uuid, dev, FMT_TEXT_ORPHAN_VG_NAME, FMT_TEXT_ORPHAN_VG_NAME, 0))) return_0; *label = lvmcache_get_label(info); lvmcache_set_device_size(info, xlate64(pvhdr->device_size_xl)); lvmcache_del_das(info); lvmcache_del_mdas(info); /* Data areas holding the PEs */ dlocn_xl = pvhdr->disk_areas_xl; while ((offset = xlate64(dlocn_xl->offset))) { lvmcache_add_da(info, offset, xlate64(dlocn_xl->size)); dlocn_xl++; } /* Metadata area headers */ dlocn_xl++; while ((offset = xlate64(dlocn_xl->offset))) { lvmcache_add_mda(info, dev, offset, xlate64(dlocn_xl->size), 0); dlocn_xl++; } baton.info = info; baton.label = *label; lvmcache_foreach_mda(info, _update_mda, &baton); lvmcache_make_valid(info); return 1; } static void _text_destroy_label(struct labeller *l __attribute__((unused)), struct label *label) { struct lvmcache_info *info = (struct lvmcache_info *) label->info; lvmcache_del_mdas(info); lvmcache_del_das(info); } static void _fmt_text_destroy(struct labeller *l) { dm_free(l); } struct label_ops _text_ops = { .can_handle = _text_can_handle, .write = _text_write, .read = _text_read, .verify = _text_can_handle, .initialise_label = _text_initialise_label, .destroy_label = _text_destroy_label, .destroy = _fmt_text_destroy, }; struct labeller *text_labeller_create(const struct format_type *fmt) { struct labeller *l; if (!(l = dm_malloc(sizeof(*l)))) { log_error("Couldn't allocate labeller object."); return NULL; } l->ops = &_text_ops; l->private = (const void *) fmt; return l; } lvm2-2.02.98/lib/format_text/text_import.h0000640000175000017500000000155612037016272017350 0ustar blankblank/* * 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 */ #ifndef _LVM_TEXT_IMPORT_H #define _LVM_TEXT_IMPORT_H struct lv_segment; struct dm_config_node; int text_import_areas(struct lv_segment *seg, const struct dm_config_node *sn, const struct dm_config_value *cv, struct dm_hash_table *pv_hash, uint64_t status); #endif lvm2-2.02.98/lib/format_text/export.c0000640000175000017500000004135712037016272016311 0ustar blankblank/* * 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 */ #include "lib.h" #include "import-export.h" #include "metadata.h" #include "display.h" #include "lvm-string.h" #include "segtype.h" #include "text_export.h" #include "lvm-version.h" #include #include #include struct formatter; __attribute__((format(printf, 3, 0))) typedef int (*out_with_comment_fn) (struct formatter * f, const char *comment, const char *fmt, va_list ap); typedef int (*nl_fn) (struct formatter * f); /* * Macro for formatted output. * out_with_comment_fn returns -1 if data didn't fit and buffer was expanded. * Then argument list is reset and out_with_comment_fn is called again. */ #define _out_with_comment(f, buffer, fmt, ap) \ do { \ va_start(ap, fmt); \ r = f->out_with_comment(f, buffer, fmt, ap); \ va_end(ap); \ } while (r == -1) /* * The first half of this file deals with * exporting the vg, ie. writing it to a file. */ struct formatter { struct dm_pool *mem; /* pv names allocated from here */ struct dm_hash_table *pv_names; /* dev_name -> pv_name (eg, pv1) */ union { FILE *fp; /* where we're writing to */ struct { char *start; uint32_t size; uint32_t used; } buf; } data; out_with_comment_fn out_with_comment; nl_fn nl; int indent; /* current level of indentation */ int error; int header; /* 1 => comments at start; 0 => end */ }; static struct utsname _utsname; static void _init(void) { static int _initialised = 0; if (_initialised) return; if (uname(&_utsname)) { log_error("uname failed: %s", strerror(errno)); memset(&_utsname, 0, sizeof(_utsname)); } _initialised = 1; } /* * Formatting functions. */ #define MAX_INDENT 5 static void _inc_indent(struct formatter *f) { if (++f->indent > MAX_INDENT) f->indent = MAX_INDENT; } static void _dec_indent(struct formatter *f) { if (!f->indent--) { log_error(INTERNAL_ERROR "problem tracking indentation"); f->indent = 0; } } /* * Newline function for prettier layout. */ static int _nl_file(struct formatter *f) { fprintf(f->data.fp, "\n"); return 1; } static int _extend_buffer(struct formatter *f) { char *newbuf; log_debug("Doubling metadata output buffer to %" PRIu32, f->data.buf.size * 2); if (!(newbuf = dm_realloc(f->data.buf.start, f->data.buf.size * 2))) { log_error("Buffer reallocation failed."); return 0; } f->data.buf.start = newbuf; f->data.buf.size *= 2; return 1; } static int _nl_raw(struct formatter *f) { /* If metadata doesn't fit, extend buffer */ if ((f->data.buf.used + 2 > f->data.buf.size) && (!_extend_buffer(f))) return_0; *(f->data.buf.start + f->data.buf.used) = '\n'; f->data.buf.used += 1; *(f->data.buf.start + f->data.buf.used) = '\0'; return 1; } #define COMMENT_TAB 6 __attribute__((format(printf, 3, 0))) static int _out_with_comment_file(struct formatter *f, const char *comment, const char *fmt, va_list ap) { int i; char white_space[MAX_INDENT + 1]; if (ferror(f->data.fp)) return 0; for (i = 0; i < f->indent; i++) white_space[i] = '\t'; white_space[i] = '\0'; fputs(white_space, f->data.fp); i = vfprintf(f->data.fp, fmt, ap); if (comment) { /* * line comments up if possible. */ i += 8 * f->indent; i /= 8; i++; do fputc('\t', f->data.fp); while (++i < COMMENT_TAB); fputs(comment, f->data.fp); } fputc('\n', f->data.fp); return 1; } __attribute__((format(printf, 3, 0))) static int _out_with_comment_raw(struct formatter *f, const char *comment __attribute__((unused)), const char *fmt, va_list ap) { int n; n = vsnprintf(f->data.buf.start + f->data.buf.used, f->data.buf.size - f->data.buf.used, fmt, ap); /* If metadata doesn't fit, extend buffer */ if (n < 0 || (n + f->data.buf.used + 2 > f->data.buf.size)) { if (!_extend_buffer(f)) return_0; return -1; /* Retry */ } f->data.buf.used += n; outnl(f); return 1; } /* * Formats a string, converting a size specified * in 512-byte sectors to a more human readable * form (eg, megabytes). We may want to lift this * for other code to use. */ static int _sectors_to_units(uint64_t sectors, char *buffer, size_t s) { static const char *_units[] = { "Kilobytes", "Megabytes", "Gigabytes", "Terabytes", "Petabytes", "Exabytes", NULL }; int i; double d = (double) sectors; /* to convert to K */ d /= 2.0; for (i = 0; (d > 1024.0) && _units[i]; i++) d /= 1024.0; return dm_snprintf(buffer, s, "# %g %s", d, _units[i]) > 0; } /* increment indention level */ void out_inc_indent(struct formatter *f) { _inc_indent(f); } /* decrement indention level */ void out_dec_indent(struct formatter *f) { _dec_indent(f); } /* insert new line */ int out_newline(struct formatter *f) { return f->nl(f); } /* * Appends a comment giving a size in more easily * readable form (eg, 4M instead of 8096). */ int out_size(struct formatter *f, uint64_t size, const char *fmt, ...) { char buffer[64]; va_list ap; int r; if (!_sectors_to_units(size, buffer, sizeof(buffer))) return 0; _out_with_comment(f, buffer, fmt, ap); return r; } /* * Appends a comment indicating that the line is * only a hint. */ int out_hint(struct formatter *f, const char *fmt, ...) { va_list ap; int r; _out_with_comment(f, "# Hint only", fmt, ap); return r; } /* * The normal output function with comment */ int out_text_with_comment(struct formatter *f, const char *comment, const char *fmt, ...) { va_list ap; int r; _out_with_comment(f, comment, fmt, ap); return r; } /* * The normal output function. */ int out_text(struct formatter *f, const char *fmt, ...) { va_list ap; int r; _out_with_comment(f, NULL, fmt, ap); return r; } static int _out_line(const char *line, void *_f) { struct formatter *f = (struct formatter *) _f; return out_text(f, "%s", line); } int out_config_node(struct formatter *f, const struct dm_config_node *cn) { return dm_config_write_node(cn, _out_line, f); } static int _print_header(struct formatter *f, const char *desc) { char *buf; time_t t; t = time(NULL); outf(f, "# Generated by LVM2 version %s: %s", LVM_VERSION, ctime(&t)); outf(f, CONTENTS_FIELD " = \"" CONTENTS_VALUE "\""); outf(f, FORMAT_VERSION_FIELD " = %d", FORMAT_VERSION_VALUE); outnl(f); if (!(buf = alloca(dm_escaped_len(desc)))) { log_error("temporary stack allocation for description" "string failed"); return 0; } outf(f, "description = \"%s\"", dm_escape_double_quotes(buf, desc)); outnl(f); outf(f, "creation_host = \"%s\"\t# %s %s %s %s %s", _utsname.nodename, _utsname.sysname, _utsname.nodename, _utsname.release, _utsname.version, _utsname.machine); outf(f, "creation_time = %lu\t# %s", t, ctime(&t)); return 1; } static int _print_flag_config(struct formatter *f, uint64_t status, int type) { char buffer[4096]; if (!print_flags(status, type | STATUS_FLAG, buffer, sizeof(buffer))) return_0; outf(f, "status = %s", buffer); if (!print_flags(status, type, buffer, sizeof(buffer))) return_0; outf(f, "flags = %s", buffer); return 1; } static int _out_tags(struct formatter *f, struct dm_list *tags) { char *tag_buffer; if (!dm_list_empty(tags)) { if (!(tag_buffer = alloc_printed_tags(tags))) return_0; if (!out_text(f, "tags = %s", tag_buffer)) { dm_free(tag_buffer); return_0; } dm_free(tag_buffer); } return 1; } static int _print_vg(struct formatter *f, struct volume_group *vg) { char buffer[4096]; if (!id_write_format(&vg->id, buffer, sizeof(buffer))) return_0; outf(f, "id = \"%s\"", buffer); outf(f, "seqno = %u", vg->seqno); if (vg->fid && vg->fid->fmt) outf(f, "format = \"%s\" # informational", vg->fid->fmt->name); if (!_print_flag_config(f, vg->status, VG_FLAGS)) return_0; if (!_out_tags(f, &vg->tags)) return_0; if (vg->system_id && *vg->system_id) outf(f, "system_id = \"%s\"", vg->system_id); outsize(f, (uint64_t) vg->extent_size, "extent_size = %u", vg->extent_size); outf(f, "max_lv = %u", vg->max_lv); outf(f, "max_pv = %u", vg->max_pv); /* Default policy is NORMAL; INHERIT is meaningless */ if (vg->alloc != ALLOC_NORMAL && vg->alloc != ALLOC_INHERIT) { outnl(f); outf(f, "allocation_policy = \"%s\"", get_alloc_string(vg->alloc)); } outf(f, "metadata_copies = %u", vg->mda_copies); return 1; } /* * Get the pv%d name from the formatters hash * table. */ static const char *_get_pv_name_from_uuid(struct formatter *f, char *uuid) { return dm_hash_lookup(f->pv_names, uuid); } static const char *_get_pv_name(struct formatter *f, struct physical_volume *pv) { char uuid[64] __attribute__((aligned(8))); if (!pv || !id_write_format(&pv->id, uuid, sizeof(uuid))) return_NULL; return _get_pv_name_from_uuid(f, uuid); } static int _print_pvs(struct formatter *f, struct volume_group *vg) { struct pv_list *pvl; struct physical_volume *pv; char buffer[4096]; char *buf; const char *name; outf(f, "physical_volumes {"); _inc_indent(f); dm_list_iterate_items(pvl, &vg->pvs) { pv = pvl->pv; if (!id_write_format(&pv->id, buffer, sizeof(buffer))) return_0; if (!(name = _get_pv_name_from_uuid(f, buffer))) return_0; outnl(f); outf(f, "%s {", name); _inc_indent(f); outf(f, "id = \"%s\"", buffer); if (!(buf = alloca(dm_escaped_len(pv_dev_name(pv))))) { log_error("temporary stack allocation for device name" "string failed"); return 0; } outhint(f, "device = \"%s\"", dm_escape_double_quotes(buf, pv_dev_name(pv))); outnl(f); if (!_print_flag_config(f, pv->status, PV_FLAGS)) return_0; if (!_out_tags(f, &pv->tags)) return_0; outsize(f, pv->size, "dev_size = %" PRIu64, pv->size); outf(f, "pe_start = %" PRIu64, pv->pe_start); outsize(f, vg->extent_size * (uint64_t) pv->pe_count, "pe_count = %u", pv->pe_count); _dec_indent(f); outf(f, "}"); } _dec_indent(f); outf(f, "}"); return 1; } static int _print_segment(struct formatter *f, struct volume_group *vg, int count, struct lv_segment *seg) { outf(f, "segment%u {", count); _inc_indent(f); outf(f, "start_extent = %u", seg->le); outsize(f, (uint64_t) seg->len * vg->extent_size, "extent_count = %u", seg->len); outnl(f); outf(f, "type = \"%s\"", seg->segtype->name); if (!_out_tags(f, &seg->tags)) return_0; if (seg->segtype->ops->text_export && !seg->segtype->ops->text_export(seg, f)) return_0; _dec_indent(f); outf(f, "}"); return 1; } int out_areas(struct formatter *f, const struct lv_segment *seg, const char *type) { const char *name; unsigned int s; outnl(f); outf(f, "%ss = [", type); _inc_indent(f); for (s = 0; s < seg->area_count; s++) { switch (seg_type(seg, s)) { case AREA_PV: if (!(name = _get_pv_name(f, seg_pv(seg, s)))) return_0; outf(f, "\"%s\", %u%s", name, seg_pe(seg, s), (s == seg->area_count - 1) ? "" : ","); break; case AREA_LV: if (!(seg->status & RAID)) { outf(f, "\"%s\", %u%s", seg_lv(seg, s)->name, seg_le(seg, s), (s == seg->area_count - 1) ? "" : ","); continue; } /* RAID devices are laid-out in metadata/data pairs */ if (!(seg_lv(seg, s)->status & RAID_IMAGE) || !(seg_metalv(seg, s)->status & RAID_META)) { log_error("RAID segment has non-RAID areas"); return 0; } outf(f, "\"%s\", \"%s\"%s", seg_metalv(seg, s)->name, seg_lv(seg, s)->name, (s == seg->area_count - 1) ? "" : ","); break; case AREA_UNASSIGNED: return 0; } } _dec_indent(f); outf(f, "]"); return 1; } static int _print_lv(struct formatter *f, struct logical_volume *lv) { struct lv_segment *seg; char buffer[4096]; int seg_count; struct tm *local_tm; time_t ts; outnl(f); outf(f, "%s {", lv->name); _inc_indent(f); /* FIXME: Write full lvid */ if (!id_write_format(&lv->lvid.id[1], buffer, sizeof(buffer))) return_0; outf(f, "id = \"%s\"", buffer); if (!_print_flag_config(f, lv->status, LV_FLAGS)) return_0; if (!_out_tags(f, &lv->tags)) return_0; if (lv->timestamp) { ts = (time_t)lv->timestamp; strncpy(buffer, "# ", sizeof(buffer)); if (!(local_tm = localtime(&ts)) || !strftime(buffer + 2, sizeof(buffer) - 2, "%Y-%m-%d %T %z", local_tm)) buffer[0] = 0; outf(f, "creation_host = \"%s\"", lv->hostname); outfc(f, buffer, "creation_time = %" PRIu64, lv->timestamp); } if (lv->alloc != ALLOC_INHERIT) outf(f, "allocation_policy = \"%s\"", get_alloc_string(lv->alloc)); switch (lv->read_ahead) { case DM_READ_AHEAD_NONE: outfc(f, "# None", "read_ahead = -1"); break; case DM_READ_AHEAD_AUTO: /* No output - use default */ break; default: outf(f, "read_ahead = %u", lv->read_ahead); } if (lv->major >= 0) outf(f, "major = %d", lv->major); if (lv->minor >= 0) outf(f, "minor = %d", lv->minor); outf(f, "segment_count = %u", dm_list_size(&lv->segments)); outnl(f); seg_count = 1; dm_list_iterate_items(seg, &lv->segments) { if (!_print_segment(f, lv->vg, seg_count++, seg)) return_0; } _dec_indent(f); outf(f, "}"); return 1; } static int _print_lvs(struct formatter *f, struct volume_group *vg) { struct lv_list *lvl; /* * Don't bother with an lv section if there are no lvs. */ if (dm_list_empty(&vg->lvs)) return 1; outf(f, "logical_volumes {"); _inc_indent(f); /* * Write visible LVs first */ dm_list_iterate_items(lvl, &vg->lvs) { if (!(lv_is_visible(lvl->lv))) continue; if (!_print_lv(f, lvl->lv)) return_0; } dm_list_iterate_items(lvl, &vg->lvs) { if ((lv_is_visible(lvl->lv))) continue; if (!_print_lv(f, lvl->lv)) return_0; } _dec_indent(f); outf(f, "}"); return 1; } /* * In the text format we refer to pv's as 'pv1', * 'pv2' etc. This function builds a hash table * to enable a quick lookup from device -> name. */ static int _build_pv_names(struct formatter *f, struct volume_group *vg) { int count = 0; struct pv_list *pvl; struct physical_volume *pv; char buffer[32], *uuid, *name; if (!(f->mem = dm_pool_create("text pv_names", 512))) return_0; if (!(f->pv_names = dm_hash_create(128))) return_0; dm_list_iterate_items(pvl, &vg->pvs) { pv = pvl->pv; /* FIXME But skip if there's already an LV called pv%d ! */ if (dm_snprintf(buffer, sizeof(buffer), "pv%d", count++) < 0) return_0; if (!(name = dm_pool_strdup(f->mem, buffer))) return_0; if (!(uuid = dm_pool_zalloc(f->mem, 64)) || !id_write_format(&pv->id, uuid, 64)) return_0; if (!dm_hash_insert(f->pv_names, uuid, name)) return_0; } return 1; } static int _text_vg_export(struct formatter *f, struct volume_group *vg, const char *desc) { int r = 0; if (!_build_pv_names(f, vg)) goto_out; if (f->header && !_print_header(f, desc)) goto_out; if (!out_text(f, "%s {", vg->name)) goto_out; _inc_indent(f); if (!_print_vg(f, vg)) goto_out; outnl(f); if (!_print_pvs(f, vg)) goto_out; outnl(f); if (!_print_lvs(f, vg)) goto_out; _dec_indent(f); if (!out_text(f, "}")) goto_out; if (!f->header && !_print_header(f, desc)) goto_out; r = 1; out: if (f->mem) { dm_pool_destroy(f->mem); f->mem = NULL; } if (f->pv_names) { dm_hash_destroy(f->pv_names); f->pv_names = NULL; } return r; } int text_vg_export_file(struct volume_group *vg, const char *desc, FILE *fp) { struct formatter *f; int r; _init(); if (!(f = dm_zalloc(sizeof(*f)))) return_0; f->data.fp = fp; f->indent = 0; f->header = 1; f->out_with_comment = &_out_with_comment_file; f->nl = &_nl_file; r = _text_vg_export(f, vg, desc); if (r) r = !ferror(f->data.fp); dm_free(f); return r; } /* Returns amount of buffer used incl. terminating NUL */ size_t text_vg_export_raw(struct volume_group *vg, const char *desc, char **buf) { struct formatter *f; size_t r = 0; _init(); if (!(f = dm_zalloc(sizeof(*f)))) return_0; f->data.buf.size = 65536; /* Initial metadata limit */ if (!(f->data.buf.start = dm_malloc(f->data.buf.size))) { log_error("text_export buffer allocation failed"); goto out; } f->indent = 0; f->header = 0; f->out_with_comment = &_out_with_comment_raw; f->nl = &_nl_raw; if (!_text_vg_export(f, vg, desc)) { dm_free(f->data.buf.start); goto_out; } r = f->data.buf.used + 1; *buf = f->data.buf.start; out: dm_free(f); return r; } size_t export_vg_to_buffer(struct volume_group *vg, char **buf) { return text_vg_export_raw(vg, "", buf); } #undef outf #undef outnl lvm2-2.02.98/lib/format_text/archive.c0000640000175000017500000002124012037016272016376 0ustar blankblank/* * 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 "format-text.h" #include "config.h" #include "import-export.h" #include "lvm-string.h" #include "lvm-file.h" #include "toolcontext.h" #include #include #include #include #include #define SECS_PER_DAY 86400 /* 24*60*60 */ /* * The format instance is given a directory path upon creation. * Each file in this directory whose name is of the form * '(.*)_[0-9]*.vg' is a config file (see lib/config.[hc]), which * contains a description of a single volume group. * * The prefix ($1 from the above regex) of the config file gives * the volume group name. * * Backup files that have expired will be removed. */ /* * A list of these is built up for our volume group. Ordered * with the least recent at the head. */ struct archive_file { struct dm_list list; const char *path; uint32_t index; }; /* * Extract vg name and version number from a filename. */ static int _split_vg(const char *filename, char *vgname, size_t vgsize, uint32_t *ix) { size_t len, vg_len; const char *dot, *underscore; len = strlen(filename); if (len < 7) return 0; dot = (filename + len - 3); if (strcmp(".vg", dot)) return 0; if (!(underscore = strrchr(filename, '_'))) return 0; if (sscanf(underscore + 1, "%u", ix) != 1) return 0; vg_len = underscore - filename; if (vg_len + 1 > vgsize) return 0; strncpy(vgname, filename, vg_len); vgname[vg_len] = '\0'; return 1; } static void _insert_archive_file(struct dm_list *head, struct archive_file *b) { struct archive_file *bf = NULL; if (dm_list_empty(head)) { dm_list_add(head, &b->list); return; } /* index reduces through list */ dm_list_iterate_items(bf, head) { if (b->index > bf->index) { dm_list_add(&bf->list, &b->list); return; } } dm_list_add_h(&bf->list, &b->list); } static char *_join_file_to_dir(struct dm_pool *mem, const char *dir, const char *name) { if (!dm_pool_begin_object(mem, 32) || !dm_pool_grow_object(mem, dir, strlen(dir)) || !dm_pool_grow_object(mem, "/", 1) || !dm_pool_grow_object(mem, name, strlen(name)) || !dm_pool_grow_object(mem, "\0", 1)) return_NULL; return dm_pool_end_object(mem); } /* * Returns a list of archive_files. */ static struct dm_list *_scan_archive(struct dm_pool *mem, const char *vgname, const char *dir) { int i, count; uint32_t ix; char vgname_found[64], *path; struct dirent **dirent; struct archive_file *af; struct dm_list *results; if (!(results = dm_pool_alloc(mem, sizeof(*results)))) return_NULL; dm_list_init(results); /* Sort fails beyond 5-digit indexes */ if ((count = scandir(dir, &dirent, NULL, alphasort)) < 0) { log_error("Couldn't scan the archive directory (%s).", dir); return 0; } for (i = 0; i < count; i++) { if (!strcmp(dirent[i]->d_name, ".") || !strcmp(dirent[i]->d_name, "..")) continue; /* check the name is the correct format */ if (!_split_vg(dirent[i]->d_name, vgname_found, sizeof(vgname_found), &ix)) continue; /* is it the vg we're interested in ? */ if (strcmp(vgname, vgname_found)) continue; if (!(path = _join_file_to_dir(mem, dir, dirent[i]->d_name))) goto_out; /* * Create a new archive_file. */ if (!(af = dm_pool_alloc(mem, sizeof(*af)))) { log_error("Couldn't create new archive file."); results = NULL; goto out; } af->index = ix; af->path = path; /* * Insert it to the correct part of the list. */ _insert_archive_file(results, af); } out: for (i = 0; i < count; i++) free(dirent[i]); free(dirent); return results; } static void _remove_expired(struct dm_list *archives, uint32_t archives_size, uint32_t retain_days, uint32_t min_archive) { struct archive_file *bf; struct stat sb; time_t retain_time; /* Make sure there are enough archives to even bother looking for * expired ones... */ if (archives_size <= min_archive) return; /* Convert retain_days into the time after which we must retain */ retain_time = time(NULL) - (time_t) retain_days *SECS_PER_DAY; /* Assume list is ordered newest first (by index) */ dm_list_iterate_back_items(bf, archives) { /* Get the mtime of the file and unlink if too old */ if (stat(bf->path, &sb)) { log_sys_error("stat", bf->path); continue; } if (sb.st_mtime > retain_time) return; log_very_verbose("Expiring archive %s", bf->path); if (unlink(bf->path)) log_sys_error("unlink", bf->path); /* Don't delete any more if we've reached the minimum */ if (--archives_size <= min_archive) return; } } int archive_vg(struct volume_group *vg, const char *dir, const char *desc, uint32_t retain_days, uint32_t min_archive) { int i, fd, rnum, renamed = 0; uint32_t ix = 0; struct archive_file *last; FILE *fp = NULL; char temp_file[PATH_MAX], archive_name[PATH_MAX]; struct dm_list *archives; /* * Write the vg out to a temporary file. */ if (!create_temp_name(dir, temp_file, sizeof(temp_file), &fd, &vg->cmd->rand_seed)) { log_error("Couldn't create temporary archive name."); return 0; } if (!(fp = fdopen(fd, "w"))) { log_error("Couldn't create FILE object for archive."); if (close(fd)) log_sys_error("close", temp_file); return 0; } if (!text_vg_export_file(vg, desc, fp)) { if (fclose(fp)) log_sys_error("fclose", temp_file); return_0; } if (lvm_fclose(fp, temp_file)) return_0; /* Leave file behind as evidence of failure */ /* * Now we want to rename this file to _index.vg. */ if (!(archives = _scan_archive(vg->cmd->mem, vg->name, dir))) return_0; if (dm_list_empty(archives)) ix = 0; else { last = dm_list_item(dm_list_first(archives), struct archive_file); ix = last->index + 1; } rnum = rand_r(&vg->cmd->rand_seed); for (i = 0; i < 10; i++) { if (dm_snprintf(archive_name, sizeof(archive_name), "%s/%s_%05u-%d.vg", dir, vg->name, ix, rnum) < 0) { log_error("Archive file name too long."); return 0; } if ((renamed = lvm_rename(temp_file, archive_name))) break; ix++; } if (!renamed) log_error("Archive rename failed for %s", temp_file); _remove_expired(archives, dm_list_size(archives) + renamed, retain_days, min_archive); return 1; } static void _display_archive(struct cmd_context *cmd, struct archive_file *af) { struct volume_group *vg = NULL; struct format_instance *tf; struct format_instance_ctx fic; struct text_context tc = {.path_live = af->path, .path_edit = NULL, .desc = NULL}; time_t when; char *desc; log_print(" "); log_print("File:\t\t%s", af->path); fic.type = FMT_INSTANCE_PRIVATE_MDAS; fic.context.private = &tc; if (!(tf = cmd->fmt_backup->ops->create_instance(cmd->fmt_backup, &fic))) { log_error("Couldn't create text instance object."); return; } /* * Read the archive file to ensure that it is valid, and * retrieve the archive time and description. */ /* FIXME Use variation on _vg_read */ if (!(vg = text_vg_import_file(tf, af->path, &when, &desc))) { log_error("Unable to read archive file."); tf->fmt->ops->destroy_instance(tf); return; } log_print("VG name: \t%s", vg->name); log_print("Description:\t%s", desc ? : ""); log_print("Backup Time:\t%s", ctime(&when)); release_vg(vg); } int archive_list(struct cmd_context *cmd, const char *dir, const char *vgname) { struct dm_list *archives; struct archive_file *af; if (!(archives = _scan_archive(cmd->mem, vgname, dir))) return_0; if (dm_list_empty(archives)) log_print("No archives found in %s.", dir); dm_list_iterate_back_items(af, archives) _display_archive(cmd, af); dm_pool_free(cmd->mem, archives); return 1; } int archive_list_file(struct cmd_context *cmd, const char *file) { struct archive_file af; af.path = file; if (!path_exists(af.path)) { log_error("Archive file %s not found.", af.path); return 0; } _display_archive(cmd, &af); return 1; } int backup_list(struct cmd_context *cmd, const char *dir, const char *vgname) { struct archive_file af; if (!(af.path = _join_file_to_dir(cmd->mem, dir, vgname))) return_0; if (path_exists(af.path)) _display_archive(cmd, &af); return 1; } lvm2-2.02.98/lib/format_text/archiver.h0000640000175000017500000000456512037016272016600 0ustar blankblank/* * 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_TOOL_ARCHIVE_H #define _LVM_TOOL_ARCHIVE_H #include "metadata-exported.h" /* * There are two operations that come under the general area of * backups. 'Archiving' occurs just before a volume group * configuration is changed. The user may configure when * archived files are expired. Typically archives will be stored * in /etc/lvm/archive. * * A 'backup' is a redundant copy of the *current* volume group * configuration. As such it should be taken just after the * volume group is changed. Only 1 backup file will exist. * Typically backups will be stored in /etc/lvm/backups. */ int archive_init(struct cmd_context *cmd, const char *dir, unsigned int keep_days, unsigned int keep_min, int enabled); void archive_exit(struct cmd_context *cmd); void archive_enable(struct cmd_context *cmd, int flag); int archive(struct volume_group *vg); int archive_display(struct cmd_context *cmd, const char *vg_name); int archive_display_file(struct cmd_context *cmd, const char *file); int backup_init(struct cmd_context *cmd, const char *dir, int enabled); void backup_exit(struct cmd_context *cmd); void backup_enable(struct cmd_context *cmd, int flag); int backup(struct volume_group *vg); int backup_locally(struct volume_group *vg); int backup_remove(struct cmd_context *cmd, const char *vg_name); struct volume_group *backup_read_vg(struct cmd_context *cmd, const char *vg_name, const char *file); int backup_restore_vg(struct cmd_context *cmd, struct volume_group *vg); int backup_restore_from_file(struct cmd_context *cmd, const char *vg_name, const char *file); int backup_restore(struct cmd_context *cmd, const char *vg_name); int backup_to_file(const char *file, const char *desc, struct volume_group *vg); void check_current_backup(struct volume_group *vg); #endif lvm2-2.02.98/lib/format_text/format-text.h0000640000175000017500000000500412037016272017234 0ustar blankblank/* * 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_FORMAT_TEXT_H #define _LVM_FORMAT_TEXT_H #include "lvm-types.h" #include "metadata.h" #define FMT_TEXT_NAME "lvm2" #define FMT_TEXT_ALIAS "text" #define FMT_TEXT_ORPHAN_VG_NAME ORPHAN_VG_NAME(FMT_TEXT_NAME) #define FMT_TEXT_MAX_MDAS_PER_PV 2 /* * Archives a vg config. 'retain_days' is the minimum number of * days that an archive file must be held for. 'min_archives' is * the minimum number of archives required to be kept for each * volume group. */ int archive_vg(struct volume_group *vg, const char *dir, const char *desc, uint32_t retain_days, uint32_t min_archive); /* * Displays a list of vg backups in a particular archive directory. */ int archive_list(struct cmd_context *cmd, const char *dir, const char *vgname); int archive_list_file(struct cmd_context *cmd, const char *file); int backup_list(struct cmd_context *cmd, const char *dir, const char *vgname); /* * The text format can read and write a volume_group to a file. */ struct text_context { const char *path_live; /* Path to file holding live metadata */ const char *path_edit; /* Path to file holding edited metadata */ const char *desc; /* Description placed inside file */ }; struct format_type *create_text_format(struct cmd_context *cmd); struct labeller *text_labeller_create(const struct format_type *fmt); int pvhdr_read(struct device *dev, char *buf); int add_da(struct dm_pool *mem, struct dm_list *das, uint64_t start, uint64_t size); void del_das(struct dm_list *das); int add_mda(const struct format_type *fmt, struct dm_pool *mem, struct dm_list *mdas, struct device *dev, uint64_t start, uint64_t size, unsigned ignored); void del_mdas(struct dm_list *mdas); /* On disk */ struct disk_locn { uint64_t offset; /* Offset in bytes to start sector */ uint64_t size; /* Bytes */ } __attribute__ ((packed)); /* Data areas (holding PEs) */ struct data_area_list { struct dm_list list; struct disk_locn disk_locn; }; #endif lvm2-2.02.98/lib/striped/0000750000175000017500000000000012037016272013727 5ustar blankblanklvm2-2.02.98/lib/striped/striped.c0000640000175000017500000001442512037016272015554 0ustar blankblank/* * Copyright (C) 2003-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 "toolcontext.h" #include "segtype.h" #include "display.h" #include "text_export.h" #include "text_import.h" #include "config.h" #include "str_list.h" #include "targets.h" #include "lvm-string.h" #include "activate.h" #include "pv_alloc.h" #include "metadata.h" static const char *_striped_name(const struct lv_segment *seg) { return (seg->area_count == 1) ? "linear" : seg->segtype->name; } static void _striped_display(const struct lv_segment *seg) { uint32_t s; if (seg->area_count == 1) display_stripe(seg, 0, " "); else { log_print(" Stripes\t\t%u", seg->area_count); if (seg->lv->vg->cmd->si_unit_consistency) log_print(" Stripe size\t\t%s", display_size(seg->lv->vg->cmd, (uint64_t) seg->stripe_size)); else log_print(" Stripe size\t\t%u KB", seg->stripe_size / 2); for (s = 0; s < seg->area_count; s++) { log_print(" Stripe %d:", s); display_stripe(seg, s, " "); } } log_print(" "); } static int _striped_text_import_area_count(const struct dm_config_node *sn, uint32_t *area_count) { if (!dm_config_get_uint32(sn, "stripe_count", area_count)) { log_error("Couldn't read 'stripe_count' for " "segment '%s'.", dm_config_parent_name(sn)); return 0; } return 1; } static int _striped_text_import(struct lv_segment *seg, const struct dm_config_node *sn, struct dm_hash_table *pv_hash) { const struct dm_config_value *cv; if ((seg->area_count != 1) && !dm_config_get_uint32(sn, "stripe_size", &seg->stripe_size)) { log_error("Couldn't read stripe_size for segment %s " "of logical volume %s.", dm_config_parent_name(sn), seg->lv->name); return 0; } if (!dm_config_get_list(sn, "stripes", &cv)) { log_error("Couldn't find stripes array for segment %s " "of logical volume %s.", dm_config_parent_name(sn), seg->lv->name); return 0; } seg->area_len /= seg->area_count; return text_import_areas(seg, sn, cv, pv_hash, 0); } static int _striped_text_export(const struct lv_segment *seg, struct formatter *f) { outf(f, "stripe_count = %u%s", seg->area_count, (seg->area_count == 1) ? "\t# linear" : ""); if (seg->area_count > 1) outsize(f, (uint64_t) seg->stripe_size, "stripe_size = %u", seg->stripe_size); return out_areas(f, seg, "stripe"); } /* * Test whether two segments could be merged by the current merging code */ static int _striped_segments_compatible(struct lv_segment *first, struct lv_segment *second) { uint32_t width; unsigned s; if ((first->area_count != second->area_count) || (first->stripe_size != second->stripe_size)) return 0; for (s = 0; s < first->area_count; s++) { /* FIXME Relax this to first area type != second area type */ /* plus the additional AREA_LV checks needed */ if ((seg_type(first, s) != AREA_PV) || (seg_type(second, s) != AREA_PV)) return 0; width = first->area_len; if ((seg_pv(first, s) != seg_pv(second, s)) || (seg_pe(first, s) + width != seg_pe(second, s))) return 0; } if (!str_list_lists_equal(&first->tags, &second->tags)) return 0; return 1; } static int _striped_merge_segments(struct lv_segment *seg1, struct lv_segment *seg2) { uint32_t s; if (!_striped_segments_compatible(seg1, seg2)) return 0; seg1->len += seg2->len; seg1->area_len += seg2->area_len; for (s = 0; s < seg1->area_count; s++) if (seg_type(seg1, s) == AREA_PV) merge_pv_segments(seg_pvseg(seg1, s), seg_pvseg(seg2, s)); return 1; } #ifdef DEVMAPPER_SUPPORT static int _striped_add_target_line(struct dev_manager *dm, struct dm_pool *mem __attribute__((unused)), struct cmd_context *cmd __attribute__((unused)), void **target_state __attribute__((unused)), struct lv_segment *seg, const struct lv_activate_opts *laopts __attribute__((unused)), struct dm_tree_node *node, uint64_t len, uint32_t *pvmove_mirror_count __attribute__((unused))) { if (!seg->area_count) { log_error(INTERNAL_ERROR "striped add_target_line called " "with no areas for %s.", seg->lv->name); return 0; } if (seg->area_count == 1) { if (!add_linear_area_to_dtree(node, len, seg->lv->vg->extent_size, cmd->use_linear_target, seg->lv->vg->name, seg->lv->name)) return_0; } else if (!dm_tree_node_add_striped_target(node, len, seg->stripe_size)) return_0; return add_areas_line(dm, seg, node, 0u, seg->area_count); } static int _striped_target_present(struct cmd_context *cmd, const struct lv_segment *seg __attribute__((unused)), unsigned *attributes __attribute__((unused))) { static int _striped_checked = 0; static int _striped_present = 0; if (!_striped_checked) _striped_present = target_present(cmd, "linear", 0) && target_present(cmd, "striped", 0); _striped_checked = 1; return _striped_present; } #endif static void _striped_destroy(struct segment_type *segtype) { dm_free(segtype); } static struct segtype_handler _striped_ops = { .name = _striped_name, .display = _striped_display, .text_import_area_count = _striped_text_import_area_count, .text_import = _striped_text_import, .text_export = _striped_text_export, .merge_segments = _striped_merge_segments, #ifdef DEVMAPPER_SUPPORT .add_target_line = _striped_add_target_line, .target_present = _striped_target_present, #endif .destroy = _striped_destroy, }; struct segment_type *init_striped_segtype(struct cmd_context *cmd) { struct segment_type *segtype = dm_zalloc(sizeof(*segtype)); if (!segtype) return_NULL; segtype->cmd = cmd; segtype->ops = &_striped_ops; segtype->name = "striped"; segtype->private = NULL; segtype->flags = SEG_CAN_SPLIT | SEG_AREAS_STRIPED | SEG_FORMAT1_SUPPORT; log_very_verbose("Initialised segtype: %s", segtype->name); return segtype; } lvm2-2.02.98/lib/thin/0000750000175000017500000000000012037016272013217 5ustar blankblanklvm2-2.02.98/lib/thin/.exported_symbols0000640000175000017500000000001512037016272016617 0ustar blankblankinit_segtype lvm2-2.02.98/lib/thin/thin.c0000640000175000017500000004640412037016272014336 0ustar blankblank/* * Copyright (C) 2011-2012 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU Lesser General Public License v.2.1. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "lib.h" #include "toolcontext.h" #include "metadata.h" #include "segtype.h" #include "text_export.h" #include "config.h" #include "activate.h" #include "str_list.h" #include "defaults.h" #ifdef DMEVENTD # include "libdevmapper-event.h" #endif /* Dm kernel module name for thin provisiong */ #define THIN_MODULE "thin-pool" /* * Macro used as return argument - returns 0. * return is left to be written in the function for better readability. */ #define SEG_LOG_ERROR(t, p...) \ log_error(t " segment %s of logical volume %s.", ## p, \ dm_config_parent_name(sn), seg->lv->name), 0; static int _thin_target_present(struct cmd_context *cmd, const struct lv_segment *seg, unsigned *attributes); static const char *_thin_pool_name(const struct lv_segment *seg) { return seg->segtype->name; } static int _thin_pool_add_message(struct lv_segment *seg, const char *key, const struct dm_config_node *sn) { const char *lv_name = NULL; struct logical_volume *lv = NULL; uint32_t delete_id = 0; dm_thin_message_t type; /* Message must have only one from: create, delete */ if (dm_config_get_str(sn, "create", &lv_name)) { if (!(lv = find_lv(seg->lv->vg, lv_name))) return SEG_LOG_ERROR("Unknown LV %s for create message in", lv_name); /* FIXME: switch to _SNAP later, if the created LV has an origin */ type = DM_THIN_MESSAGE_CREATE_THIN; } if (!dm_config_get_uint32(sn, "delete", &delete_id)) { if (!lv) return SEG_LOG_ERROR("Unknown message in"); } else { if (lv) return SEG_LOG_ERROR("Unsupported message format in"); type = DM_THIN_MESSAGE_DELETE; } if (!attach_pool_message(seg, type, lv, delete_id, 1)) return_0; return 1; } static int _thin_pool_text_import(struct lv_segment *seg, const struct dm_config_node *sn, struct dm_hash_table *pv_hash __attribute__((unused))) { const char *lv_name; struct logical_volume *pool_data_lv, *pool_metadata_lv; const char *discards_str = NULL; if (!dm_config_get_str(sn, "metadata", &lv_name)) return SEG_LOG_ERROR("Metadata must be a string in"); if (!(pool_metadata_lv = find_lv(seg->lv->vg, lv_name))) return SEG_LOG_ERROR("Unknown metadata %s in", lv_name); if (!dm_config_get_str(sn, "pool", &lv_name)) return SEG_LOG_ERROR("Pool must be a string in"); if (!(pool_data_lv = find_lv(seg->lv->vg, lv_name))) return SEG_LOG_ERROR("Unknown pool %s in", lv_name); seg->lv->status |= THIN_POOL; if (!attach_pool_metadata_lv(seg, pool_metadata_lv)) return_0; if (!attach_pool_data_lv(seg, pool_data_lv)) return_0; if (!dm_config_get_uint64(sn, "transaction_id", &seg->transaction_id)) return SEG_LOG_ERROR("Could not read transaction_id for"); if (!dm_config_get_uint32(sn, "chunk_size", &seg->chunk_size)) return SEG_LOG_ERROR("Could not read chunk_size"); if (dm_config_has_node(sn, "discards") && !dm_config_get_str(sn, "discards", &discards_str)) return SEG_LOG_ERROR("Could not read discards for"); if (!discards_str) seg->discards = THIN_DISCARDS_IGNORE; else if (!get_pool_discards(discards_str, &seg->discards)) return SEG_LOG_ERROR("Discards option unsupported for"); if (dm_config_has_node(sn, "low_water_mark") && !dm_config_get_uint64(sn, "low_water_mark", &seg->low_water_mark)) return SEG_LOG_ERROR("Could not read low_water_mark"); if ((seg->chunk_size < DM_THIN_MIN_DATA_BLOCK_SIZE) || (seg->chunk_size > DM_THIN_MAX_DATA_BLOCK_SIZE)) return SEG_LOG_ERROR("Unsupported value %u for chunk_size", seg->device_id); if (dm_config_has_node(sn, "zero_new_blocks") && !dm_config_get_uint32(sn, "zero_new_blocks", &seg->zero_new_blocks)) return SEG_LOG_ERROR("Could not read zero_new_blocks for"); /* Read messages */ for (; sn; sn = sn->sib) if (!(sn->v) && !_thin_pool_add_message(seg, sn->key, sn->child)) return_0; return 1; } static int _thin_pool_text_import_area_count(const struct dm_config_node *sn, uint32_t *area_count) { *area_count = 1; return 1; } static int _thin_pool_text_export(const struct lv_segment *seg, struct formatter *f) { unsigned cnt = 0; const struct lv_thin_message *tmsg; outf(f, "metadata = \"%s\"", seg->metadata_lv->name); outf(f, "pool = \"%s\"", seg_lv(seg, 0)->name); outf(f, "transaction_id = %" PRIu64, seg->transaction_id); outsize(f, (uint64_t) seg->chunk_size, "chunk_size = %u", seg->chunk_size); switch (seg->discards) { case THIN_DISCARDS_PASSDOWN: case THIN_DISCARDS_NO_PASSDOWN: case THIN_DISCARDS_IGNORE: outf(f, "discards = \"%s\"", get_pool_discards_name(seg->discards)); break; default: log_error(INTERNAL_ERROR "Invalid discards value %d.", seg->discards); return 0; } if (seg->low_water_mark) outf(f, "low_water_mark = %" PRIu64, seg->low_water_mark); if (seg->zero_new_blocks) outf(f, "zero_new_blocks = 1"); dm_list_iterate_items(tmsg, &seg->thin_messages) { /* Extra validation */ switch (tmsg->type) { case DM_THIN_MESSAGE_CREATE_SNAP: case DM_THIN_MESSAGE_CREATE_THIN: if (!lv_is_thin_volume(tmsg->u.lv)) { log_error(INTERNAL_ERROR "LV %s is not a thin volume.", tmsg->u.lv->name); return 0; } break; default: break; } if (!cnt) outnl(f); outf(f, "message%d {", ++cnt); out_inc_indent(f); switch (tmsg->type) { case DM_THIN_MESSAGE_CREATE_SNAP: case DM_THIN_MESSAGE_CREATE_THIN: outf(f, "create = \"%s\"", tmsg->u.lv->name); break; case DM_THIN_MESSAGE_DELETE: outf(f, "delete = %d", tmsg->u.delete_id); break; default: log_error(INTERNAL_ERROR "Passed unsupported message."); return 0; } out_dec_indent(f); outf(f, "}"); } return 1; } #ifdef DEVMAPPER_SUPPORT static int _thin_pool_add_target_line(struct dev_manager *dm, struct dm_pool *mem, struct cmd_context *cmd, void **target_state __attribute__((unused)), struct lv_segment *seg, const struct lv_activate_opts *laopts, struct dm_tree_node *node, uint64_t len, uint32_t *pvmove_mirror_count __attribute__((unused))) { static int _no_discards = 0; char *metadata_dlid, *pool_dlid; const struct lv_thin_message *lmsg; const struct logical_volume *origin; struct lvinfo info; uint64_t transaction_id = 0; unsigned attr; if (!_thin_target_present(cmd, seg, &attr)) return_0; if (!(attr & THIN_FEATURE_BLOCK_SIZE) && (seg->chunk_size & (seg->chunk_size - 1))) { log_error("Thin pool target does not support %uKiB chunk size " "(needs kernel >= 3.6).", seg->chunk_size / 2); return 0; } if (!laopts->real_pool) { if (!(pool_dlid = build_dm_uuid(mem, seg->lv->lvid.s, "tpool"))) { log_error("Failed to build uuid for thin pool LV %s.", seg->pool_lv->name); return 0; } if (!add_linear_area_to_dtree(node, len, seg->lv->vg->extent_size, cmd->use_linear_target, seg->lv->vg->name, seg->lv->name) || !dm_tree_node_add_target_area(node, NULL, pool_dlid, 0)) return_0; return 1; } if (!(metadata_dlid = build_dm_uuid(mem, seg->metadata_lv->lvid.s, NULL))) { log_error("Failed to build uuid for metadata LV %s.", seg->metadata_lv->name); return 0; } if (!(pool_dlid = build_dm_uuid(mem, seg_lv(seg, 0)->lvid.s, NULL))) { log_error("Failed to build uuid for pool LV %s.", seg_lv(seg, 0)->name); return 0; } if (!dm_tree_node_add_thin_pool_target(node, len, seg->transaction_id, metadata_dlid, pool_dlid, seg->chunk_size, seg->low_water_mark, seg->zero_new_blocks ? 0 : 1)) return_0; if (attr & THIN_FEATURE_DISCARDS) { /* FIXME: Check whether underlying dev supports discards */ if (!dm_tree_node_set_thin_pool_discard(node, seg->discards == THIN_DISCARDS_IGNORE, seg->discards == THIN_DISCARDS_NO_PASSDOWN)) return_0; } else if (seg->discards != THIN_DISCARDS_IGNORE) log_warn_suppress(_no_discards++, "WARNING: Thin pool target does " "not support discards (needs kernel >= 3.4)."); /* * Add messages only for activation tree. * Otherwise avoid checking for existence of suspended origin. * Also transation_id is checked only when snapshot origin is active. * (This might change later) */ if (!laopts->is_activate) return 1; dm_list_iterate_items(lmsg, &seg->thin_messages) { switch (lmsg->type) { case DM_THIN_MESSAGE_CREATE_THIN: origin = first_seg(lmsg->u.lv)->origin; /* Check if the origin is suspended */ if (origin && lv_info(cmd, origin, 0, &info, 0, 0) && info.exists && !info.suspended) { /* Origin is not suspended, but the transaction may have been * already transfered, so test for transaction_id and * allow to pass in the message for dmtree processing * so it will skip all messages later. */ if (!lv_thin_pool_transaction_id(seg->lv, &transaction_id)) return_0; /* Thin pool should exist and work */ if (transaction_id != seg->transaction_id) { log_error("Can't create snapshot %s as origin %s is not suspended.", lmsg->u.lv->name, origin->name); return 0; } } log_debug("Thin pool create_%s %s.", (!origin) ? "thin" : "snap", lmsg->u.lv->name); if (!dm_tree_node_add_thin_pool_message(node, (!origin) ? lmsg->type : DM_THIN_MESSAGE_CREATE_SNAP, first_seg(lmsg->u.lv)->device_id, (!origin) ? 0 : first_seg(origin)->device_id)) return_0; break; case DM_THIN_MESSAGE_DELETE: log_debug("Thin pool delete %u.", lmsg->u.delete_id); if (!dm_tree_node_add_thin_pool_message(node, lmsg->type, lmsg->u.delete_id, 0)) return_0; break; default: log_error(INTERNAL_ERROR "Unsupported message."); return 0; } } if (!dm_list_empty(&seg->thin_messages)) { /* Messages were passed, modify transaction_id as the last one */ log_debug("Thin pool set transaction id %" PRIu64 ".", seg->transaction_id); if (!dm_tree_node_add_thin_pool_message(node, DM_THIN_MESSAGE_SET_TRANSACTION_ID, seg->transaction_id - 1, seg->transaction_id)) return_0; } return 1; } static int _thin_pool_target_percent(void **target_state __attribute__((unused)), percent_t *percent, struct dm_pool *mem, struct cmd_context *cmd __attribute__((unused)), struct lv_segment *seg, char *params, uint64_t *total_numerator, uint64_t *total_denominator) { struct dm_status_thin_pool *s; if (!dm_get_status_thin_pool(mem, params, &s)) return_0; /* With 'seg' report metadata percent, otherwice data percent */ if (seg) { *percent = make_percent(s->used_metadata_blocks, s->total_metadata_blocks); *total_numerator += s->used_metadata_blocks; *total_denominator += s->total_metadata_blocks; } else { *percent = make_percent(s->used_data_blocks, s->total_data_blocks); *total_numerator += s->used_data_blocks; *total_denominator += s->total_data_blocks; } return 1; } # ifdef DMEVENTD static const char *_get_thin_dso_path(struct cmd_context *cmd) { return get_monitor_dso_path(cmd, find_config_tree_str(cmd, "dmeventd/thin_library", DEFAULT_DMEVENTD_THIN_LIB)); } /* FIXME Cache this */ static int _target_registered(struct lv_segment *seg, int *pending) { return target_registered_with_dmeventd(seg->lv->vg->cmd, _get_thin_dso_path(seg->lv->vg->cmd), seg->lv, pending); } /* FIXME This gets run while suspended and performs banned operations. */ static int _target_set_events(struct lv_segment *seg, int evmask, int set) { /* FIXME Make timeout (10) configurable */ return target_register_events(seg->lv->vg->cmd, _get_thin_dso_path(seg->lv->vg->cmd), seg->lv, evmask, set, 10); } static int _target_register_events(struct lv_segment *seg, int events) { return _target_set_events(seg, events, 1); } static int _target_unregister_events(struct lv_segment *seg, int events) { return _target_set_events(seg, events, 0); } # endif /* DMEVENTD */ #endif /* DEVMAPPER_SUPPORT */ static const char *_thin_name(const struct lv_segment *seg) { return seg->segtype->name; } static int _thin_text_import(struct lv_segment *seg, const struct dm_config_node *sn, struct dm_hash_table *pv_hash __attribute__((unused))) { const char *lv_name; struct logical_volume *pool_lv, *origin = NULL; if (!dm_config_get_str(sn, "thin_pool", &lv_name)) return SEG_LOG_ERROR("Thin pool must be a string in"); if (!(pool_lv = find_lv(seg->lv->vg, lv_name))) return SEG_LOG_ERROR("Unknown thin pool %s in", lv_name); if (!dm_config_get_uint64(sn, "transaction_id", &seg->transaction_id)) return SEG_LOG_ERROR("Could not read transaction_id for"); if (dm_config_has_node(sn, "origin")) { if (!dm_config_get_str(sn, "origin", &lv_name)) return SEG_LOG_ERROR("Origin must be a string in"); if (!(origin = find_lv(seg->lv->vg, lv_name))) return SEG_LOG_ERROR("Unknown origin %s in", lv_name); } if (!dm_config_get_uint32(sn, "device_id", &seg->device_id)) return SEG_LOG_ERROR("Could not read device_id for"); if (seg->device_id > DM_THIN_MAX_DEVICE_ID) return SEG_LOG_ERROR("Unsupported value %u for device_id", seg->device_id); if (!attach_pool_lv(seg, pool_lv, origin)) return_0; return 1; } static int _thin_text_export(const struct lv_segment *seg, struct formatter *f) { outf(f, "thin_pool = \"%s\"", seg->pool_lv->name); outf(f, "transaction_id = %" PRIu64, seg->transaction_id); outf(f, "device_id = %d", seg->device_id); if (seg->origin) outf(f, "origin = \"%s\"", seg->origin->name); return 1; } #ifdef DEVMAPPER_SUPPORT static int _thin_add_target_line(struct dev_manager *dm, struct dm_pool *mem, struct cmd_context *cmd __attribute__((unused)), void **target_state __attribute__((unused)), struct lv_segment *seg, const struct lv_activate_opts *laopts __attribute__((unused)), struct dm_tree_node *node, uint64_t len, uint32_t *pvmove_mirror_count __attribute__((unused))) { char *pool_dlid; uint32_t device_id = seg->device_id; if (!(pool_dlid = build_dm_uuid(mem, seg->pool_lv->lvid.s, "tpool"))) { log_error("Failed to build uuid for pool LV %s.", seg->pool_lv->name); return 0; } if (!dm_tree_node_add_thin_target(node, len, pool_dlid, device_id)) return_0; return 1; } static int _thin_target_percent(void **target_state __attribute__((unused)), percent_t *percent, struct dm_pool *mem, struct cmd_context *cmd __attribute__((unused)), struct lv_segment *seg, char *params, uint64_t *total_numerator, uint64_t *total_denominator) { struct dm_status_thin *s; /* Status for thin device is in sectors */ if (!dm_get_status_thin(mem, params, &s)) return_0; if (seg) { *percent = make_percent(s->mapped_sectors, seg->lv->size); *total_denominator += seg->lv->size; } else { /* No lv_segment info here */ *percent = PERCENT_INVALID; /* FIXME: Using denominator to pass the mapped info upward? */ *total_denominator += s->highest_mapped_sector; } *total_numerator += s->mapped_sectors; return 1; } static int _thin_target_present(struct cmd_context *cmd, const struct lv_segment *seg, unsigned *attributes) { static int _checked = 0; static int _present = 0; static int _attrs = 0; uint32_t maj, min, patchlevel; if (!_checked) { _present = target_present(cmd, THIN_MODULE, 1); if (!target_version(THIN_MODULE, &maj, &min, &patchlevel)) { log_error("Cannot read " THIN_MODULE " target version."); return 0; } if (maj >=1 && min >= 1) _attrs |= THIN_FEATURE_DISCARDS; else /* FIXME Log this as WARNING later only if the user asked for the feature to be used but it's not present */ log_debug("Target " THIN_MODULE " does not support discards."); if (maj >=1 && min >= 1) _attrs |= THIN_FEATURE_EXTERNAL_ORIGIN; else /* FIXME Log this as WARNING later only if the user asked for the feature to be used but it's not present */ log_debug("Target " THIN_MODULE " does not support external origins."); if (maj >=1 && min >= 4) _attrs |= THIN_FEATURE_BLOCK_SIZE; else /* FIXME Log this as WARNING later only if the user asked for the feature to be used but it's not present */ log_debug("Target " THIN_MODULE " does not support non power of 2 block sizes."); _checked = 1; } if (attributes) *attributes = _attrs; return _present; } #endif static int _thin_modules_needed(struct dm_pool *mem, const struct lv_segment *seg __attribute__((unused)), struct dm_list *modules) { if (!str_list_add(mem, modules, THIN_MODULE)) { log_error("thin string list allocation failed"); return 0; } return 1; } static void _thin_destroy(struct segment_type *segtype) { dm_free(segtype); } static struct segtype_handler _thin_pool_ops = { .name = _thin_pool_name, .text_import = _thin_pool_text_import, .text_import_area_count = _thin_pool_text_import_area_count, .text_export = _thin_pool_text_export, #ifdef DEVMAPPER_SUPPORT .add_target_line = _thin_pool_add_target_line, .target_percent = _thin_pool_target_percent, .target_present = _thin_target_present, # ifdef DMEVENTD .target_monitored = _target_registered, .target_monitor_events = _target_register_events, .target_unmonitor_events = _target_unregister_events, # endif /* DMEVENTD */ #endif .modules_needed = _thin_modules_needed, .destroy = _thin_destroy, }; static struct segtype_handler _thin_ops = { .name = _thin_name, .text_import = _thin_text_import, .text_export = _thin_text_export, #ifdef DEVMAPPER_SUPPORT .add_target_line = _thin_add_target_line, .target_percent = _thin_target_percent, .target_present = _thin_target_present, #endif .modules_needed = _thin_modules_needed, .destroy = _thin_destroy, }; #ifdef THIN_INTERNAL int init_thin_segtypes(struct cmd_context *cmd, struct segtype_library *seglib) #else /* Shared */ int init_multiple_segtypes(struct cmd_context *cmd, struct segtype_library *seglib); int init_multiple_segtypes(struct cmd_context *cmd, struct segtype_library *seglib) #endif { static const struct { struct segtype_handler *ops; const char name[16]; uint32_t flags; } reg_segtypes[] = { { &_thin_pool_ops, "thin-pool", SEG_THIN_POOL }, /* FIXME Maybe use SEG_THIN_VOLUME instead of SEG_VIRTUAL */ { &_thin_ops, "thin", SEG_THIN_VOLUME | SEG_VIRTUAL } }; struct segment_type *segtype; unsigned i; for (i = 0; i < sizeof(reg_segtypes)/sizeof(reg_segtypes[0]); ++i) { segtype = dm_zalloc(sizeof(*segtype)); if (!segtype) { log_error("Failed to allocate memory for %s segtype", reg_segtypes[i].name); return 0; } segtype->ops = reg_segtypes[i].ops; segtype->name = reg_segtypes[i].name; segtype->flags = reg_segtypes[i].flags; #ifdef DEVMAPPER_SUPPORT # ifdef DMEVENTD if ((reg_segtypes[i].flags & SEG_THIN_POOL) && _get_thin_dso_path(cmd)) segtype->flags |= SEG_MONITORED; # endif /* DMEVENTD */ #endif if (!lvm_register_segtype(seglib, segtype)) /* segtype is already destroyed */ return_0; log_very_verbose("Initialised segtype: %s", segtype->name); } return 1; } lvm2-2.02.98/lib/thin/Makefile.in0000640000175000017500000000132012037016272015261 0ustar blankblank# # Copyright (C) 2011 Red Hat, Inc. All rights reserved. # # This file is part of LVM2. # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions # of the GNU General Public License v.2. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation, # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA srcdir = @srcdir@ top_srcdir = @top_srcdir@ top_builddir = @top_builddir@ SOURCES = thin.c LIB_SHARED = liblvm2thin.$(LIB_SUFFIX) LIB_VERSION = $(LIB_VERSION_LVM) include $(top_builddir)/make.tmpl install: install_lib_shared_plugin lvm2-2.02.98/lib/cache/0000750000175000017500000000000012037016272013320 5ustar blankblanklvm2-2.02.98/lib/cache/lvmetad.h0000640000175000017500000001306012037016272015126 0ustar blankblank/* * Copyright (C) 2012 Red Hat, Inc. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU Lesser General Public License v.2.1. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _LVM_METAD_H #define _LVM_METAD_H #include "config-util.h" struct volume_group; struct cmd_context; struct dm_config_tree; enum activation_change; typedef int (*activation_handler) (struct volume_group *vg, int partial, enum activation_change activate); #ifdef LVMETAD_SUPPORT /* * Initialise the communication with lvmetad. Normally called by * lvmcache_init. Sets up a global handle for our process. */ void lvmetad_init(struct cmd_context *); /* * Override the use of lvmetad for retrieving scan results and metadata. */ void lvmetad_set_active(int); /* * Configure the socket that lvmetad_init will use to connect to the daemon. */ void lvmetad_set_socket(const char *); /* * Check whether lvmetad is active (where active means both that it is running * and that we have a working connection with it). */ int lvmetad_active(void); /* Print a warning if lvmetad is enabled but we failed to connect. */ void lvmetad_warning(void); /* * Drop connection to lvmetad. A subsequent lvmetad_init() will re-establish * the connection (possibly at a different socket path). */ void lvmetad_disconnect(void); /* * Set the "lvmetad validity token" (currently only consists of the lvmetad * filter. See lvm.conf. */ void lvmetad_set_token(const struct dm_config_value *filter); /* * Release allocated token. */ void lvmetad_release_token(void); /* * Send a new version of VG metadata to lvmetad. This is normally called after * vg_write but before vg_commit. After vg_commit, lvmetad_vg_commit is called * to seal the transaction. The result of lvmetad_vg_update is that the new * metadata is stored tentatively in lvmetad, but it is not used until * lvmetad_vg_commit. The request is validated immediately and lvmetad_vg_commit * only constitutes a pointer update. */ int lvmetad_vg_update(struct volume_group *vg); /* * Inform lvmetad that a VG has been removed. This is not entirely safe, but is * only needed during vgremove, which does not wipe PV labels and therefore * cannot mark the PVs as gone. */ int lvmetad_vg_remove(struct volume_group *vg); /* * Notify lvmetad that a PV has been found. It is not an error if the PV is * already marked as present in lvmetad. If a non-NULL vg pointer is supplied, * it is taken to represent the metadata read from the MDA(s) present on that * PV. It *is* an error if: the VG is already known to lvmetad, the sequence * number on the cached and on the discovered PV match but the metadata content * does not. */ int lvmetad_pv_found(const struct id *pvid, struct device *device, const struct format_type *fmt, uint64_t label_sector, struct volume_group *vg, activation_handler handler); /* * Inform the daemon that the device no longer exists. */ int lvmetad_pv_gone(dev_t devno, const char *pv_name, activation_handler handler); int lvmetad_pv_gone_by_dev(struct device *dev, activation_handler handler); /* * Request a list of all PVs available to lvmetad. If requested, this will also * read labels off all the PVs to populate lvmcache. */ int lvmetad_pv_list_to_lvmcache(struct cmd_context *cmd); /* * Lookup an individual PV. * If found is not NULL, it is set according to whether or not the PV is found, * otherwise if the PV is not found an error is returned. */ int lvmetad_pv_lookup(struct cmd_context *cmd, struct id pvid, int *found); int lvmetad_pv_lookup_by_dev(struct cmd_context *cmd, struct device *dev, int *found); /* * Request a list of all VGs available to lvmetad and use it to fill in * lvmcache.. */ int lvmetad_vg_list_to_lvmcache(struct cmd_context *cmd); /* * Find a VG by its ID or its name in the lvmetad cache. Gives NULL if the VG is * not found. */ struct volume_group *lvmetad_vg_lookup(struct cmd_context *cmd, const char *vgname, const char *vgid); /* * Scan a single device and update lvmetad with the result(s). */ int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev, activation_handler handler); int lvmetad_pvscan_all_devs(struct cmd_context *cmd, activation_handler handler); # else /* LVMETAD_SUPPORT */ # define lvmetad_init(cmd) do { } while (0) # define lvmetad_disconnect() do { } while (0) # define lvmetad_set_active(a) do { } while (0) # define lvmetad_set_socket(a) do { } while (0) # define lvmetad_active() (0) # define lvmetad_warning() do { } while (0) # define lvmetad_set_token(a) do { } while (0) # define lvmetad_release_token() do { } while (0) # define lvmetad_vg_update(vg) (1) # define lvmetad_vg_remove(vg) (1) # define lvmetad_pv_found(pvid, device, fmt, label_sector, vg, handler) (1) # define lvmetad_pv_gone(devno, pv_name, handler) (1) # define lvmetad_pv_gone_by_dev(dev, handler) (1) # define lvmetad_pv_list_to_lvmcache(cmd) (1) # define lvmetad_pv_lookup(cmd, pvid, found) (0) # define lvmetad_pv_lookup_by_dev(cmd, dev, found) (0) # define lvmetad_vg_list_to_lvmcache(cmd) (1) # define lvmetad_vg_lookup(cmd, vgname, vgid) (NULL) # define lvmetad_pvscan_single(cmd, dev, handler) (0) # define lvmetad_pvscan_all_devs(cmd, handler) (0) # endif /* LVMETAD_SUPPORT */ #endif lvm2-2.02.98/lib/cache/lvmcache.h0000640000175000017500000001430112037016272015253 0ustar blankblank/* * 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 /* LVM specific per-volume info */ /* Eventual replacement for struct physical_volume perhaps? */ struct cmd_context; struct format_type; struct volume_group; struct physical_volume; struct dm_config_tree; struct format_instance; struct metadata_area; struct disk_locn; struct lvmcache_vginfo; int lvmcache_init(void); void lvmcache_allow_reads_with_lvmetad(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 *lvmcache_fmt_from_vgname(struct cmd_context *cmd, const char *vgname, const char *vgid, unsigned revalidate_labels); /* Decrement and test if there are still vg holders in vginfo. */ int lvmcache_vginfo_holders_dec_and_test_for_zero(struct lvmcache_vginfo *vginfo); struct lvmcache_vginfo *lvmcache_vginfo_from_vgname(const char *vgname, const char *vgid); struct lvmcache_vginfo *lvmcache_vginfo_from_vgid(const char *vgid); struct lvmcache_info *lvmcache_info_from_pvid(const char *pvid, int valid_only); const char *lvmcache_vgname_from_vgid(struct dm_pool *mem, const char *vgid); struct device *lvmcache_device_from_pvid(struct cmd_context *cmd, const struct id *pvid, unsigned *scan_done_once, uint64_t *label_sector); const char *lvmcache_pvid_from_devname(struct cmd_context *cmd, const char *dev_name); char *lvmcache_vgname_from_pvid(struct cmd_context *cmd, const char *pvid); const char *lvmcache_vgname_from_info(struct lvmcache_info *info); int lvmcache_vgs_locked(void); int lvmcache_vgname_is_locked(const char *vgname); void lvmcache_seed_infos_from_lvmetad(struct cmd_context *cmd); /* 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(struct cmd_context *cmd, const char *vgname, const char *vgid, unsigned precommitted); void lvmcache_drop_metadata(const char *vgname, int drop_precommitted); void lvmcache_commit_metadata(const char *vgname); int lvmcache_pvid_is_locked(const char *pvid); int lvmcache_fid_add_mdas(struct lvmcache_info *info, struct format_instance *fid, const char *id, int id_len); int lvmcache_fid_add_mdas_pv(struct lvmcache_info *info, struct format_instance *fid); int lvmcache_fid_add_mdas_vg(struct lvmcache_vginfo *vginfo, struct format_instance *fid); int lvmcache_populate_pv_fields(struct lvmcache_info *info, struct physical_volume *pv, int scan_label_only); int lvmcache_check_format(struct lvmcache_info *info, const struct format_type *fmt); void lvmcache_del_mdas(struct lvmcache_info *info); void lvmcache_del_das(struct lvmcache_info *info); int lvmcache_add_mda(struct lvmcache_info *info, struct device *dev, uint64_t start, uint64_t size, unsigned ignored); int lvmcache_add_da(struct lvmcache_info *info, uint64_t start, uint64_t size); const struct format_type *lvmcache_fmt(struct lvmcache_info *info); struct label *lvmcache_get_label(struct lvmcache_info *info); void lvmcache_update_pv(struct lvmcache_info *info, struct physical_volume *pv, const struct format_type *fmt); int lvmcache_update_das(struct lvmcache_info *info, struct physical_volume *pv); int lvmcache_foreach_mda(struct lvmcache_info *info, int (*fun)(struct metadata_area *, void *), void *baton); int lvmcache_foreach_da(struct lvmcache_info *info, int (*fun)(struct disk_locn *, void *), void *baton); int lvmcache_foreach_pv(struct lvmcache_vginfo *vg, int (*fun)(struct lvmcache_info *, void *), void * baton); uint64_t lvmcache_device_size(struct lvmcache_info *info); void lvmcache_set_device_size(struct lvmcache_info *info, uint64_t size); struct device *lvmcache_device(struct lvmcache_info *info); void lvmcache_make_valid(struct lvmcache_info *info); int lvmcache_is_orphan(struct lvmcache_info *info); int lvmcache_uncertain_ownership(struct lvmcache_info *info); int lvmcache_mda_count(struct lvmcache_info *info); int lvmcache_vgid_is_cached(const char *vgid); int lvmcache_smallest_mda_size(struct lvmcache_info *info); #endif lvm2-2.02.98/lib/cache/lvmetad.c0000640000175000017500000005377712037016272015144 0ustar blankblank/* * Copyright (C) 2012 Red Hat, Inc. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU Lesser General Public License v.2.1. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "lib.h" #include "toolcontext.h" #include "metadata.h" #include "device.h" #include "lvmetad.h" #include "lvmcache.h" #include "lvmetad-client.h" #include "format-text.h" // TODO for disk_locn, used as a DA representation #include "assert.h" #include "crc.h" static daemon_handle _lvmetad; static int _lvmetad_use = 0; static int _lvmetad_connected = 0; static char *_lvmetad_token = NULL; static const char *_lvmetad_socket = NULL; static struct cmd_context *_lvmetad_cmd = NULL; void lvmetad_disconnect(void) { daemon_close(_lvmetad); _lvmetad_connected = 0; _lvmetad_cmd = NULL; } void lvmetad_init(struct cmd_context *cmd) { if (!_lvmetad_use && !access(LVMETAD_PIDFILE, F_OK)) log_warn("WARNING: lvmetad is running but disabled. Restart lvmetad before enabling it!"); if (_lvmetad_use && _lvmetad_socket && !_lvmetad_connected) { assert(_lvmetad_socket); _lvmetad = lvmetad_open(_lvmetad_socket); if (_lvmetad.socket_fd >= 0 && !_lvmetad.error) { _lvmetad_connected = 1; _lvmetad_cmd = cmd; } } } void lvmetad_warning(void) { if (_lvmetad_use && (_lvmetad.socket_fd < 0 || _lvmetad.error)) log_warn("WARNING: Failed to connect to lvmetad: %s. Falling back to internal scanning.", strerror(_lvmetad.error)); } int lvmetad_active(void) { return _lvmetad_use && _lvmetad_connected; } void lvmetad_set_active(int active) { _lvmetad_use = active; } void lvmetad_set_token(const struct dm_config_value *filter) { int ft = 0; if (_lvmetad_token) dm_free(_lvmetad_token); while (filter && filter->type == DM_CFG_STRING) { ft = calc_crc(ft, (const uint8_t *) filter->v.str, strlen(filter->v.str)); filter = filter->next; } if (!dm_asprintf(&_lvmetad_token, "filter:%u", ft)) log_warn("WARNING: Failed to set lvmetad token. Out of memory?"); } void lvmetad_release_token(void) { dm_free(_lvmetad_token); _lvmetad_token = NULL; } void lvmetad_set_socket(const char *sock) { _lvmetad_socket = sock; } static daemon_reply _lvmetad_send(const char *id, ...); static int _token_update(void) { daemon_reply repl = _lvmetad_send("token_update", NULL); if (repl.error || strcmp(daemon_reply_str(repl, "response", ""), "OK")) { daemon_reply_destroy(repl); return 0; } daemon_reply_destroy(repl); return 1; } static daemon_reply _lvmetad_send(const char *id, ...) { va_list ap; daemon_reply repl; daemon_request req; int try = 0; retry: req = daemon_request_make(id); if (_lvmetad_token) daemon_request_extend(req, "token = %s", _lvmetad_token, NULL); va_start(ap, id); daemon_request_extend_v(req, ap); va_end(ap); repl = daemon_send(_lvmetad, req); daemon_request_destroy(req); if (!repl.error && !strcmp(daemon_reply_str(repl, "response", ""), "token_mismatch") && try < 2 && !test_mode()) { if (lvmetad_pvscan_all_devs(_lvmetad_cmd, NULL)) { ++ try; daemon_reply_destroy(repl); goto retry; } } return repl; } /* * Helper; evaluate the reply from lvmetad, check for errors, print diagnostics * and return a summary success/failure exit code. * * If found is set, *found indicates whether or not device exists, * and missing device is not treated as an error. */ static int _lvmetad_handle_reply(daemon_reply reply, const char *action, const char *object, int *found) { if (reply.error) { log_error("Request to %s %s%sin lvmetad gave response %s.", action, object, *object ? " " : "", strerror(reply.error)); return 0; } /* All OK? */ if (!strcmp(daemon_reply_str(reply, "response", ""), "OK")) { if (found) *found = 1; return 1; } /* Unknown device permitted? */ if (found && !strcmp(daemon_reply_str(reply, "response", ""), "unknown")) { log_very_verbose("Request to %s %s%sin lvmetad did not find object.", action, object, *object ? " " : ""); *found = 0; return 1; } log_error("Request to %s %s%sin lvmetad gave response %s. Reason: %s", action, object, *object ? " " : "", daemon_reply_str(reply, "response", ""), daemon_reply_str(reply, "reason", "")); return 0; } static int _read_mda(struct lvmcache_info *info, struct format_type *fmt, const struct dm_config_node *cn) { struct metadata_area_ops *ops; dm_list_iterate_items(ops, &fmt->mda_ops) if (ops->mda_import_text && ops->mda_import_text(info, cn)) return 1; return 0; } static struct lvmcache_info *_pv_populate_lvmcache( struct cmd_context *cmd, struct dm_config_node *cn, dev_t fallback) { struct device *device; struct id pvid, vgid; char mda_id[32]; char da_id[32]; int i = 0; struct dm_config_node *mda = NULL; struct dm_config_node *da = NULL; uint64_t offset, size; struct lvmcache_info *info; const char *pvid_txt = dm_config_find_str(cn->child, "id", NULL), *vgid_txt = dm_config_find_str(cn->child, "vgid", NULL), *vgname = dm_config_find_str(cn->child, "vgname", NULL), *fmt_name = dm_config_find_str(cn->child, "format", NULL); dev_t devt = dm_config_find_int(cn->child, "device", 0); uint64_t devsize = dm_config_find_int64(cn->child, "dev_size", 0), label_sector = dm_config_find_int64(cn->child, "label_sector", 0); struct format_type *fmt = fmt_name ? get_format_by_name(cmd, fmt_name) : NULL; if (!fmt) { log_error("PV %s not recognised. Is the device missing?", pvid_txt); return NULL; } device = dev_cache_get_by_devt(devt, cmd->filter); if (!device && fallback) device = dev_cache_get_by_devt(fallback, cmd->filter); if (!device) { log_error("No device found for PV %s.", pvid_txt); return NULL; } if (!pvid_txt || !id_read_format(&pvid, pvid_txt)) { log_error("Missing or ill-formatted PVID for PV: %s.", pvid_txt); return NULL; } if (vgid_txt) id_read_format(&vgid, vgid_txt); else strcpy((char*)&vgid, fmt->orphan_vg_name); if (!vgname) vgname = fmt->orphan_vg_name; if (!(info = lvmcache_add(fmt->labeller, (const char *)&pvid, device, vgname, (const char *)&vgid, 0))) return_NULL; lvmcache_get_label(info)->sector = label_sector; lvmcache_set_device_size(info, devsize); lvmcache_del_das(info); lvmcache_del_mdas(info); do { sprintf(mda_id, "mda%d", i); mda = dm_config_find_node(cn->child, mda_id); if (mda) _read_mda(info, fmt, mda); ++i; } while (mda); i = 0; do { sprintf(da_id, "da%d", i); da = dm_config_find_node(cn->child, da_id); if (da) { if (!dm_config_get_uint64(da->child, "offset", &offset)) return_0; if (!dm_config_get_uint64(da->child, "size", &size)) return_0; lvmcache_add_da(info, offset, size); } ++i; } while (da); return info; } struct volume_group *lvmetad_vg_lookup(struct cmd_context *cmd, const char *vgname, const char *vgid) { struct volume_group *vg = NULL; daemon_reply reply; char uuid[64]; struct format_instance *fid; struct format_instance_ctx fic; struct dm_config_node *top; const char *name; const char *fmt_name; struct format_type *fmt; struct dm_config_node *pvcn; struct pv_list *pvl; struct lvmcache_info *info; if (!lvmetad_active()) return NULL; if (vgid) { if (!id_write_format((const struct id*)vgid, uuid, sizeof(uuid))) return_NULL; reply = _lvmetad_send("vg_lookup", "uuid = %s", uuid, NULL); } else { if (!vgname) log_error(INTERNAL_ERROR "VG name required (VGID not available)"); reply = _lvmetad_send("vg_lookup", "name = %s", vgname, NULL); } if (!reply.error && !strcmp(daemon_reply_str(reply, "response", ""), "OK")) { if (!(top = dm_config_find_node(reply.cft->root, "metadata"))) { log_error(INTERNAL_ERROR "metadata config node not found."); goto out; } name = daemon_reply_str(reply, "name", NULL); /* fall back to lvm2 if we don't know better */ fmt_name = dm_config_find_str(top, "metadata/format", "lvm2"); if (!(fmt = get_format_by_name(cmd, fmt_name))) { log_error(INTERNAL_ERROR "We do not know the format (%s) reported by lvmetad.", fmt_name); goto out; } fic.type = FMT_INSTANCE_MDAS | FMT_INSTANCE_AUX_MDAS; fic.context.vg_ref.vg_name = name; fic.context.vg_ref.vg_id = vgid; if (!(fid = fmt->ops->create_instance(fmt, &fic))) goto_out; if ((pvcn = dm_config_find_node(top, "metadata/physical_volumes"))) for (pvcn = pvcn->child; pvcn; pvcn = pvcn->sib) _pv_populate_lvmcache(cmd, pvcn, 0); top->key = name; if (!(vg = import_vg_from_config_tree(reply.cft, fid))) goto_out; dm_list_iterate_items(pvl, &vg->pvs) { if ((info = lvmcache_info_from_pvid((const char *)&pvl->pv->id, 0))) { pvl->pv->label_sector = lvmcache_get_label(info)->sector; pvl->pv->dev = lvmcache_device(info); if (!lvmcache_fid_add_mdas_pv(info, fid)) { vg = NULL; goto_out; /* FIXME error path */ } } /* else probably missing */ } lvmcache_update_vg(vg, 0); } out: daemon_reply_destroy(reply); return vg; } struct _fixup_baton { int i; int find; int ignore; }; static int _fixup_ignored(struct metadata_area *mda, void *baton) { struct _fixup_baton *b = baton; if (b->i == b->find) mda_set_ignored(mda, b->ignore); b->i ++; return 1; } static struct dm_config_tree *_export_vg_to_config_tree(struct volume_group *vg) { char *buf = NULL; struct dm_config_tree *vgmeta; if (!export_vg_to_buffer(vg, &buf)) { log_error("Could not format VG metadata."); return 0; } if (!(vgmeta = dm_config_from_string(buf))) { log_error("Error parsing VG metadata."); dm_free(buf); return 0; } dm_free(buf); return vgmeta; } int lvmetad_vg_update(struct volume_group *vg) { daemon_reply reply; struct dm_hash_node *n; struct metadata_area *mda; char mda_id[128], *num; struct pv_list *pvl; struct lvmcache_info *info; struct _fixup_baton baton; struct dm_config_tree *vgmeta; if (!vg) return 0; if (!lvmetad_active() || test_mode()) return 1; /* fake it */ if (!(vgmeta = _export_vg_to_config_tree(vg))) return_0; reply = _lvmetad_send("vg_update", "vgname = %s", vg->name, "metadata = %t", vgmeta, NULL); dm_config_destroy(vgmeta); if (!_lvmetad_handle_reply(reply, "update VG", vg->name, NULL)) { daemon_reply_destroy(reply); return 0; } daemon_reply_destroy(reply); n = (vg->fid && vg->fid->metadata_areas_index) ? dm_hash_get_first(vg->fid->metadata_areas_index) : NULL; while (n) { mda = dm_hash_get_data(vg->fid->metadata_areas_index, n); strcpy(mda_id, dm_hash_get_key(vg->fid->metadata_areas_index, n)); if ((num = strchr(mda_id, '_'))) { *num = 0; ++num; if ((info = lvmcache_info_from_pvid(mda_id, 0))) { memset(&baton, 0, sizeof(baton)); baton.find = atoi(num); baton.ignore = mda_is_ignored(mda); lvmcache_foreach_mda(info, _fixup_ignored, &baton); } } n = dm_hash_get_next(vg->fid->metadata_areas_index, n); } dm_list_iterate_items(pvl, &vg->pvs) { /* NB. the PV fmt pointer is sometimes wrong during vgconvert */ if (pvl->pv->dev && !lvmetad_pv_found(&pvl->pv->id, pvl->pv->dev, vg->fid ? vg->fid->fmt : pvl->pv->fmt, pvl->pv->label_sector, NULL, NULL)) return 0; } return 1; } int lvmetad_vg_remove(struct volume_group *vg) { char uuid[64]; daemon_reply reply; int result; if (!lvmetad_active() || test_mode()) return 1; /* just fake it */ if (!id_write_format(&vg->id, uuid, sizeof(uuid))) return_0; reply = _lvmetad_send("vg_remove", "uuid = %s", uuid, NULL); result = _lvmetad_handle_reply(reply, "remove VG", vg->name, NULL); daemon_reply_destroy(reply); return result; } int lvmetad_pv_lookup(struct cmd_context *cmd, struct id pvid, int *found) { char uuid[64]; daemon_reply reply; int result = 0; struct dm_config_node *cn; if (!lvmetad_active()) return_0; if (!id_write_format(&pvid, uuid, sizeof(uuid))) return_0; reply = _lvmetad_send("pv_lookup", "uuid = %s", uuid, NULL); if (!_lvmetad_handle_reply(reply, "lookup PV", "", found)) goto_out; if (found && !*found) goto out_success; if (!(cn = dm_config_find_node(reply.cft->root, "physical_volume"))) goto_out; else if (!_pv_populate_lvmcache(cmd, cn, 0)) goto_out; out_success: result = 1; out: daemon_reply_destroy(reply); return result; } int lvmetad_pv_lookup_by_dev(struct cmd_context *cmd, struct device *dev, int *found) { int result = 0; daemon_reply reply; struct dm_config_node *cn; if (!lvmetad_active()) return_0; reply = _lvmetad_send("pv_lookup", "device = %" PRId64, (int64_t) dev->dev, NULL); if (!_lvmetad_handle_reply(reply, "lookup PV", dev_name(dev), found)) goto_out; if (found && !*found) goto out_success; cn = dm_config_find_node(reply.cft->root, "physical_volume"); if (!cn || !_pv_populate_lvmcache(cmd, cn, dev->dev)) goto_out; out_success: result = 1; out: daemon_reply_destroy(reply); return result; } int lvmetad_pv_list_to_lvmcache(struct cmd_context *cmd) { daemon_reply reply; struct dm_config_node *cn; if (!lvmetad_active()) return 1; reply = _lvmetad_send("pv_list", NULL); if (!_lvmetad_handle_reply(reply, "list PVs", "", NULL)) { daemon_reply_destroy(reply); return_0; } if ((cn = dm_config_find_node(reply.cft->root, "physical_volumes"))) for (cn = cn->child; cn; cn = cn->sib) _pv_populate_lvmcache(cmd, cn, 0); daemon_reply_destroy(reply); return 1; } int lvmetad_vg_list_to_lvmcache(struct cmd_context *cmd) { struct volume_group *tmp; struct id vgid; const char *vgid_txt; daemon_reply reply; struct dm_config_node *cn; if (!lvmetad_active()) return 1; reply = _lvmetad_send("vg_list", NULL); if (!_lvmetad_handle_reply(reply, "list VGs", "", NULL)) { daemon_reply_destroy(reply); return_0; } if ((cn = dm_config_find_node(reply.cft->root, "volume_groups"))) for (cn = cn->child; cn; cn = cn->sib) { vgid_txt = cn->key; if (!id_read_format(&vgid, vgid_txt)) { stack; continue; } /* the call to lvmetad_vg_lookup will poke the VG into lvmcache */ tmp = lvmetad_vg_lookup(cmd, NULL, (const char*)&vgid); release_vg(tmp); } daemon_reply_destroy(reply); return 1; } struct _extract_mda_baton { int i; struct dm_config_tree *cft; struct dm_config_node *pre_sib; }; static int _extract_mda(struct metadata_area *mda, void *baton) { struct _extract_mda_baton *b = baton; struct dm_config_node *cn; char id[32]; if (!mda->ops->mda_export_text) /* do nothing */ return 1; dm_snprintf(id, 32, "mda%d", b->i); if (!(cn = make_config_node(b->cft, id, b->cft->root, b->pre_sib))) return 0; if (!mda->ops->mda_export_text(mda, b->cft, cn)) return 0; b->i ++; b->pre_sib = cn; /* for efficiency */ return 1; } static int _extract_da(struct disk_locn *da, void *baton) { struct _extract_mda_baton *b = baton; struct dm_config_node *cn; char id[32]; if (!da) return 1; dm_snprintf(id, 32, "da%d", b->i); if (!(cn = make_config_node(b->cft, id, b->cft->root, b->pre_sib))) return 0; if (!config_make_nodes(b->cft, cn, NULL, "offset = %"PRId64, (int64_t) da->offset, "size = %"PRId64, (int64_t) da->size, NULL)) return 0; b->i ++; b->pre_sib = cn; /* for efficiency */ return 1; } static int _extract_mdas(struct lvmcache_info *info, struct dm_config_tree *cft, struct dm_config_node *pre_sib) { struct _extract_mda_baton baton = { .i = 0, .cft = cft, .pre_sib = NULL }; if (!lvmcache_foreach_mda(info, &_extract_mda, &baton)) return 0; baton.i = 0; if (!lvmcache_foreach_da(info, &_extract_da, &baton)) return 0; return 1; } int lvmetad_pv_found(const struct id *pvid, struct device *device, const struct format_type *fmt, uint64_t label_sector, struct volume_group *vg, activation_handler handler) { char uuid[64]; daemon_reply reply; struct lvmcache_info *info; struct dm_config_tree *pvmeta, *vgmeta; const char *status; int result; if (!lvmetad_active() || test_mode()) return 1; if (!id_write_format(pvid, uuid, sizeof(uuid))) return_0; pvmeta = dm_config_create(); if (!pvmeta) return_0; info = lvmcache_info_from_pvid((const char *)pvid, 0); if (!(pvmeta->root = make_config_node(pvmeta, "pv", NULL, NULL))) { dm_config_destroy(pvmeta); return_0; } if (!config_make_nodes(pvmeta, pvmeta->root, NULL, "device = %"PRId64, (int64_t) device->dev, "dev_size = %"PRId64, (int64_t) (info ? lvmcache_device_size(info) : 0), "format = %s", fmt->name, "label_sector = %"PRId64, (int64_t) label_sector, "id = %s", uuid, NULL)) { dm_config_destroy(pvmeta); return_0; } if (info) /* FIXME A more direct route would be much preferable. */ _extract_mdas(info, pvmeta, pvmeta->root); if (vg) { if (!(vgmeta = _export_vg_to_config_tree(vg))) { dm_config_destroy(pvmeta); return_0; } reply = _lvmetad_send("pv_found", "pvmeta = %t", pvmeta, "vgname = %s", vg->name, "metadata = %t", vgmeta, NULL); dm_config_destroy(vgmeta); } else { if (handler) { log_error(INTERNAL_ERROR "Handler needs existing VG."); dm_free(pvmeta); return 0; } /* There are no MDAs on this PV. */ reply = _lvmetad_send("pv_found", "pvmeta = %t", pvmeta, NULL); } dm_config_destroy(pvmeta); result = _lvmetad_handle_reply(reply, "update PV", uuid, NULL); if (vg && result && (daemon_reply_int(reply, "seqno_after", -1) != vg->seqno || daemon_reply_int(reply, "seqno_after", -1) != daemon_reply_int(reply, "seqno_before", -1))) log_warn("WARNING: Inconsistent metadata found for VG %s", vg->name); if (result && handler) { status = daemon_reply_str(reply, "status", ""); if (!strcmp(status, "partial")) handler(vg, 1, CHANGE_AAY); else if (!strcmp(status, "complete")) handler(vg, 0, CHANGE_AAY); else if (!strcmp(status, "orphan")) ; else log_error("Request to %s %s in lvmetad gave status %s.", "update PV", uuid, status); } daemon_reply_destroy(reply); return result; } int lvmetad_pv_gone(dev_t device, const char *pv_name, activation_handler handler) { daemon_reply reply; int result; int found; if (!lvmetad_active() || test_mode()) return 1; /* * TODO: automatic volume deactivation takes place here *before* * all cached info is gone - call handler. Also, consider * integrating existing deactivation script that deactivates * the whole stack from top to bottom (not yet upstream). */ reply = _lvmetad_send("pv_gone", "device = %" PRId64, (int64_t) device, NULL); result = _lvmetad_handle_reply(reply, "drop PV", pv_name, &found); /* We don't care whether or not the daemon had the PV cached. */ daemon_reply_destroy(reply); return result; } int lvmetad_pv_gone_by_dev(struct device *dev, activation_handler handler) { return lvmetad_pv_gone(dev->dev, dev_name(dev), handler); } /* * The following code implements pvscan --cache. */ struct _lvmetad_pvscan_baton { struct volume_group *vg; struct format_instance *fid; }; static int _lvmetad_pvscan_single(struct metadata_area *mda, void *baton) { struct _lvmetad_pvscan_baton *b = baton; struct volume_group *this = mda->ops->vg_read(b->fid, "", mda, 1); /* FIXME Also ensure contents match etc. */ if (!b->vg || this->seqno > b->vg->seqno) b->vg = this; else if (b->vg) release_vg(this); return 1; } int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev, activation_handler handler) { struct label *label; struct lvmcache_info *info; struct _lvmetad_pvscan_baton baton; /* Create a dummy instance. */ struct format_instance_ctx fic = { .type = 0 }; if (!lvmetad_active()) { log_error("Cannot proceed since lvmetad is not active."); return 0; } if (!label_read(dev, &label, 0)) { log_print_unless_silent("No PV label found on %s.", dev_name(dev)); if (!lvmetad_pv_gone_by_dev(dev, handler)) goto_bad; return 1; } info = (struct lvmcache_info *) label->info; baton.vg = NULL; baton.fid = lvmcache_fmt(info)->ops->create_instance(lvmcache_fmt(info), &fic); if (!baton.fid) goto_bad; lvmcache_foreach_mda(info, _lvmetad_pvscan_single, &baton); /* LVM1 VGs have no MDAs. */ if (!baton.vg && lvmcache_fmt(info) == get_format_by_name(cmd, "lvm1")) baton.vg = ((struct metadata_area *) dm_list_first(&baton.fid->metadata_areas_in_use))-> ops->vg_read(baton.fid, lvmcache_vgname_from_info(info), NULL, 0); if (!baton.vg) lvmcache_fmt(info)->ops->destroy_instance(baton.fid); /* * NB. If this command failed and we are relying on lvmetad to have an * *exact* image of the system, the lvmetad instance that went out of * sync needs to be killed. */ if (!lvmetad_pv_found((const struct id *) &dev->pvid, dev, lvmcache_fmt(info), label->sector, baton.vg, handler)) { release_vg(baton.vg); goto_bad; } release_vg(baton.vg); return 1; bad: /* FIXME kill lvmetad automatically if we can */ log_error("Update of lvmetad failed. This is a serious problem.\n " "It is strongly recommended that you restart lvmetad immediately."); return 0; } int lvmetad_pvscan_all_devs(struct cmd_context *cmd, activation_handler handler) { struct dev_iter *iter; struct device *dev; daemon_reply reply; int r = 1; char *future_token; int was_silent; if (!(iter = dev_iter_create(cmd->lvmetad_filter, 1))) { log_error("dev_iter creation failed"); return 0; } future_token = _lvmetad_token; _lvmetad_token = (char *) "update in progress"; if (!_token_update()) { dev_iter_destroy(iter); _lvmetad_token = future_token; return 0; } reply = _lvmetad_send("pv_clear_all", NULL); if (!_lvmetad_handle_reply(reply, "clear status on all PVs", "", NULL)) r = 0; daemon_reply_destroy(reply); was_silent = silent_mode(); init_silent(1); while ((dev = dev_iter_get(iter))) { if (!lvmetad_pvscan_single(cmd, dev, handler)) r = 0; if (sigint_caught()) break; } init_silent(was_silent); dev_iter_destroy(iter); _lvmetad_token = future_token; if (!_token_update()) return 0; return r; } lvm2-2.02.98/lib/cache/lvmcache.c0000640000175000017500000013571312037016272015261 0ustar blankblank/* * 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 "lvmcache.h" #include "toolcontext.h" #include "dev-cache.h" #include "locking.h" #include "metadata.h" #include "filter.h" #include "filter-persistent.h" #include "memlock.h" #include "str_list.h" #include "format-text.h" #include "format_pool.h" #include "format1.h" #include "config.h" #include "lvmetad.h" #define CACHE_INVALID 0x00000001 #define CACHE_LOCKED 0x00000002 /* 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; }; /* 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; size_t vgmetadata_size; char *vgmetadata; /* Copy of VG metadata as format_text string */ struct dm_config_tree *cft; /* Config tree created from vgmetadata */ /* Lifetime is directly tied to vgmetadata */ struct volume_group *cached_vg; unsigned holders; unsigned vg_use_count; /* Counter of vg reusage */ unsigned precommitted; /* Is vgmetadata live or precommitted? */ }; static struct dm_hash_table *_pvid_hash = NULL; static struct dm_hash_table *_vgid_hash = NULL; static struct dm_hash_table *_vgname_hash = NULL; static struct dm_hash_table *_lock_hash = NULL; static DM_LIST_INIT(_vginfos); static int _scanning_in_progress = 0; static int _has_scanned = 0; static int _vgs_locked = 0; static int _vg_global_lock_held = 0; /* Global lock held when cache wiped? */ int lvmcache_init(void) { /* * FIXME add a proper lvmcache_locking_reset() that * resets the cache so no previous locks are locked */ _vgs_locked = 0; dm_list_init(&_vginfos); if (!(_vgname_hash = dm_hash_create(128))) return 0; if (!(_vgid_hash = dm_hash_create(128))) return 0; if (!(_pvid_hash = dm_hash_create(128))) return 0; if (!(_lock_hash = dm_hash_create(128))) return 0; /* * Reinitialising the cache clears the internal record of * which locks are held. The global lock can be held during * this operation so its state must be restored afterwards. */ if (_vg_global_lock_held) { lvmcache_lock_vgname(VG_GLOBAL, 0); _vg_global_lock_held = 0; } return 1; } void lvmcache_seed_infos_from_lvmetad(struct cmd_context *cmd) { if (!lvmetad_active() || _has_scanned) return; if (!lvmetad_pv_list_to_lvmcache(cmd)) { stack; return; } _has_scanned = 1; } /* Volume Group metadata cache functions */ static void _free_cached_vgmetadata(struct lvmcache_vginfo *vginfo) { if (!vginfo || !vginfo->vgmetadata) return; dm_free(vginfo->vgmetadata); vginfo->vgmetadata = NULL; /* Release also cached config tree */ if (vginfo->cft) { dm_config_destroy(vginfo->cft); vginfo->cft = NULL; } log_debug("Metadata cache: VG %s wiped.", vginfo->vgname); release_vg(vginfo->cached_vg); } /* * Cache VG metadata against the vginfo with matching vgid. */ static void _store_metadata(struct volume_group *vg, unsigned precommitted) { char uuid[64] __attribute__((aligned(8))); struct lvmcache_vginfo *vginfo; char *data; size_t size; if (!(vginfo = lvmcache_vginfo_from_vgid((const char *)&vg->id))) { stack; return; } if (!(size = export_vg_to_buffer(vg, &data))) { stack; _free_cached_vgmetadata(vginfo); return; } /* Avoid reparsing of the same data string */ if (vginfo->vgmetadata && vginfo->vgmetadata_size == size && strcmp(vginfo->vgmetadata, data) == 0) dm_free(data); else { _free_cached_vgmetadata(vginfo); vginfo->vgmetadata_size = size; vginfo->vgmetadata = data; } vginfo->precommitted = precommitted; if (!id_write_format((const struct id *)vginfo->vgid, uuid, sizeof(uuid))) { stack; return; } log_debug("Metadata cache: VG %s (%s) stored (%" PRIsize_t " bytes%s).", vginfo->vgname, uuid, size, precommitted ? ", precommitted" : ""); } static void _update_cache_info_lock_state(struct lvmcache_info *info, int locked, int *cached_vgmetadata_valid) { int was_locked = (info->status & CACHE_LOCKED) ? 1 : 0; /* * Cache becomes invalid whenever lock state changes unless * exclusive VG_GLOBAL is held (i.e. while scanning). */ if (!lvmcache_vgname_is_locked(VG_GLOBAL) && (was_locked != locked)) { info->status |= CACHE_INVALID; *cached_vgmetadata_valid = 0; } if (locked) info->status |= CACHE_LOCKED; else info->status &= ~CACHE_LOCKED; } static void _update_cache_vginfo_lock_state(struct lvmcache_vginfo *vginfo, int locked) { struct lvmcache_info *info; int cached_vgmetadata_valid = 1; dm_list_iterate_items(info, &vginfo->infos) _update_cache_info_lock_state(info, locked, &cached_vgmetadata_valid); if (!cached_vgmetadata_valid) _free_cached_vgmetadata(vginfo); } static void _update_cache_lock_state(const char *vgname, int locked) { struct lvmcache_vginfo *vginfo; if (!(vginfo = lvmcache_vginfo_from_vgname(vgname, NULL))) return; _update_cache_vginfo_lock_state(vginfo, locked); } static void _drop_metadata(const char *vgname, int drop_precommitted) { struct lvmcache_vginfo *vginfo; struct lvmcache_info *info; if (!(vginfo = lvmcache_vginfo_from_vgname(vgname, NULL))) return; /* * Invalidate cached PV labels. * If cached precommitted metadata exists that means we * already invalidated the PV labels (before caching it) * and we must not do it again. */ if (!drop_precommitted && vginfo->precommitted && !vginfo->vgmetadata) log_error(INTERNAL_ERROR "metadata commit (or revert) missing before " "dropping metadata from cache."); if (drop_precommitted || !vginfo->precommitted) dm_list_iterate_items(info, &vginfo->infos) info->status |= CACHE_INVALID; _free_cached_vgmetadata(vginfo); /* VG revert */ if (drop_precommitted) vginfo->precommitted = 0; } /* * Remote node uses this to upgrade precommited metadata to commited state * when receives vg_commit notification. * (Note that devices can be suspended here, if so, precommited metadata are already read.) */ void lvmcache_commit_metadata(const char *vgname) { struct lvmcache_vginfo *vginfo; if (!(vginfo = lvmcache_vginfo_from_vgname(vgname, NULL))) return; if (vginfo->precommitted) { log_debug("Precommitted metadata cache: VG %s upgraded to committed.", vginfo->vgname); vginfo->precommitted = 0; } } void lvmcache_drop_metadata(const char *vgname, int drop_precommitted) { /* For VG_ORPHANS, we need to invalidate all labels on orphan PVs. */ if (!strcmp(vgname, VG_ORPHANS)) { _drop_metadata(FMT_TEXT_ORPHAN_VG_NAME, 0); _drop_metadata(FMT_LVM1_ORPHAN_VG_NAME, 0); _drop_metadata(FMT_POOL_ORPHAN_VG_NAME, 0); /* Indicate that PVs could now be missing from the cache */ init_full_scan_done(0); } else if (!lvmcache_vgname_is_locked(VG_GLOBAL)) _drop_metadata(vgname, drop_precommitted); } /* * Ensure vgname2 comes after vgname1 alphabetically. * Orphan locks come last. * VG_GLOBAL comes first. */ static int _vgname_order_correct(const char *vgname1, const char *vgname2) { if (is_global_vg(vgname1)) return 1; if (is_global_vg(vgname2)) return 0; if (is_orphan_vg(vgname1)) return 0; if (is_orphan_vg(vgname2)) return 1; if (strcmp(vgname1, vgname2) < 0) return 1; return 0; } /* * Ensure VG locks are acquired in alphabetical order. */ int lvmcache_verify_lock_order(const char *vgname) { struct dm_hash_node *n; const char *vgname2; if (!_lock_hash) return_0; dm_hash_iterate(n, _lock_hash) { if (!dm_hash_get_data(_lock_hash, n)) return_0; if (!(vgname2 = dm_hash_get_key(_lock_hash, n))) { log_error(INTERNAL_ERROR "VG lock %s hits NULL.", vgname); return 0; } if (!_vgname_order_correct(vgname2, vgname)) { log_errno(EDEADLK, INTERNAL_ERROR "VG lock %s must " "be requested before %s, not after.", vgname, vgname2); return 0; } } return 1; } void lvmcache_lock_vgname(const char *vgname, int read_only __attribute__((unused))) { if (!_lock_hash && !lvmcache_init()) { log_error("Internal cache initialisation failed"); return; } if (dm_hash_lookup(_lock_hash, vgname)) log_error(INTERNAL_ERROR "Nested locking attempted on VG %s.", vgname); if (!dm_hash_insert(_lock_hash, vgname, (void *) 1)) log_error("Cache locking failure for %s", vgname); _update_cache_lock_state(vgname, 1); if (strcmp(vgname, VG_GLOBAL)) _vgs_locked++; } int lvmcache_vgname_is_locked(const char *vgname) { if (!_lock_hash) return 0; return dm_hash_lookup(_lock_hash, is_orphan_vg(vgname) ? VG_ORPHANS : vgname) ? 1 : 0; } void lvmcache_unlock_vgname(const char *vgname) { if (!dm_hash_lookup(_lock_hash, vgname)) log_error(INTERNAL_ERROR "Attempt to unlock unlocked VG %s.", vgname); _update_cache_lock_state(vgname, 0); dm_hash_remove(_lock_hash, vgname); /* FIXME Do this per-VG */ if (strcmp(vgname, VG_GLOBAL) && !--_vgs_locked) dev_close_all(); } int lvmcache_vgs_locked(void) { return _vgs_locked; } static void _vginfo_attach_info(struct lvmcache_vginfo *vginfo, struct lvmcache_info *info) { if (!vginfo) return; info->vginfo = vginfo; dm_list_add(&vginfo->infos, &info->list); } static void _vginfo_detach_info(struct lvmcache_info *info) { if (!dm_list_empty(&info->list)) { dm_list_del(&info->list); dm_list_init(&info->list); } info->vginfo = NULL; } /* If vgid supplied, require a match. */ struct lvmcache_vginfo *lvmcache_vginfo_from_vgname(const char *vgname, const char *vgid) { struct lvmcache_vginfo *vginfo; if (!vgname) return lvmcache_vginfo_from_vgid(vgid); if (!_vgname_hash) return NULL; if (!(vginfo = dm_hash_lookup(_vgname_hash, vgname))) return NULL; if (vgid) do if (!strncmp(vgid, vginfo->vgid, ID_LEN)) return vginfo; while ((vginfo = vginfo->next)); return vginfo; } const struct format_type *lvmcache_fmt_from_vgname(struct cmd_context *cmd, const char *vgname, const char *vgid, unsigned revalidate_labels) { struct lvmcache_vginfo *vginfo; struct lvmcache_info *info; struct label *label; struct dm_list *devh, *tmp; struct dm_list devs; struct device_list *devl; struct volume_group *vg; const struct format_type *fmt; char vgid_found[ID_LEN + 1] __attribute__((aligned(8))); if (!(vginfo = lvmcache_vginfo_from_vgname(vgname, vgid))) { if (!lvmetad_active()) return NULL; /* too bad */ /* If we don't have the info but we have lvmetad, we can ask * there before failing. */ if ((vg = lvmetad_vg_lookup(cmd, vgname, vgid))) { fmt = vg->fid->fmt; release_vg(vg); return fmt; } return NULL; } /* * If this function is called repeatedly, only the first one needs to revalidate. */ if (!revalidate_labels) goto out; /* * This function is normally called before reading metadata so * we check cached labels here. Unfortunately vginfo is volatile. */ dm_list_init(&devs); dm_list_iterate_items(info, &vginfo->infos) { if (!(devl = dm_malloc(sizeof(*devl)))) { log_error("device_list element allocation failed"); return NULL; } devl->dev = info->dev; dm_list_add(&devs, &devl->list); } memcpy(vgid_found, vginfo->vgid, sizeof(vgid_found)); dm_list_iterate_safe(devh, tmp, &devs) { devl = dm_list_item(devh, struct device_list); (void) label_read(devl->dev, &label, UINT64_C(0)); dm_list_del(&devl->list); dm_free(devl); } /* If vginfo changed, caller needs to rescan */ if (!(vginfo = lvmcache_vginfo_from_vgname(vgname, vgid_found)) || strncmp(vginfo->vgid, vgid_found, ID_LEN)) return NULL; out: return vginfo->fmt; } struct lvmcache_vginfo *lvmcache_vginfo_from_vgid(const char *vgid) { struct lvmcache_vginfo *vginfo; char id[ID_LEN + 1] __attribute__((aligned(8))); if (!_vgid_hash || !vgid) return NULL; /* vgid not necessarily NULL-terminated */ strncpy(&id[0], vgid, ID_LEN); id[ID_LEN] = '\0'; if (!(vginfo = dm_hash_lookup(_vgid_hash, id))) return NULL; return vginfo; } const char *lvmcache_vgname_from_vgid(struct dm_pool *mem, const char *vgid) { struct lvmcache_vginfo *vginfo; const char *vgname = NULL; if ((vginfo = lvmcache_vginfo_from_vgid(vgid))) vgname = vginfo->vgname; if (mem && vgname) return dm_pool_strdup(mem, vgname); return vgname; } static int _info_is_valid(struct lvmcache_info *info) { if (info->status & CACHE_INVALID) return 0; /* * The caller must hold the VG lock to manipulate metadata. * In a cluster, remote nodes sometimes read metadata in the * knowledge that the controlling node is holding the lock. * So if the VG appears to be unlocked here, it should be safe * to use the cached value. */ if (info->vginfo && !lvmcache_vgname_is_locked(info->vginfo->vgname)) return 1; if (!(info->status & CACHE_LOCKED)) return 0; return 1; } static int _vginfo_is_valid(struct lvmcache_vginfo *vginfo) { struct lvmcache_info *info; /* Invalid if any info is invalid */ dm_list_iterate_items(info, &vginfo->infos) if (!_info_is_valid(info)) return 0; return 1; } /* vginfo is invalid if it does not contain at least one valid info */ static int _vginfo_is_invalid(struct lvmcache_vginfo *vginfo) { struct lvmcache_info *info; dm_list_iterate_items(info, &vginfo->infos) if (_info_is_valid(info)) return 0; return 1; } /* * If valid_only is set, data will only be returned if the cached data is * known still to be valid. */ struct lvmcache_info *lvmcache_info_from_pvid(const char *pvid, int valid_only) { struct lvmcache_info *info; char id[ID_LEN + 1] __attribute__((aligned(8))); if (!_pvid_hash || !pvid) return NULL; strncpy(&id[0], pvid, ID_LEN); id[ID_LEN] = '\0'; if (!(info = dm_hash_lookup(_pvid_hash, id))) return NULL; if (valid_only && !_info_is_valid(info)) return NULL; return info; } const char *lvmcache_vgname_from_info(struct lvmcache_info *info) { if (info->vginfo) return info->vginfo->vgname; return NULL; } char *lvmcache_vgname_from_pvid(struct cmd_context *cmd, const char *pvid) { struct lvmcache_info *info; char *vgname; if (!lvmcache_device_from_pvid(cmd, (const struct id *)pvid, NULL, NULL)) { log_error("Couldn't find device with uuid %s.", pvid); return NULL; } info = lvmcache_info_from_pvid(pvid, 0); if (!info) return_NULL; if (!(vgname = dm_pool_strdup(cmd->mem, info->vginfo->vgname))) { log_errno(ENOMEM, "vgname allocation failed"); return NULL; } return vgname; } static void _rescan_entry(struct lvmcache_info *info) { struct label *label; if (info->status & CACHE_INVALID) (void) label_read(info->dev, &label, UINT64_C(0)); } static int _scan_invalid(void) { dm_hash_iter(_pvid_hash, (dm_hash_iterate_fn) _rescan_entry); return 1; } int lvmcache_label_scan(struct cmd_context *cmd, int full_scan) { struct label *label; struct dev_iter *iter; struct device *dev; struct format_type *fmt; int r = 0; if (lvmetad_active()) return 1; /* Avoid recursion when a PVID can't be found! */ if (_scanning_in_progress) return 0; _scanning_in_progress = 1; if (!_vgname_hash && !lvmcache_init()) { log_error("Internal cache initialisation failed"); goto out; } if (_has_scanned && !full_scan) { r = _scan_invalid(); goto out; } if (full_scan == 2 && (cmd->filter && !cmd->filter->use_count) && !refresh_filters(cmd)) goto_out; if (!cmd->filter || !(iter = dev_iter_create(cmd->filter, (full_scan == 2) ? 1 : 0))) { log_error("dev_iter creation failed"); goto out; } while ((dev = dev_iter_get(iter))) (void) label_read(dev, &label, UINT64_C(0)); dev_iter_destroy(iter); _has_scanned = 1; /* Perform any format-specific scanning e.g. text files */ if (cmd->independent_metadata_areas) dm_list_iterate_items(fmt, &cmd->formats) if (fmt->ops->scan && !fmt->ops->scan(fmt, NULL)) goto out; /* * If we are a long-lived process, write out the updated persistent * device cache for the benefit of short-lived processes. */ if (full_scan == 2 && cmd->is_long_lived && cmd->dump_filter) persistent_filter_dump(cmd->filter, 0); r = 1; out: _scanning_in_progress = 0; return r; } struct volume_group *lvmcache_get_vg(struct cmd_context *cmd, const char *vgname, const char *vgid, unsigned precommitted) { struct lvmcache_vginfo *vginfo; struct volume_group *vg = NULL; struct format_instance *fid; struct format_instance_ctx fic; /* * We currently do not store precommitted metadata in lvmetad at * all. This means that any request for precommitted metadata is served * using the classic scanning mechanics, and read from disk or from * lvmcache. */ if (lvmetad_active() && !precommitted) { /* Still serve the locally cached VG if available */ if (vgid && (vginfo = lvmcache_vginfo_from_vgid(vgid)) && vginfo->vgmetadata && (vg = vginfo->cached_vg)) goto out; return lvmetad_vg_lookup(cmd, vgname, vgid); } if (!vgid || !(vginfo = lvmcache_vginfo_from_vgid(vgid)) || !vginfo->vgmetadata) return NULL; if (!_vginfo_is_valid(vginfo)) return NULL; /* * Don't return cached data if either: * (i) precommitted metadata is requested but we don't have it cached * - caller should read it off disk; * (ii) live metadata is requested but we have precommitted metadata cached * and no devices are suspended so caller may read it off disk. * * If live metadata is requested but we have precommitted metadata cached * and devices are suspended, we assume this precommitted metadata has * already been preloaded and committed so it's OK to return it as live. * Note that we do not clear the PRECOMMITTED flag. */ if ((precommitted && !vginfo->precommitted) || (!precommitted && vginfo->precommitted && !critical_section())) return NULL; /* Use already-cached VG struct when available */ if ((vg = vginfo->cached_vg)) goto out; fic.type = FMT_INSTANCE_MDAS | FMT_INSTANCE_AUX_MDAS; fic.context.vg_ref.vg_name = vginfo->vgname; fic.context.vg_ref.vg_id = vgid; if (!(fid = vginfo->fmt->ops->create_instance(vginfo->fmt, &fic))) return_NULL; /* Build config tree from vgmetadata, if not yet cached */ if (!vginfo->cft && !(vginfo->cft = dm_config_from_string(vginfo->vgmetadata))) goto_bad; if (!(vg = import_vg_from_config_tree(vginfo->cft, fid))) goto_bad; /* Cache VG struct for reuse */ vginfo->cached_vg = vg; vginfo->holders = 1; vginfo->vg_use_count = 0; vg->vginfo = vginfo; if (!dm_pool_lock(vg->vgmem, detect_internal_vg_cache_corruption())) goto_bad; out: vginfo->holders++; vginfo->vg_use_count++; log_debug("Using cached %smetadata for VG %s with %u holder(s).", vginfo->precommitted ? "pre-committed " : "", vginfo->vgname, vginfo->holders); return vg; bad: _free_cached_vgmetadata(vginfo); return NULL; } // #if 0 int lvmcache_vginfo_holders_dec_and_test_for_zero(struct lvmcache_vginfo *vginfo) { log_debug("VG %s decrementing %d holder(s) at %p.", vginfo->cached_vg->name, vginfo->holders, vginfo->cached_vg); if (--vginfo->holders) return 0; if (vginfo->vg_use_count > 1) log_debug("VG %s reused %d times.", vginfo->cached_vg->name, vginfo->vg_use_count); /* Debug perform crc check only when it's been used more then once */ if (!dm_pool_unlock(vginfo->cached_vg->vgmem, detect_internal_vg_cache_corruption() && (vginfo->vg_use_count > 1))) stack; vginfo->cached_vg->vginfo = NULL; vginfo->cached_vg = NULL; return 1; } // #endif struct dm_list *lvmcache_get_vgids(struct cmd_context *cmd, int include_internal) { struct dm_list *vgids; struct lvmcache_vginfo *vginfo; // TODO plug into lvmetad here automagically? lvmcache_label_scan(cmd, 0); if (!(vgids = str_list_create(cmd->mem))) { log_error("vgids list allocation failed"); return NULL; } dm_list_iterate_items(vginfo, &_vginfos) { if (!include_internal && is_orphan_vg(vginfo->vgname)) continue; if (!str_list_add(cmd->mem, vgids, dm_pool_strdup(cmd->mem, vginfo->vgid))) { log_error("strlist allocation failed"); return NULL; } } return vgids; } struct dm_list *lvmcache_get_vgnames(struct cmd_context *cmd, int include_internal) { struct dm_list *vgnames; struct lvmcache_vginfo *vginfo; lvmcache_label_scan(cmd, 0); if (!(vgnames = str_list_create(cmd->mem))) { log_errno(ENOMEM, "vgnames list allocation failed"); return NULL; } dm_list_iterate_items(vginfo, &_vginfos) { if (!include_internal && is_orphan_vg(vginfo->vgname)) continue; if (!str_list_add(cmd->mem, vgnames, dm_pool_strdup(cmd->mem, vginfo->vgname))) { log_errno(ENOMEM, "strlist allocation failed"); return NULL; } } return vgnames; } struct dm_list *lvmcache_get_pvids(struct cmd_context *cmd, const char *vgname, const char *vgid) { struct dm_list *pvids; struct lvmcache_vginfo *vginfo; struct lvmcache_info *info; if (!(pvids = str_list_create(cmd->mem))) { log_error("pvids list allocation failed"); return NULL; } if (!(vginfo = lvmcache_vginfo_from_vgname(vgname, vgid))) return pvids; dm_list_iterate_items(info, &vginfo->infos) { if (!str_list_add(cmd->mem, pvids, dm_pool_strdup(cmd->mem, info->dev->pvid))) { log_error("strlist allocation failed"); return NULL; } } return pvids; } static struct device *_device_from_pvid(const struct id *pvid, uint64_t *label_sector) { struct lvmcache_info *info; struct label *label; if ((info = lvmcache_info_from_pvid((const char *) pvid, 0))) { if (lvmetad_active()) { if (info->label && label_sector) *label_sector = info->label->sector; return info->dev; } if (label_read(info->dev, &label, UINT64_C(0))) { info = (struct lvmcache_info *) label->info; if (id_equal(pvid, (struct id *) &info->dev->pvid)) { if (label_sector) *label_sector = label->sector; return info->dev; } } } return NULL; } struct device *lvmcache_device_from_pvid(struct cmd_context *cmd, const struct id *pvid, unsigned *scan_done_once, uint64_t *label_sector) { struct device *dev; /* Already cached ? */ dev = _device_from_pvid(pvid, label_sector); if (dev) return dev; lvmcache_label_scan(cmd, 0); /* Try again */ dev = _device_from_pvid(pvid, label_sector); if (dev) return dev; if (critical_section() || (scan_done_once && *scan_done_once)) return NULL; lvmcache_label_scan(cmd, 2); if (scan_done_once) *scan_done_once = 1; /* Try again */ dev = _device_from_pvid(pvid, label_sector); if (dev) return dev; return NULL; } const char *lvmcache_pvid_from_devname(struct cmd_context *cmd, const char *devname) { struct device *dev; struct label *label; if (!(dev = dev_cache_get(devname, cmd->filter))) { log_error("%s: Couldn't find device. Check your filters?", devname); return NULL; } if (!(label_read(dev, &label, UINT64_C(0)))) return NULL; return dev->pvid; } static int _free_vginfo(struct lvmcache_vginfo *vginfo) { struct lvmcache_vginfo *primary_vginfo, *vginfo2; int r = 1; _free_cached_vgmetadata(vginfo); vginfo2 = primary_vginfo = lvmcache_vginfo_from_vgname(vginfo->vgname, NULL); if (vginfo == primary_vginfo) { dm_hash_remove(_vgname_hash, vginfo->vgname); if (vginfo->next && !dm_hash_insert(_vgname_hash, vginfo->vgname, vginfo->next)) { log_error("_vgname_hash re-insertion for %s failed", vginfo->vgname); r = 0; } } else while (vginfo2) { if (vginfo2->next == vginfo) { vginfo2->next = vginfo->next; break; } vginfo2 = vginfo2->next; } dm_free(vginfo->vgname); dm_free(vginfo->creation_host); if (*vginfo->vgid && _vgid_hash && lvmcache_vginfo_from_vgid(vginfo->vgid) == vginfo) dm_hash_remove(_vgid_hash, vginfo->vgid); dm_list_del(&vginfo->list); dm_free(vginfo); return r; } /* * vginfo must be info->vginfo unless info is NULL */ static int _drop_vginfo(struct lvmcache_info *info, struct lvmcache_vginfo *vginfo) { if (info) _vginfo_detach_info(info); /* vginfo still referenced? */ if (!vginfo || is_orphan_vg(vginfo->vgname) || !dm_list_empty(&vginfo->infos)) return 1; if (!_free_vginfo(vginfo)) return_0; return 1; } /* Unused void lvmcache_del(struct lvmcache_info *info) { if (info->dev->pvid[0] && _pvid_hash) dm_hash_remove(_pvid_hash, info->dev->pvid); _drop_vginfo(info, info->vginfo); info->label->labeller->ops->destroy_label(info->label->labeller, info->label); dm_free(info); return; } */ static int _lvmcache_update_pvid(struct lvmcache_info *info, const char *pvid) { /* * Nothing to do if already stored with same pvid. */ if (((dm_hash_lookup(_pvid_hash, pvid)) == info) && !strcmp(info->dev->pvid, pvid)) return 1; if (*info->dev->pvid) dm_hash_remove(_pvid_hash, info->dev->pvid); strncpy(info->dev->pvid, pvid, sizeof(info->dev->pvid)); if (!dm_hash_insert(_pvid_hash, pvid, info)) { log_error("_lvmcache_update: pvid insertion failed: %s", pvid); return 0; } return 1; } /* * vginfo must be info->vginfo unless info is NULL (orphans) */ static int _lvmcache_update_vgid(struct lvmcache_info *info, struct lvmcache_vginfo *vginfo, const char *vgid) { if (!vgid || !vginfo || !strncmp(vginfo->vgid, vgid, ID_LEN)) return 1; if (vginfo && *vginfo->vgid) dm_hash_remove(_vgid_hash, vginfo->vgid); if (!vgid) { /* FIXME: unreachable code path */ log_debug("lvmcache: %s: clearing VGID", info ? dev_name(info->dev) : vginfo->vgname); return 1; } strncpy(vginfo->vgid, vgid, ID_LEN); vginfo->vgid[ID_LEN] = '\0'; if (!dm_hash_insert(_vgid_hash, vginfo->vgid, vginfo)) { log_error("_lvmcache_update: vgid hash insertion failed: %s", vginfo->vgid); return 0; } if (!is_orphan_vg(vginfo->vgname)) log_debug("lvmcache: %s: setting %s VGID to %s", (info) ? dev_name(info->dev) : "", vginfo->vgname, vginfo->vgid); return 1; } static int _insert_vginfo(struct lvmcache_vginfo *new_vginfo, const char *vgid, uint32_t vgstatus, const char *creation_host, struct lvmcache_vginfo *primary_vginfo) { struct lvmcache_vginfo *last_vginfo = primary_vginfo; char uuid_primary[64] __attribute__((aligned(8))); char uuid_new[64] __attribute__((aligned(8))); int use_new = 0; /* Pre-existing VG takes precedence. Unexported VG takes precedence. */ if (primary_vginfo) { if (!id_write_format((const struct id *)vgid, uuid_new, sizeof(uuid_new))) return_0; if (!id_write_format((const struct id *)&primary_vginfo->vgid, uuid_primary, sizeof(uuid_primary))) return_0; /* * If Primary not exported, new exported => keep * Else Primary exported, new not exported => change * Else Primary has hostname for this machine => keep * Else Primary has no hostname, new has one => change * Else New has hostname for this machine => change * Else Keep primary. */ if (!(primary_vginfo->status & EXPORTED_VG) && (vgstatus & EXPORTED_VG)) log_warn("WARNING: Duplicate VG name %s: " "Existing %s takes precedence over " "exported %s", new_vginfo->vgname, uuid_primary, uuid_new); else if ((primary_vginfo->status & EXPORTED_VG) && !(vgstatus & EXPORTED_VG)) { log_warn("WARNING: Duplicate VG name %s: " "%s takes precedence over exported %s", new_vginfo->vgname, uuid_new, uuid_primary); use_new = 1; } else if (primary_vginfo->creation_host && !strcmp(primary_vginfo->creation_host, primary_vginfo->fmt->cmd->hostname)) log_warn("WARNING: Duplicate VG name %s: " "Existing %s (created here) takes precedence " "over %s", new_vginfo->vgname, uuid_primary, uuid_new); else if (!primary_vginfo->creation_host && creation_host) { log_warn("WARNING: Duplicate VG name %s: " "%s (with creation_host) takes precedence over %s", new_vginfo->vgname, uuid_new, uuid_primary); use_new = 1; } else if (creation_host && !strcmp(creation_host, primary_vginfo->fmt->cmd->hostname)) { log_warn("WARNING: Duplicate VG name %s: " "%s (created here) takes precedence over %s", new_vginfo->vgname, uuid_new, uuid_primary); use_new = 1; } if (!use_new) { while (last_vginfo->next) last_vginfo = last_vginfo->next; last_vginfo->next = new_vginfo; return 1; } dm_hash_remove(_vgname_hash, primary_vginfo->vgname); } if (!dm_hash_insert(_vgname_hash, new_vginfo->vgname, new_vginfo)) { log_error("cache_update: vg hash insertion failed: %s", new_vginfo->vgname); return 0; } if (primary_vginfo) new_vginfo->next = primary_vginfo; return 1; } static int _lvmcache_update_vgname(struct lvmcache_info *info, const char *vgname, const char *vgid, uint32_t vgstatus, const char *creation_host, const struct format_type *fmt) { struct lvmcache_vginfo *vginfo, *primary_vginfo, *orphan_vginfo; struct lvmcache_info *info2, *info3; char mdabuf[32]; // struct lvmcache_vginfo *old_vginfo, *next; if (!vgname || (info && info->vginfo && !strcmp(info->vginfo->vgname, vgname))) return 1; /* Remove existing vginfo entry */ if (info) _drop_vginfo(info, info->vginfo); /* Get existing vginfo or create new one */ if (!(vginfo = lvmcache_vginfo_from_vgname(vgname, vgid))) { /*** FIXME - vginfo ends up duplicated instead of renamed. // Renaming? This lookup fails. if ((vginfo = vginfo_from_vgid(vgid))) { next = vginfo->next; old_vginfo = vginfo_from_vgname(vginfo->vgname, NULL); if (old_vginfo == vginfo) { dm_hash_remove(_vgname_hash, old_vginfo->vgname); if (old_vginfo->next) { if (!dm_hash_insert(_vgname_hash, old_vginfo->vgname, old_vginfo->next)) { log_error("vg hash re-insertion failed: %s", old_vginfo->vgname); return 0; } } } else do { if (old_vginfo->next == vginfo) { old_vginfo->next = vginfo->next; break; } } while ((old_vginfo = old_vginfo->next)); vginfo->next = NULL; dm_free(vginfo->vgname); if (!(vginfo->vgname = dm_strdup(vgname))) { log_error("cache vgname alloc failed for %s", vgname); return 0; } // Rename so can assume new name does not already exist if (!dm_hash_insert(_vgname_hash, vginfo->vgname, vginfo->next)) { log_error("vg hash re-insertion failed: %s", vginfo->vgname); return 0; } } else { ***/ if (!(vginfo = dm_zalloc(sizeof(*vginfo)))) { log_error("lvmcache_update_vgname: list alloc failed"); return 0; } if (!(vginfo->vgname = dm_strdup(vgname))) { dm_free(vginfo); log_error("cache vgname alloc failed for %s", vgname); return 0; } dm_list_init(&vginfo->infos); /* * If we're scanning and there's an invalidated entry, remove it. * Otherwise we risk bogus warnings of duplicate VGs. */ while ((primary_vginfo = lvmcache_vginfo_from_vgname(vgname, NULL)) && _scanning_in_progress && _vginfo_is_invalid(primary_vginfo)) { orphan_vginfo = lvmcache_vginfo_from_vgname(primary_vginfo->fmt->orphan_vg_name, NULL); if (!orphan_vginfo) { log_error(INTERNAL_ERROR "Orphan vginfo %s lost from cache.", primary_vginfo->fmt->orphan_vg_name); dm_free(vginfo->vgname); dm_free(vginfo); return 0; } dm_list_iterate_items_safe(info2, info3, &primary_vginfo->infos) { _vginfo_detach_info(info2); _vginfo_attach_info(orphan_vginfo, info2); if (info2->mdas.n) sprintf(mdabuf, " with %u mdas", dm_list_size(&info2->mdas)); else mdabuf[0] = '\0'; log_debug("lvmcache: %s: now in VG %s%s%s%s%s", dev_name(info2->dev), vgname, orphan_vginfo->vgid[0] ? " (" : "", orphan_vginfo->vgid[0] ? orphan_vginfo->vgid : "", orphan_vginfo->vgid[0] ? ")" : "", mdabuf); } if (!_drop_vginfo(NULL, primary_vginfo)) return_0; } if (!_insert_vginfo(vginfo, vgid, vgstatus, creation_host, primary_vginfo)) { dm_free(vginfo->vgname); dm_free(vginfo); return 0; } /* Ensure orphans appear last on list_iterate */ if (is_orphan_vg(vgname)) dm_list_add(&_vginfos, &vginfo->list); else dm_list_add_h(&_vginfos, &vginfo->list); /*** } ***/ } if (info) _vginfo_attach_info(vginfo, info); else if (!_lvmcache_update_vgid(NULL, vginfo, vgid)) /* Orphans */ return_0; _update_cache_vginfo_lock_state(vginfo, lvmcache_vgname_is_locked(vgname)); /* FIXME Check consistency of list! */ vginfo->fmt = fmt; if (info) { if (info->mdas.n) sprintf(mdabuf, " with %u mdas", dm_list_size(&info->mdas)); else mdabuf[0] = '\0'; log_debug("lvmcache: %s: now in VG %s%s%s%s%s", dev_name(info->dev), vgname, vginfo->vgid[0] ? " (" : "", vginfo->vgid[0] ? vginfo->vgid : "", vginfo->vgid[0] ? ")" : "", mdabuf); } else log_debug("lvmcache: initialised VG %s", vgname); return 1; } static int _lvmcache_update_vgstatus(struct lvmcache_info *info, uint32_t vgstatus, const char *creation_host) { if (!info || !info->vginfo) return 1; if ((info->vginfo->status & EXPORTED_VG) != (vgstatus & EXPORTED_VG)) log_debug("lvmcache: %s: VG %s %s exported", dev_name(info->dev), info->vginfo->vgname, vgstatus & EXPORTED_VG ? "now" : "no longer"); info->vginfo->status = vgstatus; if (!creation_host) return 1; if (info->vginfo->creation_host && !strcmp(creation_host, info->vginfo->creation_host)) return 1; if (info->vginfo->creation_host) dm_free(info->vginfo->creation_host); if (!(info->vginfo->creation_host = dm_strdup(creation_host))) { log_error("cache creation host alloc failed for %s", creation_host); return 0; } log_debug("lvmcache: %s: VG %s: Set creation host to %s.", dev_name(info->dev), info->vginfo->vgname, creation_host); return 1; } int lvmcache_add_orphan_vginfo(const char *vgname, struct format_type *fmt) { if (!_lock_hash && !lvmcache_init()) { log_error("Internal cache initialisation failed"); return 0; } return _lvmcache_update_vgname(NULL, vgname, vgname, 0, "", fmt); } int lvmcache_update_vgname_and_id(struct lvmcache_info *info, const char *vgname, const char *vgid, uint32_t vgstatus, const char *creation_host) { if (!vgname && !info->vginfo) { log_error(INTERNAL_ERROR "NULL vgname handed to cache"); /* FIXME Remove this */ vgname = info->fmt->orphan_vg_name; vgid = vgname; } /* When using lvmetad, the PV could not have become orphaned. */ if (lvmetad_active() && is_orphan_vg(vgname) && info->vginfo) return 1; /* If PV without mdas is already in a real VG, don't make it orphan */ if (is_orphan_vg(vgname) && info->vginfo && mdas_empty_or_ignored(&info->mdas) && !is_orphan_vg(info->vginfo->vgname) && critical_section()) return 1; /* If moving PV from orphan to real VG, always mark it valid */ if (!is_orphan_vg(vgname)) info->status &= ~CACHE_INVALID; if (!_lvmcache_update_vgname(info, vgname, vgid, vgstatus, creation_host, info->fmt) || !_lvmcache_update_vgid(info, info->vginfo, vgid) || !_lvmcache_update_vgstatus(info, vgstatus, creation_host)) return_0; return 1; } int lvmcache_update_vg(struct volume_group *vg, unsigned precommitted) { struct pv_list *pvl; struct lvmcache_info *info; char pvid_s[ID_LEN + 1] __attribute__((aligned(8))); pvid_s[sizeof(pvid_s) - 1] = '\0'; dm_list_iterate_items(pvl, &vg->pvs) { strncpy(pvid_s, (char *) &pvl->pv->id, sizeof(pvid_s) - 1); /* FIXME Could pvl->pv->dev->pvid ever be different? */ if ((info = lvmcache_info_from_pvid(pvid_s, 0)) && !lvmcache_update_vgname_and_id(info, vg->name, (char *) &vg->id, vg->status, NULL)) return_0; } /* store text representation of vg to cache */ if (vg->cmd->current_settings.cache_vgmetadata) _store_metadata(vg, precommitted); return 1; } struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid, struct device *dev, const char *vgname, const char *vgid, uint32_t vgstatus) { struct label *label; struct lvmcache_info *existing, *info; char pvid_s[ID_LEN + 1] __attribute__((aligned(8))); if (!_vgname_hash && !lvmcache_init()) { log_error("Internal cache initialisation failed"); return NULL; } strncpy(pvid_s, pvid, sizeof(pvid_s) - 1); pvid_s[sizeof(pvid_s) - 1] = '\0'; if (!(existing = lvmcache_info_from_pvid(pvid_s, 0)) && !(existing = lvmcache_info_from_pvid(dev->pvid, 0))) { if (!(label = label_create(labeller))) return_NULL; if (!(info = dm_zalloc(sizeof(*info)))) { log_error("lvmcache_info allocation failed"); label_destroy(label); return NULL; } label->info = info; info->label = label; dm_list_init(&info->list); info->dev = dev; lvmcache_del_mdas(info); lvmcache_del_das(info); } else { if (existing->dev != dev) { /* Is the existing entry a duplicate pvid e.g. md ? */ if (dev_subsystem_part_major(existing->dev) && !dev_subsystem_part_major(dev)) { log_very_verbose("Ignoring duplicate PV %s on " "%s - using %s %s", pvid, dev_name(dev), dev_subsystem_name(existing->dev), dev_name(existing->dev)); return NULL; } else if (dm_is_dm_major(MAJOR(existing->dev->dev)) && !dm_is_dm_major(MAJOR(dev->dev))) { log_very_verbose("Ignoring duplicate PV %s on " "%s - using dm %s", pvid, dev_name(dev), dev_name(existing->dev)); return NULL; } else if (!dev_subsystem_part_major(existing->dev) && dev_subsystem_part_major(dev)) log_very_verbose("Duplicate PV %s on %s - " "using %s %s", pvid, dev_name(existing->dev), dev_subsystem_name(existing->dev), dev_name(dev)); else if (!dm_is_dm_major(MAJOR(existing->dev->dev)) && dm_is_dm_major(MAJOR(dev->dev))) log_very_verbose("Duplicate PV %s on %s - " "using dm %s", pvid, dev_name(existing->dev), dev_name(dev)); /* FIXME If both dm, check dependencies */ //else if (dm_is_dm_major(MAJOR(existing->dev->dev)) && //dm_is_dm_major(MAJOR(dev->dev))) // else if (!strcmp(pvid_s, existing->dev->pvid)) log_error("Found duplicate PV %s: using %s not " "%s", pvid, dev_name(dev), dev_name(existing->dev)); } if (strcmp(pvid_s, existing->dev->pvid)) log_debug("Updating pvid cache to %s (%s) from %s (%s)", pvid_s, dev_name(dev), existing->dev->pvid, dev_name(existing->dev)); /* Switch over to new preferred device */ existing->dev = dev; info = existing; /* Has labeller changed? */ if (info->label->labeller != labeller) { label_destroy(info->label); if (!(info->label = label_create(labeller))) /* FIXME leaves info without label! */ return_NULL; info->label->info = info; } label = info->label; } info->fmt = (const struct format_type *) labeller->private; info->status |= CACHE_INVALID; if (!_lvmcache_update_pvid(info, pvid_s)) { if (!existing) { dm_free(info); label_destroy(label); } return NULL; } if (!lvmcache_update_vgname_and_id(info, vgname, vgid, vgstatus, NULL)) { if (!existing) { dm_hash_remove(_pvid_hash, pvid_s); strcpy(info->dev->pvid, ""); dm_free(info); label_destroy(label); } return NULL; } return info; } static void _lvmcache_destroy_entry(struct lvmcache_info *info) { _vginfo_detach_info(info); strcpy(info->dev->pvid, ""); label_destroy(info->label); dm_free(info); } static void _lvmcache_destroy_vgnamelist(struct lvmcache_vginfo *vginfo) { struct lvmcache_vginfo *next; do { next = vginfo->next; if (!_free_vginfo(vginfo)) stack; } while ((vginfo = next)); } static void _lvmcache_destroy_lockname(struct dm_hash_node *n) { char *vgname; if (!dm_hash_get_data(_lock_hash, n)) return; vgname = dm_hash_get_key(_lock_hash, n); if (!strcmp(vgname, VG_GLOBAL)) _vg_global_lock_held = 1; else log_error(INTERNAL_ERROR "Volume Group %s was not unlocked", dm_hash_get_key(_lock_hash, n)); } void lvmcache_destroy(struct cmd_context *cmd, int retain_orphans) { struct dm_hash_node *n; log_verbose("Wiping internal VG cache"); _has_scanned = 0; if (_vgid_hash) { dm_hash_destroy(_vgid_hash); _vgid_hash = NULL; } if (_pvid_hash) { dm_hash_iter(_pvid_hash, (dm_hash_iterate_fn) _lvmcache_destroy_entry); dm_hash_destroy(_pvid_hash); _pvid_hash = NULL; } if (_vgname_hash) { dm_hash_iter(_vgname_hash, (dm_hash_iterate_fn) _lvmcache_destroy_vgnamelist); dm_hash_destroy(_vgname_hash); _vgname_hash = NULL; } if (_lock_hash) { dm_hash_iterate(n, _lock_hash) _lvmcache_destroy_lockname(n); dm_hash_destroy(_lock_hash); _lock_hash = NULL; } if (!dm_list_empty(&_vginfos)) log_error(INTERNAL_ERROR "_vginfos list should be empty"); dm_list_init(&_vginfos); if (retain_orphans) if (!init_lvmcache_orphans(cmd)) stack; } int lvmcache_pvid_is_locked(const char *pvid) { struct lvmcache_info *info; info = lvmcache_info_from_pvid(pvid, 0); if (!info || !info->vginfo) return 0; return lvmcache_vgname_is_locked(info->vginfo->vgname); } int lvmcache_fid_add_mdas(struct lvmcache_info *info, struct format_instance *fid, const char *id, int id_len) { return fid_add_mdas(fid, &info->mdas, id, id_len); } int lvmcache_fid_add_mdas_pv(struct lvmcache_info *info, struct format_instance *fid) { return lvmcache_fid_add_mdas(info, fid, info->dev->pvid, ID_LEN); } int lvmcache_fid_add_mdas_vg(struct lvmcache_vginfo *vginfo, struct format_instance *fid) { struct lvmcache_info *info; dm_list_iterate_items(info, &vginfo->infos) { if (!lvmcache_fid_add_mdas_pv(info, fid)) return_0; } return 1; } static int _get_pv_if_in_vg(struct lvmcache_info *info, struct physical_volume *pv) { char vgname[NAME_LEN + 1]; char vgid[ID_LEN + 1]; if (info->vginfo && info->vginfo->vgname && !is_orphan_vg(info->vginfo->vgname)) { /* * get_pv_from_vg_by_id() may call * lvmcache_label_scan() and drop cached * vginfo so make a local copy of string. */ strcpy(vgname, info->vginfo->vgname); memcpy(vgid, info->vginfo->vgid, sizeof(vgid)); if (get_pv_from_vg_by_id(info->fmt, vgname, vgid, info->dev->pvid, pv)) return 1; } return 0; } int lvmcache_populate_pv_fields(struct lvmcache_info *info, struct physical_volume *pv, int scan_label_only) { struct data_area_list *da; /* Have we already cached vgname? */ if (!scan_label_only && _get_pv_if_in_vg(info, pv)) return 1; /* Perform full scan (just the first time) and try again */ if (!scan_label_only && !critical_section() && !full_scan_done()) { lvmcache_label_scan(info->fmt->cmd, 2); if (_get_pv_if_in_vg(info, pv)) return 1; } /* Orphan */ pv->dev = info->dev; pv->fmt = info->fmt; pv->size = info->device_size >> SECTOR_SHIFT; pv->vg_name = FMT_TEXT_ORPHAN_VG_NAME; memcpy(&pv->id, &info->dev->pvid, sizeof(pv->id)); /* Currently only support exactly one data area */ if (dm_list_size(&info->das) != 1) { log_error("Must be exactly one data area (found %d) on PV %s", dm_list_size(&info->das), dev_name(info->dev)); return 0; } dm_list_iterate_items(da, &info->das) pv->pe_start = da->disk_locn.offset >> SECTOR_SHIFT; return 1; } int lvmcache_check_format(struct lvmcache_info *info, const struct format_type *fmt) { if (info->fmt != fmt) { log_error("PV %s is a different format (seqno %s)", dev_name(info->dev), info->fmt->name); return 0; } return 1; } void lvmcache_del_mdas(struct lvmcache_info *info) { if (info->mdas.n) del_mdas(&info->mdas); dm_list_init(&info->mdas); } void lvmcache_del_das(struct lvmcache_info *info) { if (info->das.n) del_das(&info->das); dm_list_init(&info->das); } int lvmcache_add_mda(struct lvmcache_info *info, struct device *dev, uint64_t start, uint64_t size, unsigned ignored) { return add_mda(info->fmt, NULL, &info->mdas, dev, start, size, ignored); } int lvmcache_add_da(struct lvmcache_info *info, uint64_t start, uint64_t size) { return add_da(NULL, &info->das, start, size); } void lvmcache_update_pv(struct lvmcache_info *info, struct physical_volume *pv, const struct format_type *fmt) { info->device_size = pv->size << SECTOR_SHIFT; info->fmt = fmt; } int lvmcache_update_das(struct lvmcache_info *info, struct physical_volume *pv) { struct data_area_list *da; if (info->das.n) { if (!pv->pe_start) dm_list_iterate_items(da, &info->das) pv->pe_start = da->disk_locn.offset >> SECTOR_SHIFT; del_das(&info->das); } else dm_list_init(&info->das); if (!add_da(NULL, &info->das, pv->pe_start << SECTOR_SHIFT, 0 /*pv->size << SECTOR_SHIFT*/)) return_0; return 1; } int lvmcache_foreach_pv(struct lvmcache_vginfo *vginfo, int (*fun)(struct lvmcache_info *, void *), void *baton) { struct lvmcache_info *info; dm_list_iterate_items(info, &vginfo->infos) { if (!fun(info, baton)) return_0; } return 1; } int lvmcache_foreach_mda(struct lvmcache_info *info, int (*fun)(struct metadata_area *, void *), void *baton) { struct metadata_area *mda; dm_list_iterate_items(mda, &info->mdas) { if (!fun(mda, baton)) return_0; } return 1; } int lvmcache_mda_count(struct lvmcache_info *info) { return dm_list_size(&info->mdas); } int lvmcache_foreach_da(struct lvmcache_info *info, int (*fun)(struct disk_locn *, void *), void *baton) { struct data_area_list *da; dm_list_iterate_items(da, &info->das) { if (!fun(&da->disk_locn, baton)) return_0; } return 1; } /* * The lifetime of the label returned is tied to the lifetime of the * lvmcache_info which is the same as lvmcache itself. */ struct label *lvmcache_get_label(struct lvmcache_info *info) { return info->label; } void lvmcache_make_valid(struct lvmcache_info *info) { info->status &= ~CACHE_INVALID; } uint64_t lvmcache_device_size(struct lvmcache_info *info) { return info->device_size; } void lvmcache_set_device_size(struct lvmcache_info *info, uint64_t size) { info->device_size = size; } struct device *lvmcache_device(struct lvmcache_info *info) { return info->dev; } int lvmcache_is_orphan(struct lvmcache_info *info) { if (!info->vginfo) return 1; /* FIXME? */ return is_orphan_vg(info->vginfo->vgname); } int lvmcache_vgid_is_cached(const char *vgid) { struct lvmcache_vginfo *vginfo; if (lvmetad_active()) return 1; vginfo = lvmcache_vginfo_from_vgid(vgid); if (!vginfo || !vginfo->vgname) return 0; if (is_orphan_vg(vginfo->vgname)) return 0; return 1; } /* * Return true iff it is impossible to find out from this info alone whether the * PV in question is or is not an orphan. */ int lvmcache_uncertain_ownership(struct lvmcache_info *info) { return mdas_empty_or_ignored(&info->mdas); } int lvmcache_smallest_mda_size(struct lvmcache_info *info) { return find_min_mda_size(&info->mdas); } const struct format_type *lvmcache_fmt(struct lvmcache_info *info) { return info->fmt; } lvm2-2.02.98/lib/zero/0000750000175000017500000000000012037016272013234 5ustar blankblanklvm2-2.02.98/lib/zero/zero.c0000640000175000017500000000547512037016272014373 0ustar blankblank/* * 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 "toolcontext.h" #include "segtype.h" #include "display.h" #include "config.h" #include "str_list.h" #include "activate.h" static const char *_zero_name(const struct lv_segment *seg) { return seg->segtype->name; } static int _zero_merge_segments(struct lv_segment *seg1, struct lv_segment *seg2) { seg1->len += seg2->len; seg1->area_len += seg2->area_len; return 1; } #ifdef DEVMAPPER_SUPPORT static int _zero_add_target_line(struct dev_manager *dm __attribute__((unused)), struct dm_pool *mem __attribute__((unused)), struct cmd_context *cmd __attribute__((unused)), void **target_state __attribute__((unused)), struct lv_segment *seg __attribute__((unused)), const struct lv_activate_opts *laopts __attribute__((unused)), struct dm_tree_node *node,uint64_t len, uint32_t *pvmove_mirror_count __attribute__((unused))) { return dm_tree_node_add_zero_target(node, len); } static int _zero_target_present(struct cmd_context *cmd, const struct lv_segment *seg __attribute__((unused)), unsigned *attributes __attribute__((unused))) { static int _zero_checked = 0; static int _zero_present = 0; if (!_zero_checked) _zero_present = target_present(cmd, "zero", 1); _zero_checked = 1; return _zero_present; } #endif static int _zero_modules_needed(struct dm_pool *mem, const struct lv_segment *seg __attribute__((unused)), struct dm_list *modules) { if (!str_list_add(mem, modules, "zero")) { log_error("zero module string list allocation failed"); return 0; } return 1; } static void _zero_destroy(struct segment_type *segtype) { dm_free(segtype); } static struct segtype_handler _zero_ops = { .name = _zero_name, .merge_segments = _zero_merge_segments, #ifdef DEVMAPPER_SUPPORT .add_target_line = _zero_add_target_line, .target_present = _zero_target_present, #endif .modules_needed = _zero_modules_needed, .destroy = _zero_destroy, }; struct segment_type *init_zero_segtype(struct cmd_context *cmd) { struct segment_type *segtype = dm_zalloc(sizeof(*segtype)); if (!segtype) return_NULL; segtype->cmd = cmd; segtype->ops = &_zero_ops; segtype->name = "zero"; segtype->private = NULL; segtype->flags = SEG_CAN_SPLIT | SEG_VIRTUAL | SEG_CANNOT_BE_ZEROED; log_very_verbose("Initialised segtype: %s", segtype->name); return segtype; } lvm2-2.02.98/lib/Makefile.in0000640000175000017500000001002312037016272014317 0ustar blankblank# # 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 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 ("@RAID@", "shared") SUBDIRS += raid endif ifeq ("@REPLICATORS@", "shared") SUBDIRS += replicator endif ifeq ("@THIN@", "shared") SUBDIRS += thin 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-mpath.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/raid_manip.c \ metadata/replicator_manip.c \ metadata/segtype.c \ metadata/snapshot_manip.c \ metadata/thin_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 \ 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 ("@RAID@", "internal") SOURCES += raid/raid.c endif ifeq ("@REPLICATORS@", "internal") SOURCES += replicator/replicator.c endif ifeq ("@THIN@", "internal") SOURCES += thin/thin.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 ("@BUILD_LVMETAD@", "yes") SOURCES +=\ cache/lvmetad.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 \ raid \ replicator \ thin \ 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 lvm2-2.02.98/lib/metadata/0000750000175000017500000000000012037016272014035 5ustar blankblanklvm2-2.02.98/lib/metadata/lv_alloc.h0000640000175000017500000000652212037016272016007 0ustar blankblank/* * Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved. * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU 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_LV_ALLOC_H #define _LVM_LV_ALLOC_H struct lv_segment *alloc_lv_segment(const struct segment_type *segtype, struct logical_volume *lv, uint32_t le, uint32_t len, uint64_t status, uint32_t stripe_size, struct logical_volume *log_lv, struct logical_volume *thin_pool_lv, uint32_t area_count, uint32_t area_len, uint32_t chunk_size, uint32_t region_size, uint32_t extents_copied, struct lv_segment *pvmove_source_seg); struct lv_segment *alloc_snapshot_seg(struct logical_volume *lv, uint64_t status, uint32_t old_le_count); int set_lv_segment_area_pv(struct lv_segment *seg, uint32_t area_num, struct physical_volume *pv, uint32_t pe); int set_lv_segment_area_lv(struct lv_segment *seg, uint32_t area_num, struct logical_volume *lv, uint32_t le, uint64_t status); int move_lv_segment_area(struct lv_segment *seg_to, uint32_t area_to, struct lv_segment *seg_from, uint32_t area_from); int release_lv_segment_area(struct lv_segment *seg, uint32_t s, uint32_t area_reduction); int release_and_discard_lv_segment_area(struct lv_segment *seg, uint32_t s, uint32_t area_reduction); struct alloc_handle; struct alloc_handle *allocate_extents(struct volume_group *vg, struct logical_volume *lv, const struct segment_type *segtype, uint32_t stripes, uint32_t mirrors, uint32_t log_count, uint32_t log_region_size, uint32_t extents, struct dm_list *allocatable_pvs, alloc_policy_t alloc, struct dm_list *parallel_areas); int lv_add_segment(struct alloc_handle *ah, uint32_t first_area, uint32_t num_areas, struct logical_volume *lv, const struct segment_type *segtype, uint32_t stripe_size, uint64_t status, uint32_t region_size); int lv_add_mirror_areas(struct alloc_handle *ah, struct logical_volume *lv, uint32_t le, uint32_t region_size); int lv_add_mirror_lvs(struct logical_volume *lv, struct logical_volume **sub_lvs, uint32_t num_extra_areas, uint64_t status, uint32_t region_size); int lv_add_log_segment(struct alloc_handle *ah, uint32_t first_area, struct logical_volume *log_lv, uint64_t status); int lv_add_virtual_segment(struct logical_volume *lv, uint64_t status, uint32_t extents, const struct segment_type *segtype, const char *thin_pool_name); void alloc_destroy(struct alloc_handle *ah); struct dm_list *build_parallel_areas_from_lv(struct logical_volume *lv, unsigned use_pvmove_parent_lv); #endif lvm2-2.02.98/lib/metadata/thin_manip.c0000640000175000017500000002720712037016272016340 0ustar blankblank/* * Copyright (C) 2011-2012 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU Lesser General Public License v.2.1. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "lib.h" #include "activate.h" #include "locking.h" #include "metadata.h" #include "segtype.h" #include "lv_alloc.h" #include "archiver.h" #include "defaults.h" int attach_pool_metadata_lv(struct lv_segment *pool_seg, struct logical_volume *metadata_lv) { pool_seg->metadata_lv = metadata_lv; metadata_lv->status |= THIN_POOL_METADATA; lv_set_hidden(metadata_lv); return add_seg_to_segs_using_this_lv(metadata_lv, pool_seg); } int attach_pool_data_lv(struct lv_segment *pool_seg, struct logical_volume *pool_data_lv) { if (!set_lv_segment_area_lv(pool_seg, 0, pool_data_lv, 0, THIN_POOL_DATA)) return_0; lv_set_hidden(pool_data_lv); return 1; } int attach_pool_lv(struct lv_segment *seg, struct logical_volume *pool_lv, struct logical_volume *origin) { seg->pool_lv = pool_lv; seg->lv->status |= THIN_VOLUME; seg->origin = origin; if (origin && !add_seg_to_segs_using_this_lv(origin, seg)) return_0; return add_seg_to_segs_using_this_lv(pool_lv, seg); } int detach_pool_lv(struct lv_segment *seg) { struct lv_thin_message *tmsg, *tmp; struct seg_list *sl, *tsl; int no_update = 0; if (!seg->pool_lv || !lv_is_thin_pool(seg->pool_lv)) { log_error(INTERNAL_ERROR "LV %s is not a thin volume", seg->lv->name); return 0; } /* Drop any message referencing removed segment */ dm_list_iterate_items_safe(tmsg, tmp, &(first_seg(seg->pool_lv)->thin_messages)) { switch (tmsg->type) { case DM_THIN_MESSAGE_CREATE_SNAP: case DM_THIN_MESSAGE_CREATE_THIN: if (tmsg->u.lv == seg->lv) { log_debug("Discarding message for LV %s.", tmsg->u.lv->name); dm_list_del(&tmsg->list); no_update = 1; /* Replacing existing */ } break; case DM_THIN_MESSAGE_DELETE: if (tmsg->u.delete_id == seg->device_id) { log_error(INTERNAL_ERROR "Trying to delete %u again.", tmsg->u.delete_id); return 0; } break; default: log_error(INTERNAL_ERROR "Unsupported message type %u.", tmsg->type); break; } } if (!attach_pool_message(first_seg(seg->pool_lv), DM_THIN_MESSAGE_DELETE, NULL, seg->device_id, no_update)) return_0; if (!remove_seg_from_segs_using_this_lv(seg->pool_lv, seg)) return_0; if (seg->origin && !remove_seg_from_segs_using_this_lv(seg->origin, seg)) return_0; /* If thin origin, remove it from related thin snapshots */ /* * TODO: map removal of origin as snapshot lvconvert --merge? * i.e. rename thin snapshot to origin thin origin */ dm_list_iterate_items_safe(sl, tsl, &seg->lv->segs_using_this_lv) { if (!seg_is_thin_volume(sl->seg) || (seg->lv != sl->seg->origin)) continue; if (!remove_seg_from_segs_using_this_lv(seg->lv, sl->seg)) return_0; /* Thin snapshot is now regular thin volume */ sl->seg->origin = NULL; } return 1; } int attach_pool_message(struct lv_segment *pool_seg, dm_thin_message_t type, struct logical_volume *lv, uint32_t delete_id, int no_update) { struct lv_thin_message *tmsg; if (!seg_is_thin_pool(pool_seg)) { log_error(INTERNAL_ERROR "LV %s is not pool.", pool_seg->lv->name); return 0; } if (pool_has_message(pool_seg, lv, delete_id)) { if (lv) log_error("Message referring LV %s already queued in pool %s.", lv->name, pool_seg->lv->name); else log_error("Delete for device %u already queued in pool %s.", delete_id, pool_seg->lv->name); return 0; } if (!(tmsg = dm_pool_alloc(pool_seg->lv->vg->vgmem, sizeof(*tmsg)))) { log_error("Failed to allocate memory for message."); return 0; } switch (type) { case DM_THIN_MESSAGE_CREATE_SNAP: case DM_THIN_MESSAGE_CREATE_THIN: tmsg->u.lv = lv; break; case DM_THIN_MESSAGE_DELETE: tmsg->u.delete_id = delete_id; break; default: log_error(INTERNAL_ERROR "Unsupported message type %u.", type); return 0; } tmsg->type = type; /* If the 1st message is add in non-read-only mode, modify transaction_id */ if (!no_update && dm_list_empty(&pool_seg->thin_messages)) pool_seg->transaction_id++; dm_list_add(&pool_seg->thin_messages, &tmsg->list); log_debug("Added %s message", (type == DM_THIN_MESSAGE_CREATE_SNAP || type == DM_THIN_MESSAGE_CREATE_THIN) ? "create" : (type == DM_THIN_MESSAGE_DELETE) ? "delete" : "unknown"); return 1; } /* * Check whether pool has some message queued for LV or for device_id * When LV is NULL and device_id is 0 it just checks for any message. */ int pool_has_message(const struct lv_segment *seg, const struct logical_volume *lv, uint32_t device_id) { const struct lv_thin_message *tmsg; if (!seg_is_thin_pool(seg)) { log_error(INTERNAL_ERROR "LV %s is not pool.", seg->lv->name); return 0; } if (!lv && !device_id) return dm_list_empty(&seg->thin_messages); dm_list_iterate_items(tmsg, &seg->thin_messages) { switch (tmsg->type) { case DM_THIN_MESSAGE_CREATE_SNAP: case DM_THIN_MESSAGE_CREATE_THIN: if (tmsg->u.lv == lv) return 1; break; case DM_THIN_MESSAGE_DELETE: if (tmsg->u.delete_id == device_id) return 1; break; default: break; } } return 0; } int pool_below_threshold(const struct lv_segment *pool_seg) { percent_t percent; int threshold = PERCENT_1 * find_config_tree_int(pool_seg->lv->vg->cmd, "activation/thin_pool_autoextend_threshold", DEFAULT_THIN_POOL_AUTOEXTEND_THRESHOLD); /* Data */ if (!lv_thin_pool_percent(pool_seg->lv, 0, &percent)) return_0; if (percent >= threshold) return_0; /* Metadata */ if (!lv_thin_pool_percent(pool_seg->lv, 1, &percent)) return_0; if (percent >= threshold) return_0; return 1; } struct lv_segment *find_pool_seg(const struct lv_segment *seg) { struct lv_segment *pool_seg; pool_seg = get_only_segment_using_this_lv(seg->lv); if (!pool_seg) { log_error("Failed to find pool_seg for %s", seg->lv->name); return NULL; } if (!seg_is_thin_pool(pool_seg)) { log_error("%s on %s is not a pool segment", pool_seg->lv->name, seg->lv->name); return NULL; } return pool_seg; } /* * Find a free device_id for given thin_pool segment. * * \return * Free device id, or 0 if free device_id is not found. * * FIXME: Improve naive search and keep the value cached * and updated during VG lifetime (so no const for lv_segment) */ uint32_t get_free_pool_device_id(struct lv_segment *thin_pool_seg) { uint32_t max_id = 0; struct seg_list *sl; if (!seg_is_thin_pool(thin_pool_seg)) { log_error(INTERNAL_ERROR "Segment in %s is not a thin pool segment.", thin_pool_seg->lv->name); return 0; } dm_list_iterate_items(sl, &thin_pool_seg->lv->segs_using_this_lv) if (sl->seg->device_id > max_id) max_id = sl->seg->device_id; if (++max_id > DM_THIN_MAX_DEVICE_ID) { /* FIXME Find empty holes instead of aborting! */ log_error("Cannot find free device_id."); return 0; } log_debug("Found free pool device_id %u.", max_id); return max_id; } // FIXME Rename this fn: it doesn't extend an already-existing pool AFAICT int extend_pool(struct logical_volume *pool_lv, const struct segment_type *segtype, struct alloc_handle *ah, uint32_t stripes, uint32_t stripe_size) { const struct segment_type *striped; struct logical_volume *meta_lv, *data_lv; struct lv_segment *seg; const size_t len = strlen(pool_lv->name) + 16; char name[len]; if (pool_lv->le_count) { /* FIXME move code for manipulation from lv_manip.c */ log_error(INTERNAL_ERROR "Pool %s has already extents.", pool_lv->name); return 0; } /* LV is not yet a pool, so it's extension from lvcreate */ if (!(striped = get_segtype_from_string(pool_lv->vg->cmd, "striped"))) return_0; if (activation() && segtype->ops->target_present && !segtype->ops->target_present(pool_lv->vg->cmd, NULL, NULL)) { log_error("%s: Required device-mapper target(s) not " "detected in your kernel.", segtype->name); return 0; } /* Metadata segment */ if (!lv_add_segment(ah, stripes, 1, pool_lv, striped, 1, 0, 0)) return_0; if (activation()) { if (!vg_write(pool_lv->vg) || !vg_commit(pool_lv->vg)) return_0; /* * If killed here, only the VISIBLE striped pool LV is left * and user could easily remove it. * * FIXME: implement lazy clearing when activation is disabled */ /* pool_lv is a new LV so the VG lock protects us */ if (!activate_lv_local(pool_lv->vg->cmd, pool_lv) || /* Clear 4KB of metadata device for new thin-pool. */ !set_lv(pool_lv->vg->cmd, pool_lv, UINT64_C(0), 0)) { log_error("Aborting. Failed to wipe pool metadata %s.", pool_lv->name); return 0; } if (!deactivate_lv_local(pool_lv->vg->cmd, pool_lv)) { log_error("Aborting. Could not deactivate pool metadata %s.", pool_lv->name); return 0; } } else { log_warn("WARNING: Pool %s is created without initialization.", pool_lv->name); } if (dm_snprintf(name, len, "%s_tmeta", pool_lv->name) < 0) return_0; if (!(meta_lv = lv_create_empty(name, NULL, LVM_READ | LVM_WRITE, ALLOC_INHERIT, pool_lv->vg))) return_0; if (!move_lv_segments(meta_lv, pool_lv, 0, 0)) return_0; /* Pool data segment */ if (!lv_add_segment(ah, 0, stripes, pool_lv, striped, stripe_size, 0, 0)) return_0; if (!(data_lv = insert_layer_for_lv(pool_lv->vg->cmd, pool_lv, pool_lv->status, "_tdata"))) return_0; seg = first_seg(pool_lv); seg->segtype = segtype; /* Set as thin_pool segment */ seg->lv->status |= THIN_POOL; if (!attach_pool_metadata_lv(seg, meta_lv)) return_0; /* Drop reference as attach_pool_data_lv() takes it again */ remove_seg_from_segs_using_this_lv(data_lv, seg); if (!attach_pool_data_lv(seg, data_lv)) return_0; return 1; } int update_pool_lv(struct logical_volume *lv, int activate) { int monitored; if (!lv_is_thin_pool(lv)) { log_error(INTERNAL_ERROR "Updated LV %s is not pool.", lv->name); return 0; } if (dm_list_empty(&(first_seg(lv)->thin_messages))) return 1; /* No messages */ if (activate) { /* If the pool is not active, do activate deactivate */ if (!lv_is_active(lv)) { monitored = dmeventd_monitor_mode(); init_dmeventd_monitor(DMEVENTD_MONITOR_IGNORE); if (!activate_lv_excl(lv->vg->cmd, lv)) return_0; if (!deactivate_lv(lv->vg->cmd, lv)) return_0; init_dmeventd_monitor(monitored); } /* * Resume active pool to send thin messages. * origin_only is used to skip check for resumed state */ else if (!resume_lv_origin(lv->vg->cmd, lv)) { log_error("Failed to resume %s.", lv->name); return 0; } } dm_list_init(&(first_seg(lv)->thin_messages)); if (!vg_write(lv->vg) || !vg_commit(lv->vg)) return_0; backup(lv->vg); return 1; } int get_pool_discards(const char *str, thin_discards_t *discards) { if (!strcasecmp(str, "passdown")) *discards = THIN_DISCARDS_PASSDOWN; else if (!strcasecmp(str, "nopassdown")) *discards = THIN_DISCARDS_NO_PASSDOWN; else if (!strcasecmp(str, "ignore")) *discards = THIN_DISCARDS_IGNORE; else { log_error("Thin pool discards type %s is unknown.", str); return 0; } return 1; } const char *get_pool_discards_name(thin_discards_t discards) { switch (discards) { case THIN_DISCARDS_PASSDOWN: return "passdown"; case THIN_DISCARDS_NO_PASSDOWN: return "nopassdown"; case THIN_DISCARDS_IGNORE: return "ignore"; } log_error(INTERNAL_ERROR "Unknown discards type encountered."); return "unknown"; } lvm2-2.02.98/lib/metadata/segtype.c0000640000175000017500000000212012037016272015655 0ustar blankblank/* * Copyright (C) 2003-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 */ #include "lib.h" #include "toolcontext.h" #include "segtype.h" struct segment_type *get_segtype_from_string(struct cmd_context *cmd, const char *str) { struct segment_type *segtype; dm_list_iterate_items(segtype, &cmd->segtypes) { if (!strcmp(segtype->name, str)) return segtype; } if (!(segtype = init_unknown_segtype(cmd, str))) return_NULL; segtype->library = NULL; dm_list_add(&cmd->segtypes, &segtype->list); log_warn("WARNING: Unrecognised segment type %s", str); return segtype; } lvm2-2.02.98/lib/metadata/pv.h0000640000175000017500000000615312037016272014641 0ustar blankblank/* * 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 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_PV_H #define _LVM_PV_H struct id; struct device; struct format_type; struct volume_group; struct physical_volume { struct id id; struct id old_id; /* Set during pvchange -u. */ struct device *dev; const struct format_type *fmt; struct format_instance *fid; /* * vg_name and vgid are used before the parent VG struct exists. * FIXME: Investigate removal/substitution with 'vg' fields. */ const char *vg_name; struct id vgid; /* * 'vg' is set and maintained when the PV belongs to a 'pvs' * list in a parent VG struct. */ struct volume_group *vg; uint64_t status; uint64_t size; /* physical extents */ uint32_t pe_size; uint64_t pe_start; uint32_t pe_count; uint32_t pe_alloc_count; unsigned long pe_align; unsigned long pe_align_offset; /* This is true whenever the represented PV has a label associated. */ uint64_t is_labelled:1; /* NB. label_sector is valid whenever is_labelled is true */ uint64_t label_sector; struct dm_list segments; /* Ordered pv_segments covering complete PV */ struct dm_list tags; }; char *pv_fmt_dup(const struct physical_volume *pv); char *pv_name_dup(const struct physical_volume *pv); struct device *pv_dev(const struct physical_volume *pv); const char *pv_vg_name(const struct physical_volume *pv); char *pv_attr_dup(struct dm_pool *mem, const struct physical_volume *pv); const char *pv_dev_name(const struct physical_volume *pv); char *pv_uuid_dup(const struct physical_volume *pv); char *pv_tags_dup(const struct physical_volume *pv); uint64_t pv_size(const struct physical_volume *pv); uint64_t pv_size_field(const struct physical_volume *pv); uint64_t pv_dev_size(const struct physical_volume *pv); uint64_t pv_free(const struct physical_volume *pv); uint64_t pv_status(const struct physical_volume *pv); uint32_t pv_pe_size(const struct physical_volume *pv); uint64_t pv_pe_start(const struct physical_volume *pv); uint32_t pv_pe_count(const struct physical_volume *pv); uint32_t pv_pe_alloc_count(const struct physical_volume *pv); uint64_t pv_mda_size(const struct physical_volume *pv); uint64_t pv_mda_free(const struct physical_volume *pv); uint64_t pv_used(const struct physical_volume *pv); uint32_t pv_mda_count(const struct physical_volume *pv); uint32_t pv_mda_used_count(const struct physical_volume *pv); unsigned pv_mda_set_ignored(const struct physical_volume *pv, unsigned ignored); int is_orphan(const struct physical_volume *pv); int is_missing_pv(const struct physical_volume *pv); int is_pv(const struct physical_volume *pv); #endif /* _LVM_PV_H */ lvm2-2.02.98/lib/metadata/merge.c0000640000175000017500000003501712037016272015307 0ustar blankblank/* * 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 "metadata.h" #include "lv_alloc.h" #include "pv_alloc.h" #include "str_list.h" #include "segtype.h" /* * Attempt to merge two adjacent segments. * Currently only supports striped segments on AREA_PV. * Returns success if successful, in which case 'first' * gets adjusted to contain both areas. */ static int _merge(struct lv_segment *first, struct lv_segment *second) { if (!first || !second || first->segtype != second->segtype || !first->segtype->ops->merge_segments) return 0; return first->segtype->ops->merge_segments(first, second); } int lv_merge_segments(struct logical_volume *lv) { struct dm_list *segh, *t; struct lv_segment *current, *prev = NULL; if (lv->status & LOCKED || lv->status & PVMOVE) return 1; dm_list_iterate_safe(segh, t, &lv->segments) { current = dm_list_item(segh, struct lv_segment); if (_merge(prev, current)) dm_list_del(¤t->list); else prev = current; } return 1; } #define ERROR_MAX 100 #define inc_error_count \ if (error_count++ > ERROR_MAX) \ goto out /* * Verify that an LV's segments are consecutive, complete and don't overlap. */ int check_lv_segments(struct logical_volume *lv, int complete_vg) { struct lv_segment *seg, *seg2; uint32_t le = 0; unsigned seg_count = 0, seg_found; uint32_t area_multiplier, s; struct seg_list *sl; int error_count = 0; struct replicator_site *rsite; struct replicator_device *rdev; /* Check LV flags match first segment type */ if (complete_vg) { if (lv_is_thin_volume(lv) && (!(seg2 = first_seg(lv)) || !seg_is_thin_volume(seg2))) { log_error("LV %s is thin volume without first thin volume segment", lv->name); inc_error_count; } if (lv_is_thin_pool(lv) && (!(seg2 = first_seg(lv)) || !seg_is_thin_pool(seg2))) { log_error("LV %s is thin pool without first thin pool segment", lv->name); inc_error_count; } if (lv_is_thin_pool_data(lv) && (!(seg2 = first_seg(lv)) || !(seg2 = find_pool_seg(seg2)) || seg2->area_count != 1 || seg_type(seg2, 0) != AREA_LV || seg_lv(seg2, 0) != lv)) { log_error("LV %s: segment 1 pool data LV does not point back to same LV", lv->name); inc_error_count; } if (lv_is_thin_pool_metadata(lv) && (!(seg2 = first_seg(lv)) || !(seg2 = find_pool_seg(seg2)) || seg2->metadata_lv != lv)) { log_error("LV %s: segment 1 pool metadata LV does not point back to same LV", lv->name); inc_error_count; } } dm_list_iterate_items(seg, &lv->segments) { seg_count++; if (seg->le != le) { log_error("LV %s invalid: segment %u should begin at " "LE %" PRIu32 " (found %" PRIu32 ").", lv->name, seg_count, le, seg->le); inc_error_count; } area_multiplier = segtype_is_striped(seg->segtype) ? seg->area_count : 1; if (seg->area_len * area_multiplier != seg->len) { log_error("LV %s: segment %u has inconsistent " "area_len %u", lv->name, seg_count, seg->area_len); inc_error_count; } if (complete_vg && seg->log_lv && !seg_is_mirrored(seg) && !(seg->status & RAID_IMAGE)) { log_error("LV %s: segment %u log LV %s is not a " "mirror log or a RAID image", lv->name, seg_count, seg->log_lv->name); inc_error_count; } /* * Check mirror log - which is attached to the mirrored seg */ if (complete_vg && seg->log_lv && seg_is_mirrored(seg)) { if (!(seg->log_lv->status & MIRROR_LOG)) { log_error("LV %s: segment %u log LV %s is not " "a mirror log", lv->name, seg_count, seg->log_lv->name); inc_error_count; } if (!(seg2 = first_seg(seg->log_lv)) || find_mirror_seg(seg2) != seg) { log_error("LV %s: segment %u log LV does not " "point back to mirror segment", lv->name, seg_count); inc_error_count; } } if (complete_vg && seg->status & MIRROR_IMAGE) { if (!find_mirror_seg(seg) || !seg_is_mirrored(find_mirror_seg(seg))) { log_error("LV %s: segment %u mirror image " "is not mirrored", lv->name, seg_count); inc_error_count; } } /* Check the various thin segment types */ if (complete_vg) { if (seg_is_thin_pool(seg)) { if (!lv_is_thin_pool(lv)) { log_error("LV %s is missing thin pool flag for segment %u", lv->name, seg_count); inc_error_count; } if (lv_is_thin_volume(lv)) { log_error("LV %s is a thin volume that must not contain thin pool segment %u", lv->name, seg_count); inc_error_count; } if (seg->area_count != 1 || seg_type(seg, 0) != AREA_LV) { log_error("LV %s: thin pool segment %u is missing a pool data LV", lv->name, seg_count); inc_error_count; } else if (!(seg2 = first_seg(seg_lv(seg, 0))) || find_pool_seg(seg2) != seg) { log_error("LV %s: thin pool segment %u data LV does not refer back to pool LV", lv->name, seg_count); inc_error_count; } if (!seg->metadata_lv) { log_error("LV %s: thin pool segment %u is missing a pool metadata LV", lv->name, seg_count); inc_error_count; } else if (!(seg2 = first_seg(seg->metadata_lv)) || find_pool_seg(seg2) != seg) { log_error("LV %s: thin pool segment %u metadata LV does not refer back to pool LV", lv->name, seg_count); inc_error_count; } if (seg->chunk_size < DM_THIN_MIN_DATA_BLOCK_SIZE || seg->chunk_size > DM_THIN_MAX_DATA_BLOCK_SIZE) { log_error("LV %s: thin pool segment %u has chunk size %u out of range.", lv->name, seg_count, seg->chunk_size); inc_error_count; } } else { if (seg->metadata_lv) { log_error("LV %s: segment %u must not have thin pool metadata LV set", lv->name, seg_count); inc_error_count; } } if (seg_is_thin_volume(seg)) { if (!lv_is_thin_volume(lv)) { log_error("LV %s is missing thin volume flag for segment %u", lv->name, seg_count); inc_error_count; } if (lv_is_thin_pool(lv)) { log_error("LV %s is a thin pool that must not contain thin volume segment %u", lv->name, seg_count); inc_error_count; } if (!seg->pool_lv) { log_error("LV %s: segment %u is missing thin pool LV", lv->name, seg_count); inc_error_count; } else if (!lv_is_thin_pool(seg->pool_lv)) { log_error("LV %s: thin volume segment %u pool LV is not flagged as a pool LV", lv->name, seg_count); inc_error_count; } if (seg->device_id > DM_THIN_MAX_DEVICE_ID) { log_error("LV %s: thin volume segment %u has too large device id %u", lv->name, seg_count, seg->device_id); inc_error_count; } } else { if (seg->pool_lv) { log_error("LV %s: segment %u must not have thin pool LV set", lv->name, seg_count); inc_error_count; } } } if (seg_is_snapshot(seg)) { if (seg->cow && seg->cow == seg->origin) { log_error("LV %s: segment %u has same LV %s for " "both origin and snapshot", lv->name, seg_count, seg->cow->name); inc_error_count; } } if (seg_is_replicator(seg) && !check_replicator_segment(seg)) inc_error_count; for (s = 0; s < seg->area_count; s++) { if (seg_type(seg, s) == AREA_UNASSIGNED) { log_error("LV %s: segment %u has unassigned " "area %u.", lv->name, seg_count, s); inc_error_count; } else if (seg_type(seg, s) == AREA_PV) { if (!seg_pvseg(seg, s) || seg_pvseg(seg, s)->lvseg != seg || seg_pvseg(seg, s)->lv_area != s) { log_error("LV %s: segment %u has " "inconsistent PV area %u", lv->name, seg_count, s); inc_error_count; } } else { if (!seg_lv(seg, s) || seg_lv(seg, s)->vg != lv->vg || seg_lv(seg, s) == lv) { log_error("LV %s: segment %u has " "inconsistent LV area %u", lv->name, seg_count, s); inc_error_count; } if (complete_vg && seg_lv(seg, s) && (seg_lv(seg, s)->status & MIRROR_IMAGE) && (!(seg2 = find_seg_by_le(seg_lv(seg, s), seg_le(seg, s))) || find_mirror_seg(seg2) != seg)) { log_error("LV %s: segment %u mirror " "image %u missing mirror ptr", lv->name, seg_count, s); inc_error_count; } /* FIXME I don't think this ever holds? if (seg_le(seg, s) != le) { log_error("LV %s: segment %u has " "inconsistent LV area %u " "size", lv->name, seg_count, s); inc_error_count; } */ seg_found = 0; dm_list_iterate_items(sl, &seg_lv(seg, s)->segs_using_this_lv) if (sl->seg == seg) seg_found++; if (!seg_found) { log_error("LV %s segment %u uses LV %s," " but missing ptr from %s to %s", lv->name, seg_count, seg_lv(seg, s)->name, seg_lv(seg, s)->name, lv->name); inc_error_count; } else if (seg_found > 1) { log_error("LV %s has duplicated links " "to LV %s segment %u", seg_lv(seg, s)->name, lv->name, seg_count); inc_error_count; } } if (complete_vg && seg_is_mirrored(seg) && !seg_is_raid(seg) && seg_type(seg, s) == AREA_LV && seg_lv(seg, s)->le_count != seg->area_len) { log_error("LV %s: mirrored LV segment %u has " "wrong size %u (should be %u).", lv->name, s, seg_lv(seg, s)->le_count, seg->area_len); inc_error_count; } } le += seg->len; } dm_list_iterate_items(sl, &lv->segs_using_this_lv) { seg = sl->seg; seg_found = 0; for (s = 0; s < seg->area_count; s++) { if (seg_type(seg, s) != AREA_LV) continue; if (lv == seg_lv(seg, s)) seg_found++; if (seg_is_raid(seg) && (lv == seg_metalv(seg, s))) seg_found++; } if (seg_is_replicator_dev(seg)) { dm_list_iterate_items(rsite, &seg->replicator->rsites) { dm_list_iterate_items(rdev, &rsite->rdevices) { if (lv == rdev->lv || lv == rdev->slog) seg_found++; } } if (lv == seg->replicator) seg_found++; } if (seg_is_replicator(seg) && lv == seg->rlog_lv) seg_found++; if (seg->log_lv == lv) seg_found++; if (seg->metadata_lv == lv || seg->pool_lv == lv) seg_found++; if (seg_is_thin_volume(seg) && seg->origin == lv) seg_found++; if (!seg_found) { log_error("LV %s is used by LV %s:%" PRIu32 "-%" PRIu32 ", but missing ptr from %s to %s", lv->name, seg->lv->name, seg->le, seg->le + seg->len - 1, seg->lv->name, lv->name); inc_error_count; } else if (seg_found != sl->count) { log_error("Reference count mismatch: LV %s has %u " "links to LV %s:%" PRIu32 "-%" PRIu32 ", which has %u links", lv->name, sl->count, seg->lv->name, seg->le, seg->le + seg->len - 1, seg_found); inc_error_count; } seg_found = 0; dm_list_iterate_items(seg2, &seg->lv->segments) if (sl->seg == seg2) { seg_found++; break; } if (!seg_found) { log_error("LV segment %s:%" PRIu32 "-%" PRIu32 " is incorrectly listed as being used by LV %s", seg->lv->name, seg->le, seg->le + seg->len - 1, lv->name); inc_error_count; } } if (le != lv->le_count) { log_error("LV %s: inconsistent LE count %u != %u", lv->name, le, lv->le_count); inc_error_count; } out: return !error_count; } /* * Split the supplied segment at the supplied logical extent * NB Use LE numbering that works across stripes PV1: 0,2,4 PV2: 1,3,5 etc. */ static int _lv_split_segment(struct logical_volume *lv, struct lv_segment *seg, uint32_t le) { struct lv_segment *split_seg; uint32_t s; uint32_t offset = le - seg->le; uint32_t area_offset; if (!seg_can_split(seg)) { log_error("Unable to split the %s segment at LE %" PRIu32 " in LV %s", seg->segtype->ops->name(seg), le, lv->name); return 0; } /* Clone the existing segment */ if (!(split_seg = alloc_lv_segment(seg->segtype, seg->lv, seg->le, seg->len, seg->status, seg->stripe_size, seg->log_lv, seg->pool_lv, seg->area_count, seg->area_len, seg->chunk_size, seg->region_size, seg->extents_copied, seg->pvmove_source_seg))) { log_error("Couldn't allocate cloned LV segment."); return 0; } if (!str_list_dup(lv->vg->vgmem, &split_seg->tags, &seg->tags)) { log_error("LV segment tags duplication failed"); return 0; } /* In case of a striped segment, the offset has to be / stripes */ area_offset = offset; if (seg_is_striped(seg)) area_offset /= seg->area_count; split_seg->area_len -= area_offset; seg->area_len = area_offset; split_seg->len -= offset; seg->len = offset; split_seg->le = seg->le + seg->len; /* Adjust the PV mapping */ for (s = 0; s < seg->area_count; s++) { seg_type(split_seg, s) = seg_type(seg, s); /* Split area at the offset */ switch (seg_type(seg, s)) { case AREA_LV: if (!set_lv_segment_area_lv(split_seg, s, seg_lv(seg, s), seg_le(seg, s) + seg->area_len, 0)) return_0; log_debug("Split %s:%u[%u] at %u: %s LE %u", lv->name, seg->le, s, le, seg_lv(seg, s)->name, seg_le(split_seg, s)); break; case AREA_PV: if (!(seg_pvseg(split_seg, s) = assign_peg_to_lvseg(seg_pv(seg, s), seg_pe(seg, s) + seg->area_len, seg_pvseg(seg, s)->len - seg->area_len, split_seg, s))) return_0; log_debug("Split %s:%u[%u] at %u: %s PE %u", lv->name, seg->le, s, le, dev_name(seg_dev(seg, s)), seg_pe(split_seg, s)); break; case AREA_UNASSIGNED: log_error("Unassigned area %u found in segment", s); return 0; } } /* Add split off segment to the list _after_ the original one */ dm_list_add_h(&seg->list, &split_seg->list); return 1; } /* * Ensure there's a segment boundary at the given logical extent */ int lv_split_segment(struct logical_volume *lv, uint32_t le) { struct lv_segment *seg; if (!(seg = find_seg_by_le(lv, le))) { log_error("Segment with extent %" PRIu32 " in LV %s not found", le, lv->name); return 0; } /* This is a segment start already */ if (le == seg->le) return 1; if (!_lv_split_segment(lv, seg, le)) return_0; if (!vg_validate(lv->vg)) return_0; return 1; } lvm2-2.02.98/lib/metadata/snapshot_manip.c0000640000175000017500000001336012037016272017230 0ustar blankblank/* * 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 */ #include "lib.h" #include "metadata.h" #include "locking.h" #include "toolcontext.h" #include "lv_alloc.h" #include "activate.h" int lv_is_origin(const struct logical_volume *lv) { return lv->origin_count ? 1 : 0; } int lv_is_cow(const struct logical_volume *lv) { return (!lv_is_origin(lv) && lv->snapshot) ? 1 : 0; } int lv_is_visible(const struct logical_volume *lv) { if (lv->status & SNAPSHOT) return 0; if (lv_is_cow(lv)) { if (lv_is_virtual_origin(origin_from_cow(lv))) return 1; if (lv_is_merging_cow(lv)) return 0; return lv_is_visible(origin_from_cow(lv)); } return lv->status & VISIBLE_LV ? 1 : 0; } int lv_is_virtual_origin(const struct logical_volume *lv) { return (lv->status & VIRTUAL_ORIGIN) ? 1 : 0; } int lv_is_merging_origin(const struct logical_volume *origin) { return (origin->status & MERGING) ? 1 : 0; } struct lv_segment *find_merging_cow(const struct logical_volume *origin) { if (!lv_is_merging_origin(origin)) return NULL; return find_cow(origin); } int lv_is_merging_cow(const struct logical_volume *snapshot) { /* checks lv_segment's status to see if cow is merging */ return (find_cow(snapshot)->status & MERGING) ? 1 : 0; } /* Given a cow LV, return the snapshot lv_segment that uses it */ struct lv_segment *find_cow(const struct logical_volume *lv) { return lv->snapshot; } /* Given a cow LV, return its origin */ struct logical_volume *origin_from_cow(const struct logical_volume *lv) { if (lv->snapshot) return lv->snapshot->origin; return NULL; } void init_snapshot_seg(struct lv_segment *seg, struct logical_volume *origin, struct logical_volume *cow, uint32_t chunk_size, int merge) { seg->chunk_size = chunk_size; seg->origin = origin; seg->cow = cow; lv_set_hidden(cow); cow->snapshot = seg; origin->origin_count++; /* FIXME Assumes an invisible origin belongs to a sparse device */ if (!lv_is_visible(origin)) origin->status |= VIRTUAL_ORIGIN; seg->lv->status |= (SNAPSHOT | VIRTUAL); if (merge) init_snapshot_merge(seg, origin); dm_list_add(&origin->snapshot_segs, &seg->origin_list); } void init_snapshot_merge(struct lv_segment *cow_seg, struct logical_volume *origin) { /* * Even though lv_is_visible(cow_seg->lv) returns 0, * the cow_seg->lv (name: snapshotX) is _not_ hidden; * this is part of the lvm2 snapshot fiction. Must * clear VISIBLE_LV directly (lv_set_visible can't) * - cow_seg->lv->status is used to control whether 'lv' * (with user provided snapshot LV name) is visible * - this also enables vg_validate() to succeed with * merge metadata (cow_seg->lv is now "internal") */ cow_seg->lv->status &= ~VISIBLE_LV; cow_seg->status |= MERGING; origin->snapshot = cow_seg; origin->status |= MERGING; } void clear_snapshot_merge(struct logical_volume *origin) { /* clear merge attributes */ origin->snapshot->status &= ~MERGING; origin->snapshot = NULL; origin->status &= ~MERGING; } int vg_add_snapshot(struct logical_volume *origin, struct logical_volume *cow, union lvid *lvid, uint32_t extent_count, uint32_t chunk_size) { struct logical_volume *snap; struct lv_segment *seg; /* * Is the cow device already being used ? */ if (lv_is_cow(cow)) { log_error("'%s' is already in use as a snapshot.", cow->name); return 0; } if (cow == origin) { log_error("Snapshot and origin LVs must differ."); return 0; } if (!(snap = lv_create_empty("snapshot%d", lvid, LVM_READ | LVM_WRITE | VISIBLE_LV, ALLOC_INHERIT, origin->vg))) return_0; snap->le_count = extent_count; if (!(seg = alloc_snapshot_seg(snap, 0, 0))) return_0; init_snapshot_seg(seg, origin, cow, chunk_size, 0); return 1; } int vg_remove_snapshot(struct logical_volume *cow) { int merging_snapshot = 0; struct logical_volume *origin = origin_from_cow(cow); dm_list_del(&cow->snapshot->origin_list); origin->origin_count--; if (find_merging_cow(origin) == find_cow(cow)) { clear_snapshot_merge(origin); /* * preload origin IFF "snapshot-merge" target is active * - IMPORTANT: avoids preload if onactivate merge is pending */ if (lv_has_target_type(origin->vg->cmd->mem, origin, NULL, "snapshot-merge")) { /* * preload origin to: * - allow proper release of -cow * - avoid allocations with other devices suspended * when transitioning from "snapshot-merge" to * "snapshot-origin after a merge completes. */ merging_snapshot = 1; } } if (!lv_remove(cow->snapshot->lv)) { log_error("Failed to remove internal snapshot LV %s", cow->snapshot->lv->name); return 0; } cow->snapshot = NULL; lv_set_visible(cow); /* format1 must do the change in one step, with the commit last. */ if (!(origin->vg->fid->fmt->features & FMT_MDAS)) return 1; if (!vg_write(origin->vg)) return_0; if (!suspend_lv(origin->vg->cmd, origin)) { log_error("Failed to refresh %s without snapshot.", origin->name); return 0; } if (!vg_commit(origin->vg)) return_0; if (!merging_snapshot && !resume_lv(origin->vg->cmd, cow)) { log_error("Failed to resume %s.", cow->name); return 0; } if (!resume_lv(origin->vg->cmd, origin)) { log_error("Failed to resume %s.", origin->name); return 0; } return 1; } lvm2-2.02.98/lib/metadata/lv.c0000640000175000017500000003266212037016272014634 0ustar blankblank/* * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU 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 "metadata.h" #include "display.h" #include "activate.h" #include "toolcontext.h" #include "segtype.h" #include "str_list.h" #include #include static struct utsname _utsname; static int _utsinit = 0; static char *_format_pvsegs(struct dm_pool *mem, const struct lv_segment *seg, int range_format) { unsigned int s; const char *name = NULL; uint32_t extent = 0; char extent_str[32]; if (!dm_pool_begin_object(mem, 256)) { log_error("dm_pool_begin_object failed"); return NULL; } for (s = 0; s < seg->area_count; s++) { switch (seg_type(seg, s)) { case AREA_LV: name = seg_lv(seg, s)->name; extent = seg_le(seg, s); break; case AREA_PV: name = dev_name(seg_dev(seg, s)); extent = seg_pe(seg, s); break; case AREA_UNASSIGNED: name = "unassigned"; extent = 0; break; default: log_error(INTERNAL_ERROR "Unknown area segtype."); return NULL; } if (!dm_pool_grow_object(mem, name, strlen(name))) { log_error("dm_pool_grow_object failed"); return NULL; } if (dm_snprintf(extent_str, sizeof(extent_str), "%s%" PRIu32 "%s", range_format ? ":" : "(", extent, range_format ? "-" : ")") < 0) { log_error("Extent number dm_snprintf failed"); return NULL; } if (!dm_pool_grow_object(mem, extent_str, strlen(extent_str))) { log_error("dm_pool_grow_object failed"); return NULL; } if (range_format) { if (dm_snprintf(extent_str, sizeof(extent_str), "%" PRIu32, extent + seg->area_len - 1) < 0) { log_error("Extent number dm_snprintf failed"); return NULL; } if (!dm_pool_grow_object(mem, extent_str, strlen(extent_str))) { log_error("dm_pool_grow_object failed"); return NULL; } } if ((s != seg->area_count - 1) && !dm_pool_grow_object(mem, range_format ? " " : ",", 1)) { log_error("dm_pool_grow_object failed"); return NULL; } } if (!dm_pool_grow_object(mem, "\0", 1)) { log_error("dm_pool_grow_object failed"); return NULL; } return dm_pool_end_object(mem); } char *lvseg_devices(struct dm_pool *mem, const struct lv_segment *seg) { return _format_pvsegs(mem, seg, 0); } char *lvseg_seg_pe_ranges(struct dm_pool *mem, const struct lv_segment *seg) { return _format_pvsegs(mem, seg, 1); } char *lvseg_tags_dup(const struct lv_segment *seg) { return tags_format_and_copy(seg->lv->vg->vgmem, &seg->tags); } char *lvseg_segtype_dup(struct dm_pool *mem, const struct lv_segment *seg) { return dm_pool_strdup(mem, seg->segtype->ops->name(seg)); } uint64_t lvseg_chunksize(const struct lv_segment *seg) { uint64_t size; if (lv_is_cow(seg->lv)) size = (uint64_t) find_cow(seg->lv)->chunk_size; else if (lv_is_thin_pool(seg->lv)) size = (uint64_t) seg->chunk_size; else size = UINT64_C(0); return size; } uint64_t lvseg_start(const struct lv_segment *seg) { return (uint64_t) seg->le * seg->lv->vg->extent_size; } uint64_t lvseg_size(const struct lv_segment *seg) { return (uint64_t) seg->len * seg->lv->vg->extent_size; } uint32_t lv_kernel_read_ahead(const struct logical_volume *lv) { struct lvinfo info; if (!lv_info(lv->vg->cmd, lv, 0, &info, 0, 1) || !info.exists) return UINT32_MAX; return info.read_ahead; } char *lv_origin_dup(struct dm_pool *mem, const struct logical_volume *lv) { if (lv_is_cow(lv)) return lv_name_dup(mem, origin_from_cow(lv)); if (lv_is_thin_volume(lv) && first_seg(lv)->origin) return lv_name_dup(mem, first_seg(lv)->origin); return NULL; } char *lv_name_dup(struct dm_pool *mem, const struct logical_volume *lv) { return dm_pool_strdup(mem, lv->name); } char *lv_modules_dup(struct dm_pool *mem, const struct logical_volume *lv) { struct dm_list *modules; if (!(modules = str_list_create(mem))) { log_error("modules str_list allocation failed"); return NULL; } if (!list_lv_modules(mem, lv, modules)) return_NULL; return tags_format_and_copy(mem, modules); } char *lv_mirror_log_dup(struct dm_pool *mem, const struct logical_volume *lv) { struct lv_segment *seg; dm_list_iterate_items(seg, &lv->segments) if (seg_is_mirrored(seg) && seg->log_lv) return dm_pool_strdup(mem, seg->log_lv->name); return NULL; } char *lv_pool_lv_dup(struct dm_pool *mem, const struct logical_volume *lv) { struct lv_segment *seg; dm_list_iterate_items(seg, &lv->segments) if (seg_is_thin_volume(seg) && seg->pool_lv) return dm_pool_strdup(mem, seg->pool_lv->name); return NULL; } char *lv_data_lv_dup(struct dm_pool *mem, const struct logical_volume *lv) { return lv_is_thin_pool(lv) ? dm_pool_strdup(mem, seg_lv(first_seg(lv), 0)->name) : NULL; } char *lv_metadata_lv_dup(struct dm_pool *mem, const struct logical_volume *lv) { return lv_is_thin_pool(lv) ? dm_pool_strdup(mem, first_seg(lv)->metadata_lv->name) : NULL; } int lv_kernel_minor(const struct logical_volume *lv) { struct lvinfo info; if (lv_info(lv->vg->cmd, lv, 0, &info, 0, 0) && info.exists) return info.minor; return -1; } int lv_kernel_major(const struct logical_volume *lv) { struct lvinfo info; if (lv_info(lv->vg->cmd, lv, 0, &info, 0, 0) && info.exists) return info.major; return -1; } char *lv_convert_lv_dup(struct dm_pool *mem, const struct logical_volume *lv) { struct lv_segment *seg; if (lv->status & (CONVERTING|MIRRORED)) { seg = first_seg(lv); /* Temporary mirror is always area_num == 0 */ if (seg_type(seg, 0) == AREA_LV && is_temporary_mirror_layer(seg_lv(seg, 0))) return dm_pool_strdup(mem, seg_lv(seg, 0)->name); } return NULL; } char *lv_move_pv_dup(struct dm_pool *mem, const struct logical_volume *lv) { struct lv_segment *seg; dm_list_iterate_items(seg, &lv->segments) { if (seg->status & PVMOVE) return dm_pool_strdup(mem, dev_name(seg_dev(seg, 0))); } return NULL; } uint64_t lv_origin_size(const struct logical_volume *lv) { if (lv_is_cow(lv)) return (uint64_t) find_cow(lv)->len * lv->vg->extent_size; if (lv_is_origin(lv)) return lv->size; return 0; } uint64_t lv_metadata_size(const struct logical_volume *lv) { return lv_is_thin_pool(lv) ? first_seg(lv)->metadata_lv->size : 0; } char *lv_path_dup(struct dm_pool *mem, const struct logical_volume *lv) { char *repstr; size_t len; if (!*lv->vg->name) return dm_pool_strdup(mem, ""); len = strlen(lv->vg->cmd->dev_dir) + strlen(lv->vg->name) + strlen(lv->name) + 2; if (!(repstr = dm_pool_zalloc(mem, len))) { log_error("dm_pool_alloc failed"); return 0; } if (dm_snprintf(repstr, len, "%s%s/%s", lv->vg->cmd->dev_dir, lv->vg->name, lv->name) < 0) { log_error("lvpath snprintf failed"); return 0; } return repstr; } char *lv_uuid_dup(const struct logical_volume *lv) { return id_format_and_copy(lv->vg->vgmem, &lv->lvid.id[1]); } char *lv_tags_dup(const struct logical_volume *lv) { return tags_format_and_copy(lv->vg->vgmem, &lv->tags); } uint64_t lv_size(const struct logical_volume *lv) { return lv->size; } static int _lv_mimage_in_sync(const struct logical_volume *lv) { percent_t percent; struct lv_segment *mirror_seg = find_mirror_seg(first_seg(lv)); if (!(lv->status & MIRROR_IMAGE) || !mirror_seg) return_0; if (!lv_mirror_percent(lv->vg->cmd, mirror_seg->lv, 0, &percent, NULL)) return_0; return (percent == PERCENT_100) ? 1 : 0; } static int _lv_raid_image_in_sync(const struct logical_volume *lv) { percent_t percent; struct lv_segment *raid_seg; if (!(lv->status & RAID_IMAGE)) { log_error(INTERNAL_ERROR "%s is not a RAID image", lv->name); return 0; } raid_seg = get_only_segment_using_this_lv(first_seg(lv)->lv); if (!raid_seg) { log_error("Failed to find RAID segment for %s", lv->name); return 0; } if (!seg_is_raid(raid_seg)) { log_error("%s on %s is not a RAID segment", raid_seg->lv->name, lv->name); return 0; } if (!lv_raid_percent(raid_seg->lv, &percent)) return_0; if (percent == PERCENT_100) return 1; /* * FIXME: Get individual RAID image status. * The status health characters reported from a RAID target * indicate whether the whole array or just individual devices * are in-sync. If the corresponding character for this image * was 'A', we could report a more accurate status. This is * especially so in the case of failures or rebuildings. * * We need to test the health characters anyway to report * the correct 4th attr character. Just need to figure out * where to put this functionality. */ return 0; } char *lv_attr_dup(struct dm_pool *mem, const struct logical_volume *lv) { percent_t snap_percent; struct lvinfo info; struct lv_segment *seg; char *repstr; if (!(repstr = dm_pool_zalloc(mem, 10))) { log_error("dm_pool_alloc failed"); return 0; } /* Blank if this is a "free space" LV. */ if (!*lv->name) goto out; if (lv->status & PVMOVE) repstr[0] = 'p'; else if (lv->status & CONVERTING) repstr[0] = 'c'; /* Origin takes precedence over mirror and thin volume */ else if (lv_is_origin(lv)) repstr[0] = (lv_is_merging_origin(lv)) ? 'O' : 'o'; else if (lv->status & RAID) repstr[0] = (lv->status & LV_NOTSYNCED) ? 'R' : 'r'; else if (lv->status & MIRRORED) repstr[0] = (lv->status & LV_NOTSYNCED) ? 'M' : 'm'; else if (lv_is_thin_volume(lv)) repstr[0] = 'V'; else if (lv->status & VIRTUAL) repstr[0] = 'v'; else if (lv_is_thin_pool(lv)) repstr[0] = 't'; else if (lv_is_thin_pool_data(lv)) repstr[0] = 'T'; else if (lv_is_thin_pool_metadata(lv) || (lv->status & RAID_META)) repstr[0] = 'e'; else if (lv->status & MIRROR_IMAGE) repstr[0] = (_lv_mimage_in_sync(lv)) ? 'i' : 'I'; else if (lv->status & RAID_IMAGE) repstr[0] = (_lv_raid_image_in_sync(lv)) ? 'i' : 'I'; else if (lv->status & MIRROR_LOG) repstr[0] = 'l'; else if (lv_is_cow(lv)) { repstr[0] = (lv_is_merging_cow(lv)) ? 'S' : 's'; } else repstr[0] = '-'; if (lv->status & PVMOVE) repstr[1] = '-'; else if (lv->status & LVM_WRITE) repstr[1] = 'w'; else if (lv->status & LVM_READ) repstr[1] = 'r'; else repstr[1] = '-'; repstr[2] = alloc_policy_char(lv->alloc); if (lv->status & LOCKED) repstr[2] = toupper(repstr[2]); repstr[3] = (lv->status & FIXED_MINOR) ? 'm' : '-'; if (lv_info(lv->vg->cmd, lv, 0, &info, 1, 0) && info.exists) { if (info.suspended) repstr[4] = 's'; /* Suspended */ else if (info.live_table) repstr[4] = 'a'; /* Active */ else if (info.inactive_table) repstr[4] = 'i'; /* Inactive with table */ else repstr[4] = 'd'; /* Inactive without table */ /* Snapshot dropped? */ if (info.live_table && lv_is_cow(lv)) { if (!lv_snapshot_percent(lv, &snap_percent) || snap_percent == PERCENT_INVALID) { if (info.suspended) repstr[4] = 'S'; /* Susp Inv snapshot */ else repstr[4] = 'I'; /* Invalid snapshot */ } else if (snap_percent == PERCENT_MERGE_FAILED) { if (info.suspended) repstr[4] = 'M'; /* Susp snapshot merge failed */ else repstr[4] = 'm'; /* snapshot merge failed */ } } /* * 'R' indicates read-only activation of a device that * does not have metadata flagging it as read-only. */ if (repstr[1] != 'r' && info.read_only) repstr[1] = 'R'; repstr[5] = (info.open_count) ? 'o' : '-'; } else { repstr[4] = '-'; repstr[5] = '-'; } if (lv_is_thin_type(lv)) repstr[6] = 't'; else if (lv_is_raid_type(lv)) repstr[6] = 'r'; else if (lv_is_mirror_type(lv)) repstr[6] = 'm'; else if (lv_is_cow(lv) || lv_is_origin(lv)) repstr[6] = 's'; else if (lv_has_unknown_segments(lv)) repstr[6] = 'u'; else if (lv_is_virtual(lv)) repstr[6] = 'v'; else repstr[6] = '-'; if (((lv_is_thin_volume(lv) && (seg = first_seg(lv)) && seg->pool_lv && (seg = first_seg(seg->pool_lv))) || (lv_is_thin_pool(lv) && (seg = first_seg(lv)))) && seg->zero_new_blocks) repstr[7] = 'z'; else repstr[7] = '-'; if (lv->status & PARTIAL_LV) repstr[8] = 'p'; else repstr[8] = '-'; out: return repstr; } int lv_set_creation(struct logical_volume *lv, const char *hostname, uint64_t timestamp) { const char *hn; if (!hostname) { if (!_utsinit) { if (uname(&_utsname)) { log_error("uname failed: %s", strerror(errno)); memset(&_utsname, 0, sizeof(_utsname)); } _utsinit = 1; } hostname = _utsname.nodename; } if (!(hn = dm_hash_lookup(lv->vg->hostnames, hostname))) { if (!(hn = dm_pool_strdup(lv->vg->vgmem, hostname))) { log_error("Failed to duplicate hostname"); return 0; } if (!dm_hash_insert(lv->vg->hostnames, hostname, (void*)hn)) return_0; } lv->hostname = hn; lv->timestamp = timestamp ? : (uint64_t) time(NULL); return 1; } char *lv_time_dup(struct dm_pool *mem, const struct logical_volume *lv) { char buffer[50]; struct tm *local_tm; time_t ts = (time_t)lv->timestamp; if (!ts || !(local_tm = localtime(&ts)) || /* FIXME: make this lvm.conf configurable */ !strftime(buffer, sizeof(buffer), "%Y-%m-%d %T %z", local_tm)) buffer[0] = 0; return dm_pool_strdup(mem, buffer); } char *lv_host_dup(struct dm_pool *mem, const struct logical_volume *lv) { return dm_pool_strdup(mem, lv->hostname ? : ""); } lvm2-2.02.98/lib/metadata/pv_manip.c0000640000175000017500000003205612037016272016021 0ustar blankblank/* * Copyright (C) 2003 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 */ #include "lib.h" #include "metadata.h" #include "pv_alloc.h" #include "toolcontext.h" #include "locking.h" #include "defaults.h" static struct pv_segment *_alloc_pv_segment(struct dm_pool *mem, struct physical_volume *pv, uint32_t pe, uint32_t len, struct lv_segment *lvseg, uint32_t lv_area) { struct pv_segment *peg; if (!(peg = dm_pool_zalloc(mem, sizeof(*peg)))) { log_error("pv_segment allocation failed"); return NULL; } peg->pv = pv; peg->pe = pe; peg->len = len; peg->lvseg = lvseg; peg->lv_area = lv_area; dm_list_init(&peg->list); return peg; } int alloc_pv_segment_whole_pv(struct dm_pool *mem, struct physical_volume *pv) { struct pv_segment *peg; if (!pv->pe_count) return 1; /* FIXME Cope with holes in PVs */ if (!(peg = _alloc_pv_segment(mem, pv, 0, pv->pe_count, NULL, 0))) return_0; dm_list_add(&pv->segments, &peg->list); return 1; } int peg_dup(struct dm_pool *mem, struct dm_list *peg_new, struct dm_list *peg_old) { struct pv_segment *peg, *pego; dm_list_init(peg_new); dm_list_iterate_items(pego, peg_old) { if (!(peg = _alloc_pv_segment(mem, pego->pv, pego->pe, pego->len, pego->lvseg, pego->lv_area))) return_0; dm_list_add(peg_new, &peg->list); } return 1; } /* Find segment at a given physical extent in a PV */ static struct pv_segment *find_peg_by_pe(const struct physical_volume *pv, uint32_t pe) { struct pv_segment *pvseg; /* search backwards to optimise mostly used last segment split */ dm_list_iterate_back_items(pvseg, &pv->segments) if (pe >= pvseg->pe && pe < pvseg->pe + pvseg->len) return pvseg; return NULL; } /* * Split peg at given extent. * Second part is always not allocated to a LV and returned. */ static struct pv_segment *_pv_split_segment(struct dm_pool *mem, struct physical_volume *pv, struct pv_segment *peg, uint32_t pe) { struct pv_segment *peg_new; if (!(peg_new = _alloc_pv_segment(mem, peg->pv, pe, peg->len + peg->pe - pe, NULL, 0))) return_NULL; peg->len = peg->len - peg_new->len; dm_list_add_h(&peg->list, &peg_new->list); if (peg->lvseg) { peg->pv->pe_alloc_count -= peg_new->len; peg->lvseg->lv->vg->free_count += peg_new->len; } return peg_new; } /* * Ensure there is a PV segment boundary at the given extent. */ int pv_split_segment(struct dm_pool *mem, struct physical_volume *pv, uint32_t pe, struct pv_segment **pvseg_allocated) { struct pv_segment *pvseg, *pvseg_new = NULL; if (pe == pv->pe_count) goto out; if (!(pvseg = find_peg_by_pe(pv, pe))) { log_error("Segment with extent %" PRIu32 " in PV %s not found", pe, pv_dev_name(pv)); return 0; } /* This is a peg start already */ if (pe == pvseg->pe) { pvseg_new = pvseg; goto out; } if (!(pvseg_new = _pv_split_segment(mem, pv, pvseg, pe))) return_0; out: if (pvseg_allocated) *pvseg_allocated = pvseg_new; return 1; } static struct pv_segment null_pv_segment = { .pv = NULL, .pe = 0, }; struct pv_segment *assign_peg_to_lvseg(struct physical_volume *pv, uint32_t pe, uint32_t area_len, struct lv_segment *seg, uint32_t area_num) { struct pv_segment *peg = NULL; /* Missing format1 PV */ if (!pv) return &null_pv_segment; if (!pv_split_segment(seg->lv->vg->vgmem, pv, pe, &peg) || !pv_split_segment(seg->lv->vg->vgmem, pv, pe + area_len, NULL)) return_NULL; if (!peg) { log_error("Missing PV segment on %s at %u.", pv_dev_name(pv), pe); return NULL; } peg->lvseg = seg; peg->lv_area = area_num; peg->pv->pe_alloc_count += area_len; peg->lvseg->lv->vg->free_count -= area_len; return peg; } int discard_pv_segment(struct pv_segment *peg, uint32_t discard_area_reduction) { uint64_t discard_offset_sectors; uint64_t pe_start = peg->pv->pe_start; char uuid[64] __attribute__((aligned(8))); if (!peg->lvseg) { log_error("discard_pv_segment with unallocated segment: " "%s PE %" PRIu32, pv_dev_name(peg->pv), peg->pe); return 0; } /* * Only issue discards if enabled in lvm.conf and both * the device and kernel (>= 2.6.35) supports discards. */ if (!find_config_tree_bool(peg->pv->fmt->cmd, "devices/issue_discards", DEFAULT_ISSUE_DISCARDS)) return 1; /* Missing PV? */ if (is_missing_pv(peg->pv) || !peg->pv->dev) { if (!id_write_format(&peg->pv->id, uuid, sizeof(uuid))) return_0; log_verbose("Skipping discard on missing device with uuid %s.", uuid); return 1; } if (!dev_discard_max_bytes(peg->pv->fmt->cmd->sysfs_dir, peg->pv->dev) || !dev_discard_granularity(peg->pv->fmt->cmd->sysfs_dir, peg->pv->dev)) return 1; discard_offset_sectors = (peg->pe + peg->lvseg->area_len - discard_area_reduction) * (uint64_t) peg->pv->vg->extent_size + pe_start; if (!discard_offset_sectors) { /* * pe_start=0 and the PV's first extent contains the label. * Must skip past the first extent. */ discard_offset_sectors = peg->pv->vg->extent_size; discard_area_reduction--; } log_debug("Discarding %" PRIu32 " extents offset %" PRIu64 " sectors on %s.", discard_area_reduction, discard_offset_sectors, dev_name(peg->pv->dev)); if (discard_area_reduction && !dev_discard_blocks(peg->pv->dev, discard_offset_sectors << SECTOR_SHIFT, discard_area_reduction * (uint64_t) peg->pv->vg->extent_size * SECTOR_SIZE)) return_0; return 1; } int release_pv_segment(struct pv_segment *peg, uint32_t area_reduction) { if (!peg->lvseg) { log_error("release_pv_segment with unallocated segment: " "%s PE %" PRIu32, pv_dev_name(peg->pv), peg->pe); return 0; } if (peg->lvseg->area_len == area_reduction) { peg->pv->pe_alloc_count -= area_reduction; peg->lvseg->lv->vg->free_count += area_reduction; peg->lvseg = NULL; peg->lv_area = 0; /* FIXME merge free space */ return 1; } if (!pv_split_segment(peg->lvseg->lv->vg->vgmem, peg->pv, peg->pe + peg->lvseg->area_len - area_reduction, NULL)) return_0; return 1; } /* * Only for use by lv_segment merging routines. */ void merge_pv_segments(struct pv_segment *peg1, struct pv_segment *peg2) { peg1->len += peg2->len; dm_list_del(&peg2->list); } /* * Calculate the overlap, in extents, between a struct pv_segment and * a struct pe_range. */ static uint32_t _overlap_pe(const struct pv_segment *pvseg, const struct pe_range *per) { uint32_t start; uint32_t end; start = max(pvseg->pe, per->start); end = min(pvseg->pe + pvseg->len, per->start + per->count); if (end < start) return 0; else return end - start; } /* * Returns: number of free PEs in a struct pv_list */ uint32_t pv_list_extents_free(const struct dm_list *pvh) { struct pv_list *pvl; struct pe_range *per; uint32_t extents = 0; struct pv_segment *pvseg; dm_list_iterate_items(pvl, pvh) { dm_list_iterate_items(per, pvl->pe_ranges) { dm_list_iterate_items(pvseg, &pvl->pv->segments) { if (!pvseg_is_allocated(pvseg)) extents += _overlap_pe(pvseg, per); } } } return extents; } /* * Check all pv_segments in VG for consistency */ int check_pv_segments(struct volume_group *vg) { struct physical_volume *pv; struct pv_list *pvl; struct pv_segment *peg; unsigned s, segno; uint32_t start_pe, alloced; uint32_t pv_count = 0, free_count = 0, extent_count = 0; int ret = 1; dm_list_iterate_items(pvl, &vg->pvs) { pv = pvl->pv; segno = 0; start_pe = 0; alloced = 0; pv_count++; dm_list_iterate_items(peg, &pv->segments) { s = peg->lv_area; /* FIXME Remove this next line eventually */ log_debug("%s %u: %6u %6u: %s(%u:%u)", pv_dev_name(pv), segno++, peg->pe, peg->len, peg->lvseg ? peg->lvseg->lv->name : "NULL", peg->lvseg ? peg->lvseg->le : 0, s); /* FIXME Add details here on failure instead */ if (start_pe != peg->pe) { log_error("Gap in pvsegs: %u, %u", start_pe, peg->pe); ret = 0; } if (peg->lvseg) { if (seg_type(peg->lvseg, s) != AREA_PV) { log_error("Wrong lvseg area type"); ret = 0; } if (seg_pvseg(peg->lvseg, s) != peg) { log_error("Inconsistent pvseg pointers"); ret = 0; } if (peg->lvseg->area_len != peg->len) { log_error("Inconsistent length: %u %u", peg->len, peg->lvseg->area_len); ret = 0; } alloced += peg->len; } start_pe += peg->len; } if (start_pe != pv->pe_count) { log_error("PV segment pe_count mismatch: %u != %u", start_pe, pv->pe_count); ret = 0; } if (alloced != pv->pe_alloc_count) { log_error("PV segment pe_alloc_count mismatch: " "%u != %u", alloced, pv->pe_alloc_count); ret = 0; } extent_count += start_pe; free_count += (start_pe - alloced); } if (pv_count != vg->pv_count) { log_error("PV segment VG pv_count mismatch: %u != %u", pv_count, vg->pv_count); ret = 0; } if (free_count != vg->free_count) { log_error("PV segment VG free_count mismatch: %u != %u", free_count, vg->free_count); ret = 0; } if (extent_count != vg->extent_count) { log_error("PV segment VG extent_count mismatch: %u != %u", extent_count, vg->extent_count); ret = 0; } return ret; } static int _reduce_pv(struct physical_volume *pv, struct volume_group *vg, uint32_t old_pe_count, uint32_t new_pe_count) { struct pv_segment *peg, *pegt; if (new_pe_count < pv->pe_alloc_count) { log_error("%s: cannot resize to %" PRIu32 " extents " "as %" PRIu32 " are allocated.", pv_dev_name(pv), new_pe_count, pv->pe_alloc_count); return 0; } /* Check PEs to be removed are not already allocated */ dm_list_iterate_items(peg, &pv->segments) { if (peg->pe + peg->len <= new_pe_count) continue; if (peg->lvseg) { log_error("%s: cannot resize to %" PRIu32 " extents as " "later ones are allocated.", pv_dev_name(pv), new_pe_count); return 0; } } if (!pv_split_segment(vg->vgmem, pv, new_pe_count, NULL)) return_0; dm_list_iterate_items_safe(peg, pegt, &pv->segments) { if (peg->pe + peg->len > new_pe_count) dm_list_del(&peg->list); } pv->pe_count = new_pe_count; vg->extent_count -= (old_pe_count - new_pe_count); vg->free_count -= (old_pe_count - new_pe_count); return 1; } static int _extend_pv(struct physical_volume *pv, struct volume_group *vg, uint32_t old_pe_count, uint32_t new_pe_count) { struct pv_segment *peg; if ((uint64_t) new_pe_count * pv->pe_size > pv->size ) { log_error("%s: cannot resize to %" PRIu32 " extents as there " "is only room for %" PRIu64 ".", pv_dev_name(pv), new_pe_count, pv->size / pv->pe_size); return 0; } if (!(peg = _alloc_pv_segment(pv->fmt->cmd->mem, pv, old_pe_count, new_pe_count - old_pe_count, NULL, 0))) return_0; dm_list_add(&pv->segments, &peg->list); pv->pe_count = new_pe_count; vg->extent_count += (new_pe_count - old_pe_count); vg->free_count += (new_pe_count - old_pe_count); return 1; } /* * Resize a PV in a VG, adding or removing segments as needed. * New size must fit within pv->size. */ int pv_resize(struct physical_volume *pv, struct volume_group *vg, uint64_t size) { uint32_t old_pe_count, new_pe_count = 0; if (size < pv_min_size()) { log_error("Size must exceed minimum of %" PRIu64 " sectors on PV %s.", pv_min_size(), pv_dev_name(pv)); return 0; } if (size < pv_pe_start(pv)) { log_error("Size must exceed physical extent start " "of %" PRIu64 " sectors on PV %s.", pv_pe_start(pv), pv_dev_name(pv)); } old_pe_count = pv->pe_count; if (!pv->fmt->ops->pv_resize(pv->fmt, pv, vg, size)) { log_error("Format specific resize of PV %s failed.", pv_dev_name(pv)); return 0; } /* pv->pe_count is 0 now! We need to recalculate! */ /* If there's a VG, calculate new PE count value. */ if (vg) { /* FIXME: Maybe PE calculation should go into pv->fmt->resize? (like it is for pv->fmt->setup) */ if (!(new_pe_count = pv_size(pv) / vg->extent_size)) { log_error("Size must leave space for at least one physical " "extent of %" PRIu32 " sectors on PV %s.", pv_pe_size(pv), pv_dev_name(pv)); return 0; } if (new_pe_count == old_pe_count) { pv->pe_count = old_pe_count; log_verbose("No change to size of physical volume %s.", pv_dev_name(pv)); return 1; } log_verbose("Resizing physical volume %s from %" PRIu32 " to %" PRIu32 " extents.", pv_dev_name(pv), pv->pe_count, new_pe_count); if (new_pe_count > old_pe_count) return _extend_pv(pv, vg, old_pe_count, new_pe_count); else return _reduce_pv(pv, vg, old_pe_count, new_pe_count); } return 1; } lvm2-2.02.98/lib/metadata/pv_map.h0000640000175000017500000000412312037016272015471 0ustar blankblank/* * Copyright (C) 2001-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_PV_MAP_H #define _LVM_PV_MAP_H #include "metadata.h" /* * The in core rep. only stores a mapping from * logical extents to physical extents against an * lv. Sometimes, when allocating a new lv for * instance, it is useful to have the inverse * mapping available. */ struct pv_area { struct pv_map *map; uint32_t start; uint32_t count; /* Number of extents unreserved during a single allocation pass. */ uint32_t unreserved; struct dm_list list; /* pv_map.areas */ }; /* * When building up a potential group of "parallel" extent ranges during * an allocation attempt, track the maximum number of extents that may * need to be used as a particular parallel area. Several of these * structs may reference the same pv_area, but 'used' may differ between * them. The sum of all the 'used' variables referring to the same * pv_area may not exceed that area's count, so we cannot allocate the * same extents twice. */ struct pv_area_used { struct pv_area *pva; uint32_t used; }; struct pv_map { struct physical_volume *pv; struct dm_list areas; /* struct pv_areas */ uint32_t pe_count; /* Total number of PEs */ struct dm_list list; }; /* * Find intersection between available_pvs and free space in VG */ struct dm_list *create_pv_maps(struct dm_pool *mem, struct volume_group *vg, struct dm_list *allocatable_pvs); void consume_pv_area(struct pv_area *area, uint32_t to_go); void reinsert_changed_pv_area(struct pv_area *pva); uint32_t pv_maps_size(struct dm_list *pvms); #endif lvm2-2.02.98/lib/metadata/vg.h0000640000175000017500000001170212037016272014624 0ustar blankblank/* * 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 */ #ifndef _LVM_VG_H #define _LVM_VG_H struct cmd_context; struct dm_pool; struct format_instance; struct dm_list; struct id; typedef enum { ALLOC_INVALID, ALLOC_CONTIGUOUS, ALLOC_CLING, ALLOC_CLING_BY_TAGS, /* Internal - never written or displayed. */ ALLOC_NORMAL, ALLOC_ANYWHERE, ALLOC_INHERIT } alloc_policy_t; struct pv_to_create { struct dm_list list; struct physical_volume *pv; struct pvcreate_params *pp; }; #define MAX_EXTENT_COUNT (UINT32_MAX) struct volume_group { struct cmd_context *cmd; struct dm_pool *vgmem; struct format_instance *fid; struct lvmcache_vginfo *vginfo; struct dm_list *cmd_vgs;/* List of wanted/locked and opened VGs */ uint32_t cmd_missing_vgs;/* Flag marks missing VG */ uint32_t seqno; /* Metadata sequence number */ alloc_policy_t alloc; uint64_t status; struct id id; const char *name; const char *old_name; /* Set during vgrename and vgcfgrestore */ char *system_id; uint32_t extent_size; uint32_t extent_count; uint32_t free_count; uint32_t max_lv; uint32_t max_pv; /* physical volumes */ uint32_t pv_count; struct dm_list pvs; /* * List of physical volumes that were used in vgextend but do not carry * a PV label yet. They need to be pvcreate'd at vg_write time. */ struct dm_list pvs_to_create; /* * logical volumes * The following relationship should always hold: * dm_list_size(lvs) = user visible lv_count + snapshot_count + other invisible LVs * * Snapshots consist of 2 instances of "struct logical_volume": * - cow (lv_name is visible to the user) * - snapshot (lv_name is 'snapshotN') * * Mirrors consist of multiple instances of "struct logical_volume": * - one for the mirror log * - one for each mirror leg * - one for the user-visible mirror LV */ struct dm_list lvs; struct dm_list tags; /* * FIXME: Move the next fields into a different struct? */ /* * List of removed physical volumes by pvreduce. * They have to get cleared on vg_commit. */ struct dm_list removed_pvs; uint32_t open_mode; /* FIXME: read or write - check lock type? */ /* * Store result of the last vg_read(). * 0 for success else appropriate FAILURE_* bits set. */ uint32_t read_status; uint32_t mda_copies; /* target number of mdas for this VG */ struct dm_hash_table *hostnames; /* map of creation hostnames */ }; struct volume_group *alloc_vg(const char *pool_name, struct cmd_context *cmd, const char *vg_name); /* * release_vg() must be called on every struct volume_group allocated * by vg_create() or vg_read_internal() to free it when no longer required. */ void release_vg(struct volume_group *vg); void free_orphan_vg(struct volume_group *vg); char *vg_fmt_dup(const struct volume_group *vg); char *vg_name_dup(const struct volume_group *vg); char *vg_system_id_dup(const struct volume_group *vg); uint32_t vg_seqno(const struct volume_group *vg); uint64_t vg_status(const struct volume_group *vg); int vg_set_alloc_policy(struct volume_group *vg, alloc_policy_t alloc); int vg_set_clustered(struct volume_group *vg, int clustered); uint64_t vg_size(const struct volume_group *vg); uint64_t vg_free(const struct volume_group *vg); uint64_t vg_extent_size(const struct volume_group *vg); int vg_set_extent_size(struct volume_group *vg, uint32_t new_extent_size); uint64_t vg_extent_count(const struct volume_group *vg); uint64_t vg_free_count(const struct volume_group *vg); uint64_t vg_pv_count(const struct volume_group *vg); uint64_t vg_max_pv(const struct volume_group *vg); int vg_set_max_pv(struct volume_group *vg, uint32_t max_pv); uint64_t vg_max_lv(const struct volume_group *vg); int vg_set_max_lv(struct volume_group *vg, uint32_t max_lv); uint32_t vg_mda_count(const struct volume_group *vg); uint32_t vg_mda_used_count(const struct volume_group *vg); uint32_t vg_mda_copies(const struct volume_group *vg); int vg_set_mda_copies(struct volume_group *vg, uint32_t mda_copies); /* * Returns visible LV count - number of LVs from user perspective */ unsigned vg_visible_lvs(const struct volume_group *vg); /* * Count snapshot LVs. */ unsigned snapshot_count(const struct volume_group *vg); uint64_t vg_mda_size(const struct volume_group *vg); uint64_t vg_mda_free(const struct volume_group *vg); char *vg_attr_dup(struct dm_pool *mem, const struct volume_group *vg); char *vg_uuid_dup(const struct volume_group *vg); char *vg_tags_dup(const struct volume_group *vg); #endif /* _LVM_VG_H */ lvm2-2.02.98/lib/metadata/mirror.c0000640000175000017500000016504612037016272015530 0ustar blankblank/* * Copyright (C) 2003-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 */ #include "lib.h" #include "metadata.h" #include "toolcontext.h" #include "segtype.h" #include "display.h" #include "archiver.h" #include "activate.h" #include "lv_alloc.h" #include "lvm-string.h" #include "str_list.h" #include "locking.h" /* FIXME Should not be used in this file */ #include "defaults.h" /* FIXME: should this be defaults.h? */ /* These are necessary for _write_log_header() */ #include "xlate.h" #define MIRROR_MAGIC 0x4D695272 #define MIRROR_DISK_VERSION 2 /* These are the flags that represent the mirror failure restoration policies */ #define MIRROR_REMOVE 0 #define MIRROR_ALLOCATE 1 #define MIRROR_ALLOCATE_ANYWHERE 2 /* * Returns true if the lv is temporary mirror layer for resync */ int is_temporary_mirror_layer(const struct logical_volume *lv) { if (lv->status & MIRROR_IMAGE && lv->status & MIRRORED && !(lv->status & LOCKED)) return 1; return 0; } /* * Return a temporary LV for resyncing added mirror image. * Add other mirror legs to lvs list. */ struct logical_volume *find_temporary_mirror(const struct logical_volume *lv) { struct lv_segment *seg; if (!(lv->status & MIRRORED)) return NULL; seg = first_seg(lv); /* Temporary mirror is always area_num == 0 */ if (seg_type(seg, 0) == AREA_LV && is_temporary_mirror_layer(seg_lv(seg, 0))) return seg_lv(seg, 0); return NULL; } /* * cluster_mirror_is_available * * Check if the proper kernel module and log daemon are running. * Caller should check for 'vg_is_clustered(lv->vg)' before making * this call. * * Returns: 1 if available, 0 otherwise */ static int _cluster_mirror_is_available(struct logical_volume *lv) { unsigned attr = 0; struct cmd_context *cmd = lv->vg->cmd; const struct segment_type *segtype; if (!(segtype = get_segtype_from_string(cmd, "mirror"))) return_0; if (!segtype->ops->target_present) return_0; if (!segtype->ops->target_present(lv->vg->cmd, NULL, &attr)) return_0; if (!(attr & MIRROR_LOG_CLUSTERED)) return 0; return 1; } /* * Returns the number of mirrors of the LV */ uint32_t lv_mirror_count(const struct logical_volume *lv) { struct lv_segment *seg; uint32_t s, mirrors; if (!(lv->status & MIRRORED)) return 1; seg = first_seg(lv); /* FIXME: RAID10 only supports 2 copies right now */ if (!strcmp(seg->segtype->name, "raid10")) return 2; if (lv->status & PVMOVE) return seg->area_count; mirrors = 0; for (s = 0; s < seg->area_count; s++) { if (seg_type(seg, s) != AREA_LV) continue; if (is_temporary_mirror_layer(seg_lv(seg, s))) mirrors += lv_mirror_count(seg_lv(seg, s)); else mirrors++; } return mirrors ? mirrors : 1; } struct lv_segment *find_mirror_seg(struct lv_segment *seg) { struct lv_segment *mirror_seg; mirror_seg = get_only_segment_using_this_lv(seg->lv); if (!mirror_seg) { log_error("Failed to find mirror_seg for %s", seg->lv->name); return NULL; } if (!seg_is_mirrored(mirror_seg)) { log_error("%s on %s is not a mirror segments", mirror_seg->lv->name, seg->lv->name); return NULL; } return mirror_seg; } /* * Reduce the region size if necessary to ensure * the volume size is a multiple of the region size. */ uint32_t adjusted_mirror_region_size(uint32_t extent_size, uint32_t extents, uint32_t region_size) { uint64_t region_max; region_max = (1 << (ffs((int)extents) - 1)) * (uint64_t) extent_size; if (region_max < UINT32_MAX && region_size > region_max) { region_size = (uint32_t) region_max; log_print_unless_silent("Using reduced mirror region size of %" PRIu32 " sectors", region_size); } return region_size; } /* * shift_mirror_images * @mirrored_seg * @mimage: The position (index) of the image to move to the end * * When dealing with removal of legs, we often move a 'removable leg' * to the back of the 'areas' array. It is critically important not * to simply swap it for the last area in the array. This would have * the affect of reordering the remaining legs - altering position of * the primary. So, we must shuffle all of the areas in the array * to maintain their relative position before moving the 'removable * leg' to the end. * * Short illustration of the problem: * - Mirror consists of legs A, B, C and we want to remove A * - We swap A and C and then remove A, leaving C, B * This scenario is problematic in failure cases where A dies, because * B becomes the primary. If the above happens, we effectively throw * away any changes made between the time of failure and the time of * restructuring the mirror. * * So, any time we want to move areas to the end to be removed, use * this function. */ int shift_mirror_images(struct lv_segment *mirrored_seg, unsigned mimage) { unsigned i; struct lv_segment_area area; if (mimage >= mirrored_seg->area_count) { log_error("Invalid index (%u) of mirror image supplied " "to shift_mirror_images()", mimage); return 0; } area = mirrored_seg->areas[mimage]; /* Shift remaining images down to fill the hole */ for (i = mimage + 1; i < mirrored_seg->area_count; i++) mirrored_seg->areas[i-1] = mirrored_seg->areas[i]; /* Place this one at the end */ mirrored_seg->areas[i-1] = area; return 1; } /* * This function writes a new header to the mirror log header to the lv * * Returns: 1 on success, 0 on failure */ static int _write_log_header(struct cmd_context *cmd, struct logical_volume *lv) { struct device *dev; char *name; struct { /* The mirror log header */ uint32_t magic; uint32_t version; uint64_t nr_regions; } log_header; log_header.magic = xlate32(MIRROR_MAGIC); log_header.version = xlate32(MIRROR_DISK_VERSION); log_header.nr_regions = xlate64((uint64_t)-1); if (!(name = dm_pool_alloc(cmd->mem, PATH_MAX))) { log_error("Name allocation failed - log header not written (%s)", lv->name); return 0; } if (dm_snprintf(name, PATH_MAX, "%s%s/%s", cmd->dev_dir, lv->vg->name, lv->name) < 0) { log_error("Name too long - log header not written (%s)", lv->name); return 0; } log_verbose("Writing log header to device, %s", lv->name); if (!(dev = dev_cache_get(name, NULL))) { log_error("%s: not found: log header not written", name); return 0; } if (!dev_open_quiet(dev)) return 0; if (!dev_write(dev, UINT64_C(0), sizeof(log_header), &log_header)) { log_error("Failed to write log header to %s", name); dev_close_immediate(dev); return 0; } dev_close_immediate(dev); return 1; } /* * Initialize mirror log contents */ static int _init_mirror_log(struct cmd_context *cmd, struct logical_volume *log_lv, int in_sync, struct dm_list *tags, int remove_on_failure) { struct str_list *sl; struct lvinfo info; uint64_t orig_status = log_lv->status; int was_active = 0; if (test_mode()) { log_verbose("Test mode: Skipping mirror log initialisation."); return 1; } if (!activation() && in_sync) { log_error("Aborting. Unable to create in-sync mirror log " "while activation is disabled."); return 0; } /* If the LV is active, deactivate it first. */ if (lv_info(cmd, log_lv, 0, &info, 0, 0) && info.exists) { (void)deactivate_lv(cmd, log_lv); /* * FIXME: workaround to fail early * Ensure that log is really deactivated because deactivate_lv * on cluster do not fail if there is log_lv with different UUID. */ if (lv_info(cmd, log_lv, 0, &info, 0, 0) && info.exists) { log_error("Aborting. Unable to deactivate mirror log."); goto revert_new_lv; } was_active = 1; } /* Temporary make it visible for set_lv() */ lv_set_visible(log_lv); /* Temporary tag mirror log for activation */ dm_list_iterate_items(sl, tags) if (!str_list_add(cmd->mem, &log_lv->tags, sl->str)) { log_error("Aborting. Unable to tag mirror log."); goto activate_lv; } /* store mirror log on disk(s) */ if (!vg_write(log_lv->vg) || !vg_commit(log_lv->vg)) goto activate_lv; backup(log_lv->vg); /* Wait for events following any deactivation before reactivating */ sync_local_dev_names(cmd); if (!activate_lv(cmd, log_lv)) { log_error("Aborting. Failed to activate mirror log."); goto revert_new_lv; } /* Remove the temporary tags */ dm_list_iterate_items(sl, tags) str_list_del(&log_lv->tags, sl->str); if (activation() && !set_lv(cmd, log_lv, log_lv->size, in_sync ? -1 : 0)) { log_error("Aborting. Failed to wipe mirror log."); goto deactivate_and_revert_new_lv; } if (activation() && !_write_log_header(cmd, log_lv)) { log_error("Aborting. Failed to write mirror log header."); goto deactivate_and_revert_new_lv; } if (!deactivate_lv(cmd, log_lv)) { log_error("Aborting. Failed to deactivate mirror log. " "Manual intervention required."); return 0; } lv_set_hidden(log_lv); if (was_active && !activate_lv(cmd, log_lv)) return_0; return 1; deactivate_and_revert_new_lv: if (!deactivate_lv(cmd, log_lv)) { log_error("Unable to deactivate mirror log LV. " "Manual intervention required."); return 0; } revert_new_lv: log_lv->status = orig_status; dm_list_iterate_items(sl, tags) str_list_del(&log_lv->tags, sl->str); if (remove_on_failure && !lv_remove(log_lv)) { log_error("Manual intervention may be required to remove " "abandoned log LV before retrying."); return 0; } if (!vg_write(log_lv->vg) || !vg_commit(log_lv->vg)) log_error("Manual intervention may be required to " "remove/restore abandoned log LV before retrying."); else backup(log_lv->vg); activate_lv: if (was_active && !remove_on_failure && !activate_lv(cmd, log_lv)) return_0; return 0; } /* * Activate an LV similarly (i.e. SH or EX) to a given "model" LV */ static int _activate_lv_like_model(struct logical_volume *model, struct logical_volume *lv) { if (lv_is_active_exclusive(model)) { if (!activate_lv_excl(lv->vg->cmd, lv)) return_0; } else { if (!activate_lv(lv->vg->cmd, lv)) return_0; } return 1; } /* * Delete independent/orphan LV, it must acquire lock. */ static int _delete_lv(struct logical_volume *mirror_lv, struct logical_volume *lv) { struct cmd_context *cmd = mirror_lv->vg->cmd; struct str_list *sl; /* Inherit tags - maybe needed for activation */ if (!str_list_match_list(&mirror_lv->tags, &lv->tags, NULL)) { dm_list_iterate_items(sl, &mirror_lv->tags) if (!str_list_add(cmd->mem, &lv->tags, sl->str)) { log_error("Aborting. Unable to tag."); return 0; } if (!vg_write(mirror_lv->vg) || !vg_commit(mirror_lv->vg)) { log_error("Intermediate VG commit for orphan volume failed."); return 0; } } // FIXME: shouldn't the activation type be based on mirror_lv, not lv? if (!_activate_lv_like_model(lv, lv)) return_0; /* FIXME Is this superfluous now? */ sync_local_dev_names(cmd); if (!deactivate_lv(cmd, lv)) return_0; if (!lv_remove(lv)) return_0; return 1; } static int _merge_mirror_images(struct logical_volume *lv, const struct dm_list *mimages) { uint32_t addition = dm_list_size(mimages); struct logical_volume **img_lvs; struct lv_list *lvl; int i = 0; if (!addition) return 1; if (!(img_lvs = alloca(sizeof(*img_lvs) * addition))) return_0; dm_list_iterate_items(lvl, mimages) img_lvs[i++] = lvl->lv; return lv_add_mirror_lvs(lv, img_lvs, addition, MIRROR_IMAGE, first_seg(lv)->region_size); } /* Unlink the relationship between the segment and its log_lv */ struct logical_volume *detach_mirror_log(struct lv_segment *mirrored_seg) { struct logical_volume *log_lv; if (!mirrored_seg->log_lv) return NULL; log_lv = mirrored_seg->log_lv; mirrored_seg->log_lv = NULL; lv_set_visible(log_lv); log_lv->status &= ~MIRROR_LOG; remove_seg_from_segs_using_this_lv(log_lv, mirrored_seg); return log_lv; } /* Check if mirror image LV is removable with regard to given removable_pvs */ int is_mirror_image_removable(struct logical_volume *mimage_lv, void *baton) { struct physical_volume *pv; struct lv_segment *seg; int pv_found; struct pv_list *pvl; uint32_t s; struct dm_list *removable_pvs = baton; if (!baton || dm_list_empty(removable_pvs)) return 1; dm_list_iterate_items(seg, &mimage_lv->segments) { for (s = 0; s < seg->area_count; s++) { if (seg_type(seg, s) != AREA_PV) { /* FIXME Recurse for AREA_LV? */ /* Structure of seg_lv is unknown. * Not removing this LV for safety. */ return 0; } pv = seg_pv(seg, s); pv_found = 0; dm_list_iterate_items(pvl, removable_pvs) { if (id_equal(&pv->id, &pvl->pv->id)) { pv_found = 1; break; } if (pvl->pv->dev && pv->dev && pv->dev->dev == pvl->pv->dev->dev) { pv_found = 1; break; } } if (!pv_found) return 0; } } return 1; } /* * _move_removable_mimages_to_end * * We always detach mimage LVs from the end of the areas array. * This function will push 'count' mimages to the end of the array * based on if their PVs are removable. * * This is an all or nothing function. Either the user specifies * enough removable PVs to satisfy count, or they don't specify * any removable_pvs at all (in which case all PVs in the mirror * are considered removable). */ static int _move_removable_mimages_to_end(struct logical_volume *lv, uint32_t count, struct dm_list *removable_pvs) { int i; struct logical_volume *sub_lv; struct lv_segment *mirrored_seg = first_seg(lv); if (!removable_pvs) return 1; for (i = mirrored_seg->area_count - 1; (i >= 0) && count; i--) { sub_lv = seg_lv(mirrored_seg, i); if (!is_temporary_mirror_layer(sub_lv) && is_mirror_image_removable(sub_lv, removable_pvs)) { if (!shift_mirror_images(mirrored_seg, i)) return_0; count--; } } return !count; } static int _mirrored_lv_in_sync(struct logical_volume *lv) { percent_t sync_percent; if (!lv_mirror_percent(lv->vg->cmd, lv, 0, &sync_percent, NULL)) { if (lv_is_active_but_not_locally(lv)) log_error("Unable to determine mirror sync status of" " remotely active LV, %s/%s", lv->vg->name, lv->name); else log_error("Unable to determine mirror " "sync status of %s/%s.", lv->vg->name, lv->name); return 0; } return (sync_percent == PERCENT_100) ? 1 : 0; } /* * Split off 'split_count' legs from a mirror * * Returns: 0 on error, 1 on success */ static int _split_mirror_images(struct logical_volume *lv, const char *split_name, uint32_t split_count, struct dm_list *removable_pvs) { uint32_t i; struct logical_volume *sub_lv = NULL; struct logical_volume *new_lv = NULL; struct logical_volume *detached_log_lv = NULL; struct lv_segment *mirrored_seg = first_seg(lv); struct dm_list split_images; struct lv_list *lvl; struct cmd_context *cmd = lv->vg->cmd; if (!(lv->status & MIRRORED)) { log_error("Unable to split non-mirrored LV, %s", lv->name); return 0; } if (!split_count) { log_error(INTERNAL_ERROR "split_count is zero!"); return 0; } log_verbose("Detaching %d images from mirror, %s", split_count, lv->name); if (!_move_removable_mimages_to_end(lv, split_count, removable_pvs)) { /* * FIXME: Allow incomplete specification of removable PVs? * * I am forcing the user to either specify no * removable PVs or all of them. Should we allow * them to just specify some - making us pick the rest? */ log_error("Insufficient removable PVs given" " to satisfy request"); return 0; } /* * Step 1: * Remove the images from the mirror. * Make them visible, independent LVs (don't change names yet). * Track them in a list for later instantiation. */ dm_list_init(&split_images); for (i = 0; i < split_count; i++) { mirrored_seg->area_count--; sub_lv = seg_lv(mirrored_seg, mirrored_seg->area_count); sub_lv->status &= ~MIRROR_IMAGE; if (!release_lv_segment_area(mirrored_seg, mirrored_seg->area_count, mirrored_seg->area_len)) return_0; log_very_verbose("%s assigned to be split", sub_lv->name); if (!new_lv) { lv_set_visible(sub_lv); new_lv = sub_lv; continue; } /* If there is more than one image being split, add to list */ lvl = dm_pool_alloc(lv->vg->vgmem, sizeof(*lvl)); if (!lvl) { log_error("lv_list alloc failed"); return 0; } lvl->lv = sub_lv; dm_list_add(&split_images, &lvl->list); } new_lv->name = dm_pool_strdup(lv->vg->vgmem, split_name); if (!new_lv->name) { log_error("Unable to rename newly split LV"); return 0; } if (!dm_list_empty(&split_images)) { size_t len = strlen(new_lv->name) + 32; char *layer_name, format[len]; /* * A number of images have been split and * a new mirror layer must be formed */ if (!insert_layer_for_lv(cmd, new_lv, 0, "_mimage_%d")) { log_error("Failed to build new mirror, %s", new_lv->name); return 0; } first_seg(new_lv)->region_size = mirrored_seg->region_size; dm_list_iterate_items(lvl, &split_images) { sub_lv = lvl->lv; if (dm_snprintf(format, len, "%s_mimage_%%d", new_lv->name) < 0) { log_error("Failed to build new image name."); return 0; } layer_name = dm_pool_alloc(lv->vg->vgmem, len); if (!layer_name) { log_error("Unable to allocate memory"); return 0; } if (!generate_lv_name(lv->vg, format, layer_name, len)|| sscanf(layer_name, format, &i) != 1) { log_error("Failed to generate new image names"); return 0; } sub_lv->name = layer_name; } if (!_merge_mirror_images(new_lv, &split_images)) { log_error("Failed to group split " "images into new mirror"); return 0; } /* * We don't allow splitting a mirror that is not in-sync, * so we can bring the newly split mirror up without a * resync. (It will be a 'core' log mirror after all.) */ init_mirror_in_sync(1); } sub_lv = NULL; /* * If no more mirrors, remove mirror layer. * The sub_lv is removed entirely later - leaving * only the top-level (now linear) LV. */ if (mirrored_seg->area_count == 1) { sub_lv = seg_lv(mirrored_seg, 0); sub_lv->status &= ~MIRROR_IMAGE; lv_set_visible(sub_lv); detached_log_lv = detach_mirror_log(mirrored_seg); if (!remove_layer_from_lv(lv, sub_lv)) return_0; lv->status &= ~MIRRORED; lv->status &= ~LV_NOTSYNCED; } if (!vg_write(mirrored_seg->lv->vg)) { log_error("Intermediate VG metadata write failed."); return 0; } /* * Suspend the mirror - this includes all the sub-LVs and * soon-to-be-split sub-LVs */ if (!suspend_lv(cmd, mirrored_seg->lv)) { log_error("Failed to lock %s", mirrored_seg->lv->name); vg_revert(mirrored_seg->lv->vg); return 0; } if (!vg_commit(mirrored_seg->lv->vg)) { resume_lv(cmd, mirrored_seg->lv); return 0; } log_very_verbose("Updating \"%s\" in kernel", mirrored_seg->lv->name); /* * Resume the mirror - this also activates the visible, independent * soon-to-be-split sub-LVs */ if (!resume_lv(cmd, mirrored_seg->lv)) { log_error("Problem resuming %s", mirrored_seg->lv->name); return 0; } /* * Recycle newly split LV so it is properly renamed. * Cluster requires the extra deactivate/activate calls. */ if (vg_is_clustered(lv->vg) && (!deactivate_lv(cmd, new_lv) || !_activate_lv_like_model(lv, new_lv))) { log_error("Failed to rename newly split LV in the kernel"); return 0; } if (!suspend_lv(cmd, new_lv) || !resume_lv(cmd, new_lv)) { log_error("Failed to rename newly split LV in the kernel"); return 0; } /* Remove original mirror layer if it has been converted to linear */ if (sub_lv && !_delete_lv(lv, sub_lv)) return_0; /* Remove the log if it has been converted to linear */ if (detached_log_lv && !_delete_lv(lv, detached_log_lv)) return_0; return 1; } /* * Remove num_removed images from mirrored_seg * * Arguments: * num_removed: the requested (maximum) number of mirrors to be removed * removable_pvs: if not NULL and list not empty, only mirrors using PVs * in this list will be removed * remove_log: if non-zero, log_lv will be removed * (even if it's 0, log_lv will be removed if there is no * mirror remaining after the removal) * collapse: if non-zero, instead of removing, remove the temporary * mirror layer and merge mirrors to the original LV. * removable_pvs should be NULL and num_removed should be * seg->area_count - 1. * removed: if non NULL, the number of removed mirror images is set * as a result * * If collapse is non-zero, is guaranteed to be equal to num_removed. * * Return values: * Failure (0) means something unexpected has happend and * the caller should abort. * Even if no mirror was removed (e.g. no LV matches to 'removable_pvs'), * returns success (1). */ static int _remove_mirror_images(struct logical_volume *lv, uint32_t num_removed, int (*is_removable)(struct logical_volume *, void *), void *removable_baton, unsigned remove_log, unsigned collapse, uint32_t *removed, int preferred_only) { uint32_t m; int32_t s; struct logical_volume *sub_lv; struct logical_volume *detached_log_lv = NULL; struct logical_volume *temp_layer_lv = NULL; struct lv_segment *mirrored_seg = first_seg(lv); uint32_t old_area_count = mirrored_seg->area_count; uint32_t new_area_count = mirrored_seg->area_count; struct lv_list *lvl; struct dm_list tmp_orphan_lvs; int orig_removed = num_removed; if (removed) *removed = 0; log_very_verbose("Reducing mirror set %s from %" PRIu32 " to %" PRIu32 " image(s)%s.", lv->name, old_area_count, old_area_count - num_removed, remove_log ? " and no log volume" : ""); if (collapse && (old_area_count - num_removed != 1)) { log_error("Incompatible parameters to _remove_mirror_images"); return 0; } num_removed = 0; /* Move removable_pvs to end of array */ for (s = mirrored_seg->area_count - 1; s >= 0 && old_area_count - new_area_count < orig_removed; s--) { sub_lv = seg_lv(mirrored_seg, s); if (!(is_temporary_mirror_layer(sub_lv) && lv_mirror_count(sub_lv) != 1) && is_removable(sub_lv, removable_baton)) { /* * Check if the user is trying to pull the * primary mirror image when the mirror is * not in-sync. */ if ((s == 0) && !_mirrored_lv_in_sync(lv) && !(lv->status & PARTIAL_LV)) { log_error("Unable to remove primary mirror image while mirror is not in-sync"); return 0; } if (!shift_mirror_images(mirrored_seg, s)) return_0; --new_area_count; ++num_removed; } } if (!preferred_only) num_removed = orig_removed; /* * If removable_pvs were specified, then they have been shifted * to the end to ensure they are removed. The remaining balance * of images left to remove will be taken from the unspecified. */ new_area_count = old_area_count - num_removed; if (num_removed && old_area_count == new_area_count) return 1; /* Remove mimage LVs from the segment */ dm_list_init(&tmp_orphan_lvs); for (m = new_area_count; m < mirrored_seg->area_count; m++) { seg_lv(mirrored_seg, m)->status &= ~MIRROR_IMAGE; lv_set_visible(seg_lv(mirrored_seg, m)); if (!(lvl = dm_pool_alloc(lv->vg->cmd->mem, sizeof(*lvl)))) { log_error("lv_list alloc failed"); return 0; } lvl->lv = seg_lv(mirrored_seg, m); dm_list_add(&tmp_orphan_lvs, &lvl->list); if (!release_lv_segment_area(mirrored_seg, m, mirrored_seg->area_len)) return_0; } mirrored_seg->area_count = new_area_count; /* If no more mirrors, remove mirror layer */ /* As an exceptional case, if the lv is temporary layer, * leave the LV as mirrored and let the lvconvert completion * to remove the layer. */ if (new_area_count == 1 && !is_temporary_mirror_layer(lv)) { temp_layer_lv = seg_lv(mirrored_seg, 0); temp_layer_lv->status &= ~MIRROR_IMAGE; lv_set_visible(temp_layer_lv); detached_log_lv = detach_mirror_log(mirrored_seg); if (!remove_layer_from_lv(lv, temp_layer_lv)) return_0; if (collapse && !_merge_mirror_images(lv, &tmp_orphan_lvs)) { log_error("Failed to add mirror images"); return 0; } /* * No longer a mirror? Even though new_area_count was 1, * _merge_mirror_images may have resulted into lv being still a * mirror. Fix up the flags if we only have one image left. */ if (lv_mirror_count(lv) == 1) { lv->status &= ~MIRRORED; lv->status &= ~LV_NOTSYNCED; } mirrored_seg = first_seg(lv); if (remove_log && !detached_log_lv) detached_log_lv = detach_mirror_log(mirrored_seg); } else if (new_area_count == 0) { log_very_verbose("All mimages of %s are gone", lv->name); /* All mirror images are gone. * It can happen for vgreduce --removemissing. */ detached_log_lv = detach_mirror_log(mirrored_seg); lv->status &= ~MIRRORED; lv->status &= ~LV_NOTSYNCED; if (!replace_lv_with_error_segment(lv)) return_0; } else if (remove_log) detached_log_lv = detach_mirror_log(mirrored_seg); /* * The log may be removed due to repair. If the log * happens to be a mirrored log, then there is a special * case we need to consider. One of the images of a * mirrored log can fail followed shortly afterwards by * a failure of the second. This means that the top-level * mirror is waiting for writes to the log to finish, but * they never will unless the mirrored log can be repaired * or replaced with an error target. Since both the devices * have failed, we must replace with error target - it is * the only way to release the pending writes. */ if (detached_log_lv && lv_is_mirrored(detached_log_lv) && (detached_log_lv->status & PARTIAL_LV)) { struct lv_segment *seg = first_seg(detached_log_lv); log_very_verbose("%s being removed due to failures", detached_log_lv->name); /* * We are going to replace the mirror with an * error segment, but before we do, we must remember * all of the LVs that must be deleted later (i.e. * the sub-lv's) */ for (m = 0; m < seg->area_count; m++) { seg_lv(seg, m)->status &= ~MIRROR_IMAGE; lv_set_visible(seg_lv(seg, m)); if (!(lvl = dm_pool_alloc(lv->vg->cmd->mem, sizeof(*lvl)))) { log_error("dm_pool_alloc failed"); return 0; } lvl->lv = seg_lv(seg, m); dm_list_add(&tmp_orphan_lvs, &lvl->list); } if (!replace_lv_with_error_segment(detached_log_lv)) { log_error("Failed error target substitution for %s", detached_log_lv->name); return 0; } if (!vg_write(detached_log_lv->vg)) { log_error("intermediate VG write failed."); return 0; } if (!suspend_lv(detached_log_lv->vg->cmd, detached_log_lv)) { log_error("Failed to suspend %s", detached_log_lv->name); return 0; } if (!vg_commit(detached_log_lv->vg)) { if (!resume_lv(detached_log_lv->vg->cmd, detached_log_lv)) stack; return_0; } if (!resume_lv(detached_log_lv->vg->cmd, detached_log_lv)) { log_error("Failed to resume %s", detached_log_lv->name); return 0; } } /* * To successfully remove these unwanted LVs we need to * remove the LVs from the mirror set, commit that metadata * then deactivate and remove them fully. */ if (!vg_write(mirrored_seg->lv->vg)) { log_error("intermediate VG write failed."); return 0; } if (!suspend_lv_origin(mirrored_seg->lv->vg->cmd, mirrored_seg->lv)) { log_error("Failed to lock %s", mirrored_seg->lv->name); vg_revert(mirrored_seg->lv->vg); return 0; } /* FIXME: second suspend should not be needed * Explicitly suspend temporary LV. * This balances critical_section_inc() calls with critical_section_dec() * in resume (both local and cluster) and also properly propagates precommitted * metadata into dm table on other nodes. * FIXME: check propagation of suspend with visible flag */ if (temp_layer_lv && !suspend_lv(temp_layer_lv->vg->cmd, temp_layer_lv)) log_error("Problem suspending temporary LV %s", temp_layer_lv->name); if (!vg_commit(mirrored_seg->lv->vg)) { if (!resume_lv(mirrored_seg->lv->vg->cmd, mirrored_seg->lv)) stack; return_0; } log_very_verbose("Updating \"%s\" in kernel", mirrored_seg->lv->name); /* * Avoid having same mirror target loaded twice simultaneously by first * resuming the removed LV which now contains an error segment. * As it's now detached from mirrored_seg->lv we must resume it * explicitly. */ if (temp_layer_lv && !resume_lv(temp_layer_lv->vg->cmd, temp_layer_lv)) { log_error("Problem resuming temporary LV, %s", temp_layer_lv->name); return 0; } if (!resume_lv_origin(mirrored_seg->lv->vg->cmd, mirrored_seg->lv)) { log_error("Problem reactivating %s", mirrored_seg->lv->name); return 0; } /* Save or delete the 'orphan' LVs */ if (!collapse) { dm_list_iterate_items(lvl, &tmp_orphan_lvs) if (!_delete_lv(lv, lvl->lv)) return_0; } if (temp_layer_lv && !_delete_lv(lv, temp_layer_lv)) return_0; if (detached_log_lv && !_delete_lv(lv, detached_log_lv)) return_0; /* Mirror with only 1 area is 'in sync'. */ if (new_area_count == 1 && is_temporary_mirror_layer(lv)) { if (first_seg(lv)->log_lv && !_init_mirror_log(lv->vg->cmd, first_seg(lv)->log_lv, 1, &lv->tags, 0)) { /* As a result, unnecessary sync may run after * collapsing. But safe.*/ log_error("Failed to initialize log device"); return 0; } } if (removed) *removed = old_area_count - new_area_count; log_very_verbose("%" PRIu32 " image(s) removed from %s", old_area_count - new_area_count, lv->name); return 1; } /* * Remove the number of mirror images from the LV */ int remove_mirror_images(struct logical_volume *lv, uint32_t num_mirrors, int (*is_removable)(struct logical_volume *, void *), void *removable_baton, unsigned remove_log) { uint32_t num_removed, removed_once, r; uint32_t existing_mirrors = lv_mirror_count(lv); struct logical_volume *next_lv = lv; int preferred_only = 1; int retries = 0; num_removed = existing_mirrors - num_mirrors; /* num_removed can be 0 if the function is called just to remove log */ do { if (num_removed < first_seg(next_lv)->area_count) removed_once = num_removed; else removed_once = first_seg(next_lv)->area_count - 1; if (!_remove_mirror_images(next_lv, removed_once, is_removable, removable_baton, remove_log, 0, &r, preferred_only)) return_0; if (r < removed_once || !removed_once) { /* Some mirrors are removed from the temporary mirror, * but the temporary layer still exists. * Down the stack and retry for remainder. */ next_lv = find_temporary_mirror(next_lv); if (!next_lv) { preferred_only = 0; next_lv = lv; } } num_removed -= r; /* * if there are still images to be removed, try again; this is * required since some temporary layers may have been reduced * to 1, at which point they are made removable, just like * normal images */ if (!next_lv && !preferred_only && !retries && num_removed) { ++retries; preferred_only = 1; } } while (next_lv && num_removed); if (num_removed) { if (num_removed == existing_mirrors - num_mirrors) log_error("No mirror images found using specified PVs."); else { log_error("%u images are removed out of requested %u.", existing_mirrors - lv_mirror_count(lv), existing_mirrors - num_mirrors); } return 0; } return 1; } static int _no_removable_images(struct logical_volume *lv __attribute__((unused)), void *baton __attribute__((unused))) { return 0; } /* * Collapsing temporary mirror layers. * * When mirrors are added to already-mirrored LV, a temporary mirror layer * is inserted at the top of the stack to reduce resync work. * The function will remove the intermediate layer and collapse the stack * as far as mirrors are in-sync. * * The function is destructive: to remove intermediate mirror layers, * VG metadata commits and suspend/resume are necessary. */ int collapse_mirrored_lv(struct logical_volume *lv) { struct logical_volume *tmp_lv; struct lv_segment *mirror_seg; while ((tmp_lv = find_temporary_mirror(lv))) { mirror_seg = find_mirror_seg(first_seg(tmp_lv)); if (!mirror_seg) { log_error("Failed to find mirrored LV for %s", tmp_lv->name); return 0; } if (!_mirrored_lv_in_sync(mirror_seg->lv)) { log_verbose("Not collapsing %s: out-of-sync", mirror_seg->lv->name); return 1; } if (!_remove_mirror_images(mirror_seg->lv, mirror_seg->area_count - 1, _no_removable_images, NULL, 0, 1, NULL, 0)) { log_error("Failed to release mirror images"); return 0; } } return 1; } #if 0 /* FIXME: reconfigure_mirror_images: remove this code? */ static int _get_mirror_fault_policy(struct cmd_context *cmd __attribute__((unused)), int log_policy) { const char *policy; if (log_policy) policy = dm_config_find_str(NULL, "activation/mirror_log_fault_policy", DEFAULT_MIRROR_LOG_FAULT_POLICY); else { policy = dm_config_find_str(NULL, "activation/mirror_image_fault_policy", NULL); if (!policy) policy = dm_config_find_str(NULL, "activation/mirror_device_fault_policy", DEFAULT_MIRROR_IMAGE_FAULT_POLICY); } if (!strcmp(policy, "remove")) return MIRROR_REMOVE; else if (!strcmp(policy, "allocate")) return MIRROR_ALLOCATE; else if (!strcmp(policy, "allocate_anywhere")) return MIRROR_ALLOCATE_ANYWHERE; if (log_policy) log_error("Bad activation/mirror_log_fault_policy"); else log_error("Bad activation/mirror_device_fault_policy"); return MIRROR_REMOVE; } static int _get_mirror_log_fault_policy(struct cmd_context *cmd) { return _get_mirror_fault_policy(cmd, 1); } static int _get_mirror_device_fault_policy(struct cmd_context *cmd) { return _get_mirror_fault_policy(cmd, 0); } /* * replace_mirror_images * @mirrored_seg: segment (which may be linear now) to restore * @num_mirrors: number of copies we should end up with * @replace_log: replace log if not present * @in_sync: was the original mirror in-sync? * * in_sync will be set to 0 if new mirror devices are being added * In other words, it is only useful if the log (and only the log) * is being restored. * * Returns: 0 on failure, 1 on reconfig, -1 if no reconfig done */ static int _replace_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirrors, int log_policy, int in_sync) { int r = -1; struct logical_volume *lv = mirrored_seg->lv; /* FIXME: Use lvconvert rather than duplicating its code */ if (mirrored_seg->area_count < num_mirrors) { log_warn("WARNING: Failed to replace mirror device in %s/%s", mirrored_seg->lv->vg->name, mirrored_seg->lv->name); if ((mirrored_seg->area_count > 1) && !mirrored_seg->log_lv) log_warn("WARNING: Use 'lvconvert -m %d %s/%s --corelog' to replace failed devices", num_mirrors - 1, lv->vg->name, lv->name); else log_warn("WARNING: Use 'lvconvert -m %d %s/%s' to replace failed devices", num_mirrors - 1, lv->vg->name, lv->name); r = 0; /* REMEMBER/FIXME: set in_sync to 0 if a new mirror device was added */ in_sync = 0; } /* * FIXME: right now, we ignore the allocation policy specified to * allocate the new log. */ if ((mirrored_seg->area_count > 1) && !mirrored_seg->log_lv && (log_policy != MIRROR_REMOVE)) { log_warn("WARNING: Failed to replace mirror log device in %s/%s", lv->vg->name, lv->name); log_warn("WARNING: Use 'lvconvert -m %d %s/%s' to replace failed devices", mirrored_seg->area_count - 1 , lv->vg->name, lv->name); r = 0; } return r; } int reconfigure_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirrors, struct dm_list *removable_pvs, unsigned remove_log) { int r; int in_sync; int log_policy, dev_policy; uint32_t old_num_mirrors = mirrored_seg->area_count; int had_log = (mirrored_seg->log_lv) ? 1 : 0; /* was the mirror in-sync before problems? */ in_sync = _mirrored_lv_in_sync(mirrored_seg->lv); /* * While we are only removing devices, we can have sync set. * Setting this is only useful if we are moving to core log * otherwise the disk log will contain the sync information */ init_mirror_in_sync(in_sync); r = _remove_mirror_images(mirrored_seg->lv, old_num_mirrors - num_mirrors, is_mirror_image_removable, removable_pvs, remove_log, 0, NULL, 0); if (!r) /* Unable to remove bad devices */ return 0; log_warn("WARNING: Bad device removed from mirror volume, %s/%s", mirrored_seg->lv->vg->name, mirrored_seg->lv->name); log_policy = _get_mirror_log_fault_policy(mirrored_seg->lv->vg->cmd); dev_policy = _get_mirror_device_fault_policy(mirrored_seg->lv->vg->cmd); r = _replace_mirror_images(mirrored_seg, (dev_policy != MIRROR_REMOVE) ? old_num_mirrors : num_mirrors, log_policy, in_sync); if (!r) /* Failed to replace device(s) */ log_warn("WARNING: Unable to find substitute device for mirror volume, %s/%s", mirrored_seg->lv->vg->name, mirrored_seg->lv->name); else if (r > 0) /* Success in replacing device(s) */ log_warn("WARNING: Mirror volume, %s/%s restored - substitute for failed device found.", mirrored_seg->lv->vg->name, mirrored_seg->lv->name); else /* Bad device removed, but not replaced because of policy */ if (mirrored_seg->area_count == 1) { log_warn("WARNING: Mirror volume, %s/%s converted to linear due to device failure.", mirrored_seg->lv->vg->name, mirrored_seg->lv->name); } else if (had_log && !mirrored_seg->log_lv) { log_warn("WARNING: Mirror volume, %s/%s disk log removed due to device failure.", mirrored_seg->lv->vg->name, mirrored_seg->lv->name); } /* * If we made it here, we at least removed the bad device. * Consider this success. */ return 1; } #endif static int _create_mimage_lvs(struct alloc_handle *ah, uint32_t num_mirrors, uint32_t stripes, uint32_t stripe_size, struct logical_volume *lv, struct logical_volume **img_lvs, int log) { uint32_t m, first_area; char *img_name; size_t len; len = strlen(lv->name) + 32; if (!(img_name = alloca(len))) { log_error("img_name allocation failed. " "Remove new LV and retry."); return 0; } if (dm_snprintf(img_name, len, "%s_mimage_%%d", lv->name) < 0) { log_error("img_name allocation failed. " "Remove new LV and retry."); return 0; } for (m = 0; m < num_mirrors; m++) { if (!(img_lvs[m] = lv_create_empty(img_name, NULL, LVM_READ | LVM_WRITE, ALLOC_INHERIT, lv->vg))) { log_error("Aborting. Failed to create mirror image LV. " "Remove new LV and retry."); return 0; } if (log) { first_area = m * stripes + (log - 1); if (!lv_add_log_segment(ah, first_area, img_lvs[m], 0)) { log_error("Failed to add mirror image segment" " to %s. Remove new LV and retry.", img_lvs[m]->name); return 0; } } else { if (!lv_add_segment(ah, m * stripes, stripes, img_lvs[m], get_segtype_from_string(lv->vg->cmd, "striped"), stripe_size, 0, 0)) { log_error("Aborting. Failed to add mirror image segment " "to %s. Remove new LV and retry.", img_lvs[m]->name); return 0; } } } return 1; } /* * Remove mirrors from each segment. * 'new_mirrors' is the number of mirrors after the removal. '0' for linear. * If 'status_mask' is non-zero, the removal happens only when all segments * has the status bits on. */ int remove_mirrors_from_segments(struct logical_volume *lv, uint32_t new_mirrors, uint64_t status_mask) { struct lv_segment *seg; uint32_t s; /* Check the segment params are compatible */ dm_list_iterate_items(seg, &lv->segments) { if (!seg_is_mirrored(seg)) { log_error("Segment is not mirrored: %s:%" PRIu32, lv->name, seg->le); return 0; } if ((seg->status & status_mask) != status_mask) { log_error("Segment status does not match: %s:%" PRIu32 " status:0x%" PRIx64 "/0x%" PRIx64, lv->name, seg->le, seg->status, status_mask); return 0; } } /* Convert the segments */ dm_list_iterate_items(seg, &lv->segments) { if (!new_mirrors && seg->extents_copied == seg->area_len) { if (!move_lv_segment_area(seg, 0, seg, 1)) return_0; } for (s = new_mirrors + 1; s < seg->area_count; s++) if (!release_and_discard_lv_segment_area(seg, s, seg->area_len)) return_0; seg->area_count = new_mirrors + 1; if (!new_mirrors) seg->segtype = get_segtype_from_string(lv->vg->cmd, "striped"); } return 1; } const char *get_pvmove_pvname_from_lv_mirr(struct logical_volume *lv_mirr) { struct lv_segment *seg; dm_list_iterate_items(seg, &lv_mirr->segments) { if (!seg_is_mirrored(seg)) continue; if (seg_type(seg, 0) != AREA_PV) continue; return dev_name(seg_dev(seg, 0)); } return NULL; } /* * Find first pvmove LV referenced by a segment of an LV. */ struct logical_volume *find_pvmove_lv_in_lv(struct logical_volume *lv) { struct lv_segment *seg; uint32_t s; dm_list_iterate_items(seg, &lv->segments) { for (s = 0; s < seg->area_count; s++) { if (seg_type(seg, s) != AREA_LV) continue; if (seg_lv(seg, s)->status & PVMOVE) return seg_lv(seg, s); } } return NULL; } const char *get_pvmove_pvname_from_lv(struct logical_volume *lv) { struct logical_volume *pvmove_lv; pvmove_lv = find_pvmove_lv_in_lv(lv); if (pvmove_lv) return get_pvmove_pvname_from_lv_mirr(pvmove_lv); else return NULL; } struct logical_volume *find_pvmove_lv(struct volume_group *vg, struct device *dev, uint64_t lv_type) { struct lv_list *lvl; struct logical_volume *lv; struct lv_segment *seg; /* Loop through all LVs */ dm_list_iterate_items(lvl, &vg->lvs) { lv = lvl->lv; if (!(lv->status & lv_type)) continue; /* Check segment origins point to pvname */ dm_list_iterate_items(seg, &lv->segments) { if (seg_type(seg, 0) != AREA_PV) continue; if (seg_dev(seg, 0) != dev) continue; return lv; } } return NULL; } struct logical_volume *find_pvmove_lv_from_pvname(struct cmd_context *cmd, struct volume_group *vg, const char *name, const char *uuid __attribute__((unused)), uint64_t lv_type) { struct physical_volume *pv; struct logical_volume *lv; if (!(pv = find_pv_by_name(cmd, name))) return_NULL; lv = find_pvmove_lv(vg, pv->dev, lv_type); free_pv_fid(pv); return lv; } struct dm_list *lvs_using_lv(struct cmd_context *cmd, struct volume_group *vg, struct logical_volume *lv) { struct dm_list *lvs; struct logical_volume *lv1; struct lv_list *lvl, *lvl1; struct lv_segment *seg; uint32_t s; if (!(lvs = dm_pool_alloc(cmd->mem, sizeof(*lvs)))) { log_error("lvs list alloc failed"); return NULL; } dm_list_init(lvs); /* Loop through all LVs except the one supplied */ dm_list_iterate_items(lvl1, &vg->lvs) { lv1 = lvl1->lv; if (lv1 == lv) continue; /* Find whether any segment points at the supplied LV */ dm_list_iterate_items(seg, &lv1->segments) { for (s = 0; s < seg->area_count; s++) { if (seg_type(seg, s) != AREA_LV || seg_lv(seg, s) != lv) continue; if (!(lvl = dm_pool_alloc(cmd->mem, sizeof(*lvl)))) { log_error("lv_list alloc failed"); return NULL; } lvl->lv = lv1; dm_list_add(lvs, &lvl->list); goto next_lv; } } next_lv: ; } return lvs; } percent_t copy_percent(const struct logical_volume *lv_mirr) { uint32_t numerator = 0u, denominator = 0u; struct lv_segment *seg; dm_list_iterate_items(seg, &lv_mirr->segments) { denominator += seg->area_len; if (seg_is_mirrored(seg) && seg->area_count > 1) numerator += seg->extents_copied; else numerator += seg->area_len; } return denominator ? make_percent( numerator, denominator ) : 100.0; } /* * Fixup mirror pointers after single-pass segment import */ int fixup_imported_mirrors(struct volume_group *vg) { struct lv_list *lvl; struct lv_segment *seg; dm_list_iterate_items(lvl, &vg->lvs) { dm_list_iterate_items(seg, &lvl->lv->segments) { if (seg->segtype != get_segtype_from_string(vg->cmd, "mirror")) continue; if (seg->log_lv && !add_seg_to_segs_using_this_lv(seg->log_lv, seg)) return_0; } } return 1; } /* * Add mirrors to "linear" or "mirror" segments */ int add_mirrors_to_segments(struct cmd_context *cmd, struct logical_volume *lv, uint32_t mirrors, uint32_t region_size, struct dm_list *allocatable_pvs, alloc_policy_t alloc) { struct alloc_handle *ah; const struct segment_type *segtype; struct dm_list *parallel_areas; uint32_t adjusted_region_size; int r = 1; if (!(parallel_areas = build_parallel_areas_from_lv(lv, 1))) return_0; if (!(segtype = get_segtype_from_string(cmd, "mirror"))) return_0; adjusted_region_size = adjusted_mirror_region_size(lv->vg->extent_size, lv->le_count, region_size); if (!(ah = allocate_extents(lv->vg, NULL, segtype, 1, mirrors, 0, 0, lv->le_count, allocatable_pvs, alloc, parallel_areas))) { log_error("Unable to allocate mirror extents for %s.", lv->name); return 0; } if (!lv_add_mirror_areas(ah, lv, 0, adjusted_region_size)) { log_error("Failed to add mirror areas to %s", lv->name); r = 0; } alloc_destroy(ah); return r; } /* * Convert mirror log * * FIXME: Can't handle segment-by-segment mirror (like pvmove) */ int remove_mirror_log(struct cmd_context *cmd, struct logical_volume *lv, struct dm_list *removable_pvs, int force) { percent_t sync_percent; struct lvinfo info; struct volume_group *vg = lv->vg; /* Unimplemented features */ if (dm_list_size(&lv->segments) != 1) { log_error("Multiple-segment mirror is not supported"); return 0; } /* Had disk log, switch to core. */ if (lv_info(cmd, lv, 0, &info, 0, 0) && info.exists) { if (!lv_mirror_percent(cmd, lv, 0, &sync_percent, NULL)) { log_error("Unable to determine mirror sync status."); return 0; } } else if (vg_is_clustered(vg)) { log_error("Unable to convert the log of an inactive " "cluster mirror, %s", lv->name); return 0; } else if (force || yes_no_prompt("Full resync required to convert " "inactive mirror %s to core log. " "Proceed? [y/n]: ", lv->name) == 'y') sync_percent = 0; else return 0; if (sync_percent == PERCENT_100) init_mirror_in_sync(1); else { /* A full resync will take place */ lv->status &= ~LV_NOTSYNCED; init_mirror_in_sync(0); } if (!remove_mirror_images(lv, lv_mirror_count(lv), is_mirror_image_removable, removable_pvs, 1U)) return_0; return 1; } static struct logical_volume *_create_mirror_log(struct logical_volume *lv, struct alloc_handle *ah, alloc_policy_t alloc, const char *lv_name, const char *suffix) { struct logical_volume *log_lv; char *log_name; size_t len; len = strlen(lv_name) + 32; if (!(log_name = alloca(len))) { log_error("log_name allocation failed."); return NULL; } if (dm_snprintf(log_name, len, "%s%s", lv_name, suffix) < 0) { log_error("log_name allocation failed."); return NULL; } if (!(log_lv = lv_create_empty(log_name, NULL, VISIBLE_LV | LVM_READ | LVM_WRITE, alloc, lv->vg))) return_NULL; if (!lv_add_log_segment(ah, 0, log_lv, MIRROR_LOG)) return_NULL; return log_lv; } /* * Returns: 1 on success, 0 on error */ static int _form_mirror(struct cmd_context *cmd, struct alloc_handle *ah, struct logical_volume *lv, uint32_t mirrors, uint32_t stripes, uint32_t stripe_size, uint32_t region_size, int log) { struct logical_volume **img_lvs; /* * insert a mirror layer */ if (dm_list_size(&lv->segments) != 1 || seg_type(first_seg(lv), 0) != AREA_LV) if (!insert_layer_for_lv(cmd, lv, 0, "_mimage_%d")) return 0; /* * create mirror image LVs */ if (!(img_lvs = alloca(sizeof(*img_lvs) * mirrors))) { log_error("img_lvs allocation failed. " "Remove new LV and retry."); return 0; } if (!_create_mimage_lvs(ah, mirrors, stripes, stripe_size, lv, img_lvs, log)) return 0; if (!lv_add_mirror_lvs(lv, img_lvs, mirrors, MIRROR_IMAGE | (lv->status & LOCKED), region_size)) { log_error("Aborting. Failed to add mirror segment. " "Remove new LV and retry."); return 0; } return 1; } static struct logical_volume *_set_up_mirror_log(struct cmd_context *cmd, struct alloc_handle *ah, struct logical_volume *lv, uint32_t log_count, uint32_t region_size, alloc_policy_t alloc, int in_sync) { struct logical_volume *log_lv; const char *suffix, *lv_name; char *tmp_name; size_t len; struct lv_segment *seg; init_mirror_in_sync(in_sync); /* Mirror log name is lv_name + suffix, determined as the following: * 1. suffix is: * o "_mlog" for the original mirror LV. * o "_mlogtmp_%d" for temporary mirror LV, * 2. lv_name is: * o lv->name, if the log is temporary * o otherwise, the top-level LV name */ seg = first_seg(lv); if (seg_type(seg, 0) == AREA_LV && strstr(seg_lv(seg, 0)->name, MIRROR_SYNC_LAYER)) { lv_name = lv->name; suffix = "_mlogtmp_%d"; } else if ((lv_name = strstr(lv->name, MIRROR_SYNC_LAYER))) { len = lv_name - lv->name; tmp_name = alloca(len + 1); tmp_name[len] = '\0'; lv_name = strncpy(tmp_name, lv->name, len); suffix = "_mlog"; } else { lv_name = lv->name; suffix = "_mlog"; } if (!(log_lv = _create_mirror_log(lv, ah, alloc, lv_name, suffix))) { log_error("Failed to create mirror log."); return NULL; } if ((log_count > 1) && !_form_mirror(cmd, ah, log_lv, log_count-1, 1, 0, region_size, 2)) { log_error("Failed to form mirrored log."); return NULL; } if (!_init_mirror_log(cmd, log_lv, in_sync, &lv->tags, 1)) { log_error("Failed to initialise mirror log."); return NULL; } return log_lv; } int attach_mirror_log(struct lv_segment *seg, struct logical_volume *log_lv) { seg->log_lv = log_lv; log_lv->status |= MIRROR_LOG; lv_set_hidden(log_lv); return add_seg_to_segs_using_this_lv(log_lv, seg); } int add_mirror_log(struct cmd_context *cmd, struct logical_volume *lv, uint32_t log_count, uint32_t region_size, struct dm_list *allocatable_pvs, alloc_policy_t alloc) { struct alloc_handle *ah; const struct segment_type *segtype; struct dm_list *parallel_areas; percent_t sync_percent; int in_sync; struct logical_volume *log_lv; unsigned old_log_count; int r = 0; if (vg_is_clustered(lv->vg) && (log_count > 1)) { log_error("Log type, \"mirrored\", is unavailable to cluster mirrors"); return 0; } if (dm_list_size(&lv->segments) != 1) { log_error("Multiple-segment mirror is not supported"); return 0; } if (lv_is_active_but_not_locally(lv)) { log_error("Unable to convert the log of a mirror, %s, that is " "active remotely but not locally", lv->name); return 0; } log_lv = first_seg(lv)->log_lv; old_log_count = (log_lv) ? lv_mirror_count(log_lv) : 0; if (old_log_count == log_count) { log_verbose("Mirror already has a %s log", !log_count ? "core" : (log_count == 1) ? "disk" : "mirrored"); return 1; } if (!(parallel_areas = build_parallel_areas_from_lv(lv, 0))) return_0; if (!(segtype = get_segtype_from_string(cmd, "mirror"))) return_0; if (activation() && segtype->ops->target_present && !segtype->ops->target_present(cmd, NULL, NULL)) { log_error("%s: Required device-mapper target(s) not " "detected in your kernel", segtype->name); return 0; } /* allocate destination extents */ ah = allocate_extents(lv->vg, NULL, segtype, 0, 0, log_count - old_log_count, region_size, lv->le_count, allocatable_pvs, alloc, parallel_areas); if (!ah) { log_error("Unable to allocate extents for mirror log."); return 0; } if (old_log_count) { /* Converting from disk to mirrored log */ if (!_form_mirror(cmd, ah, log_lv, log_count - 1, 1, 0, region_size, 1)) { log_error("Failed to convert mirror log"); return 0; } r = 1; goto out; } /* check sync status */ if (mirror_in_sync() || (lv_mirror_percent(cmd, lv, 0, &sync_percent, NULL) && (sync_percent == PERCENT_100))) in_sync = 1; else in_sync = 0; if (!(log_lv = _set_up_mirror_log(cmd, ah, lv, log_count, region_size, alloc, in_sync))) goto_out; if (!attach_mirror_log(first_seg(lv), log_lv)) goto_out; r = 1; out: alloc_destroy(ah); return r; } /* * Convert "linear" LV to "mirror". */ int add_mirror_images(struct cmd_context *cmd, struct logical_volume *lv, uint32_t mirrors, uint32_t stripes, uint32_t stripe_size, uint32_t region_size, struct dm_list *allocatable_pvs, alloc_policy_t alloc, uint32_t log_count) { struct alloc_handle *ah; const struct segment_type *segtype; struct dm_list *parallel_areas; struct logical_volume *log_lv = NULL; /* * allocate destination extents */ if (!(parallel_areas = build_parallel_areas_from_lv(lv, 0))) return_0; if (!(segtype = get_segtype_from_string(cmd, "mirror"))) return_0; ah = allocate_extents(lv->vg, NULL, segtype, stripes, mirrors, log_count, region_size, lv->le_count, allocatable_pvs, alloc, parallel_areas); if (!ah) { log_error("Unable to allocate extents for mirror(s)."); return 0; } /* * create and initialize mirror log */ if (log_count && !(log_lv = _set_up_mirror_log(cmd, ah, lv, log_count, (region_size > lv->vg->extent_size) ? lv->vg->extent_size : region_size, alloc, mirror_in_sync()))) { stack; goto out_remove_images; } /* The log initialization involves vg metadata commit. So from here on, if failure occurs, the log must be explicitly removed and the updated vg metadata should be committed. */ if (!_form_mirror(cmd, ah, lv, mirrors, stripes, stripe_size, region_size, 0)) goto out_remove_log; if (log_count && !attach_mirror_log(first_seg(lv), log_lv)) stack; alloc_destroy(ah); return 1; out_remove_log: if (log_lv) { if (!lv_remove(log_lv) || !vg_write(log_lv->vg) || !vg_commit(log_lv->vg)) log_error("Manual intervention may be required to remove " "abandoned log LV before retrying."); else backup(log_lv->vg); } out_remove_images: alloc_destroy(ah); return 0; } /* * Generic interface for adding mirror and/or mirror log. * 'mirror' is the number of mirrors to be added. * 'pvs' is either allocatable pvs. */ int lv_add_mirrors(struct cmd_context *cmd, struct logical_volume *lv, uint32_t mirrors, uint32_t stripes, uint32_t stripe_size, uint32_t region_size, uint32_t log_count, struct dm_list *pvs, alloc_policy_t alloc, uint32_t flags) { if (!mirrors && !log_count) { log_error("No conversion is requested"); return 0; } if (vg_is_clustered(lv->vg)) { /* FIXME: review check of lv_is_active_remotely */ /* FIXME: move this test out of this function */ /* Skip test for pvmove mirrors, it can use local mirror */ if (!(lv->status & (PVMOVE | LOCKED)) && !_cluster_mirror_is_available(lv)) { log_error("Shared cluster mirrors are not available."); return 0; } /* * No mirrored logs for cluster mirrors until * log daemon is multi-threaded. */ if (log_count > 1) { log_error("Log type, \"mirrored\", is unavailable to cluster mirrors"); return 0; } } /* For corelog mirror, activation code depends on * the global mirror_in_sync status. As we are adding * a new mirror, it should be set as 'out-of-sync' * so that the sync starts. */ /* However, MIRROR_SKIP_INIT_SYNC even overrides it. */ if (flags & MIRROR_SKIP_INIT_SYNC) init_mirror_in_sync(1); else if (!log_count) init_mirror_in_sync(0); if (flags & MIRROR_BY_SEG) { if (log_count) { log_error("Persistent log is not supported on " "segment-by-segment mirroring"); return 0; } if (stripes > 1) { log_error("Striped-mirroring is not supported on " "segment-by-segment mirroring"); return 0; } return add_mirrors_to_segments(cmd, lv, mirrors, region_size, pvs, alloc); } else if (flags & MIRROR_BY_LV) { if (!mirrors) return add_mirror_log(cmd, lv, log_count, region_size, pvs, alloc); return add_mirror_images(cmd, lv, mirrors, stripes, stripe_size, region_size, pvs, alloc, log_count); } log_error("Unsupported mirror conversion type"); return 0; } int lv_split_mirror_images(struct logical_volume *lv, const char *split_name, uint32_t split_count, struct dm_list *removable_pvs) { int r; if (find_lv_in_vg(lv->vg, split_name)) { log_error("Logical Volume \"%s\" already exists in " "volume group \"%s\"", split_name, lv->vg->name); return 0; } /* Can't split a mirror that is not in-sync... unless force? */ if (!_mirrored_lv_in_sync(lv)) { log_error("Unable to split mirror that is not in-sync."); return 0; } /* * FIXME: Generate default name when not supplied. * * If we were going to generate a default name, we would * do it here. Better to wait for a decision on the form * of the default name when '--track_deltas' (the ability * to merge a split leg back in and only copy the changes) * is being implemented. For now, we force the user to * come up with a name for their LV. */ r = _split_mirror_images(lv, split_name, split_count, removable_pvs); if (!r) return 0; return 1; } /* * Generic interface for removing mirror and/or mirror log. * 'mirror' is the number of mirrors to be removed. * 'pvs' is removable pvs. */ int lv_remove_mirrors(struct cmd_context *cmd __attribute__((unused)), struct logical_volume *lv, uint32_t mirrors, uint32_t log_count, int (*is_removable)(struct logical_volume *, void *), void *removable_baton, uint64_t status_mask) { uint32_t new_mirrors; struct lv_segment *seg; if (!mirrors && !log_count) { log_error("No conversion is requested"); return 0; } seg = first_seg(lv); if (!seg_is_mirrored(seg)) { log_error("Not a mirror segment"); return 0; } if (lv_mirror_count(lv) <= mirrors) { log_error("Removing more than existing: %d <= %d", seg->area_count, mirrors); return 0; } new_mirrors = lv_mirror_count(lv) - mirrors - 1; /* MIRROR_BY_LV */ if (seg_type(seg, 0) == AREA_LV && seg_lv(seg, 0)->status & MIRROR_IMAGE) return remove_mirror_images(lv, new_mirrors + 1, is_removable, removable_baton, log_count ? 1U : 0); /* MIRROR_BY_SEG */ if (log_count) { log_error("Persistent log is not supported on " "segment-by-segment mirroring"); return 0; } return remove_mirrors_from_segments(lv, new_mirrors, status_mask); } lvm2-2.02.98/lib/metadata/lv_manip.c0000640000175000017500000040226212037016272016015 0ustar blankblank/* * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU 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 "metadata.h" #include "locking.h" #include "pv_map.h" #include "lvm-string.h" #include "toolcontext.h" #include "lv_alloc.h" #include "pv_alloc.h" #include "display.h" #include "segtype.h" #include "archiver.h" #include "activate.h" #include "str_list.h" #include "defaults.h" typedef enum { PREFERRED, USE_AREA, NEXT_PV, NEXT_AREA } area_use_t; /* FIXME: remove RAID_METADATA_AREA_LEN macro after defining 'raid_log_extents'*/ #define RAID_METADATA_AREA_LEN 1 /* FIXME These ended up getting used differently from first intended. Refactor. */ /* Only one of A_CONTIGUOUS_TO_LVSEG, A_CLING_TO_LVSEG, A_CLING_TO_ALLOCED may be set */ #define A_CONTIGUOUS_TO_LVSEG 0x01 /* Must be contiguous to an existing segment */ #define A_CLING_TO_LVSEG 0x02 /* Must use same disks as existing LV segment */ #define A_CLING_TO_ALLOCED 0x04 /* Must use same disks as already-allocated segment */ #define A_CLING_BY_TAGS 0x08 /* Must match tags against existing segment */ #define A_CAN_SPLIT 0x10 /* * Constant parameters during a single allocation attempt. */ struct alloc_parms { alloc_policy_t alloc; unsigned flags; /* Holds A_* */ struct lv_segment *prev_lvseg; uint32_t extents_still_needed; }; /* * Holds varying state of each allocation attempt. */ struct alloc_state { struct pv_area_used *areas; uint32_t areas_size; uint32_t log_area_count_still_needed; /* Number of areas still needing to be allocated for the log */ uint32_t allocated; /* Total number of extents allocated so far */ }; struct lv_names { const char *old; const char *new; }; int add_seg_to_segs_using_this_lv(struct logical_volume *lv, struct lv_segment *seg) { struct seg_list *sl; dm_list_iterate_items(sl, &lv->segs_using_this_lv) { if (sl->seg == seg) { sl->count++; return 1; } } log_very_verbose("Adding %s:%" PRIu32 " as an user of %s", seg->lv->name, seg->le, lv->name); if (!(sl = dm_pool_zalloc(lv->vg->vgmem, sizeof(*sl)))) { log_error("Failed to allocate segment list"); return 0; } sl->count = 1; sl->seg = seg; dm_list_add(&lv->segs_using_this_lv, &sl->list); return 1; } int remove_seg_from_segs_using_this_lv(struct logical_volume *lv, struct lv_segment *seg) { struct seg_list *sl; dm_list_iterate_items(sl, &lv->segs_using_this_lv) { if (sl->seg != seg) continue; if (sl->count > 1) sl->count--; else { log_very_verbose("%s:%" PRIu32 " is no longer a user " "of %s", seg->lv->name, seg->le, lv->name); dm_list_del(&sl->list); } return 1; } return 0; } /* * This is a function specialized for the common case where there is * only one segment which uses the LV. * e.g. the LV is a layer inserted by insert_layer_for_lv(). * * In general, walk through lv->segs_using_this_lv. */ struct lv_segment *get_only_segment_using_this_lv(struct logical_volume *lv) { struct seg_list *sl; if (dm_list_size(&lv->segs_using_this_lv) != 1) { log_error("%s is expected to have only one segment using it, " "while it has %d", lv->name, dm_list_size(&lv->segs_using_this_lv)); return NULL; } dm_list_iterate_items(sl, &lv->segs_using_this_lv) break; /* first item */ if (sl->count != 1) { log_error("%s is expected to have only one segment using it, " "while %s:%" PRIu32 " uses it %d times", lv->name, sl->seg->lv->name, sl->seg->le, sl->count); return NULL; } return sl->seg; } /* * PVs used by a segment of an LV */ struct seg_pvs { struct dm_list list; struct dm_list pvs; /* struct pv_list */ uint32_t le; uint32_t len; }; static struct seg_pvs *_find_seg_pvs_by_le(struct dm_list *list, uint32_t le) { struct seg_pvs *spvs; dm_list_iterate_items(spvs, list) if (le >= spvs->le && le < spvs->le + spvs->len) return spvs; return NULL; } /* * Find first unused LV number. */ uint32_t find_free_lvnum(struct logical_volume *lv) { int lvnum_used[MAX_RESTRICTED_LVS + 1] = { 0 }; uint32_t i = 0; struct lv_list *lvl; int lvnum; dm_list_iterate_items(lvl, &lv->vg->lvs) { lvnum = lvnum_from_lvid(&lvl->lv->lvid); if (lvnum <= MAX_RESTRICTED_LVS) lvnum_used[lvnum] = 1; } while (lvnum_used[i]) i++; /* FIXME What if none are free? */ return i; } /* * All lv_segments get created here. */ struct lv_segment *alloc_lv_segment(const struct segment_type *segtype, struct logical_volume *lv, uint32_t le, uint32_t len, uint64_t status, uint32_t stripe_size, struct logical_volume *log_lv, struct logical_volume *thin_pool_lv, uint32_t area_count, uint32_t area_len, uint32_t chunk_size, uint32_t region_size, uint32_t extents_copied, struct lv_segment *pvmove_source_seg) { struct lv_segment *seg; struct dm_pool *mem = lv->vg->vgmem; uint32_t areas_sz = area_count * sizeof(*seg->areas); if (!segtype) { log_error(INTERNAL_ERROR "alloc_lv_segment: Missing segtype."); return NULL; } if (!(seg = dm_pool_zalloc(mem, sizeof(*seg)))) return_NULL; if (!(seg->areas = dm_pool_zalloc(mem, areas_sz))) { dm_pool_free(mem, seg); return_NULL; } if (segtype_is_raid(segtype) && !(seg->meta_areas = dm_pool_zalloc(mem, areas_sz))) { dm_pool_free(mem, seg); /* frees everything alloced since seg */ return_NULL; } seg->segtype = segtype; seg->lv = lv; seg->le = le; seg->len = len; seg->status = status; seg->stripe_size = stripe_size; seg->area_count = area_count; seg->area_len = area_len; seg->chunk_size = chunk_size; seg->region_size = region_size; seg->extents_copied = extents_copied; seg->pvmove_source_seg = pvmove_source_seg; dm_list_init(&seg->tags); dm_list_init(&seg->thin_messages); if (thin_pool_lv) { /* If this thin volume, thin snapshot is being created */ if (lv_is_thin_volume(thin_pool_lv)) { seg->transaction_id = first_seg(first_seg(thin_pool_lv)->pool_lv)->transaction_id; if (!attach_pool_lv(seg, first_seg(thin_pool_lv)->pool_lv, thin_pool_lv)) return_NULL; } else { seg->transaction_id = first_seg(thin_pool_lv)->transaction_id; if (!attach_pool_lv(seg, thin_pool_lv, NULL)) return_NULL; } } if (log_lv && !attach_mirror_log(seg, log_lv)) return_NULL; return seg; } struct lv_segment *alloc_snapshot_seg(struct logical_volume *lv, uint64_t status, uint32_t old_le_count) { struct lv_segment *seg; const struct segment_type *segtype; segtype = get_segtype_from_string(lv->vg->cmd, "snapshot"); if (!segtype) { log_error("Failed to find snapshot segtype"); return NULL; } if (!(seg = alloc_lv_segment(segtype, lv, old_le_count, lv->le_count - old_le_count, status, 0, NULL, NULL, 0, lv->le_count - old_le_count, 0, 0, 0, NULL))) { log_error("Couldn't allocate new snapshot segment."); return NULL; } dm_list_add(&lv->segments, &seg->list); lv->status |= VIRTUAL; return seg; } static int _release_and_discard_lv_segment_area(struct lv_segment *seg, uint32_t s, uint32_t area_reduction, int with_discard) { if (seg_type(seg, s) == AREA_UNASSIGNED) return 1; if (seg_type(seg, s) == AREA_PV) { if (with_discard && !discard_pv_segment(seg_pvseg(seg, s), area_reduction)) return_0; if (!release_pv_segment(seg_pvseg(seg, s), area_reduction)) return_0; if (seg->area_len == area_reduction) seg_type(seg, s) = AREA_UNASSIGNED; return 1; } if ((seg_lv(seg, s)->status & MIRROR_IMAGE) || (seg_lv(seg, s)->status & THIN_POOL_DATA)) { if (!lv_reduce(seg_lv(seg, s), area_reduction)) return_0; /* FIXME: any upper level reporting */ return 1; } if (seg_lv(seg, s)->status & RAID_IMAGE) { /* * FIXME: Use lv_reduce not lv_remove * We use lv_remove for now, because I haven't figured out * why lv_reduce won't remove the LV. lv_reduce(seg_lv(seg, s), area_reduction); */ if (area_reduction != seg->area_len) { log_error("Unable to reduce RAID LV - operation not implemented."); return_0; } else { if (!lv_remove(seg_lv(seg, s))) { log_error("Failed to remove RAID image %s", seg_lv(seg, s)->name); return 0; } } /* Remove metadata area if image has been removed */ if (area_reduction == seg->area_len) { if (!lv_reduce(seg_metalv(seg, s), seg_metalv(seg, s)->le_count)) { log_error("Failed to remove RAID meta-device %s", seg_metalv(seg, s)->name); return 0; } } return 1; } if (area_reduction == seg->area_len) { log_very_verbose("Remove %s:%" PRIu32 "[%" PRIu32 "] from " "the top of LV %s:%" PRIu32, seg->lv->name, seg->le, s, seg_lv(seg, s)->name, seg_le(seg, s)); remove_seg_from_segs_using_this_lv(seg_lv(seg, s), seg); seg_lv(seg, s) = NULL; seg_le(seg, s) = 0; seg_type(seg, s) = AREA_UNASSIGNED; } return 1; } int release_and_discard_lv_segment_area(struct lv_segment *seg, uint32_t s, uint32_t area_reduction) { return _release_and_discard_lv_segment_area(seg, s, area_reduction, 1); } int release_lv_segment_area(struct lv_segment *seg, uint32_t s, uint32_t area_reduction) { return _release_and_discard_lv_segment_area(seg, s, area_reduction, 0); } /* * Move a segment area from one segment to another */ int move_lv_segment_area(struct lv_segment *seg_to, uint32_t area_to, struct lv_segment *seg_from, uint32_t area_from) { struct physical_volume *pv; struct logical_volume *lv; uint32_t pe, le; switch (seg_type(seg_from, area_from)) { case AREA_PV: pv = seg_pv(seg_from, area_from); pe = seg_pe(seg_from, area_from); if (!release_lv_segment_area(seg_from, area_from, seg_from->area_len)) return_0; if (!release_lv_segment_area(seg_to, area_to, seg_to->area_len)) return_0; if (!set_lv_segment_area_pv(seg_to, area_to, pv, pe)) return_0; break; case AREA_LV: lv = seg_lv(seg_from, area_from); le = seg_le(seg_from, area_from); if (!release_lv_segment_area(seg_from, area_from, seg_from->area_len)) return_0; if (!release_lv_segment_area(seg_to, area_to, seg_to->area_len)) return_0; if (!set_lv_segment_area_lv(seg_to, area_to, lv, le, 0)) return_0; break; case AREA_UNASSIGNED: if (!release_lv_segment_area(seg_to, area_to, seg_to->area_len)) return_0; } return 1; } /* * Link part of a PV to an LV segment. */ int set_lv_segment_area_pv(struct lv_segment *seg, uint32_t area_num, struct physical_volume *pv, uint32_t pe) { seg->areas[area_num].type = AREA_PV; if (!(seg_pvseg(seg, area_num) = assign_peg_to_lvseg(pv, pe, seg->area_len, seg, area_num))) return_0; return 1; } /* * Link one LV segment to another. Assumes sizes already match. */ int set_lv_segment_area_lv(struct lv_segment *seg, uint32_t area_num, struct logical_volume *lv, uint32_t le, uint64_t status) { log_very_verbose("Stack %s:%" PRIu32 "[%" PRIu32 "] on LV %s:%" PRIu32, seg->lv->name, seg->le, area_num, lv->name, le); if (status & RAID_META) { seg->meta_areas[area_num].type = AREA_LV; seg_metalv(seg, area_num) = lv; if (le) { log_error(INTERNAL_ERROR "Meta le != 0"); return 0; } seg_metale(seg, area_num) = 0; } else { seg->areas[area_num].type = AREA_LV; seg_lv(seg, area_num) = lv; seg_le(seg, area_num) = le; } lv->status |= status; if (!add_seg_to_segs_using_this_lv(lv, seg)) return_0; return 1; } /* * Prepare for adding parallel areas to an existing segment. */ static int _lv_segment_add_areas(struct logical_volume *lv, struct lv_segment *seg, uint32_t new_area_count) { struct lv_segment_area *newareas; uint32_t areas_sz = new_area_count * sizeof(*newareas); if (!(newareas = dm_pool_zalloc(lv->vg->cmd->mem, areas_sz))) return_0; memcpy(newareas, seg->areas, seg->area_count * sizeof(*seg->areas)); seg->areas = newareas; seg->area_count = new_area_count; return 1; } /* * Reduce the size of an lv_segment. New size can be zero. */ static int _lv_segment_reduce(struct lv_segment *seg, uint32_t reduction) { uint32_t area_reduction, s; /* Caller must ensure exact divisibility */ if (seg_is_striped(seg)) { if (reduction % seg->area_count) { log_error("Segment extent reduction %" PRIu32 " not divisible by #stripes %" PRIu32, reduction, seg->area_count); return 0; } area_reduction = (reduction / seg->area_count); } else area_reduction = reduction; for (s = 0; s < seg->area_count; s++) if (!release_and_discard_lv_segment_area(seg, s, area_reduction)) return_0; seg->len -= reduction; seg->area_len -= area_reduction; return 1; } /* * Entry point for all LV reductions in size. */ static int _lv_reduce(struct logical_volume *lv, uint32_t extents, int delete) { struct lv_segment *seg; uint32_t count = extents; uint32_t reduction; dm_list_iterate_back_items(seg, &lv->segments) { if (!count) break; if (seg->len <= count) { /* remove this segment completely */ /* FIXME Check this is safe */ if (seg->log_lv && !lv_remove(seg->log_lv)) return_0; if (seg->metadata_lv && !lv_remove(seg->metadata_lv)) return_0; if (seg->pool_lv) { if (!detach_pool_lv(seg)) return_0; } dm_list_del(&seg->list); reduction = seg->len; } else reduction = count; if (!_lv_segment_reduce(seg, reduction)) return_0; count -= reduction; } lv->le_count -= extents; lv->size = (uint64_t) lv->le_count * lv->vg->extent_size; if (!delete) return 1; /* Remove the LV if it is now empty */ if (!lv->le_count && !unlink_lv_from_vg(lv)) return_0; else if (lv->vg->fid->fmt->ops->lv_setup && !lv->vg->fid->fmt->ops->lv_setup(lv->vg->fid, lv)) return_0; return 1; } /* * Empty an LV. */ int lv_empty(struct logical_volume *lv) { return _lv_reduce(lv, lv->le_count, 0); } /* * Empty an LV and add error segment. */ int replace_lv_with_error_segment(struct logical_volume *lv) { uint32_t len = lv->le_count; if (len && !lv_empty(lv)) return_0; /* Minimum size required for a table. */ if (!len) len = 1; /* * Since we are replacing the whatever-was-there with * an error segment, we should also clear any flags * that suggest it is anything other than "error". */ lv->status &= ~(MIRRORED|PVMOVE); /* FIXME: Should we bug if we find a log_lv attached? */ if (!lv_add_virtual_segment(lv, 0, len, get_segtype_from_string(lv->vg->cmd, "error"), NULL)) return_0; return 1; } /* * Remove given number of extents from LV. */ int lv_reduce(struct logical_volume *lv, uint32_t extents) { return _lv_reduce(lv, extents, 1); } /* * Completely remove an LV. */ int lv_remove(struct logical_volume *lv) { if (!lv_reduce(lv, lv->le_count)) return_0; return 1; } /* * A set of contiguous physical extents allocated */ struct alloced_area { struct dm_list list; struct physical_volume *pv; uint32_t pe; uint32_t len; }; /* * Details of an allocation attempt */ struct alloc_handle { struct cmd_context *cmd; struct dm_pool *mem; alloc_policy_t alloc; /* Overall policy */ uint32_t new_extents; /* Number of new extents required */ uint32_t area_count; /* Number of parallel areas */ uint32_t parity_count; /* Adds to area_count, but not area_multiple */ uint32_t area_multiple; /* seg->len = area_len * area_multiple */ uint32_t log_area_count; /* Number of parallel logs */ uint32_t metadata_area_count; /* Number of parallel metadata areas */ uint32_t log_len; /* Length of log/metadata_area */ uint32_t region_size; /* Mirror region size */ uint32_t total_area_len; /* Total number of parallel extents */ unsigned maximise_cling; unsigned mirror_logs_separate; /* Force mirror logs on separate PVs? */ /* * RAID devices require a metadata area that accompanies each * device. During initial creation, it is best to look for space * that is new_extents + log_len and then split that between two * allocated areas when found. 'alloc_and_split_meta' indicates * that this is the desired dynamic. */ unsigned alloc_and_split_meta; const struct dm_config_node *cling_tag_list_cn; struct dm_list *parallel_areas; /* PVs to avoid */ /* * Contains area_count lists of areas allocated to data stripes * followed by log_area_count lists of areas allocated to log stripes. */ struct dm_list alloced_areas[0]; }; static uint32_t _calc_area_multiple(const struct segment_type *segtype, const uint32_t area_count, const uint32_t stripes) { if (!area_count) return 1; /* Striped */ if (segtype_is_striped(segtype)) return area_count; /* Parity RAID (e.g. RAID 4/5/6) */ if (segtype_is_raid(segtype) && segtype->parity_devs) { /* * As articulated in _alloc_init, we can tell by * the area_count whether a replacement drive is * being allocated; and if this is the case, then * there is no area_multiple that should be used. */ if (area_count <= segtype->parity_devs) return 1; return area_count - segtype->parity_devs; } /* RAID10 - only has 2-way mirror right now */ if (!strcmp(segtype->name, "raid10")) { // FIXME: I'd like the 'stripes' arg always given if (!stripes) return area_count / 2; return stripes; } /* Mirrored stripes */ if (stripes) return stripes; /* Mirrored */ return 1; } /* * Returns log device size in extents, algorithm from kernel code */ #define BYTE_SHIFT 3 static uint32_t mirror_log_extents(uint32_t region_size, uint32_t pe_size, uint32_t area_len) { size_t area_size, bitset_size, log_size, region_count; area_size = (size_t)area_len * pe_size; region_count = dm_div_up(area_size, region_size); /* Work out how many "unsigned long"s we need to hold the bitset. */ bitset_size = dm_round_up(region_count, sizeof(uint32_t) << BYTE_SHIFT); bitset_size >>= BYTE_SHIFT; /* Log device holds both header and bitset. */ log_size = dm_round_up((MIRROR_LOG_OFFSET << SECTOR_SHIFT) + bitset_size, 1 << SECTOR_SHIFT); log_size >>= SECTOR_SHIFT; log_size = dm_div_up(log_size, pe_size); /* * Kernel requires a mirror to be at least 1 region large. So, * if our mirror log is itself a mirror, it must be at least * 1 region large. This restriction may not be necessary for * non-mirrored logs, but we apply the rule anyway. * * (The other option is to make the region size of the log * mirror smaller than the mirror it is acting as a log for, * but that really complicates things. It's much easier to * keep the region_size the same for both.) */ return (log_size > (region_size / pe_size)) ? log_size : (region_size / pe_size); } /* * Preparation for a specific allocation attempt * stripes and mirrors refer to the parallel areas used for data. * If log_area_count > 1 it is always mirrored (not striped). */ static struct alloc_handle *_alloc_init(struct cmd_context *cmd, struct dm_pool *mem, const struct segment_type *segtype, alloc_policy_t alloc, uint32_t new_extents, uint32_t mirrors, uint32_t stripes, uint32_t metadata_area_count, uint32_t extent_size, uint32_t region_size, struct dm_list *parallel_areas) { struct alloc_handle *ah; uint32_t s, area_count, alloc_count, parity_count; size_t size = 0; /* FIXME Caller should ensure this */ if (mirrors && !stripes) stripes = 1; if (segtype_is_virtual(segtype)) area_count = 0; else if (mirrors > 1) area_count = mirrors * stripes; else area_count = stripes; size = sizeof(*ah); /* * It is a requirement that RAID 4/5/6 are created with a number of * stripes that is greater than the number of parity devices. (e.g * RAID4/5 must have at least 2 stripes and RAID6 must have at least * 3.) It is also a constraint that, when replacing individual devices * in a RAID 4/5/6 array, no more devices can be replaced than * there are parity devices. (Otherwise, there would not be enough * redundancy to maintain the array.) Understanding these two * constraints allows us to infer whether the caller of this function * is intending to allocate an entire array or just replacement * component devices. In the former case, we must account for the * necessary parity_count. In the later case, we do not need to * account for the extra parity devices because the array already * exists and they only want replacement drives. */ parity_count = (area_count <= segtype->parity_devs) ? 0 : segtype->parity_devs; alloc_count = area_count + parity_count; if (segtype_is_raid(segtype) && metadata_area_count) /* RAID has a meta area for each device */ alloc_count *= 2; else /* mirrors specify their exact log count */ alloc_count += metadata_area_count; size += sizeof(ah->alloced_areas[0]) * alloc_count; if (!(ah = dm_pool_zalloc(mem, size))) { log_error("allocation handle allocation failed"); return NULL; } ah->cmd = cmd; if (segtype_is_virtual(segtype)) return ah; if (!(area_count + metadata_area_count)) { log_error(INTERNAL_ERROR "_alloc_init called for non-virtual segment with no disk space."); return NULL; } if (!(ah->mem = dm_pool_create("allocation", 1024))) { log_error("allocation pool creation failed"); return NULL; } if (mirrors || stripes) ah->new_extents = new_extents; else ah->new_extents = 0; ah->area_count = area_count; ah->parity_count = parity_count; ah->region_size = region_size; ah->alloc = alloc; /* * For the purposes of allocation, area_count and parity_count are * kept separately. However, the 'area_count' field in an * lv_segment includes both; and this is what '_calc_area_multiple' * is calculated from. So, we must pass in the total count to get * a correct area_multiple. */ ah->area_multiple = _calc_area_multiple(segtype, area_count + parity_count, stripes); ah->mirror_logs_separate = find_config_tree_bool(cmd, "allocation/mirror_logs_require_separate_pvs", DEFAULT_MIRROR_LOGS_REQUIRE_SEPARATE_PVS); if (segtype_is_raid(segtype)) { if (metadata_area_count) { if (metadata_area_count != area_count) log_error(INTERNAL_ERROR "Bad metadata_area_count"); ah->metadata_area_count = area_count; ah->alloc_and_split_meta = 1; ah->log_len = RAID_METADATA_AREA_LEN; /* * We need 'log_len' extents for each * RAID device's metadata_area */ ah->new_extents += (ah->log_len * ah->area_multiple); } else { ah->log_area_count = 0; ah->log_len = 0; } } else if (segtype_is_thin_pool(segtype)) { ah->log_area_count = metadata_area_count; /* thin_pool uses region_size to pass metadata size in extents */ ah->log_len = ah->region_size; ah->region_size = 0; ah->mirror_logs_separate = find_config_tree_bool(cmd, "allocation/thin_pool_metadata_require_separate_pvs", DEFAULT_THIN_POOL_METADATA_REQUIRE_SEPARATE_PVS); } else { ah->log_area_count = metadata_area_count; ah->log_len = !metadata_area_count ? 0 : mirror_log_extents(ah->region_size, extent_size, new_extents / ah->area_multiple); } for (s = 0; s < alloc_count; s++) dm_list_init(&ah->alloced_areas[s]); ah->parallel_areas = parallel_areas; ah->cling_tag_list_cn = find_config_tree_node(cmd, "allocation/cling_tag_list"); ah->maximise_cling = find_config_tree_bool(cmd, "allocation/maximise_cling", DEFAULT_MAXIMISE_CLING); return ah; } void alloc_destroy(struct alloc_handle *ah) { if (ah->mem) dm_pool_destroy(ah->mem); } /* Is there enough total space or should we give up immediately? */ static int _sufficient_pes_free(struct alloc_handle *ah, struct dm_list *pvms, uint32_t allocated, uint32_t extents_still_needed) { uint32_t area_extents_needed = (extents_still_needed - allocated) * ah->area_count / ah->area_multiple; uint32_t parity_extents_needed = (extents_still_needed - allocated) * ah->parity_count / ah->area_multiple; uint32_t metadata_extents_needed = ah->metadata_area_count * RAID_METADATA_AREA_LEN; /* One each */ uint32_t total_extents_needed = area_extents_needed + parity_extents_needed + metadata_extents_needed; uint32_t free_pes = pv_maps_size(pvms); if (total_extents_needed > free_pes) { log_error("Insufficient free space: %" PRIu32 " extents needed," " but only %" PRIu32 " available", total_extents_needed, free_pes); return 0; } return 1; } /* For striped mirrors, all the areas are counted, through the mirror layer */ static uint32_t _stripes_per_mimage(struct lv_segment *seg) { struct lv_segment *last_lvseg; if (seg_is_mirrored(seg) && seg->area_count && seg_type(seg, 0) == AREA_LV) { last_lvseg = dm_list_item(dm_list_last(&seg_lv(seg, 0)->segments), struct lv_segment); if (seg_is_striped(last_lvseg)) return last_lvseg->area_count; } return 1; } static void _init_alloc_parms(struct alloc_handle *ah, struct alloc_parms *alloc_parms, alloc_policy_t alloc, struct lv_segment *prev_lvseg, unsigned can_split, uint32_t allocated, uint32_t extents_still_needed) { alloc_parms->alloc = alloc; alloc_parms->prev_lvseg = prev_lvseg; alloc_parms->flags = 0; alloc_parms->extents_still_needed = extents_still_needed; /* Are there any preceding segments we must follow on from? */ if (alloc_parms->prev_lvseg) { if (alloc_parms->alloc == ALLOC_CONTIGUOUS) alloc_parms->flags |= A_CONTIGUOUS_TO_LVSEG; else if ((alloc_parms->alloc == ALLOC_CLING) || (alloc_parms->alloc == ALLOC_CLING_BY_TAGS)) alloc_parms->flags |= A_CLING_TO_LVSEG; } else /* * A cling allocation that follows a successful contiguous allocation * must use the same PVs (or else fail). */ if ((alloc_parms->alloc == ALLOC_CLING) || (alloc_parms->alloc == ALLOC_CLING_BY_TAGS)) alloc_parms->flags |= A_CLING_TO_ALLOCED; if (alloc_parms->alloc == ALLOC_CLING_BY_TAGS) alloc_parms->flags |= A_CLING_BY_TAGS; /* * For normal allocations, if any extents have already been found * for allocation, prefer to place further extents on the same disks as * have already been used. */ if (ah->maximise_cling && alloc_parms->alloc == ALLOC_NORMAL && allocated != alloc_parms->extents_still_needed) alloc_parms->flags |= A_CLING_TO_ALLOCED; if (can_split) alloc_parms->flags |= A_CAN_SPLIT; } static int _log_parallel_areas(struct dm_pool *mem, struct dm_list *parallel_areas) { struct seg_pvs *spvs; struct pv_list *pvl; char *pvnames; if (!parallel_areas) return 1; dm_list_iterate_items(spvs, parallel_areas) { if (!dm_pool_begin_object(mem, 256)) { log_error("dm_pool_begin_object failed"); return 0; } dm_list_iterate_items(pvl, &spvs->pvs) { if (!dm_pool_grow_object(mem, pv_dev_name(pvl->pv), strlen(pv_dev_name(pvl->pv)))) { log_error("dm_pool_grow_object failed"); dm_pool_abandon_object(mem); return 0; } if (!dm_pool_grow_object(mem, " ", 1)) { log_error("dm_pool_grow_object failed"); dm_pool_abandon_object(mem); return 0; } } if (!dm_pool_grow_object(mem, "\0", 1)) { log_error("dm_pool_grow_object failed"); dm_pool_abandon_object(mem); return 0; } pvnames = dm_pool_end_object(mem); log_debug("Parallel PVs at LE %" PRIu32 " length %" PRIu32 ": %s", spvs->le, spvs->len, pvnames); dm_pool_free(mem, pvnames); } return 1; } static int _setup_alloced_segment(struct logical_volume *lv, uint64_t status, uint32_t area_count, uint32_t stripe_size, const struct segment_type *segtype, struct alloced_area *aa, uint32_t region_size) { uint32_t s, extents, area_multiple; struct lv_segment *seg; area_multiple = _calc_area_multiple(segtype, area_count, 0); if (!(seg = alloc_lv_segment(segtype, lv, lv->le_count, aa[0].len * area_multiple, status, stripe_size, NULL, NULL, area_count, aa[0].len, 0u, region_size, 0u, NULL))) { log_error("Couldn't allocate new LV segment."); return 0; } for (s = 0; s < area_count; s++) if (!set_lv_segment_area_pv(seg, s, aa[s].pv, aa[s].pe)) return_0; dm_list_add(&lv->segments, &seg->list); extents = aa[0].len * area_multiple; lv->le_count += extents; lv->size += (uint64_t) extents *lv->vg->extent_size; if (segtype_is_mirrored(segtype)) lv->status |= MIRRORED; return 1; } static int _setup_alloced_segments(struct logical_volume *lv, struct dm_list *alloced_areas, uint32_t area_count, uint64_t status, uint32_t stripe_size, const struct segment_type *segtype, uint32_t region_size) { struct alloced_area *aa; dm_list_iterate_items(aa, &alloced_areas[0]) { if (!_setup_alloced_segment(lv, status, area_count, stripe_size, segtype, aa, region_size)) return_0; } return 1; } /* * This function takes a list of pv_areas and adds them to allocated_areas. * If the complete area is not needed then it gets split. * The part used is removed from the pv_map so it can't be allocated twice. */ static int _alloc_parallel_area(struct alloc_handle *ah, uint32_t max_to_allocate, struct alloc_state *alloc_state, uint32_t ix_log_offset) { uint32_t area_len, len; uint32_t s; uint32_t ix_log_skip = 0; /* How many areas to skip in middle of array to reach log areas */ uint32_t total_area_count; struct alloced_area *aa; struct pv_area *pva; total_area_count = ah->area_count + alloc_state->log_area_count_still_needed; total_area_count += ah->parity_count; if (!total_area_count) { log_error(INTERNAL_ERROR "_alloc_parallel_area called without any allocation to do."); return 1; } area_len = max_to_allocate / ah->area_multiple; /* Reduce area_len to the smallest of the areas */ for (s = 0; s < ah->area_count + ah->parity_count; s++) if (area_len > alloc_state->areas[s].used) area_len = alloc_state->areas[s].used; len = (ah->alloc_and_split_meta) ? total_area_count * 2 : total_area_count; len *= sizeof(*aa); if (!(aa = dm_pool_alloc(ah->mem, len))) { log_error("alloced_area allocation failed"); return 0; } /* * Areas consists of area_count areas for data stripes, then * ix_log_skip areas to skip, then log_area_count areas to use for the * log, then some areas too small for the log. */ len = area_len; for (s = 0; s < total_area_count; s++) { if (s == (ah->area_count + ah->parity_count)) { ix_log_skip = ix_log_offset - ah->area_count; len = ah->log_len; } pva = alloc_state->areas[s + ix_log_skip].pva; if (ah->alloc_and_split_meta) { /* * The metadata area goes at the front of the allocated * space for now, but could easily go at the end (or * middle!). * * Even though we split these two from the same * allocation, we store the images at the beginning * of the areas array and the metadata at the end. */ s += ah->area_count + ah->parity_count; aa[s].pv = pva->map->pv; aa[s].pe = pva->start; aa[s].len = ah->log_len; log_debug("Allocating parallel metadata area %" PRIu32 " on %s start PE %" PRIu32 " length %" PRIu32 ".", (s - (ah->area_count + ah->parity_count)), pv_dev_name(aa[s].pv), aa[s].pe, ah->log_len); consume_pv_area(pva, ah->log_len); dm_list_add(&ah->alloced_areas[s], &aa[s].list); s -= ah->area_count + ah->parity_count; } aa[s].len = (ah->alloc_and_split_meta) ? len - ah->log_len : len; /* Skip empty allocations */ if (!aa[s].len) continue; aa[s].pv = pva->map->pv; aa[s].pe = pva->start; log_debug("Allocating parallel area %" PRIu32 " on %s start PE %" PRIu32 " length %" PRIu32 ".", s, pv_dev_name(aa[s].pv), aa[s].pe, aa[s].len); consume_pv_area(pva, aa[s].len); dm_list_add(&ah->alloced_areas[s], &aa[s].list); } /* Only need to alloc metadata from the first batch */ ah->alloc_and_split_meta = 0; ah->total_area_len += area_len; alloc_state->allocated += area_len * ah->area_multiple; return 1; } /* * Call fn for each AREA_PV used by the LV segment at lv:le of length *max_seg_len. * If any constituent area contains more than one segment, max_seg_len is * reduced to cover only the first. * fn should return 0 on error, 1 to continue scanning or >1 to terminate without error. * In the last case, this function passes on the return code. */ static int _for_each_pv(struct cmd_context *cmd, struct logical_volume *lv, uint32_t le, uint32_t len, struct lv_segment *seg, uint32_t *max_seg_len, uint32_t first_area, uint32_t max_areas, int top_level_area_index, int only_single_area_segments, int (*fn)(struct cmd_context *cmd, struct pv_segment *peg, uint32_t s, void *data), void *data) { uint32_t s; uint32_t remaining_seg_len, area_len, area_multiple; uint32_t stripes_per_mimage = 1; int r = 1; if (!seg && !(seg = find_seg_by_le(lv, le))) { log_error("Failed to find segment for %s extent %" PRIu32, lv->name, le); return 0; } /* Remaining logical length of segment */ remaining_seg_len = seg->len - (le - seg->le); if (remaining_seg_len > len) remaining_seg_len = len; if (max_seg_len && *max_seg_len > remaining_seg_len) *max_seg_len = remaining_seg_len; area_multiple = _calc_area_multiple(seg->segtype, seg->area_count, 0); area_len = remaining_seg_len / area_multiple ? : 1; /* For striped mirrors, all the areas are counted, through the mirror layer */ if (top_level_area_index == -1) stripes_per_mimage = _stripes_per_mimage(seg); for (s = first_area; s < seg->area_count && (!max_areas || s <= max_areas); s++) { if (seg_type(seg, s) == AREA_LV) { if (!(r = _for_each_pv(cmd, seg_lv(seg, s), seg_le(seg, s) + (le - seg->le) / area_multiple, area_len, NULL, max_seg_len, 0, (stripes_per_mimage == 1) && only_single_area_segments ? 1U : 0U, (top_level_area_index != -1) ? top_level_area_index : (int) (s * stripes_per_mimage), only_single_area_segments, fn, data))) stack; } else if (seg_type(seg, s) == AREA_PV) if (!(r = fn(cmd, seg_pvseg(seg, s), top_level_area_index != -1 ? (uint32_t) top_level_area_index + s : s, data))) stack; if (r != 1) return r; } /* FIXME only_single_area_segments used as workaround to skip log LV - needs new param? */ if (!only_single_area_segments && seg_is_mirrored(seg) && seg->log_lv) { if (!(r = _for_each_pv(cmd, seg->log_lv, 0, seg->log_lv->le_count, NULL, NULL, 0, 0, 0, only_single_area_segments, fn, data))) stack; if (r != 1) return r; } /* FIXME Add snapshot cow LVs etc. */ return 1; } static int _comp_area(const void *l, const void *r) { const struct pv_area_used *lhs = (const struct pv_area_used *) l; const struct pv_area_used *rhs = (const struct pv_area_used *) r; if (lhs->used < rhs->used) return 1; else if (lhs->used > rhs->used) return -1; return 0; } /* * Search for pvseg that matches condition */ struct pv_match { int (*condition)(struct pv_match *pvmatch, struct pv_segment *pvseg, struct pv_area *pva); struct pv_area_used *areas; struct pv_area *pva; uint32_t areas_size; const struct dm_config_node *cling_tag_list_cn; int s; /* Area index of match */ }; /* * Is PV area on the same PV? */ static int _is_same_pv(struct pv_match *pvmatch __attribute((unused)), struct pv_segment *pvseg, struct pv_area *pva) { if (pvseg->pv != pva->map->pv) return 0; return 1; } /* * Does PV area have a tag listed in allocation/cling_tag_list that * matches a tag of the PV of the existing segment? */ static int _pvs_have_matching_tag(const struct dm_config_node *cling_tag_list_cn, struct physical_volume *pv1, struct physical_volume *pv2) { const struct dm_config_value *cv; const char *str; const char *tag_matched; for (cv = cling_tag_list_cn->v; cv; cv = cv->next) { if (cv->type != DM_CFG_STRING) { log_error("Ignoring invalid string in config file entry " "allocation/cling_tag_list"); continue; } str = cv->v.str; if (!*str) { log_error("Ignoring empty string in config file entry " "allocation/cling_tag_list"); continue; } if (*str != '@') { log_error("Ignoring string not starting with @ in config file entry " "allocation/cling_tag_list: %s", str); continue; } str++; if (!*str) { log_error("Ignoring empty tag in config file entry " "allocation/cling_tag_list"); continue; } /* Wildcard matches any tag against any tag. */ if (!strcmp(str, "*")) { if (!str_list_match_list(&pv1->tags, &pv2->tags, &tag_matched)) continue; else { log_debug("Matched allocation PV tag %s on existing %s with free space on %s.", tag_matched, pv_dev_name(pv1), pv_dev_name(pv2)); return 1; } } if (!str_list_match_item(&pv1->tags, str) || !str_list_match_item(&pv2->tags, str)) continue; else { log_debug("Matched allocation PV tag %s on existing %s with free space on %s.", str, pv_dev_name(pv1), pv_dev_name(pv2)); return 1; } } return 0; } static int _has_matching_pv_tag(struct pv_match *pvmatch, struct pv_segment *pvseg, struct pv_area *pva) { return _pvs_have_matching_tag(pvmatch->cling_tag_list_cn, pvseg->pv, pva->map->pv); } /* * Is PV area contiguous to PV segment? */ static int _is_contiguous(struct pv_match *pvmatch __attribute((unused)), struct pv_segment *pvseg, struct pv_area *pva) { if (pvseg->pv != pva->map->pv) return 0; if (pvseg->pe + pvseg->len != pva->start) return 0; return 1; } static void _reserve_area(struct pv_area_used *area_used, struct pv_area *pva, uint32_t required, uint32_t ix_pva, uint32_t unreserved) { log_debug("%s allocation area %" PRIu32 " %s %s start PE %" PRIu32 " length %" PRIu32 " leaving %" PRIu32 ".", area_used->pva ? "Changing " : "Considering", ix_pva - 1, area_used->pva ? "to" : "as", dev_name(pva->map->pv->dev), pva->start, required, unreserved); area_used->pva = pva; area_used->used = required; } static int _is_condition(struct cmd_context *cmd __attribute__((unused)), struct pv_segment *pvseg, uint32_t s, void *data) { struct pv_match *pvmatch = data; if (pvmatch->areas[s].pva) return 1; /* Area already assigned */ if (!pvmatch->condition(pvmatch, pvseg, pvmatch->pva)) return 1; /* Continue */ if (s >= pvmatch->areas_size) return 1; /* * Only used for cling and contiguous policies (which only make one allocation per PV) * so it's safe to say all the available space is used. */ _reserve_area(&pvmatch->areas[s], pvmatch->pva, pvmatch->pva->count, s + 1, 0); return 2; /* Finished */ } /* * Is pva on same PV as any existing areas? */ static int _check_cling(struct alloc_handle *ah, const struct dm_config_node *cling_tag_list_cn, struct lv_segment *prev_lvseg, struct pv_area *pva, struct alloc_state *alloc_state) { struct pv_match pvmatch; int r; uint32_t le, len; pvmatch.condition = cling_tag_list_cn ? _has_matching_pv_tag : _is_same_pv; pvmatch.areas = alloc_state->areas; pvmatch.areas_size = alloc_state->areas_size; pvmatch.pva = pva; pvmatch.cling_tag_list_cn = cling_tag_list_cn; if (ah->maximise_cling) { /* Check entire LV */ le = 0; len = prev_lvseg->le + prev_lvseg->len; } else { /* Only check 1 LE at end of previous LV segment */ le = prev_lvseg->le + prev_lvseg->len - 1; len = 1; } /* FIXME Cope with stacks by flattening */ if (!(r = _for_each_pv(ah->cmd, prev_lvseg->lv, le, len, NULL, NULL, 0, 0, -1, 1, _is_condition, &pvmatch))) stack; if (r != 2) return 0; return 1; } /* * Is pva contiguous to any existing areas or on the same PV? */ static int _check_contiguous(struct cmd_context *cmd, struct lv_segment *prev_lvseg, struct pv_area *pva, struct alloc_state *alloc_state) { struct pv_match pvmatch; int r; pvmatch.condition = _is_contiguous; pvmatch.areas = alloc_state->areas; pvmatch.areas_size = alloc_state->areas_size; pvmatch.pva = pva; pvmatch.cling_tag_list_cn = NULL; /* FIXME Cope with stacks by flattening */ if (!(r = _for_each_pv(cmd, prev_lvseg->lv, prev_lvseg->le + prev_lvseg->len - 1, 1, NULL, NULL, 0, 0, -1, 1, _is_condition, &pvmatch))) stack; if (r != 2) return 0; return 1; } /* * Is pva on same PV as any areas already used in this allocation attempt? */ static int _check_cling_to_alloced(struct alloc_handle *ah, const struct dm_config_node *cling_tag_list_cn, struct pv_area *pva, struct alloc_state *alloc_state) { unsigned s; struct alloced_area *aa; /* * Ignore log areas. They are always allocated whole as part of the * first allocation. If they aren't yet set, we know we've nothing to do. */ if (alloc_state->log_area_count_still_needed) return 0; for (s = 0; s < ah->area_count; s++) { if (alloc_state->areas[s].pva) continue; /* Area already assigned */ dm_list_iterate_items(aa, &ah->alloced_areas[s]) { if ((!cling_tag_list_cn && (pva->map->pv == aa[0].pv)) || (cling_tag_list_cn && _pvs_have_matching_tag(cling_tag_list_cn, pva->map->pv, aa[0].pv))) { _reserve_area(&alloc_state->areas[s], pva, pva->count, s + 1, 0); return 1; } } } return 0; } static int _pv_is_parallel(struct physical_volume *pv, struct dm_list *parallel_pvs) { struct pv_list *pvl; dm_list_iterate_items(pvl, parallel_pvs) if (pv == pvl->pv) return 1; return 0; } /* * Decide whether or not to try allocation from supplied area pva. * alloc_state->areas may get modified. */ static area_use_t _check_pva(struct alloc_handle *ah, struct pv_area *pva, uint32_t still_needed, const struct alloc_parms *alloc_parms, struct alloc_state *alloc_state, unsigned already_found_one, unsigned iteration_count, unsigned log_iteration_count) { unsigned s; /* Skip fully-reserved areas (which are not currently removed from the list). */ if (!pva->unreserved) return NEXT_AREA; /* FIXME Should this test be removed? */ if (iteration_count) /* * Don't use an area twice. */ for (s = 0; s < alloc_state->areas_size; s++) if (alloc_state->areas[s].pva == pva) return NEXT_AREA; /* If maximise_cling is set, perform several checks, otherwise perform exactly one. */ if (!iteration_count && !log_iteration_count && alloc_parms->flags & (A_CONTIGUOUS_TO_LVSEG | A_CLING_TO_LVSEG | A_CLING_TO_ALLOCED)) { /* Contiguous? */ if (((alloc_parms->flags & A_CONTIGUOUS_TO_LVSEG) || (ah->maximise_cling && alloc_parms->prev_lvseg)) && _check_contiguous(ah->cmd, alloc_parms->prev_lvseg, pva, alloc_state)) return PREFERRED; /* Try next area on same PV if looking for contiguous space */ if (alloc_parms->flags & A_CONTIGUOUS_TO_LVSEG) return NEXT_AREA; /* Cling to prev_lvseg? */ if (((alloc_parms->flags & A_CLING_TO_LVSEG) || (ah->maximise_cling && alloc_parms->prev_lvseg)) && _check_cling(ah, NULL, alloc_parms->prev_lvseg, pva, alloc_state)) /* If this PV is suitable, use this first area */ return PREFERRED; /* Cling_to_alloced? */ if ((alloc_parms->flags & A_CLING_TO_ALLOCED) && _check_cling_to_alloced(ah, NULL, pva, alloc_state)) return PREFERRED; /* Cling_by_tags? */ if (!(alloc_parms->flags & A_CLING_BY_TAGS) || !ah->cling_tag_list_cn) return NEXT_PV; if (alloc_parms->prev_lvseg) { if (_check_cling(ah, ah->cling_tag_list_cn, alloc_parms->prev_lvseg, pva, alloc_state)) return PREFERRED; } else if (_check_cling_to_alloced(ah, ah->cling_tag_list_cn, pva, alloc_state)) return PREFERRED; /* All areas on this PV give same result so pointless checking more */ return NEXT_PV; } /* Normal/Anywhere */ /* Is it big enough on its own? */ if (pva->unreserved * ah->area_multiple < still_needed && ((!(alloc_parms->flags & A_CAN_SPLIT) && !ah->log_area_count) || (already_found_one && alloc_parms->alloc != ALLOC_ANYWHERE))) return NEXT_PV; return USE_AREA; } /* * Decide how many extents we're trying to obtain from a given area. * Removes the extents from further consideration. */ static uint32_t _calc_required_extents(struct alloc_handle *ah, struct pv_area *pva, unsigned ix_pva, uint32_t max_to_allocate, alloc_policy_t alloc) { uint32_t required = max_to_allocate / ah->area_multiple; /* * Update amount unreserved - effectively splitting an area * into two or more parts. If the whole stripe doesn't fit, * reduce amount we're looking for. */ if (alloc == ALLOC_ANYWHERE) { if (ix_pva - 1 >= ah->area_count) required = ah->log_len; } else if (required < ah->log_len) required = ah->log_len; if (required >= pva->unreserved) { required = pva->unreserved; pva->unreserved = 0; } else { pva->unreserved -= required; reinsert_changed_pv_area(pva); } return required; } static int _reserve_required_area(struct alloc_handle *ah, uint32_t max_to_allocate, unsigned ix_pva, struct pv_area *pva, struct alloc_state *alloc_state, alloc_policy_t alloc) { uint32_t required = _calc_required_extents(ah, pva, ix_pva, max_to_allocate, alloc); uint32_t s; /* Expand areas array if needed after an area was split. */ if (ix_pva > alloc_state->areas_size) { alloc_state->areas_size *= 2; if (!(alloc_state->areas = dm_realloc(alloc_state->areas, sizeof(*alloc_state->areas) * (alloc_state->areas_size)))) { log_error("Memory reallocation for parallel areas failed."); return 0; } for (s = alloc_state->areas_size / 2; s < alloc_state->areas_size; s++) alloc_state->areas[s].pva = NULL; } _reserve_area(&alloc_state->areas[ix_pva - 1], pva, required, ix_pva, pva->unreserved); return 1; } static void _clear_areas(struct alloc_state *alloc_state) { uint32_t s; for (s = 0; s < alloc_state->areas_size; s++) alloc_state->areas[s].pva = NULL; } static void _reset_unreserved(struct dm_list *pvms) { struct pv_map *pvm; struct pv_area *pva; dm_list_iterate_items(pvm, pvms) dm_list_iterate_items(pva, &pvm->areas) if (pva->unreserved != pva->count) { pva->unreserved = pva->count; reinsert_changed_pv_area(pva); } } static void _report_needed_allocation_space(struct alloc_handle *ah, struct alloc_state *alloc_state) { const char *metadata_type; uint32_t parallel_areas_count, parallel_area_size; uint32_t metadata_count, metadata_size; parallel_area_size = (ah->new_extents - alloc_state->allocated) / ah->area_multiple - ((ah->alloc_and_split_meta) ? ah->log_len : 0); parallel_areas_count = ah->area_count + ah->parity_count; metadata_size = ah->log_len; if (ah->alloc_and_split_meta) { metadata_type = "RAID metadata area"; metadata_count = parallel_areas_count; } else { metadata_type = "mirror log"; metadata_count = alloc_state->log_area_count_still_needed; } log_debug("Still need %" PRIu32 " total extents:", parallel_area_size * parallel_areas_count + metadata_size * metadata_count); log_debug(" %" PRIu32 " (%" PRIu32 " data/%" PRIu32 " parity) parallel areas of %" PRIu32 " extents each", parallel_areas_count, ah->area_count, ah->parity_count, parallel_area_size); log_debug(" %" PRIu32 " %ss of %" PRIu32 " extents each", metadata_count, metadata_type, metadata_size); } /* * Returns 1 regardless of whether any space was found, except on error. */ static int _find_some_parallel_space(struct alloc_handle *ah, const struct alloc_parms *alloc_parms, struct dm_list *pvms, struct alloc_state *alloc_state, struct dm_list *parallel_pvs, uint32_t max_to_allocate) { unsigned ix = 0; unsigned last_ix; struct pv_map *pvm; struct pv_area *pva; unsigned preferred_count = 0; unsigned already_found_one; unsigned ix_offset = 0; /* Offset for non-preferred allocations */ unsigned ix_log_offset; /* Offset to start of areas to use for log */ unsigned too_small_for_log_count; /* How many too small for log? */ unsigned iteration_count = 0; /* cling_to_alloced may need 2 iterations */ unsigned log_iteration_count = 0; /* extra iteration for logs on data devices */ struct alloced_area *aa; uint32_t s; uint32_t devices_needed = ah->area_count + ah->parity_count; /* ix_offset holds the number of parallel allocations that must be contiguous/cling */ /* At most one of A_CONTIGUOUS_TO_LVSEG, A_CLING_TO_LVSEG or A_CLING_TO_ALLOCED may be set */ if (alloc_parms->flags & (A_CONTIGUOUS_TO_LVSEG | A_CLING_TO_LVSEG)) ix_offset = _stripes_per_mimage(alloc_parms->prev_lvseg) * alloc_parms->prev_lvseg->area_count; if (alloc_parms->flags & A_CLING_TO_ALLOCED) ix_offset = ah->area_count; if (alloc_parms->alloc == ALLOC_NORMAL || (alloc_parms->flags & A_CLING_TO_ALLOCED)) log_debug("Cling_to_allocated is %sset", alloc_parms->flags & A_CLING_TO_ALLOCED ? "" : "not "); _clear_areas(alloc_state); _reset_unreserved(pvms); _report_needed_allocation_space(ah, alloc_state); /* ix holds the number of areas found on other PVs */ do { if (log_iteration_count) { log_debug("Found %u areas for %" PRIu32 " parallel areas and %" PRIu32 " log areas so far.", ix, devices_needed, alloc_state->log_area_count_still_needed); } else if (iteration_count) log_debug("Filled %u out of %u preferred areas so far.", preferred_count, ix_offset); /* * Provide for escape from the loop if no progress is made. * This should not happen: ALLOC_ANYWHERE should be able to use * all available space. (If there aren't enough extents, the code * should not reach this point.) */ last_ix = ix; /* * Put the smallest area of each PV that is at least the * size we need into areas array. If there isn't one * that fits completely and we're allowed more than one * LV segment, then take the largest remaining instead. */ dm_list_iterate_items(pvm, pvms) { /* PV-level checks */ if (dm_list_empty(&pvm->areas)) continue; /* Next PV */ if (alloc_parms->alloc != ALLOC_ANYWHERE) { /* Don't allocate onto the log PVs */ if (ah->log_area_count) dm_list_iterate_items(aa, &ah->alloced_areas[ah->area_count]) for (s = 0; s < ah->log_area_count; s++) if (!aa[s].pv) goto next_pv; /* FIXME Split into log and non-log parallel_pvs and only check the log ones if log_iteration? */ /* (I've temporatily disabled the check.) */ /* Avoid PVs used by existing parallel areas */ if (!log_iteration_count && parallel_pvs && _pv_is_parallel(pvm->pv, parallel_pvs)) goto next_pv; /* * Avoid PVs already set aside for log. * We only reach here if there were enough PVs for the main areas but * not enough for the logs. */ if (log_iteration_count) { for (s = devices_needed; s < ix + ix_offset; s++) if (alloc_state->areas[s].pva && alloc_state->areas[s].pva->map->pv == pvm->pv) goto next_pv; /* On a second pass, avoid PVs already used in an uncommitted area */ } else if (iteration_count) for (s = 0; s < devices_needed; s++) if (alloc_state->areas[s].pva && alloc_state->areas[s].pva->map->pv == pvm->pv) goto next_pv; } already_found_one = 0; /* First area in each list is the largest */ dm_list_iterate_items(pva, &pvm->areas) { /* * There are two types of allocations, which can't be mixed at present. * PREFERRED are stored immediately in a specific parallel slot. * USE_AREA are stored for later, then sorted and chosen from. */ switch(_check_pva(ah, pva, max_to_allocate, alloc_parms, alloc_state, already_found_one, iteration_count, log_iteration_count)) { case PREFERRED: preferred_count++; /* Fall through */ case NEXT_PV: goto next_pv; case NEXT_AREA: continue; case USE_AREA: /* * Except with ALLOC_ANYWHERE, replace first area with this * one which is smaller but still big enough. */ if (!already_found_one || alloc_parms->alloc == ALLOC_ANYWHERE) { ix++; already_found_one = 1; } /* Reserve required amount of pva */ if (!_reserve_required_area(ah, max_to_allocate, ix + ix_offset, pva, alloc_state, alloc_parms->alloc)) return_0; } } next_pv: /* With ALLOC_ANYWHERE we ignore further PVs once we have at least enough areas */ /* With cling and contiguous we stop if we found a match for *all* the areas */ /* FIXME Rename these variables! */ if ((alloc_parms->alloc == ALLOC_ANYWHERE && ix + ix_offset >= devices_needed + alloc_state->log_area_count_still_needed) || (preferred_count == ix_offset && (ix_offset == devices_needed + alloc_state->log_area_count_still_needed))) break; } } while ((alloc_parms->alloc == ALLOC_ANYWHERE && last_ix != ix && ix < devices_needed + alloc_state->log_area_count_still_needed) || /* With cling_to_alloced and normal, if there were gaps in the preferred areas, have a second iteration */ (alloc_parms->alloc == ALLOC_NORMAL && preferred_count && (preferred_count < ix_offset || alloc_state->log_area_count_still_needed) && (alloc_parms->flags & A_CLING_TO_ALLOCED) && !iteration_count++) || /* Extra iteration needed to fill log areas on PVs already used? */ (alloc_parms->alloc == ALLOC_NORMAL && preferred_count == ix_offset && !ah->mirror_logs_separate && (ix + preferred_count >= devices_needed) && (ix + preferred_count < devices_needed + alloc_state->log_area_count_still_needed) && !log_iteration_count++)); if (preferred_count < ix_offset && !(alloc_parms->flags & A_CLING_TO_ALLOCED)) return 1; if (ix + preferred_count < devices_needed + alloc_state->log_area_count_still_needed) return 1; /* Sort the areas so we allocate from the biggest */ if (log_iteration_count) { if (ix > devices_needed + 1) { log_debug("Sorting %u log areas", ix - devices_needed); qsort(alloc_state->areas + devices_needed, ix - devices_needed, sizeof(*alloc_state->areas), _comp_area); } } else if (ix > 1) { log_debug("Sorting %u areas", ix); qsort(alloc_state->areas + ix_offset, ix, sizeof(*alloc_state->areas), _comp_area); } /* If there are gaps in our preferred areas, fill then from the sorted part of the array */ if (preferred_count && preferred_count != ix_offset) { for (s = 0; s < devices_needed; s++) if (!alloc_state->areas[s].pva) { alloc_state->areas[s].pva = alloc_state->areas[ix_offset].pva; alloc_state->areas[s].used = alloc_state->areas[ix_offset].used; alloc_state->areas[ix_offset++].pva = NULL; } } /* * First time around, if there's a log, allocate it on the * smallest device that has space for it. */ too_small_for_log_count = 0; ix_log_offset = 0; /* FIXME This logic is due to its heritage and can be simplified! */ if (alloc_state->log_area_count_still_needed) { /* How many areas are too small for the log? */ while (too_small_for_log_count < ix_offset + ix && (*(alloc_state->areas + ix_offset + ix - 1 - too_small_for_log_count)).used < ah->log_len) too_small_for_log_count++; ix_log_offset = ix_offset + ix - too_small_for_log_count - ah->log_area_count; } if (ix + ix_offset < devices_needed + (alloc_state->log_area_count_still_needed ? alloc_state->log_area_count_still_needed + too_small_for_log_count : 0)) return 1; /* * Finally add the space identified to the list of areas to be used. */ if (!_alloc_parallel_area(ah, max_to_allocate, alloc_state, ix_log_offset)) return_0; /* * Log is always allocated first time. */ alloc_state->log_area_count_still_needed = 0; return 1; } /* * Choose sets of parallel areas to use, respecting any constraints * supplied in alloc_parms. */ static int _find_max_parallel_space_for_one_policy(struct alloc_handle *ah, struct alloc_parms *alloc_parms, struct dm_list *pvms, struct alloc_state *alloc_state) { uint32_t max_tmp; uint32_t max_to_allocate; /* Maximum extents to allocate this time */ uint32_t old_allocated; uint32_t next_le; struct seg_pvs *spvs; struct dm_list *parallel_pvs; /* FIXME This algorithm needs a lot of cleaning up! */ /* FIXME anywhere doesn't find all space yet */ do { parallel_pvs = NULL; max_to_allocate = alloc_parms->extents_still_needed - alloc_state->allocated; /* * If there are existing parallel PVs, avoid them and reduce * the maximum we can allocate in one go accordingly. */ if (ah->parallel_areas) { next_le = (alloc_parms->prev_lvseg ? alloc_parms->prev_lvseg->le + alloc_parms->prev_lvseg->len : 0) + alloc_state->allocated / ah->area_multiple; dm_list_iterate_items(spvs, ah->parallel_areas) { if (next_le >= spvs->le + spvs->len) continue; max_tmp = max_to_allocate + alloc_state->allocated; /* * Because a request that groups metadata and * data together will be split, we must adjust * the comparison accordingly. */ if (ah->alloc_and_split_meta) max_tmp -= ah->log_len; if (max_tmp > (spvs->le + spvs->len) * ah->area_multiple) { max_to_allocate = (spvs->le + spvs->len) * ah->area_multiple - alloc_state->allocated; max_to_allocate += ah->alloc_and_split_meta ? ah->log_len : 0; } parallel_pvs = &spvs->pvs; break; } } old_allocated = alloc_state->allocated; if (!_find_some_parallel_space(ah, alloc_parms, pvms, alloc_state, parallel_pvs, max_to_allocate)) return_0; /* * If we didn't allocate anything this time with ALLOC_NORMAL and had * A_CLING_TO_ALLOCED set, try again without it. * * For ALLOC_NORMAL, if we did allocate something without the * flag set, set it and continue so that further allocations * remain on the same disks where possible. */ if (old_allocated == alloc_state->allocated) { if ((alloc_parms->alloc == ALLOC_NORMAL) && (alloc_parms->flags & A_CLING_TO_ALLOCED)) alloc_parms->flags &= ~A_CLING_TO_ALLOCED; else break; /* Give up */ } else if (ah->maximise_cling && alloc_parms->alloc == ALLOC_NORMAL && !(alloc_parms->flags & A_CLING_TO_ALLOCED)) alloc_parms->flags |= A_CLING_TO_ALLOCED; } while ((alloc_parms->alloc != ALLOC_CONTIGUOUS) && alloc_state->allocated != alloc_parms->extents_still_needed && (alloc_parms->flags & A_CAN_SPLIT)); return 1; } /* * Allocate several segments, each the same size, in parallel. * If mirrored_pv and mirrored_pe are supplied, it is used as * the first area, and additional areas are allocated parallel to it. */ static int _allocate(struct alloc_handle *ah, struct volume_group *vg, struct logical_volume *lv, unsigned can_split, struct dm_list *allocatable_pvs) { uint32_t old_allocated; struct lv_segment *prev_lvseg = NULL; int r = 0; struct dm_list *pvms; alloc_policy_t alloc; struct alloc_parms alloc_parms; struct alloc_state alloc_state; alloc_state.allocated = lv ? lv->le_count : 0; if (alloc_state.allocated >= ah->new_extents && !ah->log_area_count) { log_error("_allocate called with no work to do!"); return 1; } if (ah->area_multiple > 1 && (ah->new_extents - alloc_state.allocated) % ah->area_multiple) { log_error("Number of extents requested (%d) needs to be divisible by %d.", ah->new_extents - alloc_state.allocated, ah->area_multiple); return 0; } alloc_state.log_area_count_still_needed = ah->log_area_count; if (ah->alloc == ALLOC_CONTIGUOUS) can_split = 0; if (lv && !dm_list_empty(&lv->segments)) prev_lvseg = dm_list_item(dm_list_last(&lv->segments), struct lv_segment); /* * Build the sets of available areas on the pv's. */ if (!(pvms = create_pv_maps(ah->mem, vg, allocatable_pvs))) return_0; if (!_log_parallel_areas(ah->mem, ah->parallel_areas)) stack; alloc_state.areas_size = dm_list_size(pvms); if (alloc_state.areas_size && alloc_state.areas_size < (ah->area_count + ah->parity_count + ah->log_area_count)) { if (ah->alloc != ALLOC_ANYWHERE && ah->mirror_logs_separate) { log_error("Not enough PVs with free space available " "for parallel allocation."); log_error("Consider --alloc anywhere if desperate."); return 0; } alloc_state.areas_size = ah->area_count + ah->parity_count + ah->log_area_count; } /* Upper bound if none of the PVs in prev_lvseg is in pvms */ /* FIXME Work size out properly */ if (prev_lvseg) alloc_state.areas_size += _stripes_per_mimage(prev_lvseg) * prev_lvseg->area_count; /* Allocate an array of pv_areas to hold the largest space on each PV */ if (!(alloc_state.areas = dm_malloc(sizeof(*alloc_state.areas) * alloc_state.areas_size))) { log_error("Couldn't allocate areas array."); return 0; } /* * cling includes implicit cling_by_tags * but it does nothing unless the lvm.conf setting is present. */ if (ah->alloc == ALLOC_CLING) ah->alloc = ALLOC_CLING_BY_TAGS; /* Attempt each defined allocation policy in turn */ for (alloc = ALLOC_CONTIGUOUS; alloc <= ah->alloc; alloc++) { /* Skip cling_by_tags if no list defined */ if (alloc == ALLOC_CLING_BY_TAGS && !ah->cling_tag_list_cn) continue; old_allocated = alloc_state.allocated; log_debug("Trying allocation using %s policy.", get_alloc_string(alloc)); if (!_sufficient_pes_free(ah, pvms, alloc_state.allocated, ah->new_extents)) goto_out; _init_alloc_parms(ah, &alloc_parms, alloc, prev_lvseg, can_split, alloc_state.allocated, ah->new_extents); if (!_find_max_parallel_space_for_one_policy(ah, &alloc_parms, pvms, &alloc_state)) goto_out; if ((alloc_state.allocated == ah->new_extents && !alloc_state.log_area_count_still_needed) || (!can_split && (alloc_state.allocated != old_allocated))) break; } if (alloc_state.allocated != ah->new_extents) { log_error("Insufficient suitable %sallocatable extents " "for logical volume %s: %u more required", can_split ? "" : "contiguous ", lv ? lv->name : "", (ah->new_extents - alloc_state.allocated) * ah->area_count / ah->area_multiple); goto out; } if (alloc_state.log_area_count_still_needed) { log_error("Insufficient free space for log allocation " "for logical volume %s.", lv ? lv->name : ""); goto out; } r = 1; out: dm_free(alloc_state.areas); return r; } int lv_add_virtual_segment(struct logical_volume *lv, uint64_t status, uint32_t extents, const struct segment_type *segtype, const char *thin_pool_name) { struct lv_segment *seg; struct logical_volume *thin_pool_lv = NULL; struct lv_list *lvl; uint32_t size; if (thin_pool_name) { if (!(lvl = find_lv_in_vg(lv->vg, thin_pool_name))) { log_error("Unable to find existing pool LV %s in VG %s.", thin_pool_name, lv->vg->name); return 0; } thin_pool_lv = lvl->lv; size = first_seg(thin_pool_lv)->chunk_size; if (lv->vg->extent_size < size) { /* Align extents on chunk boundary size */ size = ((uint64_t)lv->vg->extent_size * extents + size - 1) / size * size / lv->vg->extent_size; if (size != extents) { log_print_unless_silent("Rounding size (%d extents) up to chunk boundary " "size (%d extents).", extents, size); extents = size; } } } if (!dm_list_empty(&lv->segments) && (seg = last_seg(lv)) && (seg->segtype == segtype)) { seg->area_len += extents; seg->len += extents; } else { if (!(seg = alloc_lv_segment(segtype, lv, lv->le_count, extents, status, 0, NULL, thin_pool_lv, 0, extents, 0, 0, 0, NULL))) { log_error("Couldn't allocate new zero segment."); return 0; } lv->status |= VIRTUAL; dm_list_add(&lv->segments, &seg->list); } lv->le_count += extents; lv->size += (uint64_t) extents *lv->vg->extent_size; return 1; } /* * Entry point for all extent allocations. */ struct alloc_handle *allocate_extents(struct volume_group *vg, struct logical_volume *lv, const struct segment_type *segtype, uint32_t stripes, uint32_t mirrors, uint32_t log_count, uint32_t region_size, uint32_t extents, struct dm_list *allocatable_pvs, alloc_policy_t alloc, struct dm_list *parallel_areas) { struct alloc_handle *ah; uint32_t new_extents; if (segtype_is_virtual(segtype)) { log_error("allocate_extents does not handle virtual segments"); return NULL; } if (!allocatable_pvs) { log_error(INTERNAL_ERROR "Missing allocatable pvs."); return NULL; } if (vg->fid->fmt->ops->segtype_supported && !vg->fid->fmt->ops->segtype_supported(vg->fid, segtype)) { log_error("Metadata format (%s) does not support required " "LV segment type (%s).", vg->fid->fmt->name, segtype->name); log_error("Consider changing the metadata format by running " "vgconvert."); return NULL; } if (alloc >= ALLOC_INHERIT) alloc = vg->alloc; new_extents = (lv ? lv->le_count : 0) + extents; if (!(ah = _alloc_init(vg->cmd, vg->cmd->mem, segtype, alloc, new_extents, mirrors, stripes, log_count, vg->extent_size, region_size, parallel_areas))) return_NULL; if (!_allocate(ah, vg, lv, 1, allocatable_pvs)) { alloc_destroy(ah); return_NULL; } return ah; } /* * Add new segments to an LV from supplied list of areas. */ int lv_add_segment(struct alloc_handle *ah, uint32_t first_area, uint32_t num_areas, struct logical_volume *lv, const struct segment_type *segtype, uint32_t stripe_size, uint64_t status, uint32_t region_size) { if (!segtype) { log_error("Missing segtype in lv_add_segment()."); return 0; } if (segtype_is_virtual(segtype)) { log_error("lv_add_segment cannot handle virtual segments"); return 0; } if ((status & MIRROR_LOG) && dm_list_size(&lv->segments)) { log_error("Log segments can only be added to an empty LV"); return 0; } if (!_setup_alloced_segments(lv, &ah->alloced_areas[first_area], num_areas, status, stripe_size, segtype, region_size)) return_0; if ((segtype->flags & SEG_CAN_SPLIT) && !lv_merge_segments(lv)) { log_error("Couldn't merge segments after extending " "logical volume."); return 0; } if (lv->vg->fid->fmt->ops->lv_setup && !lv->vg->fid->fmt->ops->lv_setup(lv->vg->fid, lv)) return_0; return 1; } /* * "mirror" segment type doesn't support split. * So, when adding mirrors to linear LV segment, first split it, * then convert it to "mirror" and add areas. */ static struct lv_segment *_convert_seg_to_mirror(struct lv_segment *seg, uint32_t region_size, struct logical_volume *log_lv) { struct lv_segment *newseg; uint32_t s; if (!seg_is_striped(seg)) { log_error("Can't convert non-striped segment to mirrored."); return NULL; } if (seg->area_count > 1) { log_error("Can't convert striped segment with multiple areas " "to mirrored."); return NULL; } if (!(newseg = alloc_lv_segment(get_segtype_from_string(seg->lv->vg->cmd, "mirror"), seg->lv, seg->le, seg->len, seg->status, seg->stripe_size, log_lv, NULL, seg->area_count, seg->area_len, seg->chunk_size, region_size, seg->extents_copied, NULL))) { log_error("Couldn't allocate converted LV segment"); return NULL; } for (s = 0; s < seg->area_count; s++) if (!move_lv_segment_area(newseg, s, seg, s)) return_NULL; seg->pvmove_source_seg = NULL; /* Not maintained after allocation */ dm_list_add(&seg->list, &newseg->list); dm_list_del(&seg->list); return newseg; } /* * Add new areas to mirrored segments */ int lv_add_mirror_areas(struct alloc_handle *ah, struct logical_volume *lv, uint32_t le, uint32_t region_size) { struct alloced_area *aa; struct lv_segment *seg; uint32_t current_le = le; uint32_t s, old_area_count, new_area_count; dm_list_iterate_items(aa, &ah->alloced_areas[0]) { if (!(seg = find_seg_by_le(lv, current_le))) { log_error("Failed to find segment for %s extent %" PRIu32, lv->name, current_le); return 0; } /* Allocator assures aa[0].len <= seg->area_len */ if (aa[0].len < seg->area_len) { if (!lv_split_segment(lv, seg->le + aa[0].len)) { log_error("Failed to split segment at %s " "extent %" PRIu32, lv->name, le); return 0; } } if (!seg_is_mirrored(seg) && (!(seg = _convert_seg_to_mirror(seg, region_size, NULL)))) return_0; old_area_count = seg->area_count; new_area_count = old_area_count + ah->area_count; if (!_lv_segment_add_areas(lv, seg, new_area_count)) return_0; for (s = 0; s < ah->area_count; s++) { if (!set_lv_segment_area_pv(seg, s + old_area_count, aa[s].pv, aa[s].pe)) return_0; } current_le += seg->area_len; } lv->status |= MIRRORED; if (lv->vg->fid->fmt->ops->lv_setup && !lv->vg->fid->fmt->ops->lv_setup(lv->vg->fid, lv)) return_0; return 1; } /* * Add mirror image LVs to mirrored segments */ int lv_add_mirror_lvs(struct logical_volume *lv, struct logical_volume **sub_lvs, uint32_t num_extra_areas, uint64_t status, uint32_t region_size) { struct lv_segment *seg; uint32_t old_area_count, new_area_count; uint32_t m; struct segment_type *mirror_segtype; seg = first_seg(lv); if (dm_list_size(&lv->segments) != 1 || seg_type(seg, 0) != AREA_LV) { log_error("Mirror layer must be inserted before adding mirrors"); return 0; } mirror_segtype = get_segtype_from_string(lv->vg->cmd, "mirror"); if (seg->segtype != mirror_segtype) if (!(seg = _convert_seg_to_mirror(seg, region_size, NULL))) return_0; if (region_size && region_size != seg->region_size) { log_error("Conflicting region_size"); return 0; } old_area_count = seg->area_count; new_area_count = old_area_count + num_extra_areas; if (!_lv_segment_add_areas(lv, seg, new_area_count)) { log_error("Failed to allocate widened LV segment for %s.", lv->name); return 0; } for (m = 0; m < old_area_count; m++) seg_lv(seg, m)->status |= status; for (m = old_area_count; m < new_area_count; m++) { if (!set_lv_segment_area_lv(seg, m, sub_lvs[m - old_area_count], 0, status)) return_0; lv_set_hidden(sub_lvs[m - old_area_count]); } lv->status |= MIRRORED; return 1; } /* * Turn an empty LV into a mirror log. * * FIXME: Mirrored logs are built inefficiently. * A mirrored log currently uses the same layout that a mirror * LV uses. The mirror layer sits on top of AREA_LVs which form the * legs, rather on AREA_PVs. This is done to allow re-use of the * various mirror functions to also handle the mirrored LV that makes * up the log. * * If we used AREA_PVs under the mirror layer of a log, we could * assemble it all at once by calling 'lv_add_segment' with the * appropriate segtype (mirror/stripe), like this: * lv_add_segment(ah, ah->area_count, ah->log_area_count, * log_lv, segtype, 0, MIRROR_LOG, 0); * * For now, we use the same mechanism to build a mirrored log as we * do for building a mirrored LV: 1) create initial LV, 2) add a * mirror layer, and 3) add the remaining copy LVs */ int lv_add_log_segment(struct alloc_handle *ah, uint32_t first_area, struct logical_volume *log_lv, uint64_t status) { return lv_add_segment(ah, ah->area_count + first_area, 1, log_lv, get_segtype_from_string(log_lv->vg->cmd, "striped"), 0, status, 0); } static int _lv_insert_empty_sublvs(struct logical_volume *lv, const struct segment_type *segtype, uint32_t stripe_size, uint32_t region_size, uint32_t devices) { struct logical_volume *sub_lv; uint32_t i; uint64_t sub_lv_status = 0; const char *layer_name; size_t len = strlen(lv->name) + 32; char img_name[len]; struct lv_segment *mapseg; if (lv->le_count || !dm_list_empty(&lv->segments)) { log_error(INTERNAL_ERROR "Non-empty LV passed to _lv_insert_empty_sublv"); return 0; } if (segtype_is_raid(segtype)) { lv->status |= RAID; sub_lv_status = RAID_IMAGE; layer_name = "rimage"; } else if (segtype_is_mirrored(segtype)) { lv->status |= MIRRORED; sub_lv_status = MIRROR_IMAGE; layer_name = "mimage"; } else return_0; /* * First, create our top-level segment for our top-level LV */ if (!(mapseg = alloc_lv_segment(segtype, lv, 0, 0, lv->status, stripe_size, NULL, NULL, devices, 0, 0, region_size, 0, NULL))) { log_error("Failed to create mapping segment for %s", lv->name); return 0; } /* * Next, create all of our sub_lv's and link them in. */ for (i = 0; i < devices; i++) { /* Data LVs */ if (devices > 1) { if (dm_snprintf(img_name, len, "%s_%s_%u", lv->name, layer_name, i) < 0) return_0; } else { if (dm_snprintf(img_name, len, "%s_%s", lv->name, layer_name) < 0) return_0; } /* FIXME Should use ALLOC_INHERIT here and inherit from parent LV */ if (!(sub_lv = lv_create_empty(img_name, NULL, LVM_READ | LVM_WRITE, lv->alloc, lv->vg))) return_0; if (!set_lv_segment_area_lv(mapseg, i, sub_lv, 0, sub_lv_status)) return_0; /* Metadata LVs for raid */ if (segtype_is_raid(segtype)) { if (dm_snprintf(img_name, len, "%s_rmeta_%u", lv->name, i) < 0) return_0; } else continue; /* FIXME Should use ALLOC_INHERIT here and inherit from parent LV */ if (!(sub_lv = lv_create_empty(img_name, NULL, LVM_READ | LVM_WRITE, lv->alloc, lv->vg))) return_0; if (!set_lv_segment_area_lv(mapseg, i, sub_lv, 0, RAID_META)) return_0; } dm_list_add(&lv->segments, &mapseg->list); return 1; } static int _lv_extend_layered_lv(struct alloc_handle *ah, struct logical_volume *lv, uint32_t extents, uint32_t first_area, uint32_t stripes, uint32_t stripe_size) { const struct segment_type *segtype; struct logical_volume *sub_lv, *meta_lv; struct lv_segment *seg; uint32_t fa, s; int clear_metadata = 0; segtype = get_segtype_from_string(lv->vg->cmd, "striped"); /* * The component devices of a "striped" LV all go in the same * LV. However, RAID has an LV for each device - making the * 'stripes' and 'stripe_size' parameters meaningless. */ if (seg_is_raid(first_seg(lv))) { stripes = 1; stripe_size = 0; } seg = first_seg(lv); for (fa = first_area, s = 0; s < seg->area_count; s++) { if (is_temporary_mirror_layer(seg_lv(seg, s))) { if (!_lv_extend_layered_lv(ah, seg_lv(seg, s), extents, fa, stripes, stripe_size)) return_0; fa += lv_mirror_count(seg_lv(seg, s)); continue; } sub_lv = seg_lv(seg, s); if (!lv_add_segment(ah, fa, stripes, sub_lv, segtype, stripe_size, sub_lv->status, 0)) { log_error("Aborting. Failed to extend %s in %s.", sub_lv->name, lv->name); return 0; } /* Extend metadata LVs only on initial creation */ if (seg_is_raid(seg) && !lv->le_count) { if (!seg->meta_areas) { log_error("No meta_areas for RAID type"); return 0; } meta_lv = seg_metalv(seg, s); if (!lv_add_segment(ah, fa + seg->area_count, 1, meta_lv, segtype, 0, meta_lv->status, 0)) { log_error("Failed to extend %s in %s.", meta_lv->name, lv->name); return 0; } lv_set_visible(meta_lv); clear_metadata = 1; } fa += stripes; } if (clear_metadata) { /* * We must clear the metadata areas upon creation. */ if (!vg_write(lv->vg) || !vg_commit(lv->vg)) return_0; for (s = 0; s < seg->area_count; s++) { meta_lv = seg_metalv(seg, s); if (test_mode()) { lv_set_hidden(meta_lv); continue; } if (!activate_lv(meta_lv->vg->cmd, meta_lv)) { log_error("Failed to activate %s/%s for clearing", meta_lv->vg->name, meta_lv->name); return 0; } log_verbose("Clearing metadata area of %s/%s", meta_lv->vg->name, meta_lv->name); /* * Rather than wiping meta_lv->size, we can simply * wipe '1' to remove the superblock of any previous * RAID devices. It is much quicker. */ if (!set_lv(meta_lv->vg->cmd, meta_lv, 1, 0)) { log_error("Failed to zero %s/%s", meta_lv->vg->name, meta_lv->name); return 0; } if (!deactivate_lv(meta_lv->vg->cmd, meta_lv)) { log_error("Failed to deactivate %s/%s", meta_lv->vg->name, meta_lv->name); return 0; } lv_set_hidden(meta_lv); } } seg->area_len += extents; seg->len += extents; lv->le_count += extents; lv->size += (uint64_t) extents * lv->vg->extent_size; /* * The MD bitmap is limited to being able to track 2^21 regions. * The region_size must be adjusted to meet that criteria. */ while (seg_is_raid(seg) && (seg->region_size < (lv->size / (1 << 21)))) { seg->region_size *= 2; log_very_verbose("Forced to adjust RAID region_size to %uS", seg->region_size); } return 1; } /* * Entry point for single-step LV allocation + extension. */ int lv_extend(struct logical_volume *lv, const struct segment_type *segtype, uint32_t stripes, uint32_t stripe_size, uint32_t mirrors, uint32_t region_size, uint32_t extents, const char *thin_pool_name, struct dm_list *allocatable_pvs, alloc_policy_t alloc) { int r = 1; int log_count = 0; struct alloc_handle *ah; uint32_t sub_lv_count; log_very_verbose("Extending segment type, %s", segtype->name); if (segtype_is_virtual(segtype)) return lv_add_virtual_segment(lv, 0u, extents, segtype, thin_pool_name); if (!lv->le_count && segtype_is_thin_pool(segtype)) { /* Thin pool allocation treats its metadata device like a mirror log. */ /* FIXME Allow pool and data on same device with NORMAL */ /* FIXME Support striped metadata pool */ log_count = 1; } else if (segtype_is_raid(segtype) && !lv->le_count) log_count = mirrors * stripes; /* FIXME log_count should be 1 for mirrors */ if (!(ah = allocate_extents(lv->vg, lv, segtype, stripes, mirrors, log_count, region_size, extents, allocatable_pvs, alloc, NULL))) return_0; if (segtype_is_thin_pool(segtype)) { if (!lv->le_count) { if (!(r = extend_pool(lv, segtype, ah, stripes, stripe_size))) stack; } else if (!(r = _lv_extend_layered_lv(ah, lv, extents, 0, stripes, stripe_size))) stack; } else if (!segtype_is_mirrored(segtype) && !segtype_is_raid(segtype)) { if (!(r = lv_add_segment(ah, 0, ah->area_count, lv, segtype, stripe_size, 0u, 0))) stack; } else { /* * For RAID, all the devices are AREA_LV. * However, for 'mirror on stripe' using non-RAID targets, * the mirror legs are AREA_LV while the stripes underneath * are AREA_PV. */ if (segtype_is_raid(segtype)) sub_lv_count = mirrors * stripes + segtype->parity_devs; else sub_lv_count = mirrors; if (!lv->le_count && !(r = _lv_insert_empty_sublvs(lv, segtype, stripe_size, region_size, sub_lv_count))) { log_error("Failed to insert layer for %s", lv->name); goto out; } if (!(r = _lv_extend_layered_lv(ah, lv, extents, 0, stripes, stripe_size))) goto_out; /* * If we are expanding an existing mirror, we can skip the * resync of the extension if the LV is currently in-sync * and the LV has the LV_NOTSYNCED flag set. */ if ((lv->le_count != extents) && segtype_is_mirrored(segtype) && (lv->status & LV_NOTSYNCED)) { percent_t sync_percent = PERCENT_INVALID; if (!lv_is_active(lv)) { log_error("%s/%s is not active." " Unable to get sync percent.", lv->vg->name, lv->name); /* FIXME Support --force */ if (yes_no_prompt("Do full resync of extended " "portion of %s/%s? [y/n]: ", lv->vg->name, lv->name) == 'y') goto out; r = 0; goto out; } if (!(r = lv_mirror_percent(lv->vg->cmd, lv, 0, &sync_percent, NULL))) { log_error("Failed to get sync percent for %s/%s", lv->vg->name, lv->name); goto out; } else if (sync_percent == PERCENT_100) { log_verbose("Skipping initial resync for " "extended portion of %s/%s", lv->vg->name, lv->name); init_mirror_in_sync(1); lv->status |= LV_NOTSYNCED; } else { log_error("%s/%s cannot be extended while" " it is recovering.", lv->vg->name, lv->name); r = 0; goto out; } } } out: alloc_destroy(ah); return r; } /* * Minimal LV renaming function. * Metadata transaction should be made by caller. * Assumes new_name is allocated from cmd->mem pool. */ static int _rename_single_lv(struct logical_volume *lv, char *new_name) { struct volume_group *vg = lv->vg; if (find_lv_in_vg(vg, new_name)) { log_error("Logical volume \"%s\" already exists in " "volume group \"%s\"", new_name, vg->name); return 0; } if (lv->status & LOCKED) { log_error("Cannot rename locked LV %s", lv->name); return 0; } lv->name = new_name; return 1; } /* * Rename sub LV. * 'lv_name_old' and 'lv_name_new' are old and new names of the main LV. */ static int _rename_sub_lv(struct cmd_context *cmd, struct logical_volume *lv, const char *lv_name_old, const char *lv_name_new) { const char *suffix; char *new_name; size_t len; /* * A sub LV name starts with lv_name_old + '_'. * The suffix follows lv_name_old and includes '_'. */ len = strlen(lv_name_old); if (strncmp(lv->name, lv_name_old, len) || lv->name[len] != '_') { log_error("Cannot rename \"%s\": name format not recognized " "for internal LV \"%s\"", lv_name_old, lv->name); return 0; } suffix = lv->name + len; /* * Compose a new name for sub lv: * e.g. new name is "lvol1_mlog" * if the sub LV is "lvol0_mlog" and * a new name for main LV is "lvol1" */ len = strlen(lv_name_new) + strlen(suffix) + 1; new_name = dm_pool_alloc(cmd->mem, len); if (!new_name) { log_error("Failed to allocate space for new name"); return 0; } if (dm_snprintf(new_name, len, "%s%s", lv_name_new, suffix) < 0) { log_error("Failed to create new name"); return 0; } /* Rename it */ return _rename_single_lv(lv, new_name); } /* Callback for for_each_sub_lv */ static int _rename_cb(struct cmd_context *cmd, struct logical_volume *lv, void *data) { struct lv_names *lv_names = (struct lv_names *) data; return _rename_sub_lv(cmd, lv, lv_names->old, lv_names->new); } /* * Loop down sub LVs and call fn for each. * fn is responsible to log necessary information on failure. */ int for_each_sub_lv(struct cmd_context *cmd, struct logical_volume *lv, int (*fn)(struct cmd_context *cmd, struct logical_volume *lv, void *data), void *data) { struct logical_volume *org; struct lv_segment *seg; uint32_t s; if (lv_is_cow(lv) && lv_is_virtual_origin(org = origin_from_cow(lv))) { if (!fn(cmd, org, data)) return_0; if (!for_each_sub_lv(cmd, org, fn, data)) return_0; } dm_list_iterate_items(seg, &lv->segments) { if (seg->log_lv) { if (!fn(cmd, seg->log_lv, data)) return_0; if (!for_each_sub_lv(cmd, seg->log_lv, fn, data)) return_0; } if (seg->metadata_lv) { if (!fn(cmd, seg->metadata_lv, data)) return_0; if (!for_each_sub_lv(cmd, seg->metadata_lv, fn, data)) return_0; } for (s = 0; s < seg->area_count; s++) { if (seg_type(seg, s) != AREA_LV) continue; if (!fn(cmd, seg_lv(seg, s), data)) return_0; if (!for_each_sub_lv(cmd, seg_lv(seg, s), fn, data)) return_0; } if (!seg_is_raid(seg)) continue; /* RAID has meta_areas */ for (s = 0; s < seg->area_count; s++) { if (seg_metatype(seg, s) != AREA_LV) continue; if (!fn(cmd, seg_metalv(seg, s), data)) return_0; if (!for_each_sub_lv(cmd, seg_metalv(seg, s), fn, data)) return_0; } } return 1; } /* * Core of LV renaming routine. * VG must be locked by caller. */ int lv_rename_update(struct cmd_context *cmd, struct logical_volume *lv, const char *new_name, int update_mda) { struct volume_group *vg = lv->vg; struct lv_names lv_names; DM_LIST_INIT(lvs_changed); struct lv_list lvl, lvl2, *lvlp; int r = 0; /* rename is not allowed on sub LVs */ if (!lv_is_visible(lv)) { log_error("Cannot rename internal LV \"%s\".", lv->name); return 0; } if (find_lv_in_vg(vg, new_name)) { log_error("Logical volume \"%s\" already exists in " "volume group \"%s\"", new_name, vg->name); return 0; } if (lv->status & LOCKED) { log_error("Cannot rename locked LV %s", lv->name); return 0; } if (update_mda && !archive(vg)) return 0; /* rename sub LVs */ lv_names.old = lv->name; lv_names.new = new_name; if (!for_each_sub_lv(cmd, lv, _rename_cb, (void *) &lv_names)) return 0; /* rename main LV */ if (!(lv->name = dm_pool_strdup(cmd->mem, new_name))) { log_error("Failed to allocate space for new name"); return 0; } lvl.lv = lv; dm_list_add(&lvs_changed, &lvl.list); /* rename active virtual origin too */ if (lv_is_cow(lv) && lv_is_virtual_origin(lvl2.lv = origin_from_cow(lv))) dm_list_add_h(&lvs_changed, &lvl2.list); if (!update_mda) return 1; log_verbose("Writing out updated volume group"); if (!vg_write(vg)) return 0; if (!suspend_lvs(cmd, &lvs_changed, vg)) goto_out; if (!(r = vg_commit(vg))) stack; /* * FIXME: resume LVs in reverse order to prevent memory * lock imbalance when resuming virtual snapshot origin * (resume of snapshot resumes origin too) */ dm_list_iterate_back_items(lvlp, &lvs_changed) if (!resume_lv(cmd, lvlp->lv)) stack; out: backup(vg); return r; } /* * Core of LV renaming routine. * VG must be locked by caller. */ int lv_rename(struct cmd_context *cmd, struct logical_volume *lv, const char *new_name) { return lv_rename_update(cmd, lv, new_name, 1); } char *generate_lv_name(struct volume_group *vg, const char *format, char *buffer, size_t len) { struct lv_list *lvl; int high = -1, i; dm_list_iterate_items(lvl, &vg->lvs) { if (sscanf(lvl->lv->name, format, &i) != 1) continue; if (i > high) high = i; } if (dm_snprintf(buffer, len, format, high + 1) < 0) return NULL; return buffer; } int vg_max_lv_reached(struct volume_group *vg) { if (!vg->max_lv) return 0; if (vg->max_lv > vg_visible_lvs(vg)) return 0; log_verbose("Maximum number of logical volumes (%u) reached " "in volume group %s", vg->max_lv, vg->name); return 1; } struct logical_volume *alloc_lv(struct dm_pool *mem) { struct logical_volume *lv; if (!(lv = dm_pool_zalloc(mem, sizeof(*lv)))) { log_error("Unable to allocate logical volume structure"); return NULL; } lv->snapshot = NULL; dm_list_init(&lv->snapshot_segs); dm_list_init(&lv->segments); dm_list_init(&lv->tags); dm_list_init(&lv->segs_using_this_lv); dm_list_init(&lv->rsites); return lv; } /* * Create a new empty LV. */ struct logical_volume *lv_create_empty(const char *name, union lvid *lvid, uint64_t status, alloc_policy_t alloc, struct volume_group *vg) { struct format_instance *fi = vg->fid; struct logical_volume *lv; char dname[NAME_LEN]; if (vg_max_lv_reached(vg)) stack; if (strstr(name, "%d") && !(name = generate_lv_name(vg, name, dname, sizeof(dname)))) { log_error("Failed to generate unique name for the new " "logical volume"); return NULL; } else if (find_lv_in_vg(vg, name)) { log_error("Unable to create LV %s in Volume Group %s: " "name already in use.", name, vg->name); return NULL; } log_verbose("Creating logical volume %s", name); if (!(lv = alloc_lv(vg->vgmem))) return_NULL; if (!(lv->name = dm_pool_strdup(vg->vgmem, name))) goto_bad; lv->status = status; lv->alloc = alloc; lv->read_ahead = vg->cmd->default_settings.read_ahead; lv->major = -1; lv->minor = -1; lv->size = UINT64_C(0); lv->le_count = 0; if (lvid) lv->lvid = *lvid; if (!link_lv_to_vg(vg, lv)) goto_bad; if (!lv_set_creation(lv, NULL, 0)) goto_bad; if (fi->fmt->ops->lv_setup && !fi->fmt->ops->lv_setup(fi, lv)) goto_bad; return lv; bad: dm_pool_free(vg->vgmem, lv); return NULL; } static int _add_pvs(struct cmd_context *cmd, struct pv_segment *peg, uint32_t s __attribute__((unused)), void *data) { struct seg_pvs *spvs = (struct seg_pvs *) data; struct pv_list *pvl; /* Don't add again if it's already on list. */ if (find_pv_in_pv_list(&spvs->pvs, peg->pv)) return 1; if (!(pvl = dm_pool_alloc(cmd->mem, sizeof(*pvl)))) { log_error("pv_list allocation failed"); return 0; } pvl->pv = peg->pv; dm_list_add(&spvs->pvs, &pvl->list); return 1; } /* * Construct dm_list of segments of LVs showing which PVs they use. * For pvmove we use the *parent* LV so we can pick up stripes & existing mirrors etc. */ struct dm_list *build_parallel_areas_from_lv(struct logical_volume *lv, unsigned use_pvmove_parent_lv) { struct cmd_context *cmd = lv->vg->cmd; struct dm_list *parallel_areas; struct seg_pvs *spvs; uint32_t current_le = 0; uint32_t raid_multiple; struct lv_segment *seg = first_seg(lv); if (!(parallel_areas = dm_pool_alloc(cmd->mem, sizeof(*parallel_areas)))) { log_error("parallel_areas allocation failed"); return NULL; } dm_list_init(parallel_areas); do { if (!(spvs = dm_pool_zalloc(cmd->mem, sizeof(*spvs)))) { log_error("allocation failed"); return NULL; } dm_list_init(&spvs->pvs); spvs->le = current_le; spvs->len = lv->le_count - current_le; dm_list_add(parallel_areas, &spvs->list); if (use_pvmove_parent_lv && !(seg = find_seg_by_le(lv, current_le))) { log_error("Failed to find segment for %s extent %" PRIu32, lv->name, current_le); return 0; } /* Find next segment end */ /* FIXME Unnecessary nesting! */ if (!_for_each_pv(cmd, use_pvmove_parent_lv ? seg->pvmove_source_seg->lv : lv, use_pvmove_parent_lv ? seg->pvmove_source_seg->le : current_le, use_pvmove_parent_lv ? spvs->len * _calc_area_multiple(seg->pvmove_source_seg->segtype, seg->pvmove_source_seg->area_count, 0) : spvs->len, use_pvmove_parent_lv ? seg->pvmove_source_seg : NULL, &spvs->len, 0, 0, -1, 0, _add_pvs, (void *) spvs)) return_NULL; current_le = spvs->le + spvs->len; raid_multiple = (seg->segtype->parity_devs) ? seg->area_count - seg->segtype->parity_devs : 1; } while ((current_le * raid_multiple) < lv->le_count); /* FIXME Merge adjacent segments with identical PV lists (avoids need for contiguous allocation attempts between successful allocations) */ return parallel_areas; } int link_lv_to_vg(struct volume_group *vg, struct logical_volume *lv) { struct lv_list *lvl; if (vg_max_lv_reached(vg)) stack; if (!(lvl = dm_pool_zalloc(vg->vgmem, sizeof(*lvl)))) return_0; lvl->lv = lv; lv->vg = vg; dm_list_add(&vg->lvs, &lvl->list); return 1; } int unlink_lv_from_vg(struct logical_volume *lv) { struct lv_list *lvl; if (!(lvl = find_lv_in_vg(lv->vg, lv->name))) return_0; dm_list_del(&lvl->list); return 1; } void lv_set_visible(struct logical_volume *lv) { if (lv_is_visible(lv)) return; lv->status |= VISIBLE_LV; log_debug("LV %s in VG %s is now visible.", lv->name, lv->vg->name); } void lv_set_hidden(struct logical_volume *lv) { if (!lv_is_visible(lv)) return; lv->status &= ~VISIBLE_LV; log_debug("LV %s in VG %s is now hidden.", lv->name, lv->vg->name); } int lv_remove_single(struct cmd_context *cmd, struct logical_volume *lv, const force_t force) { struct volume_group *vg; struct lvinfo info; struct logical_volume *format1_origin = NULL; int format1_reload_required = 0; int visible; struct logical_volume *pool_lv = NULL; int ask_discard; vg = lv->vg; if (!vg_check_status(vg, LVM_WRITE)) return_0; if (lv_is_origin(lv)) { log_error("Can't remove logical volume \"%s\" under snapshot", lv->name); return 0; } if (lv->status & MIRROR_IMAGE) { log_error("Can't remove logical volume %s used by a mirror", lv->name); return 0; } if (lv->status & MIRROR_LOG) { log_error("Can't remove logical volume %s used as mirror log", lv->name); return 0; } if (lv->status & (RAID_META | RAID_IMAGE)) { log_error("Can't remove logical volume %s used as RAID device", lv->name); return 0; } if (lv_is_thin_pool_data(lv) || lv_is_thin_pool_metadata(lv)) { log_error("Can't remove logical volume %s used by a thin pool.", lv->name); return 0; } else if (lv_is_thin_volume(lv)) pool_lv = first_seg(lv)->pool_lv; if (lv->status & LOCKED) { log_error("Can't remove locked LV %s", lv->name); return 0; } /* FIXME Ensure not referred to by another existing LVs */ ask_discard = find_config_tree_bool(cmd, "devices/issue_discards", DEFAULT_ISSUE_DISCARDS); if (lv_info(cmd, lv, 0, &info, 1, 0)) { if (!lv_check_not_in_use(cmd, lv, &info)) return_0; if ((force == PROMPT) && lv_is_visible(lv) && lv_is_active(lv)) { if (yes_no_prompt("Do you really want to remove%s active " "%slogical volume %s? [y/n]: ", ask_discard ? " and DISCARD" : "", vg_is_clustered(vg) ? "clustered " : "", lv->name) == 'n') { log_error("Logical volume %s not removed", lv->name); return 0; } else { ask_discard = 0; } } } if ((force == PROMPT) && ask_discard && yes_no_prompt("Do you really want to remove and DISCARD " "logical volume %s? [y/n]: ", lv->name) == 'n') { log_error("Logical volume %s not removed", lv->name); return 0; } if (!archive(vg)) return 0; if (lv_is_cow(lv)) { /* Old format1 code */ if (!(lv->vg->fid->fmt->features & FMT_MDAS)) format1_origin = origin_from_cow(lv); log_verbose("Removing snapshot %s", lv->name); /* vg_remove_snapshot() will preload origin/former snapshots */ if (!vg_remove_snapshot(lv)) return_0; } /* FIXME Review and fix the snapshot error paths! */ if (!deactivate_lv(cmd, lv)) { log_error("Unable to deactivate logical volume \"%s\"", lv->name); return 0; } /* Clear thin pool stacked messages */ if (pool_lv && !pool_has_message(first_seg(pool_lv), lv, 0) && !update_pool_lv(pool_lv, 1)) { log_error("Failed to update thin pool %s.", pool_lv->name); return 0; } visible = lv_is_visible(lv); log_verbose("Releasing logical volume \"%s\"", lv->name); if (!lv_remove(lv)) { log_error("Error releasing logical volume \"%s\"", lv->name); return 0; } /* * Old format1 code: If no snapshots left reload without -real. */ if (format1_origin && !lv_is_origin(format1_origin)) { log_warn("WARNING: Support for snapshots with old LVM1-style metadata is deprecated."); log_warn("WARNING: Please use lvconvert to update to lvm2 metadata at your convenience."); format1_reload_required = 1; } /* store it on disks */ if (!vg_write(vg)) return_0; /* format1 */ if (format1_reload_required && !suspend_lv(cmd, format1_origin)) log_error("Failed to refresh %s without snapshot.", format1_origin->name); if (!vg_commit(vg)) return_0; /* format1 */ if (format1_reload_required && !resume_lv(cmd, format1_origin)) { log_error("Failed to resume %s.", format1_origin->name); return 0; } /* Release unneeded blocks in thin pool */ /* TODO: defer when multiple LVs relased at once */ if (pool_lv && !update_pool_lv(pool_lv, 1)) { log_error("Failed to update thin pool %s.", pool_lv->name); return 0; } backup(vg); if (visible) log_print_unless_silent("Logical volume \"%s\" successfully removed", lv->name); return 1; } /* * remove LVs with its dependencies - LV leaf nodes should be removed first */ int lv_remove_with_dependencies(struct cmd_context *cmd, struct logical_volume *lv, const force_t force, unsigned level) { percent_t snap_percent; struct dm_list *snh, *snht; struct seg_list *sl, *tsl; struct lvinfo info; if (lv_is_cow(lv)) { /* * A merging snapshot cannot be removed directly unless * it has been invalidated or failed merge removal is requested. */ if (lv_is_merging_cow(lv) && !level) { if (lv_info(lv->vg->cmd, lv, 0, &info, 1, 0) && info.exists && info.live_table) { if (!lv_snapshot_percent(lv, &snap_percent)) { log_error("Failed to obtain merging snapshot progress percentage for logical volume %s.", lv->name); return 0; } if ((snap_percent != PERCENT_INVALID) && (snap_percent != PERCENT_MERGE_FAILED)) { log_error("Can't remove merging snapshot logical volume \"%s\"", lv->name); return 0; } else if ((snap_percent == PERCENT_MERGE_FAILED) && (force == PROMPT) && yes_no_prompt("Removing snapshot \"%s\" that failed to merge may leave origin \"%s\" inconsistent. " "Proceed? [y/n]: ", lv->name, origin_from_cow(lv)->name) == 'n') { log_error("Logical volume %s not removed.", lv->name); return 0; } } } } if (lv_is_origin(lv)) { /* Remove snapshot LVs first */ if ((force == PROMPT) && /* Active snapshot already needs to confirm each active LV */ !lv_is_active(lv) && yes_no_prompt("Removing origin %s will also remove %u " "snapshots(s). Proceed? [y/n]: ", lv->name, lv->origin_count) == 'n') { log_error("Logical volume %s not removed.", lv->name); return 0; } dm_list_iterate_safe(snh, snht, &lv->snapshot_segs) if (!lv_remove_with_dependencies(cmd, dm_list_struct_base(snh, struct lv_segment, origin_list)->cow, force, level + 1)) return_0; } if (lv_is_used_thin_pool(lv)) { /* Remove thin LVs first */ if ((force == PROMPT) && yes_no_prompt("Removing pool %s will also remove %u " "thin volume(s). OK? [y/n]: ", lv->name, /* Note: Snaphosts not included */ dm_list_size(&lv->segs_using_this_lv)) == 'n') { log_error("Logical volume %s not removed.", lv->name); return 0; } dm_list_iterate_items_safe(sl, tsl, &lv->segs_using_this_lv) if (!lv_remove_with_dependencies(cmd, sl->seg->lv, force, level + 1)) return_0; } return lv_remove_single(cmd, lv, force); } /* * insert_layer_for_segments_on_pv() inserts a layer segment for a segment area. * However, layer modification could split the underlying layer segment. * This function splits the parent area according to keep the 1:1 relationship * between the parent area and the underlying layer segment. * Since the layer LV might have other layers below, build_parallel_areas() * is used to find the lowest-level segment boundaries. */ static int _split_parent_area(struct lv_segment *seg, uint32_t s, struct dm_list *layer_seg_pvs) { uint32_t parent_area_len, parent_le, layer_le; uint32_t area_multiple; struct seg_pvs *spvs; if (seg_is_striped(seg)) area_multiple = seg->area_count; else area_multiple = 1; parent_area_len = seg->area_len; parent_le = seg->le; layer_le = seg_le(seg, s); while (parent_area_len > 0) { /* Find the layer segment pointed at */ if (!(spvs = _find_seg_pvs_by_le(layer_seg_pvs, layer_le))) { log_error("layer segment for %s:%" PRIu32 " not found", seg->lv->name, parent_le); return 0; } if (spvs->le != layer_le) { log_error("Incompatible layer boundary: " "%s:%" PRIu32 "[%" PRIu32 "] on %s:%" PRIu32, seg->lv->name, parent_le, s, seg_lv(seg, s)->name, layer_le); return 0; } if (spvs->len < parent_area_len) { parent_le += spvs->len * area_multiple; if (!lv_split_segment(seg->lv, parent_le)) return_0; } parent_area_len -= spvs->len; layer_le += spvs->len; } return 1; } /* * Split the parent LV segments if the layer LV below it is splitted. */ int split_parent_segments_for_layer(struct cmd_context *cmd, struct logical_volume *layer_lv) { struct lv_list *lvl; struct logical_volume *parent_lv; struct lv_segment *seg; uint32_t s; struct dm_list *parallel_areas; if (!(parallel_areas = build_parallel_areas_from_lv(layer_lv, 0))) return_0; /* Loop through all LVs except itself */ dm_list_iterate_items(lvl, &layer_lv->vg->lvs) { parent_lv = lvl->lv; if (parent_lv == layer_lv) continue; /* Find all segments that point at the layer LV */ dm_list_iterate_items(seg, &parent_lv->segments) { for (s = 0; s < seg->area_count; s++) { if (seg_type(seg, s) != AREA_LV || seg_lv(seg, s) != layer_lv) continue; if (!_split_parent_area(seg, s, parallel_areas)) return_0; } } } return 1; } /* Remove a layer from the LV */ int remove_layers_for_segments(struct cmd_context *cmd, struct logical_volume *lv, struct logical_volume *layer_lv, uint64_t status_mask, struct dm_list *lvs_changed) { struct lv_segment *seg, *lseg; uint32_t s; int lv_changed = 0; struct lv_list *lvl; log_very_verbose("Removing layer %s for segments of %s", layer_lv->name, lv->name); /* Find all segments that point at the temporary mirror */ dm_list_iterate_items(seg, &lv->segments) { for (s = 0; s < seg->area_count; s++) { if (seg_type(seg, s) != AREA_LV || seg_lv(seg, s) != layer_lv) continue; /* Find the layer segment pointed at */ if (!(lseg = find_seg_by_le(layer_lv, seg_le(seg, s)))) { log_error("Layer segment found: %s:%" PRIu32, layer_lv->name, seg_le(seg, s)); return 0; } /* Check the segment params are compatible */ if (!seg_is_striped(lseg) || lseg->area_count != 1) { log_error("Layer is not linear: %s:%" PRIu32, layer_lv->name, lseg->le); return 0; } if ((lseg->status & status_mask) != status_mask) { log_error("Layer status does not match: " "%s:%" PRIu32 " status: 0x%" PRIx64 "/0x%" PRIx64, layer_lv->name, lseg->le, lseg->status, status_mask); return 0; } if (lseg->le != seg_le(seg, s) || lseg->area_len != seg->area_len) { log_error("Layer boundary mismatch: " "%s:%" PRIu32 "-%" PRIu32 " on " "%s:%" PRIu32 " / " "%" PRIu32 "-%" PRIu32 " / ", lv->name, seg->le, seg->area_len, layer_lv->name, seg_le(seg, s), lseg->le, lseg->area_len); return 0; } if (!move_lv_segment_area(seg, s, lseg, 0)) return_0; /* Replace mirror with error segment */ if (!(lseg->segtype = get_segtype_from_string(lv->vg->cmd, "error"))) { log_error("Missing error segtype"); return 0; } lseg->area_count = 0; /* First time, add LV to list of LVs affected */ if (!lv_changed && lvs_changed) { if (!(lvl = dm_pool_alloc(cmd->mem, sizeof(*lvl)))) { log_error("lv_list alloc failed"); return 0; } lvl->lv = lv; dm_list_add(lvs_changed, &lvl->list); lv_changed = 1; } } } if (lv_changed && !lv_merge_segments(lv)) stack; return 1; } /* Remove a layer */ int remove_layers_for_segments_all(struct cmd_context *cmd, struct logical_volume *layer_lv, uint64_t status_mask, struct dm_list *lvs_changed) { struct lv_list *lvl; struct logical_volume *lv1; /* Loop through all LVs except the temporary mirror */ dm_list_iterate_items(lvl, &layer_lv->vg->lvs) { lv1 = lvl->lv; if (lv1 == layer_lv) continue; if (!remove_layers_for_segments(cmd, lv1, layer_lv, status_mask, lvs_changed)) return_0; } if (!lv_empty(layer_lv)) return_0; return 1; } int move_lv_segments(struct logical_volume *lv_to, struct logical_volume *lv_from, uint64_t set_status, uint64_t reset_status) { struct lv_segment *seg; dm_list_iterate_items(seg, &lv_to->segments) if (seg->origin) { log_error("Can't move snapshot segment."); return 0; } dm_list_init(&lv_to->segments); dm_list_splice(&lv_to->segments, &lv_from->segments); dm_list_iterate_items(seg, &lv_to->segments) { seg->lv = lv_to; seg->status &= ~reset_status; seg->status |= set_status; } lv_to->le_count = lv_from->le_count; lv_to->size = lv_from->size; lv_from->le_count = 0; lv_from->size = 0; return 1; } /* Remove a layer from the LV */ int remove_layer_from_lv(struct logical_volume *lv, struct logical_volume *layer_lv) { struct logical_volume *parent; struct lv_segment *parent_seg; struct segment_type *segtype; log_very_verbose("Removing layer %s for %s", layer_lv->name, lv->name); if (!(parent_seg = get_only_segment_using_this_lv(layer_lv))) { log_error("Failed to find layer %s in %s", layer_lv->name, lv->name); return 0; } parent = parent_seg->lv; /* * Before removal, the layer should be cleaned up, * i.e. additional segments and areas should have been removed. */ if (dm_list_size(&parent->segments) != 1 || parent_seg->area_count != 1 || seg_type(parent_seg, 0) != AREA_LV || layer_lv != seg_lv(parent_seg, 0) || parent->le_count != layer_lv->le_count) return_0; if (!lv_empty(parent)) return_0; if (!move_lv_segments(parent, layer_lv, 0, 0)) return_0; /* Replace the empty layer with error segment */ segtype = get_segtype_from_string(lv->vg->cmd, "error"); if (!lv_add_virtual_segment(layer_lv, 0, parent->le_count, segtype, NULL)) return_0; return 1; } /* * Create and insert a linear LV "above" lv_where. * After the insertion, a new LV named lv_where->name + suffix is created * and all segments of lv_where is moved to the new LV. * lv_where will have a single segment which maps linearly to the new LV. */ struct logical_volume *insert_layer_for_lv(struct cmd_context *cmd, struct logical_volume *lv_where, uint64_t status, const char *layer_suffix) { int r; char *name; size_t len; struct str_list *sl; struct logical_volume *layer_lv; struct segment_type *segtype; struct lv_segment *mapseg; struct lv_names lv_names; unsigned exclusive = 0; /* create an empty layer LV */ len = strlen(lv_where->name) + 32; if (!(name = alloca(len))) { log_error("layer name allocation failed. " "Remove new LV and retry."); return NULL; } if (dm_snprintf(name, len, "%s%s", lv_where->name, layer_suffix) < 0) { log_error("layer name allocation failed. " "Remove new LV and retry."); return NULL; } if (!(layer_lv = lv_create_empty(name, NULL, LVM_READ | LVM_WRITE, ALLOC_INHERIT, lv_where->vg))) { log_error("Creation of layer LV failed"); return NULL; } if (lv_is_active_exclusive_locally(lv_where)) exclusive = 1; if (lv_is_active(lv_where) && strstr(name, "_mimagetmp")) { log_very_verbose("Creating transient LV %s for mirror conversion in VG %s.", name, lv_where->vg->name); segtype = get_segtype_from_string(cmd, "error"); if (!lv_add_virtual_segment(layer_lv, 0, lv_where->le_count, segtype, NULL)) { log_error("Creation of transient LV %s for mirror conversion in VG %s failed.", name, lv_where->vg->name); return NULL; } /* Temporary tags for activation of the transient LV */ dm_list_iterate_items(sl, &lv_where->tags) if (!str_list_add(cmd->mem, &layer_lv->tags, sl->str)) { log_error("Aborting. Unable to tag" " transient mirror layer."); return NULL; } if (!vg_write(lv_where->vg)) { log_error("Failed to write intermediate VG %s metadata for mirror conversion.", lv_where->vg->name); return NULL; } if (!vg_commit(lv_where->vg)) { log_error("Failed to commit intermediate VG %s metadata for mirror conversion.", lv_where->vg->name); vg_revert(lv_where->vg); return NULL; } if (exclusive) r = activate_lv_excl(cmd, layer_lv); else r = activate_lv(cmd, layer_lv); if (!r) { log_error("Failed to resume transient LV" " %s for mirror conversion in VG %s.", name, lv_where->vg->name); return NULL; } /* Remove the temporary tags */ dm_list_iterate_items(sl, &lv_where->tags) str_list_del(&layer_lv->tags, sl->str); } log_very_verbose("Inserting layer %s for %s", layer_lv->name, lv_where->name); if (!move_lv_segments(layer_lv, lv_where, 0, 0)) return_NULL; if (!(segtype = get_segtype_from_string(cmd, "striped"))) return_NULL; /* allocate a new linear segment */ if (!(mapseg = alloc_lv_segment(segtype, lv_where, 0, layer_lv->le_count, status, 0, NULL, NULL, 1, layer_lv->le_count, 0, 0, 0, NULL))) return_NULL; /* map the new segment to the original underlying are */ if (!set_lv_segment_area_lv(mapseg, 0, layer_lv, 0, 0)) return_NULL; /* add the new segment to the layer LV */ dm_list_add(&lv_where->segments, &mapseg->list); lv_where->le_count = layer_lv->le_count; lv_where->size = (uint64_t) lv_where->le_count * lv_where->vg->extent_size; /* * recuresively rename sub LVs * currently supported only for thin data layer * FIXME: without strcmp it breaks mirrors.... */ if (strcmp(layer_suffix, "_tdata") == 0) { lv_names.old = lv_where->name; lv_names.new = layer_lv->name; if (!for_each_sub_lv(cmd, layer_lv, _rename_cb, (void *) &lv_names)) return 0; } return layer_lv; } /* * Extend and insert a linear layer LV beneath the source segment area. */ static int _extend_layer_lv_for_segment(struct logical_volume *layer_lv, struct lv_segment *seg, uint32_t s, uint64_t status) { struct lv_segment *mapseg; struct segment_type *segtype; struct physical_volume *src_pv = seg_pv(seg, s); uint32_t src_pe = seg_pe(seg, s); if (seg_type(seg, s) != AREA_PV && seg_type(seg, s) != AREA_LV) return_0; if (!(segtype = get_segtype_from_string(layer_lv->vg->cmd, "striped"))) return_0; /* FIXME Incomplete message? Needs more context */ log_very_verbose("Inserting %s:%" PRIu32 "-%" PRIu32 " of %s/%s", pv_dev_name(src_pv), src_pe, src_pe + seg->area_len - 1, seg->lv->vg->name, seg->lv->name); /* allocate a new segment */ if (!(mapseg = alloc_lv_segment(segtype, layer_lv, layer_lv->le_count, seg->area_len, status, 0, NULL, NULL, 1, seg->area_len, 0, 0, 0, seg))) return_0; /* map the new segment to the original underlying are */ if (!move_lv_segment_area(mapseg, 0, seg, s)) return_0; /* add the new segment to the layer LV */ dm_list_add(&layer_lv->segments, &mapseg->list); layer_lv->le_count += seg->area_len; layer_lv->size += (uint64_t) seg->area_len * layer_lv->vg->extent_size; /* map the original area to the new segment */ if (!set_lv_segment_area_lv(seg, s, layer_lv, mapseg->le, 0)) return_0; return 1; } /* * Match the segment area to PEs in the pvl * (the segment area boundary should be aligned to PE ranges by * _adjust_layer_segments() so that there is no partial overlap.) */ static int _match_seg_area_to_pe_range(struct lv_segment *seg, uint32_t s, struct pv_list *pvl) { struct pe_range *per; uint32_t pe_start, per_end; if (!pvl) return 1; if (seg_type(seg, s) != AREA_PV || seg_dev(seg, s) != pvl->pv->dev) return 0; pe_start = seg_pe(seg, s); /* Do these PEs match to any of the PEs in pvl? */ dm_list_iterate_items(per, pvl->pe_ranges) { per_end = per->start + per->count - 1; if ((pe_start < per->start) || (pe_start > per_end)) continue; /* FIXME Missing context in this message - add LV/seg details */ log_debug("Matched PE range %s:%" PRIu32 "-%" PRIu32 " against " "%s %" PRIu32 " len %" PRIu32, dev_name(pvl->pv->dev), per->start, per_end, dev_name(seg_dev(seg, s)), seg_pe(seg, s), seg->area_len); return 1; } return 0; } /* * For each segment in lv_where that uses a PV in pvl directly, * split the segment if it spans more than one underlying PV. */ static int _align_segment_boundary_to_pe_range(struct logical_volume *lv_where, struct pv_list *pvl) { struct lv_segment *seg; struct pe_range *per; uint32_t pe_start, pe_end, per_end, stripe_multiplier, s; if (!pvl) return 1; /* Split LV segments to match PE ranges */ dm_list_iterate_items(seg, &lv_where->segments) { for (s = 0; s < seg->area_count; s++) { if (seg_type(seg, s) != AREA_PV || seg_dev(seg, s) != pvl->pv->dev) continue; /* Do these PEs match with the condition? */ dm_list_iterate_items(per, pvl->pe_ranges) { pe_start = seg_pe(seg, s); pe_end = pe_start + seg->area_len - 1; per_end = per->start + per->count - 1; /* No overlap? */ if ((pe_end < per->start) || (pe_start > per_end)) continue; if (seg_is_striped(seg)) stripe_multiplier = seg->area_count; else stripe_multiplier = 1; if ((per->start != pe_start && per->start > pe_start) && !lv_split_segment(lv_where, seg->le + (per->start - pe_start) * stripe_multiplier)) return_0; if ((per_end != pe_end && per_end < pe_end) && !lv_split_segment(lv_where, seg->le + (per_end - pe_start + 1) * stripe_multiplier)) return_0; } } } return 1; } /* * Scan lv_where for segments on a PV in pvl, and for each one found * append a linear segment to lv_layer and insert it between the two. * * If pvl is empty, a layer is placed under the whole of lv_where. * If the layer is inserted, lv_where is added to lvs_changed. */ int insert_layer_for_segments_on_pv(struct cmd_context *cmd, struct logical_volume *lv_where, struct logical_volume *layer_lv, uint64_t status, struct pv_list *pvl, struct dm_list *lvs_changed) { struct lv_segment *seg; struct lv_list *lvl; int lv_used = 0; uint32_t s; log_very_verbose("Inserting layer %s for segments of %s on %s", layer_lv->name, lv_where->name, pvl ? pv_dev_name(pvl->pv) : "any"); if (!_align_segment_boundary_to_pe_range(lv_where, pvl)) return_0; /* Work through all segments on the supplied PV */ dm_list_iterate_items(seg, &lv_where->segments) { for (s = 0; s < seg->area_count; s++) { if (!_match_seg_area_to_pe_range(seg, s, pvl)) continue; /* First time, add LV to list of LVs affected */ if (!lv_used && lvs_changed) { if (!(lvl = dm_pool_alloc(cmd->mem, sizeof(*lvl)))) { log_error("lv_list alloc failed"); return 0; } lvl->lv = lv_where; dm_list_add(lvs_changed, &lvl->list); lv_used = 1; } if (!_extend_layer_lv_for_segment(layer_lv, seg, s, status)) { log_error("Failed to insert segment in layer " "LV %s under %s:%" PRIu32 "-%" PRIu32, layer_lv->name, lv_where->name, seg->le, seg->le + seg->len); return 0; } } } return 1; } /* * Initialize the LV with 'value'. */ int set_lv(struct cmd_context *cmd, struct logical_volume *lv, uint64_t sectors, int value) { struct device *dev; char *name; /* * FIXME: * also, more than 4k * say, reiserfs puts it's superblock 32k in, IIRC * k, I'll drop a fixme to that effect * (I know the device is at least 4k, but not 32k) */ if (!(name = dm_pool_alloc(cmd->mem, PATH_MAX))) { log_error("Name allocation failed - device not cleared"); return 0; } if (dm_snprintf(name, PATH_MAX, "%s%s/%s", cmd->dev_dir, lv->vg->name, lv->name) < 0) { log_error("Name too long - device not cleared (%s)", lv->name); return 0; } sync_local_dev_names(cmd); /* Wait until devices are available */ log_verbose("Clearing start of logical volume \"%s\"", lv->name); if (!(dev = dev_cache_get(name, NULL))) { log_error("%s: not found: device not cleared", name); return 0; } if (!dev_open_quiet(dev)) return_0; if (!sectors) sectors = UINT64_C(4096) >> SECTOR_SHIFT; if (sectors > lv->size) sectors = lv->size; if (!dev_set(dev, UINT64_C(0), (size_t) sectors << SECTOR_SHIFT, value)) stack; dev_flush(dev); if (!dev_close_immediate(dev)) stack; return 1; } static struct logical_volume *_create_virtual_origin(struct cmd_context *cmd, struct volume_group *vg, const char *lv_name, uint32_t permission, uint64_t voriginextents) { const struct segment_type *segtype; size_t len; char *vorigin_name; struct logical_volume *lv; if (!(segtype = get_segtype_from_string(cmd, "zero"))) { log_error("Zero segment type for virtual origin not found"); return NULL; } len = strlen(lv_name) + 32; if (!(vorigin_name = alloca(len)) || dm_snprintf(vorigin_name, len, "%s_vorigin", lv_name) < 0) { log_error("Virtual origin name allocation failed."); return NULL; } if (!(lv = lv_create_empty(vorigin_name, NULL, permission, ALLOC_INHERIT, vg))) return_NULL; if (!lv_extend(lv, segtype, 1, 0, 1, 0, voriginextents, NULL, NULL, ALLOC_INHERIT)) return_NULL; /* store vg on disk(s) */ if (!vg_write(vg) || !vg_commit(vg)) return_NULL; backup(vg); return lv; } /* Thin notes: * If lp->thin OR lp->activate is AY*, activate the pool if not already active. * If lp->thin, create thin LV within the pool - as a snapshot if lp->snapshot. * If lp->activate is AY*, activate it. * If lp->activate was AN* and the pool was originally inactive, deactivate it. */ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg, struct lvcreate_params *lp, const char *new_lv_name) { struct cmd_context *cmd = vg->cmd; uint32_t size_rest; uint64_t status = UINT64_C(0); struct logical_volume *lv, *org = NULL; struct logical_volume *pool_lv; struct lv_list *lvl; int origin_active = 0; struct lvinfo info; if (new_lv_name && find_lv_in_vg(vg, new_lv_name)) { log_error("Logical volume \"%s\" already exists in " "volume group \"%s\"", new_lv_name, lp->vg_name); return NULL; } if (vg_max_lv_reached(vg)) { log_error("Maximum number of logical volumes (%u) reached " "in volume group %s", vg->max_lv, vg->name); return NULL; } if ((segtype_is_mirrored(lp->segtype) || segtype_is_raid(lp->segtype) || segtype_is_thin(lp->segtype)) && !(vg->fid->fmt->features & FMT_SEGMENTS)) { log_error("Metadata does not support %s segments.", lp->segtype->name); return NULL; } if (lp->read_ahead != DM_READ_AHEAD_AUTO && lp->read_ahead != DM_READ_AHEAD_NONE && (vg->fid->fmt->features & FMT_RESTRICTED_READAHEAD) && (lp->read_ahead < 2 || lp->read_ahead > 120)) { log_error("Metadata only supports readahead values between 2 and 120."); return NULL; } if (lp->stripe_size > vg->extent_size) { log_error("Reducing requested stripe size %s to maximum, " "physical extent size %s", display_size(cmd, (uint64_t) lp->stripe_size), display_size(cmd, (uint64_t) vg->extent_size)); lp->stripe_size = vg->extent_size; } /* Need to check the vg's format to verify this - the cmd format isn't setup properly yet */ if (lp->stripes > 1 && !(vg->fid->fmt->features & FMT_UNLIMITED_STRIPESIZE) && (lp->stripe_size > STRIPE_SIZE_MAX)) { log_error("Stripe size may not exceed %s", display_size(cmd, (uint64_t) STRIPE_SIZE_MAX)); return NULL; } if ((size_rest = lp->extents % lp->stripes)) { log_print_unless_silent("Rounding size (%d extents) up to stripe boundary " "size (%d extents)", lp->extents, lp->extents - size_rest + lp->stripes); lp->extents = lp->extents - size_rest + lp->stripes; } /* Does LV need to be zeroed? Thin handles this as a per-pool in-kernel setting. */ if (lp->zero && !segtype_is_thin(lp->segtype) && !activation()) { log_error("Can't wipe start of new LV without using " "device-mapper kernel driver"); return NULL; } status |= lp->permission | VISIBLE_LV; if (lp->snapshot && lp->thin) { if (!(org = find_lv(vg, lp->origin))) { log_error("Couldn't find origin volume '%s'.", lp->origin); return NULL; } if (org->status & LOCKED) { log_error("Snapshots of locked devices are not supported."); return NULL; } lp->voriginextents = org->le_count; } else if (lp->snapshot) { if (!activation()) { log_error("Can't create snapshot without using " "device-mapper kernel driver"); return NULL; } /* Must zero cow */ status |= LVM_WRITE; if (lp->voriginsize) origin_active = 1; else { if (!(org = find_lv(vg, lp->origin))) { log_error("Couldn't find origin volume '%s'.", lp->origin); return NULL; } if (lv_is_virtual_origin(org)) { log_error("Can't share virtual origins. " "Use --virtualsize."); return NULL; } if (lv_is_cow(org)) { log_error("Snapshots of snapshots are not " "supported yet."); return NULL; } if (org->status & LOCKED) { log_error("Snapshots of locked devices are not " "supported yet"); return NULL; } if (lv_is_merging_origin(org)) { log_error("Snapshots of an origin that has a " "merging snapshot is not supported"); return NULL; } if (lv_is_thin_type(org) && !lv_is_thin_volume(org)) { log_error("Snapshots of thin pool %sdevices " "are not supported.", lv_is_thin_pool_data(org) ? "data " : lv_is_thin_pool_metadata(org) ? "metadata " : ""); return NULL; } if (lv_is_mirror_type(org) && !seg_is_raid(first_seg(org))) { log_warn("WARNING: Snapshots of mirrors can deadlock under rare device failures."); log_warn("WARNING: Consider using the raid1 mirror type to avoid this."); log_warn("WARNING: See global/mirror_segtype_default in lvm.conf."); } if (!lv_info(cmd, org, 0, &info, 0, 0)) { log_error("Check for existence of active snapshot " "origin '%s' failed.", org->name); return NULL; } origin_active = info.exists; if (vg_is_clustered(vg) && !lv_is_active_exclusive_locally(org)) { log_error("%s must be active exclusively to" " create snapshot", org->name); return NULL; } } } if (!seg_is_thin_volume(lp) && !lp->extents) { log_error("Unable to create new logical volume with no extents"); return NULL; } if (seg_is_thin_pool(lp) && ((uint64_t)lp->extents * vg->extent_size < lp->chunk_size)) { log_error("Unable to create thin pool smaller than 1 chunk."); return NULL; } if (lp->snapshot && !lp->thin && ((uint64_t)lp->extents * vg->extent_size < 2 * lp->chunk_size)) { log_error("Unable to create a snapshot smaller than 2 chunks."); return NULL; } if (!seg_is_virtual(lp) && vg->free_count < lp->extents) { log_error("Volume group \"%s\" has insufficient free space " "(%u extents): %u required.", vg->name, vg->free_count, lp->extents); return NULL; } if (lp->stripes > dm_list_size(lp->pvh) && lp->alloc != ALLOC_ANYWHERE) { log_error("Number of stripes (%u) must not exceed " "number of physical volumes (%d)", lp->stripes, dm_list_size(lp->pvh)); return NULL; } if (!activation() && (seg_is_mirrored(lp) || seg_is_raid(lp) || seg_is_thin_pool(lp))) { /* * FIXME: For thin pool add some code to allow delayed * initialization of empty thin pool volume. * i.e. using some LV flag, fake message,... * and testing for metadata pool header signature? */ log_error("Can't create %s without using " "device-mapper kernel driver.", segtype_is_raid(lp->segtype) ? lp->segtype->name : segtype_is_mirrored(lp->segtype) ? "mirror" : "thin pool volume"); return NULL; } /* The snapshot segment gets created later */ if (lp->snapshot && !lp->thin && !(lp->segtype = get_segtype_from_string(cmd, "striped"))) return_NULL; if (!archive(vg)) return_NULL; if (!dm_list_empty(&lp->tags)) { if (!(vg->fid->fmt->features & FMT_TAGS)) { log_error("Volume group %s does not support tags", vg->name); return NULL; } } if (seg_is_thin_volume(lp) && ((lp->activate == CHANGE_AY) || (lp->activate == CHANGE_AE) || (lp->activate == CHANGE_ALY))) { /* Ensure all stacked messages are submitted */ if (!(lvl = find_lv_in_vg(vg, lp->pool))) { log_error("Unable to find existing pool LV %s in VG %s.", lp->pool, vg->name); return NULL; } if (!update_pool_lv(lvl->lv, 1)) return_NULL; } if (vg_is_clustered(vg) && segtype_is_raid(lp->segtype)) { /* * FIXME: * We could allow a RAID LV to be created as long as it * is activated exclusively. Any subsequent activations * would have to be enforced as exclusive also. * * For now, we disallow the existence of RAID LVs in a * cluster VG */ log_error("Unable to create a %s logical volume in a cluster.", lp->segtype->name); return NULL; } if (segtype_is_mirrored(lp->segtype) || segtype_is_raid(lp->segtype)) { init_mirror_in_sync(lp->nosync); if (lp->nosync) { log_warn("WARNING: New %s won't be synchronised. " "Don't read what you didn't write!", lp->segtype->name); status |= LV_NOTSYNCED; } lp->region_size = adjusted_mirror_region_size(vg->extent_size, lp->extents, lp->region_size); } if (!(lv = lv_create_empty(new_lv_name ? : "lvol%d", NULL, status, lp->alloc, vg))) return_NULL; if (lp->read_ahead != lv->read_ahead) { log_verbose("Setting read ahead sectors"); lv->read_ahead = lp->read_ahead; } if (!seg_is_thin_pool(lp) && lp->minor >= 0) { lv->major = lp->major; lv->minor = lp->minor; lv->status |= FIXED_MINOR; log_verbose("Setting device number to (%d, %d)", lv->major, lv->minor); } dm_list_splice(&lv->tags, &lp->tags); if (!lv_extend(lv, lp->segtype, lp->stripes, lp->stripe_size, lp->mirrors, seg_is_thin_pool(lp) ? lp->poolmetadataextents : lp->region_size, seg_is_thin_volume(lp) ? lp->voriginextents : lp->extents, seg_is_thin_volume(lp) ? (org ? org->name : lp->pool) : NULL, lp->pvh, lp->alloc)) return_NULL; if (seg_is_thin_pool(lp)) { first_seg(lv)->zero_new_blocks = lp->zero ? 1 : 0; first_seg(lv)->chunk_size = lp->chunk_size; first_seg(lv)->discards = lp->discards; /* FIXME: use lowwatermark via lvm.conf global for all thinpools ? */ first_seg(lv)->low_water_mark = 0; } else if (seg_is_thin_volume(lp)) { pool_lv = first_seg(lv)->pool_lv; if (!(first_seg(lv)->device_id = get_free_pool_device_id(first_seg(pool_lv)))) { stack; goto revert_new_lv; } if (!attach_pool_message(first_seg(pool_lv), DM_THIN_MESSAGE_CREATE_THIN, lv, 0, 0)) { stack; goto revert_new_lv; } } /* FIXME Log allocation and attachment should have happened inside lv_extend. */ if (lp->log_count && !seg_is_raid(first_seg(lv)) && seg_is_mirrored(first_seg(lv))) { if (!add_mirror_log(cmd, lv, lp->log_count, first_seg(lv)->region_size, lp->pvh, lp->alloc)) { stack; goto revert_new_lv; } } /* store vg on disk(s) */ if (!vg_write(vg) || !vg_commit(vg)) return_NULL; backup(vg); /* * Check for autoactivation. * If the LV passes the auto activation filter, activate * it just as if CHANGE_AY was used, CHANGE_AN otherwise. */ if (lp->activate == CHANGE_AAY) lp->activate = lv_passes_auto_activation_filter(cmd, lv) ? CHANGE_ALY : CHANGE_ALN; if (test_mode()) { log_verbose("Test mode: Skipping activation and zeroing."); goto out; } if (seg_is_thin(lp)) { /* For snapshot, suspend active thin origin first */ if (org && lv_is_active(org)) { if (!pool_below_threshold(first_seg(first_seg(org)->pool_lv))) { log_error("Cannot create thin snapshot. Pool %s/%s is filled " "over the autoextend threshold.", org->vg->name, first_seg(org)->pool_lv->name); goto revert_new_lv; } if (!suspend_lv_origin(cmd, org)) { log_error("Failed to suspend thin snapshot origin %s/%s.", org->vg->name, org->name); goto revert_new_lv; } if (!resume_lv_origin(cmd, org)) { /* deptree updates thin-pool */ log_error("Failed to resume thin snapshot origin %s/%s.", org->vg->name, org->name); goto revert_new_lv; } /* At this point remove pool messages, snapshot is active */ if (!update_pool_lv(first_seg(org)->pool_lv, 0)) { stack; goto deactivate_and_revert_new_lv; } } if (((lp->activate == CHANGE_AY) || (lp->activate == CHANGE_AE) || (lp->activate == CHANGE_ALY))) { /* At this point send message to kernel thin mda */ pool_lv = lv_is_thin_pool(lv) ? lv : first_seg(lv)->pool_lv; if (!update_pool_lv(pool_lv, 1)) { stack; goto deactivate_and_revert_new_lv; } if (!activate_lv_excl(cmd, lv)) { log_error("Aborting. Failed to activate thin %s.", lv->name); goto deactivate_and_revert_new_lv; } } } else if (lp->snapshot) { if (!activate_lv_excl(cmd, lv)) { log_error("Aborting. Failed to activate snapshot " "exception store."); goto revert_new_lv; } } else if ((lp->activate == CHANGE_AY && !activate_lv(cmd, lv)) || (lp->activate == CHANGE_AE && !activate_lv_excl(cmd, lv)) || (lp->activate == CHANGE_ALY && !activate_lv_local(cmd, lv))) { log_error("Failed to activate new LV."); if (lp->zero) goto deactivate_and_revert_new_lv; return NULL; } if (!seg_is_thin(lp) && !lp->zero && !lp->snapshot) log_warn("WARNING: \"%s\" not zeroed", lv->name); else if ((!seg_is_thin(lp) || (lv_is_thin_volume(lv) && !first_seg(first_seg(lv)->pool_lv)->zero_new_blocks)) && !set_lv(cmd, lv, UINT64_C(0), 0)) { log_error("Aborting. Failed to wipe %s.", lp->snapshot ? "snapshot exception store" : "start of new LV"); goto deactivate_and_revert_new_lv; } if (lp->snapshot && !lp->thin) { /* Reset permission after zeroing */ if (!(lp->permission & LVM_WRITE)) lv->status &= ~LVM_WRITE; /* COW area must be deactivated if origin is not active */ if (!origin_active && !deactivate_lv(cmd, lv)) { log_error("Aborting. Couldn't deactivate snapshot " "COW area. Manual intervention required."); return NULL; } /* A virtual origin must be activated explicitly. */ if (lp->voriginsize && (!(org = _create_virtual_origin(cmd, vg, lv->name, lp->permission, lp->voriginextents)) || !activate_lv_excl(cmd, org))) { log_error("Couldn't create virtual origin for LV %s", lv->name); if (org && !lv_remove(org)) stack; goto deactivate_and_revert_new_lv; } /* cow LV remains active and becomes snapshot LV */ if (!vg_add_snapshot(org, lv, NULL, org->le_count, lp->chunk_size)) { log_error("Couldn't create snapshot."); goto deactivate_and_revert_new_lv; } /* store vg on disk(s) */ if (!vg_write(vg)) return_NULL; if (!suspend_lv(cmd, org)) { log_error("Failed to suspend origin %s", org->name); vg_revert(vg); return NULL; } if (!vg_commit(vg)) return_NULL; if (!resume_lv(cmd, org)) { log_error("Problem reactivating origin %s", org->name); return NULL; } } /* FIXME out of sequence */ backup(vg); out: return lv; deactivate_and_revert_new_lv: if (!deactivate_lv(cmd, lv)) { log_error("Unable to deactivate failed new LV. " "Manual intervention required."); return NULL; } revert_new_lv: /* FIXME Better to revert to backup of metadata? */ if (!lv_remove(lv) || !vg_write(vg) || !vg_commit(vg)) log_error("Manual intervention may be required to remove " "abandoned LV(s) before retrying."); else backup(vg); return NULL; } int lv_create_single(struct volume_group *vg, struct lvcreate_params *lp) { struct logical_volume *lv; /* Create thin pool first if necessary */ if (lp->create_thin_pool) { if (!seg_is_thin_pool(lp) && !(lp->segtype = get_segtype_from_string(vg->cmd, "thin-pool"))) return_0; if (!(lv = _lv_create_an_lv(vg, lp, lp->pool))) return_0; if (!lp->thin) goto out; lp->pool = lv->name; if (!(lp->segtype = get_segtype_from_string(vg->cmd, "thin"))) return_0; } if (!(lv = _lv_create_an_lv(vg, lp, lp->lv_name))) return_0; out: log_print_unless_silent("Logical volume \"%s\" created", lv->name); return 1; } lvm2-2.02.98/lib/metadata/replicator_manip.c0000640000175000017500000004102312037016272017532 0ustar blankblank/* * 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 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 "locking.h" #include "metadata.h" #include "segtype.h" #include "toolcontext.h" /* Add lv as replicator_dev device */ int replicator_dev_add_rimage(struct replicator_device *rdev, struct logical_volume *lv) { if (!lv || !rdev) return_0; if (lv_is_rimage(lv)) { log_error("Logical volume %s is already part of other " "replicator.", lv->name); return 0; } if (rdev->lv) { log_error("Logical volume %s can not be attached to an " "already defined replicator device", lv->name); return 0; } lv_set_hidden(lv); lv->rdevice = rdev; rdev->lv = lv; return add_seg_to_segs_using_this_lv(lv, rdev->replicator_dev); } /* Remove lv from replicator_dev device */ struct logical_volume *replicator_dev_remove_rimage(struct replicator_device *rdev) { struct logical_volume *lv; if (!rdev || !rdev->lv) return_NULL; lv = rdev->lv; if (!remove_seg_from_segs_using_this_lv(lv, rdev->replicator_dev)) return_NULL; /* FIXME: - check for site references */ rdev->lv = NULL; lv->rdevice = NULL; lv_set_visible(lv); return lv; } int replicator_dev_add_slog(struct replicator_device *rdev, struct logical_volume *slog) { if (!slog || !rdev) return_0; if (rdev->slog) { log_error("Replicator device in site %s already has sync log.", rdev->rsite->name); return 0; } if (slog->rdevice) { log_error("Sync log %s is already used by replicator %s.", slog->name, slog->rdevice->rsite->replicator->name); return 0; } lv_set_hidden(slog); slog->rdevice = rdev; rdev->slog = slog; return add_seg_to_segs_using_this_lv(slog, rdev->replicator_dev); } struct logical_volume *replicator_dev_remove_slog(struct replicator_device *rdev) { struct logical_volume *lv; if (!rdev) return_NULL; lv = rdev->slog; if (!lv) { log_error("Replicator device in site %s does not have sync log.", rdev->rsite->name); return NULL; } if (!remove_seg_from_segs_using_this_lv(lv, rdev->replicator_dev)) return_NULL; rdev->slog = NULL; lv->rdevice = NULL; lv_set_visible(lv); return lv; } int replicator_add_replicator_dev(struct logical_volume *replicator_lv, struct lv_segment *replicator_dev_seg) { if (!replicator_lv) return_0; if (!(replicator_lv->status & REPLICATOR)) { dm_list_init(&replicator_lv->rsites); lv_set_hidden(replicator_lv); replicator_lv->status |= REPLICATOR; } if (!replicator_dev_seg) return 1; if (replicator_dev_seg->replicator) { log_error("Replicator device %s is already part of replicator.", replicator_dev_seg->lv->name); return 0; } replicator_dev_seg->replicator = replicator_lv; return add_seg_to_segs_using_this_lv(replicator_lv, replicator_dev_seg); } /** * Returns rimage ?? lv upon succeful detach of device * entire LV entry should be removed by this crootall ?? */ struct logical_volume *replicator_remove_replicator_dev(struct lv_segment *replicator_dev_seg) { struct logical_volume *lv = NULL; log_error("FIXME: not implemented."); #if 0 /* FIXME: - this is going to be complex.... */ if (!replicator_dev_seg) return_NULL; /* if slog or rimage - exit */ if (!remove_seg_from_segs_using_this_lv(lv, replicator_seg)) return_NULL; replicator_seg->rlog_lv = NULL; lv->status &= ~REPLICATOR_LOG; lv_set_visible(lv); #endif return lv; } int replicator_add_rlog(struct lv_segment *replicator_seg, struct logical_volume *rlog_lv) { if (!rlog_lv) return_0; if (rlog_lv->status & REPLICATOR_LOG) { log_error("Rlog device %s is already used.", rlog_lv->name); return 0; } lv_set_hidden(rlog_lv); rlog_lv->status |= REPLICATOR_LOG; replicator_seg->rlog_lv = rlog_lv; return add_seg_to_segs_using_this_lv(rlog_lv, replicator_seg); } struct logical_volume *replicator_remove_rlog(struct lv_segment *replicator_seg) { struct logical_volume *lv; if (!replicator_seg) return_0; if (!(lv = replicator_seg->rlog_lv)) { log_error("Replog segment %s does not have rlog.", replicator_seg->lv->name); return NULL; } if (!remove_seg_from_segs_using_this_lv(lv, replicator_seg)) return_NULL; replicator_seg->rlog_lv = NULL; lv->status &= ~REPLICATOR_LOG; lv_set_visible(lv); return lv; } #if 0 /* * Create new LV to pretend the original LV * this target will have a 'replicator' segment */ int lv_add_replicator(struct logical_volume *origin, const char *rep_suffix) { struct logical_volume *rep_lv; char *name; size_t slen; if (!(name = strstr(origin->name, rep_suffix))) { log_error("Failed to find replicator suffix %s in LV name %s", rep_suffix, origin->name); return 0; } slen = (size_t)(name - origin->name); name = alloca(slen + 1); memcpy(name, origin->name, slen); name[slen] = 0; if ((rep_lv = find_lv(origin->vg, name))) { rep_lv->status |= VIRTUAL; return 1; } if (!(rep_lv = lv_create_empty(name, &origin->lvid, LVM_READ | LVM_WRITE | VISIBLE_LV, ALLOC_INHERIT, origin->vg))) return_0; if (!lv_add_virtual_segment(rep_lv, 0, origin->le_count, get_segtype_from_string(origin->vg->cmd, "error"))) return_0; rep_lv->status |= VIRTUAL; return 1; } int lv_remove_replicator(struct logical_volume *lv) { return 1; } #endif /* * Check all replicator structures: * only non-clustered VG for Replicator * only one segment in replicator LV * site has correct combination of operation_mode parameters * site and related devices have correct index numbers * duplicate site names, site indexes, device names, device indexes */ int check_replicator_segment(const struct lv_segment *rseg) { struct replicator_site *rsite, *rsiteb; struct replicator_device *rdev, *rdevb; struct logical_volume *lv = rseg->lv; int r = 1; if (vg_is_clustered(lv->vg)) { log_error("Volume Group %s of replicator %s is clustered", lv->vg->name, lv->name); return 0; } if (dm_list_size(&lv->segments) != 1) { log_error("Replicator %s segment size %d != 1", lv->name, dm_list_size(&lv->segments)); return 0; } dm_list_iterate_items(rsite, &lv->rsites) { if (rsite->op_mode == DM_REPLICATOR_SYNC) { if (rsite->fall_behind_timeout) { log_error("Defined fall_behind_timeout=" "%d for sync replicator %s/%s.", rsite->fall_behind_timeout, lv->name, rsite->name); r = 0; } if (rsite->fall_behind_ios) { log_error("Defined fall_behind_ios=" "%d for sync replicator %s/%s.", rsite->fall_behind_ios, lv->name, rsite->name); r = 0; } if (rsite->fall_behind_data) { log_error("Defined fall_behind_data=" "%" PRIu64 " for sync replicator %s/%s.", rsite->fall_behind_data, lv->name, rsite->name); r = 0; } } else { if (rsite->fall_behind_timeout && rsite->fall_behind_ios) { log_error("Defined fall_behind_timeout and" " fall_behind_ios for async replicator %s/%s.", lv->name, rsite->name); r = 0; } if (rsite->fall_behind_timeout && rsite->fall_behind_data) { log_error("Defined fall_behind_timeout and" " fall_behind_data for async replicator %s/%s.", lv->name, rsite->name); r = 0; } if (rsite->fall_behind_ios && rsite->fall_behind_data) { log_error("Defined fall_behind_ios and" " fall_behind_data for async replicator %s/%s.", lv->name, rsite->name); r = 0; } if (!rsite->fall_behind_ios && !rsite->fall_behind_data && !rsite->fall_behind_timeout) { log_error("fall_behind_timeout," " fall_behind_ios and fall_behind_data are" " undefined for async replicator %s/%s.", lv->name, rsite->name); r = 0; } } dm_list_iterate_items(rsiteb, &lv->rsites) { if (rsite == rsiteb) break; if (strcasecmp(rsite->name, rsiteb->name) == 0) { log_error("Duplicate site name " "%s detected for replicator %s.", rsite->name, lv->name); r = 0; } if ((rsite->vg_name && rsiteb->vg_name && strcasecmp(rsite->vg_name, rsiteb->vg_name) == 0) || (!rsite->vg_name && !rsiteb->vg_name)) { log_error("Duplicate VG name " "%s detected for replicator %s.", (rsite->vg_name) ? rsite->vg_name : "", lv->name); r = 0; } if (rsite->site_index == rsiteb->site_index) { log_error("Duplicate site index %d detected " "for replicator site %s/%s.", rsite->site_index, lv->name, rsite->name); r = 0; } if (rsite->site_index > rseg->rsite_index_highest) { log_error("Site index %d > %d (too high) " "for replicator site %s/%s.", rsite->site_index, rseg->rsite_index_highest, lv->name, rsite->name); r = 0; } } dm_list_iterate_items(rdev, &rsite->rdevices) { dm_list_iterate_items(rdevb, &rsite->rdevices) { if (rdev == rdevb) break; if (rdev->slog && (rdev->slog == rdevb->slog)) { log_error("Duplicate sync log %s " "detected for replicator %s.", rdev->slog->name, lv->name); r = 0; } if (strcasecmp(rdev->name, rdevb->name) == 0) { log_error("Duplicate device name %s " "detected for replicator %s.", rdev->name, lv->name); r = 0; } if (rdev->device_index == rdevb->device_index) { log_error("Duplicate device index %" PRId64 " detected for " "replicator site %s/%s.", rdev->device_index, lv->name, rsite->name); r = 0; } if (rdev->device_index > rseg->rdevice_index_highest) { log_error("Device index %" PRIu64 " > %" PRIu64 " (too high) " "for replicator site %s/%s.", rdev->device_index, rseg->rdevice_index_highest, lv->name, rsite->name); r = 0; } } } } return r; } /** * Is this segment part of active replicator */ int lv_is_active_replicator_dev(const struct logical_volume *lv) { return ((lv->status & REPLICATOR) && lv->rdevice && lv->rdevice->rsite && lv->rdevice->rsite->state == REPLICATOR_STATE_ACTIVE); } /** * Is this LV replicator control device */ int lv_is_replicator(const struct logical_volume *lv) { return ((lv->status & REPLICATOR) && !dm_list_empty(&lv->segments) && seg_is_replicator(first_seg(lv))); } /** * Is this LV replicator device */ int lv_is_replicator_dev(const struct logical_volume *lv) { return ((lv->status & REPLICATOR) && !dm_list_empty(&lv->segments) && seg_is_replicator_dev(first_seg(lv))); } /** * Is this LV replicated origin lv */ int lv_is_rimage(const struct logical_volume *lv) { return (lv->rdevice && lv->rdevice->lv == lv); } /** * Is this LV sync log */ int lv_is_slog(const struct logical_volume *lv) { return (lv->rdevice && lv->rdevice->slog == lv); } /** * Returns first replicator-dev in site in case the LV is replicator-dev, * NULL otherwise */ struct logical_volume *first_replicator_dev(const struct logical_volume *lv) { struct replicator_device *rdev; struct replicator_site *rsite; if (lv_is_replicator_dev(lv)) dm_list_iterate_items(rsite, &first_seg(lv)->replicator->rsites) { dm_list_iterate_items(rdev, &rsite->rdevices) return rdev->replicator_dev->lv; break; } return NULL; } /** * Add VG open parameters to sorted cmd_vg list. * * Maintain the alphabeticaly ordered list, avoid duplications. * * \return Returns newly created or already present cmd_vg entry, * or NULL in error case. */ struct cmd_vg *cmd_vg_add(struct dm_pool *mem, struct dm_list *cmd_vgs, const char *vg_name, const char *vgid, uint32_t flags) { struct cmd_vg *cvl, *ins; if (!vg_name && !vgid) { log_error("Either vg_name or vgid must be set."); return NULL; } /* Is it already in the list ? */ if ((cvl = cmd_vg_lookup(cmd_vgs, vg_name, vgid))) return cvl; if (!(cvl = dm_pool_zalloc(mem, sizeof(*cvl)))) { log_error("Allocation of cmd_vg failed."); return NULL; } if (vg_name && !(cvl->vg_name = dm_pool_strdup(mem, vg_name))) { dm_pool_free(mem, cvl); log_error("Allocation of vg_name failed."); return NULL; } if (vgid && !(cvl->vgid = dm_pool_strdup(mem, vgid))) { dm_pool_free(mem, cvl); log_error("Allocation of vgid failed."); return NULL; } cvl->flags = flags; if (vg_name) dm_list_iterate_items(ins, cmd_vgs) if (strcmp(vg_name, ins->vg_name) < 0) { cmd_vgs = &ins->list; /* new position */ break; } dm_list_add(cmd_vgs, &cvl->list); return cvl; } /** * Find cmd_vg with given vg_name in cmd_vgs list. * * \param cmd_vgs List of cmd_vg entries. * * \param vg_name Name of VG to be found. * \param vgid UUID of VG to be found. * * \return Returns cmd_vg entry if vg_name or vgid is found, * NULL otherwise. */ struct cmd_vg *cmd_vg_lookup(struct dm_list *cmd_vgs, const char *vg_name, const char *vgid) { struct cmd_vg *cvl; dm_list_iterate_items(cvl, cmd_vgs) if ((vgid && cvl->vgid && !strcmp(vgid, cvl->vgid)) || (vg_name && cvl->vg_name && !strcmp(vg_name, cvl->vg_name))) return cvl; return NULL; } /** * Read and lock multiple VGs stored in cmd_vgs list alphabeticaly. * On the success list head pointer is set to VGs' cmd_vgs. * (supports FAILED_INCONSISTENT) * * \param cmd_vg Contains list of cmd_vg entries. * * \return Returns 1 if all VG in cmd_vgs list are correctly * openned and locked, 0 otherwise. */ int cmd_vg_read(struct cmd_context *cmd, struct dm_list *cmd_vgs) { struct cmd_vg *cvl; /* Iterate through alphabeticaly ordered cmd_vg list */ dm_list_iterate_items(cvl, cmd_vgs) { cvl->vg = vg_read(cmd, cvl->vg_name, cvl->vgid, cvl->flags); if (vg_read_error(cvl->vg)) { log_debug("Failed to vg_read %s", cvl->vg_name); return 0; } cvl->vg->cmd_vgs = cmd_vgs; /* Make it usable in VG */ } return 1; } /** * Release opened and locked VGs from list. * * \param cmd_vgs Contains list of cmd_vg entries. */ void free_cmd_vgs(struct dm_list *cmd_vgs) { struct cmd_vg *cvl; /* Backward iterate cmd_vg list */ dm_list_iterate_back_items(cvl, cmd_vgs) { if (vg_read_error(cvl->vg)) release_vg(cvl->vg); else unlock_and_release_vg(cvl->vg->cmd, cvl->vg, cvl->vg_name); cvl->vg = NULL; } } /** * Find all needed remote VGs for processing given LV. * Missing VGs are added to VG's cmd_vg list and flag cmd_missing_vgs is set. */ int find_replicator_vgs(struct logical_volume *lv) { struct replicator_site *rsite; int ret = 1; if (!lv_is_replicator_dev(lv)) return 1; dm_list_iterate_items(rsite, &first_seg(lv)->replicator->rsites) { if (!rsite->vg_name || !lv->vg->cmd_vgs || cmd_vg_lookup(lv->vg->cmd_vgs, rsite->vg_name, NULL)) continue; ret = 0; /* Using cmd memory pool for cmd_vg list allocation */ if (!cmd_vg_add(lv->vg->cmd->mem, lv->vg->cmd_vgs, rsite->vg_name, NULL, 0)) { lv->vg->cmd_missing_vgs = 0; /* do not retry */ stack; break; } log_debug("VG: %s added as missing.", rsite->vg_name); lv->vg->cmd_missing_vgs++; } return ret; } /** * Read all remote VGs from lv's replicator sites. * Function is used in activation context and needs all VGs already locked. */ int lv_read_replicator_vgs(struct logical_volume *lv) { struct replicator_device *rdev; struct replicator_site *rsite; struct volume_group *vg; if (!lv_is_replicator_dev(lv)) return 1; dm_list_iterate_items(rsite, &first_seg(lv)->replicator->rsites) { if (!rsite->vg_name) continue; vg = vg_read(lv->vg->cmd, rsite->vg_name, 0, 0); // READ_WITHOUT_LOCK if (vg_read_error(vg)) { log_error("Unable to read volume group %s", rsite->vg_name); goto bad; } rsite->vg = vg; /* FIXME: handling missing LVs needs to be better */ dm_list_iterate_items(rdev, &rsite->rdevices) if (!(rdev->lv = find_lv(vg, rdev->name))) { log_error("Unable to find %s in volume group %s", rdev->name, rsite->vg_name); goto bad; } } return 1; bad: lv_release_replicator_vgs(lv); return 0; } /** * Release all VG resources taken by lv's replicator sites. * Function is used in activation context and needs all VGs already locked. */ void lv_release_replicator_vgs(struct logical_volume *lv) { struct replicator_site *rsite; if (!lv_is_replicator_dev(lv)) return; dm_list_iterate_back_items(rsite, &first_seg(lv)->replicator->rsites) if (rsite->vg_name && rsite->vg) { release_vg(rsite->vg); rsite->vg = NULL; } } lvm2-2.02.98/lib/metadata/raid_manip.c0000640000175000017500000013724112037016272016315 0ustar blankblank/* * Copyright (C) 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 "metadata.h" #include "toolcontext.h" #include "segtype.h" #include "display.h" #include "activate.h" #include "lv_alloc.h" #include "lvm-string.h" #define RAID_REGION_SIZE 1024 static int _lv_is_raid_with_tracking(const struct logical_volume *lv, struct logical_volume **tracking) { uint32_t s; struct lv_segment *seg; *tracking = NULL; seg = first_seg(lv); if (!(lv->status & RAID)) return 0; for (s = 0; s < seg->area_count; s++) if (lv_is_visible(seg_lv(seg, s)) && !(seg_lv(seg, s)->status & LVM_WRITE)) *tracking = seg_lv(seg, s); return *tracking ? 1 : 0; } int lv_is_raid_with_tracking(const struct logical_volume *lv) { struct logical_volume *tracking; return _lv_is_raid_with_tracking(lv, &tracking); } uint32_t lv_raid_image_count(const struct logical_volume *lv) { struct lv_segment *seg = first_seg(lv); if (!seg_is_raid(seg)) return 1; return seg->area_count; } /* * Resume sub-LVs first, then top-level LV */ static int _bottom_up_resume(struct logical_volume *lv) { uint32_t s; struct lv_segment *seg = first_seg(lv); if (seg_is_raid(seg) && (seg->area_count > 1)) { for (s = 0; s < seg->area_count; s++) if (!resume_lv(lv->vg->cmd, seg_lv(seg, s)) || !resume_lv(lv->vg->cmd, seg_metalv(seg, s))) return_0; } return resume_lv(lv->vg->cmd, lv); } static int _activate_sublv_preserving_excl(struct logical_volume *top_lv, struct logical_volume *sub_lv) { struct cmd_context *cmd = top_lv->vg->cmd; /* If top RAID was EX, use EX */ if (lv_is_active_exclusive_locally(top_lv)) { if (!activate_lv_excl(cmd, sub_lv)) return_0; } else { if (!activate_lv(cmd, sub_lv)) return_0; } return 1; } /* * _lv_is_on_pv * @lv: * @pv: * * If any of the component devices of the LV are on the given PV, 1 * is returned; otherwise 0. For example if one of the images of a RAID * (or its metadata device) is on the PV, 1 would be returned for the * top-level LV. * If you wish to check the images themselves, you should pass them. * * FIXME: This should be made more generic, possibly use 'for_each_sub_lv', * and be put in lv_manip.c. 'for_each_sub_lv' does not yet allow us to * short-circuit execution or pass back the values we need yet though... */ static int _lv_is_on_pv(struct logical_volume *lv, struct physical_volume *pv) { uint32_t s; struct physical_volume *pv2; struct lv_segment *seg; if (!lv) return 0; seg = first_seg(lv); if (!seg) return 0; /* Check mirror log */ if (_lv_is_on_pv(seg->log_lv, pv)) return 1; /* Check stack of LVs */ dm_list_iterate_items(seg, &lv->segments) { for (s = 0; s < seg->area_count; s++) { if (seg_type(seg, s) == AREA_PV) { pv2 = seg_pv(seg, s); if (id_equal(&pv->id, &pv2->id)) return 1; if (pv->dev && pv2->dev && (pv->dev->dev == pv2->dev->dev)) return 1; } if ((seg_type(seg, s) == AREA_LV) && _lv_is_on_pv(seg_lv(seg, s), pv)) return 1; if (!seg_is_raid(seg)) continue; /* This is RAID, so we know the meta_area is AREA_LV */ if (_lv_is_on_pv(seg_metalv(seg, s), pv)) return 1; } } return 0; } static int _lv_is_on_pvs(struct logical_volume *lv, struct dm_list *pvs) { struct pv_list *pvl; dm_list_iterate_items(pvl, pvs) if (_lv_is_on_pv(lv, pvl->pv)) { log_debug("%s is on %s", lv->name, pv_dev_name(pvl->pv)); return 1; } else log_debug("%s is not on %s", lv->name, pv_dev_name(pvl->pv)); return 0; } static int _get_pv_list_for_lv(struct logical_volume *lv, struct dm_list *pvs) { uint32_t s; struct pv_list *pvl; struct lv_segment *seg = first_seg(lv); if (!seg_is_linear(seg)) { log_error(INTERNAL_ERROR "_get_pv_list_for_lv only handles linear volumes"); return 0; } log_debug("Getting list of PVs that %s/%s is on:", lv->vg->name, lv->name); dm_list_iterate_items(seg, &lv->segments) { for (s = 0; s < seg->area_count; s++) { if (seg_type(seg, s) != AREA_PV) { log_error(INTERNAL_ERROR "Linear seg_type should be AREA_PV"); return 0; } if (!(pvl = dm_pool_zalloc(lv->vg->cmd->mem, sizeof(*pvl)))) { log_error("Failed to allocate memory"); return 0; } pvl->pv = seg_pv(seg, s); log_debug(" %s/%s is on %s", lv->vg->name, lv->name, pv_dev_name(pvl->pv)); dm_list_add(pvs, &pvl->list); } } return 1; } /* * _raid_in_sync * @lv * * _raid_in_sync works for all types of RAID segtypes, as well * as 'mirror' segtype. (This is because 'lv_raid_percent' is * simply a wrapper around 'lv_mirror_percent'. * * Returns: 1 if in-sync, 0 otherwise. */ static int _raid_in_sync(struct logical_volume *lv) { percent_t sync_percent; if (!lv_raid_percent(lv, &sync_percent)) { log_error("Unable to determine sync status of %s/%s.", lv->vg->name, lv->name); return 0; } return (sync_percent == PERCENT_100) ? 1 : 0; } /* * _raid_remove_top_layer * @lv * @removal_list * * Remove top layer of RAID LV in order to convert to linear. * This function makes no on-disk changes. The residual LVs * returned in 'removal_list' must be freed by the caller. * * Returns: 1 on succes, 0 on failure */ static int _raid_remove_top_layer(struct logical_volume *lv, struct dm_list *removal_list) { struct lv_list *lvl_array, *lvl; struct lv_segment *seg = first_seg(lv); if (!seg_is_mirrored(seg)) { log_error(INTERNAL_ERROR "Unable to remove RAID layer from segment type %s", seg->segtype->ops->name(seg)); return 0; } if (seg->area_count != 1) { log_error(INTERNAL_ERROR "Unable to remove RAID layer when there" " is more than one sub-lv"); return 0; } lvl_array = dm_pool_alloc(lv->vg->vgmem, 2 * sizeof(*lvl)); if (!lvl_array) { log_error("Memory allocation failed."); return 0; } /* Add last metadata area to removal_list */ lvl_array[0].lv = seg_metalv(seg, 0); lv_set_visible(seg_metalv(seg, 0)); remove_seg_from_segs_using_this_lv(seg_metalv(seg, 0), seg); seg_metatype(seg, 0) = AREA_UNASSIGNED; dm_list_add(removal_list, &(lvl_array[0].list)); /* Remove RAID layer and add residual LV to removal_list*/ seg_lv(seg, 0)->status &= ~RAID_IMAGE; lv_set_visible(seg_lv(seg, 0)); lvl_array[1].lv = seg_lv(seg, 0); dm_list_add(removal_list, &(lvl_array[1].list)); if (!remove_layer_from_lv(lv, seg_lv(seg, 0))) return_0; lv->status &= ~(MIRRORED | RAID); return 1; } /* * _clear_lv * @lv * * If LV is active: * clear first block of device * otherwise: * activate, clear, deactivate * * Returns: 1 on success, 0 on failure */ static int _clear_lv(struct logical_volume *lv) { int was_active = lv_is_active(lv); if (test_mode()) return 1; if (!was_active && !activate_lv(lv->vg->cmd, lv)) { log_error("Failed to activate %s for clearing", lv->name); return 0; } log_verbose("Clearing metadata area of %s/%s", lv->vg->name, lv->name); /* * Rather than wiping lv->size, we can simply * wipe the first sector to remove the superblock of any previous * RAID devices. It is much quicker. */ if (!set_lv(lv->vg->cmd, lv, 1, 0)) { log_error("Failed to zero %s", lv->name); return 0; } if (!was_active && !deactivate_lv(lv->vg->cmd, lv)) { log_error("Failed to deactivate %s", lv->name); return 0; } return 1; } /* Makes on-disk metadata changes */ static int _clear_lvs(struct dm_list *lv_list) { struct lv_list *lvl; struct volume_group *vg = NULL; if (dm_list_empty(lv_list)) { log_debug(INTERNAL_ERROR "Empty list of LVs given for clearing"); return 1; } dm_list_iterate_items(lvl, lv_list) { if (!lv_is_visible(lvl->lv)) { log_error(INTERNAL_ERROR "LVs must be set visible before clearing"); return 0; } vg = lvl->lv->vg; } /* * FIXME: only vg_[write|commit] if LVs are not already written * as visible in the LVM metadata (which is never the case yet). */ if (!vg || !vg_write(vg) || !vg_commit(vg)) return_0; dm_list_iterate_items(lvl, lv_list) if (!_clear_lv(lvl->lv)) return 0; return 1; } /* * _shift_and_rename_image_components * @seg: Top-level RAID segment * * Shift all higher indexed segment areas down to fill in gaps where * there are 'AREA_UNASSIGNED' areas and rename data/metadata LVs so * that their names match their new index. When finished, set * seg->area_count to new reduced total. * * Returns: 1 on success, 0 on failure */ static int _shift_and_rename_image_components(struct lv_segment *seg) { int len; char *shift_name; uint32_t s, missing; struct cmd_context *cmd = seg->lv->vg->cmd; /* * All LVs must be properly named for their index before * shifting begins. (e.g. Index '0' must contain *_rimage_0 and * *_rmeta_0. Index 'n' must contain *_rimage_n and *_rmeta_n.) */ if (!seg_is_raid(seg)) return_0; if (seg->area_count > 10) { /* * FIXME: Handling more would mean I'd have * to handle double digits */ log_error("Unable handle arrays with more than 10 devices"); return 0; } log_very_verbose("Shifting images in %s", seg->lv->name); for (s = 0, missing = 0; s < seg->area_count; s++) { if (seg_type(seg, s) == AREA_UNASSIGNED) { if (seg_metatype(seg, s) != AREA_UNASSIGNED) { log_error(INTERNAL_ERROR "Metadata segment area" " #%d should be AREA_UNASSIGNED", s); return 0; } missing++; continue; } if (!missing) continue; log_very_verbose("Shifting %s and %s by %u", seg_metalv(seg, s)->name, seg_lv(seg, s)->name, missing); /* Alter rmeta name */ shift_name = dm_pool_strdup(cmd->mem, seg_metalv(seg, s)->name); if (!shift_name) { log_error("Memory allocation failed."); return 0; } len = strlen(shift_name) - 1; shift_name[len] -= missing; seg_metalv(seg, s)->name = shift_name; /* Alter rimage name */ shift_name = dm_pool_strdup(cmd->mem, seg_lv(seg, s)->name); if (!shift_name) { log_error("Memory allocation failed."); return 0; } len = strlen(shift_name) - 1; shift_name[len] -= missing; seg_lv(seg, s)->name = shift_name; seg->areas[s - missing] = seg->areas[s]; seg->meta_areas[s - missing] = seg->meta_areas[s]; } seg->area_count -= missing; return 1; } /* * Create an LV of specified type. Set visible after creation. * This function does not make metadata changes. */ static int _alloc_image_component(struct logical_volume *lv, const char *alt_base_name, struct alloc_handle *ah, uint32_t first_area, uint64_t type, struct logical_volume **new_lv) { uint64_t status; size_t len = strlen(lv->name) + 32; char img_name[len]; const char *base_name = (alt_base_name) ? alt_base_name : lv->name; struct logical_volume *tmp_lv; const struct segment_type *segtype; if (type == RAID_META) { if (dm_snprintf(img_name, len, "%s_rmeta_%%d", base_name) < 0) return_0; } else if (type == RAID_IMAGE) { if (dm_snprintf(img_name, len, "%s_rimage_%%d", base_name) < 0) return_0; } else { log_error(INTERNAL_ERROR "Bad type provided to _alloc_raid_component"); return 0; } if (!ah) { first_area = 0; log_error(INTERNAL_ERROR "Stand-alone %s area allocation not implemented", (type == RAID_META) ? "metadata" : "data"); return 0; } status = LVM_READ | LVM_WRITE | LV_REBUILD | type; tmp_lv = lv_create_empty(img_name, NULL, status, ALLOC_INHERIT, lv->vg); if (!tmp_lv) { log_error("Failed to allocate new raid component, %s", img_name); return 0; } segtype = get_segtype_from_string(lv->vg->cmd, "striped"); if (!lv_add_segment(ah, first_area, 1, tmp_lv, segtype, 0, status, 0)) { log_error("Failed to add segment to LV, %s", img_name); return 0; } lv_set_visible(tmp_lv); *new_lv = tmp_lv; return 1; } static int _alloc_image_components(struct logical_volume *lv, struct dm_list *pvs, uint32_t count, struct dm_list *new_meta_lvs, struct dm_list *new_data_lvs) { uint32_t s; uint32_t region_size; uint32_t extents; struct lv_segment *seg = first_seg(lv); const struct segment_type *segtype; struct alloc_handle *ah; struct dm_list *parallel_areas; struct logical_volume *tmp_lv; struct lv_list *lvl_array; lvl_array = dm_pool_alloc(lv->vg->vgmem, sizeof(*lvl_array) * count * 2); if (!lvl_array) return_0; if (!(parallel_areas = build_parallel_areas_from_lv(lv, 0))) return_0; if (seg_is_linear(seg)) region_size = RAID_REGION_SIZE; else region_size = seg->region_size; if (seg_is_raid(seg)) segtype = seg->segtype; else if (!(segtype = get_segtype_from_string(lv->vg->cmd, "raid1"))) return_0; /* * The number of extents is based on the RAID type. For RAID1, * each of the rimages is the same size - 'le_count'. However * for RAID 4/5/6, the stripes add together (NOT including the parity * devices) to equal 'le_count'. Thus, when we are allocating * individual devies, we must specify how large the individual device * is along with the number we want ('count'). */ extents = (segtype->parity_devs) ? (lv->le_count / (seg->area_count - segtype->parity_devs)) : lv->le_count; if (!(ah = allocate_extents(lv->vg, NULL, segtype, 0, count, count, region_size, extents, pvs, lv->alloc, parallel_areas))) return_0; for (s = 0; s < count; s++) { /* * The allocation areas are grouped together. First * come the rimage allocated areas, then come the metadata * allocated areas. Thus, the metadata areas are pulled * from 's + count'. */ if (!_alloc_image_component(lv, NULL, ah, s + count, RAID_META, &tmp_lv)) return_0; lvl_array[s + count].lv = tmp_lv; dm_list_add(new_meta_lvs, &(lvl_array[s + count].list)); if (!_alloc_image_component(lv, NULL, ah, s, RAID_IMAGE, &tmp_lv)) return_0; lvl_array[s].lv = tmp_lv; dm_list_add(new_data_lvs, &(lvl_array[s].list)); } alloc_destroy(ah); return 1; } /* * _alloc_rmeta_for_lv * @lv * * Allocate a RAID metadata device for the given LV (which is or will * be the associated RAID data device). The new metadata device must * be allocated from the same PV(s) as the data device. */ static int _alloc_rmeta_for_lv(struct logical_volume *data_lv, struct logical_volume **meta_lv) { struct dm_list allocatable_pvs; struct alloc_handle *ah; struct lv_segment *seg = first_seg(data_lv); char *p, base_name[strlen(data_lv->name) + 1]; dm_list_init(&allocatable_pvs); if (!seg_is_linear(seg)) { log_error(INTERNAL_ERROR "Unable to allocate RAID metadata " "area for non-linear LV, %s", data_lv->name); return 0; } sprintf(base_name, "%s", data_lv->name); if ((p = strstr(base_name, "_mimage_"))) *p = '\0'; if (!_get_pv_list_for_lv(data_lv, &allocatable_pvs)) { log_error("Failed to build list of PVs for %s/%s", data_lv->vg->name, data_lv->name); return 0; } if (!(ah = allocate_extents(data_lv->vg, NULL, seg->segtype, 0, 1, 0, seg->region_size, 1 /*RAID_METADATA_AREA_LEN*/, &allocatable_pvs, data_lv->alloc, NULL))) return_0; if (!_alloc_image_component(data_lv, base_name, ah, 0, RAID_META, meta_lv)) return_0; alloc_destroy(ah); return 1; } static int _raid_add_images(struct logical_volume *lv, uint32_t new_count, struct dm_list *pvs) { int rebuild_flag_cleared = 0; uint32_t s; uint32_t old_count = lv_raid_image_count(lv); uint32_t count = new_count - old_count; uint64_t status_mask = -1; struct cmd_context *cmd = lv->vg->cmd; struct lv_segment *seg = first_seg(lv); struct dm_list meta_lvs, data_lvs; struct lv_list *lvl; struct lv_segment_area *new_areas; if (lv->status & LV_NOTSYNCED) { log_error("Can't add image to out-of-sync RAID LV:" " use 'lvchange --resync' first."); return 0; } if (!_raid_in_sync(lv)) { log_error("Can't add image to RAID LV that" " is still initializing."); return 0; } dm_list_init(&meta_lvs); /* For image addition */ dm_list_init(&data_lvs); /* For image addition */ /* * If the segtype is linear, then we must allocate a metadata * LV to accompany it. */ if (seg_is_linear(seg)) { /* A complete resync will be done, no need to mark each sub-lv */ status_mask = ~(LV_REBUILD); if (!(lvl = dm_pool_alloc(lv->vg->vgmem, sizeof(*lvl)))) { log_error("Memory allocation failed"); return 0; } if (!_alloc_rmeta_for_lv(lv, &lvl->lv)) return_0; dm_list_add(&meta_lvs, &lvl->list); } else if (!seg_is_raid(seg)) { log_error("Unable to add RAID images to %s of segment type %s", lv->name, seg->segtype->ops->name(seg)); return 0; } else if (!_raid_in_sync(lv)) { log_error("Unable to add RAID images until %s is in-sync", lv->name); return 0; } if (!_alloc_image_components(lv, pvs, count, &meta_lvs, &data_lvs)) { log_error("Failed to allocate new image components"); return 0; } /* * If linear, we must correct data LV names. They are off-by-one * because the linear volume hasn't taken its proper name of "_rimage_0" * yet. This action must be done before '_clear_lvs' because it * commits the LVM metadata before clearing the LVs. */ if (seg_is_linear(seg)) { char *name; size_t len; struct dm_list *l; struct lv_list *lvl_tmp; dm_list_iterate(l, &data_lvs) { if (l == dm_list_last(&data_lvs)) { lvl = dm_list_item(l, struct lv_list); len = strlen(lv->name) + strlen("_rimage_XXX"); if (!(name = dm_pool_alloc(lv->vg->vgmem, len))) { log_error("Failed to allocate rimage name."); return 0; } sprintf(name, "%s_rimage_%u", lv->name, count); lvl->lv->name = name; continue; } lvl = dm_list_item(l, struct lv_list); lvl_tmp = dm_list_item(l->n, struct lv_list); lvl->lv->name = lvl_tmp->lv->name; } } /* Metadata LVs must be cleared before being added to the array */ if (!_clear_lvs(&meta_lvs)) goto fail; if (seg_is_linear(seg)) { first_seg(lv)->status |= RAID_IMAGE; if (!insert_layer_for_lv(lv->vg->cmd, lv, RAID | LVM_READ | LVM_WRITE, "_rimage_0")) return_0; lv->status |= RAID; seg = first_seg(lv); seg_lv(seg, 0)->status |= RAID_IMAGE | LVM_READ | LVM_WRITE; seg->region_size = RAID_REGION_SIZE; /* MD's bitmap is limited to tracking 2^21 regions */ while (seg->region_size < (lv->size / (1 << 21))) { seg->region_size *= 2; log_very_verbose("Setting RAID1 region_size to %uS", seg->region_size); } seg->segtype = get_segtype_from_string(lv->vg->cmd, "raid1"); if (!seg->segtype) return_0; } /* FIXME: It would be proper to activate the new LVs here, instead of having them activated by the suspend. However, this causes residual device nodes to be left for these sub-lvs. dm_list_iterate_items(lvl, &meta_lvs) if (!do_correct_activate(lv, lvl->lv)) return_0; dm_list_iterate_items(lvl, &data_lvs) if (!do_correct_activate(lv, lvl->lv)) return_0; */ /* Expand areas array */ if (!(new_areas = dm_pool_zalloc(lv->vg->cmd->mem, new_count * sizeof(*new_areas)))) goto fail; memcpy(new_areas, seg->areas, seg->area_count * sizeof(*seg->areas)); seg->areas = new_areas; /* Expand meta_areas array */ if (!(new_areas = dm_pool_zalloc(lv->vg->cmd->mem, new_count * sizeof(*new_areas)))) goto fail; if (seg->meta_areas) memcpy(new_areas, seg->meta_areas, seg->area_count * sizeof(*seg->meta_areas)); seg->meta_areas = new_areas; seg->area_count = new_count; /* Add extra meta area when converting from linear */ s = (old_count == 1) ? 0 : old_count; /* Set segment areas for metadata sub_lvs */ dm_list_iterate_items(lvl, &meta_lvs) { log_debug("Adding %s to %s", lvl->lv->name, lv->name); lvl->lv->status &= status_mask; first_seg(lvl->lv)->status &= status_mask; if (!set_lv_segment_area_lv(seg, s, lvl->lv, 0, lvl->lv->status)) { log_error("Failed to add %s to %s", lvl->lv->name, lv->name); goto fail; } s++; } s = old_count; /* Set segment areas for data sub_lvs */ dm_list_iterate_items(lvl, &data_lvs) { log_debug("Adding %s to %s", lvl->lv->name, lv->name); lvl->lv->status &= status_mask; first_seg(lvl->lv)->status &= status_mask; if (!set_lv_segment_area_lv(seg, s, lvl->lv, 0, lvl->lv->status)) { log_error("Failed to add %s to %s", lvl->lv->name, lv->name); goto fail; } s++; } /* * FIXME: Failure handling during these points is harder. */ dm_list_iterate_items(lvl, &meta_lvs) lv_set_hidden(lvl->lv); dm_list_iterate_items(lvl, &data_lvs) lv_set_hidden(lvl->lv); if (!vg_write(lv->vg)) { log_error("Failed to write changes to %s in %s", lv->name, lv->vg->name); return 0; } if (!suspend_lv_origin(cmd, lv)) { log_error("Failed to suspend %s/%s before committing changes", lv->vg->name, lv->name); return 0; } if (!vg_commit(lv->vg)) { log_error("Failed to commit changes to %s in %s", lv->name, lv->vg->name); return 0; } if (!resume_lv_origin(cmd, lv)) { log_error("Failed to resume %s/%s after committing changes", lv->vg->name, lv->name); return 0; } /* * Now that the 'REBUILD' has made its way to the kernel, we must * remove the flag so that the individual devices are not rebuilt * upon every activation. */ seg = first_seg(lv); for (s = 0; s < seg->area_count; s++) { if ((seg_lv(seg, s)->status & LV_REBUILD) || (seg_metalv(seg, s)->status & LV_REBUILD)) { seg_metalv(seg, s)->status &= ~LV_REBUILD; seg_lv(seg, s)->status &= ~LV_REBUILD; rebuild_flag_cleared = 1; } } if (rebuild_flag_cleared && (!vg_write(lv->vg) || !vg_commit(lv->vg))) { log_error("Failed to clear REBUILD flag for %s/%s components", lv->vg->name, lv->name); return 0; } return 1; fail: /* Cleanly remove newly-allocated LVs that failed insertion attempt */ dm_list_iterate_items(lvl, &meta_lvs) if (!lv_remove(lvl->lv)) return_0; dm_list_iterate_items(lvl, &data_lvs) if (!lv_remove(lvl->lv)) return_0; return_0; } /* * _extract_image_components * @seg * @idx: The index in the areas array to remove * @extracted_rmeta: The displaced metadata LV * @extracted_rimage: The displaced data LV * * This function extracts the image components - setting the respective * 'extracted' pointers. It appends '_extracted' to the LVs' names, so that * there are not future conflicts. It does /not/ commit the results. * (IOW, erroring-out requires no unwinding of operations.) * * This function does /not/ attempt to: * 1) shift the 'areas' or 'meta_areas' arrays. * The '[meta_]areas' are left as AREA_UNASSIGNED. * 2) Adjust the seg->area_count * 3) Name the extracted LVs appropriately (appends '_extracted' to names) * These actions must be performed by the caller. * * Returns: 1 on success, 0 on failure */ static int _extract_image_components(struct lv_segment *seg, uint32_t idx, struct logical_volume **extracted_rmeta, struct logical_volume **extracted_rimage) { int len; char *tmp_name; struct volume_group *vg = seg->lv->vg; struct logical_volume *data_lv = seg_lv(seg, idx); struct logical_volume *meta_lv = seg_metalv(seg, idx); log_very_verbose("Extracting image components %s and %s from %s", data_lv->name, meta_lv->name, seg->lv->name); data_lv->status &= ~RAID_IMAGE; meta_lv->status &= ~RAID_META; lv_set_visible(data_lv); lv_set_visible(meta_lv); /* release removes data and meta areas */ remove_seg_from_segs_using_this_lv(data_lv, seg); remove_seg_from_segs_using_this_lv(meta_lv, seg); seg_type(seg, idx) = AREA_UNASSIGNED; seg_metatype(seg, idx) = AREA_UNASSIGNED; len = strlen(meta_lv->name) + strlen("_extracted") + 1; tmp_name = dm_pool_alloc(vg->vgmem, len); if (!tmp_name) return_0; sprintf(tmp_name, "%s_extracted", meta_lv->name); meta_lv->name = tmp_name; len = strlen(data_lv->name) + strlen("_extracted") + 1; tmp_name = dm_pool_alloc(vg->vgmem, len); if (!tmp_name) return_0; sprintf(tmp_name, "%s_extracted", data_lv->name); data_lv->name = tmp_name; *extracted_rmeta = meta_lv; *extracted_rimage = data_lv; return 1; } /* * _raid_extract_images * @lv * @new_count: The absolute count of images (e.g. '2' for a 2-way mirror) * @target_pvs: The list of PVs that are candidates for removal * @shift: If set, use _shift_and_rename_image_components(). * Otherwise, leave the [meta_]areas as AREA_UNASSIGNED and * seg->area_count unchanged. * @extracted_[meta|data]_lvs: The LVs removed from the array. If 'shift' * is set, then there will likely be name conflicts. * * This function extracts _both_ portions of the indexed image. It * does /not/ commit the results. (IOW, erroring-out requires no unwinding * of operations.) * * Returns: 1 on success, 0 on failure */ static int _raid_extract_images(struct logical_volume *lv, uint32_t new_count, struct dm_list *target_pvs, int shift, struct dm_list *extracted_meta_lvs, struct dm_list *extracted_data_lvs) { int s, extract, lvl_idx = 0; struct lv_list *lvl_array; struct lv_segment *seg = first_seg(lv); struct logical_volume *rmeta_lv, *rimage_lv; extract = seg->area_count - new_count; log_verbose("Extracting %u %s from %s/%s", extract, (extract > 1) ? "images" : "image", lv->vg->name, lv->name); lvl_array = dm_pool_alloc(lv->vg->vgmem, sizeof(*lvl_array) * extract * 2); if (!lvl_array) return_0; for (s = seg->area_count - 1; (s >= 0) && extract; s--) { if (!_lv_is_on_pvs(seg_lv(seg, s), target_pvs) || !_lv_is_on_pvs(seg_metalv(seg, s), target_pvs)) continue; if (!_raid_in_sync(lv) && (!seg_is_mirrored(seg) || (s == 0))) { log_error("Unable to extract %sRAID image" " while RAID array is not in-sync", seg_is_mirrored(seg) ? "primary " : ""); return 0; } if (!_extract_image_components(seg, s, &rmeta_lv, &rimage_lv)) { log_error("Failed to extract %s from %s", seg_lv(seg, s)->name, lv->name); return 0; } if (shift && !_shift_and_rename_image_components(seg)) { log_error("Failed to shift and rename image components"); return 0; } lvl_array[lvl_idx].lv = rmeta_lv; lvl_array[lvl_idx + 1].lv = rimage_lv; dm_list_add(extracted_meta_lvs, &(lvl_array[lvl_idx++].list)); dm_list_add(extracted_data_lvs, &(lvl_array[lvl_idx++].list)); extract--; } if (extract) { log_error("Unable to extract enough images to satisfy request"); return 0; } return 1; } static int _raid_remove_images(struct logical_volume *lv, uint32_t new_count, struct dm_list *pvs) { struct dm_list removal_list; struct lv_list *lvl; dm_list_init(&removal_list); if (!_raid_extract_images(lv, new_count, pvs, 1, &removal_list, &removal_list)) { log_error("Failed to extract images from %s/%s", lv->vg->name, lv->name); return 0; } /* Convert to linear? */ if (new_count == 1) { if (!_raid_remove_top_layer(lv, &removal_list)) { log_error("Failed to remove RAID layer" " after linear conversion"); return 0; } lv->status &= ~LV_NOTSYNCED; } if (!vg_write(lv->vg)) { log_error("Failed to write changes to %s in %s", lv->name, lv->vg->name); return 0; } if (!suspend_lv(lv->vg->cmd, lv)) { log_error("Failed to suspend %s/%s before committing changes", lv->vg->name, lv->name); return 0; } if (!vg_commit(lv->vg)) { log_error("Failed to commit changes to %s in %s", lv->name, lv->vg->name); return 0; } /* * We resume the extracted sub-LVs first so they are renamed * and won't conflict with the remaining (possibly shifted) * sub-LVs. */ dm_list_iterate_items(lvl, &removal_list) { if (!resume_lv(lv->vg->cmd, lvl->lv)) { log_error("Failed to resume extracted LVs"); return 0; } } /* * Resume the remaining LVs * We must start by resuming the sub-LVs first (which would * otherwise be handled automatically) because the shifting * of positions could otherwise cause name collisions. For * example, if position 0 of a 3-way array is removed, position * 1 and 2 must be shifted and renamed 0 and 1. If position 2 * tries to rename first, it will collide with the existing * position 1. */ if (!_bottom_up_resume(lv)) { log_error("Failed to resume %s/%s after committing changes", lv->vg->name, lv->name); return 0; } /* * Eliminate the extracted LVs */ sync_local_dev_names(lv->vg->cmd); if (!dm_list_empty(&removal_list)) { dm_list_iterate_items(lvl, &removal_list) { if (!deactivate_lv(lv->vg->cmd, lvl->lv)) return_0; if (!lv_remove(lvl->lv)) return_0; } if (!vg_write(lv->vg) || !vg_commit(lv->vg)) return_0; } return 1; } /* * lv_raid_change_image_count * @lv * @new_count: The absolute count of images (e.g. '2' for a 2-way mirror) * @pvs: The list of PVs that are candidates for removal (or empty list) * * RAID arrays have 'images' which are composed of two parts, they are: * - 'rimage': The data/parity holding portion * - 'rmeta' : The metadata holding portion (i.e. superblock/bitmap area) * This function adds or removes _both_ portions of the image and commits * the results. * * Returns: 1 on success, 0 on failure */ int lv_raid_change_image_count(struct logical_volume *lv, uint32_t new_count, struct dm_list *pvs) { uint32_t old_count = lv_raid_image_count(lv); if (old_count == new_count) { log_error("%s/%s already has image count of %d", lv->vg->name, lv->name, new_count); return 1; } if (old_count > new_count) return _raid_remove_images(lv, new_count, pvs); return _raid_add_images(lv, new_count, pvs); } int lv_raid_split(struct logical_volume *lv, const char *split_name, uint32_t new_count, struct dm_list *splittable_pvs) { struct lv_list *lvl; struct dm_list removal_list, data_list; struct cmd_context *cmd = lv->vg->cmd; uint32_t old_count = lv_raid_image_count(lv); struct logical_volume *tracking; struct dm_list tracking_pvs; dm_list_init(&removal_list); dm_list_init(&data_list); if ((old_count - new_count) != 1) { log_error("Unable to split more than one image from %s/%s", lv->vg->name, lv->name); return 0; } if (!seg_is_mirrored(first_seg(lv))) { log_error("Unable to split logical volume of segment type, %s", first_seg(lv)->segtype->ops->name(first_seg(lv))); return 0; } if (find_lv_in_vg(lv->vg, split_name)) { log_error("Logical Volume \"%s\" already exists in %s", split_name, lv->vg->name); return 0; } if (!_raid_in_sync(lv)) { log_error("Unable to split %s/%s while it is not in-sync.", lv->vg->name, lv->name); return 0; } /* * We only allow a split while there is tracking if it is to * complete the split of the tracking sub-LV */ if (_lv_is_raid_with_tracking(lv, &tracking)) { if (!_lv_is_on_pvs(tracking, splittable_pvs)) { log_error("Unable to split additional image from %s " "while tracking changes for %s", lv->name, tracking->name); return 0; } else { /* Ensure we only split the tracking image */ dm_list_init(&tracking_pvs); splittable_pvs = &tracking_pvs; if (!_get_pv_list_for_lv(tracking, splittable_pvs)) return_0; } } if (!_raid_extract_images(lv, new_count, splittable_pvs, 1, &removal_list, &data_list)) { log_error("Failed to extract images from %s/%s", lv->vg->name, lv->name); return 0; } /* Convert to linear? */ if ((new_count == 1) && !_raid_remove_top_layer(lv, &removal_list)) { log_error("Failed to remove RAID layer after linear conversion"); return 0; } /* Get first item */ dm_list_iterate_items(lvl, &data_list) break; lvl->lv->name = split_name; if (!vg_write(lv->vg)) { log_error("Failed to write changes to %s in %s", lv->name, lv->vg->name); return 0; } if (!suspend_lv(cmd, lv)) { log_error("Failed to suspend %s/%s before committing changes", lv->vg->name, lv->name); return 0; } if (!vg_commit(lv->vg)) { log_error("Failed to commit changes to %s in %s", lv->name, lv->vg->name); return 0; } /* * First resume the newly split LV and LVs on the removal list. * This is necessary so that there are no name collisions due to * the original RAID LV having possibly had sub-LVs that have been * shifted and renamed. */ if (!resume_lv(cmd, lvl->lv)) return_0; dm_list_iterate_items(lvl, &removal_list) if (!resume_lv(cmd, lvl->lv)) return_0; /* * Resume the remaining LVs * We must start by resuming the sub-LVs first (which would * otherwise be handled automatically) because the shifting * of positions could otherwise cause name collisions. For * example, if position 0 of a 3-way array is split, position * 1 and 2 must be shifted and renamed 0 and 1. If position 2 * tries to rename first, it will collide with the existing * position 1. */ if (!_bottom_up_resume(lv)) { log_error("Failed to resume %s/%s after committing changes", lv->vg->name, lv->name); return 0; } /* * Eliminate the residual LVs */ dm_list_iterate_items(lvl, &removal_list) { if (!deactivate_lv(cmd, lvl->lv)) return_0; if (!lv_remove(lvl->lv)) return_0; } if (!vg_write(lv->vg) || !vg_commit(lv->vg)) return_0; return 1; } /* * lv_raid_split_and_track * @lv * @splittable_pvs * * Only allows a single image to be split while tracking. The image * never actually leaves the mirror. It is simply made visible. This * action triggers two things: 1) users are able to access the (data) image * and 2) lower layers replace images marked with a visible flag with * error targets. * * Returns: 1 on success, 0 on error */ int lv_raid_split_and_track(struct logical_volume *lv, struct dm_list *splittable_pvs) { int s; struct lv_segment *seg = first_seg(lv); if (!seg_is_mirrored(seg)) { log_error("Unable to split images from non-mirrored RAID"); return 0; } if (!_raid_in_sync(lv)) { log_error("Unable to split image from %s/%s while not in-sync", lv->vg->name, lv->name); return 0; } /* Cannot track two split images at once */ if (lv_is_raid_with_tracking(lv)) { log_error("Cannot track more than one split image at a time"); return 0; } for (s = seg->area_count - 1; s >= 0; s--) { if (!_lv_is_on_pvs(seg_lv(seg, s), splittable_pvs)) continue; lv_set_visible(seg_lv(seg, s)); seg_lv(seg, s)->status &= ~LVM_WRITE; break; } if (s >= (int) seg->area_count) { log_error("Unable to find image to satisfy request"); return 0; } if (!vg_write(lv->vg)) { log_error("Failed to write changes to %s in %s", lv->name, lv->vg->name); return 0; } if (!suspend_lv(lv->vg->cmd, lv)) { log_error("Failed to suspend %s/%s before committing changes", lv->vg->name, lv->name); return 0; } if (!vg_commit(lv->vg)) { log_error("Failed to commit changes to %s in %s", lv->name, lv->vg->name); return 0; } log_print_unless_silent("%s split from %s for read-only purposes.", seg_lv(seg, s)->name, lv->name); /* Resume original LV */ if (!resume_lv(lv->vg->cmd, lv)) { log_error("Failed to resume %s/%s after committing changes", lv->vg->name, lv->name); return 0; } /* Activate the split (and tracking) LV */ if (!_activate_sublv_preserving_excl(lv, seg_lv(seg, s))) return 0; log_print_unless_silent("Use 'lvconvert --merge %s/%s' to merge back into %s", lv->vg->name, seg_lv(seg, s)->name, lv->name); return 1; } int lv_raid_merge(struct logical_volume *image_lv) { uint32_t s; char *p, *lv_name; struct lv_list *lvl; struct logical_volume *lv; struct logical_volume *meta_lv = NULL; struct lv_segment *seg; struct volume_group *vg = image_lv->vg; lv_name = dm_pool_strdup(vg->vgmem, image_lv->name); if (!lv_name) return_0; if (!(p = strstr(lv_name, "_rimage_"))) { log_error("Unable to merge non-mirror image %s/%s", vg->name, image_lv->name); return 0; } *p = '\0'; /* lv_name is now that of top-level RAID */ if (image_lv->status & LVM_WRITE) { log_error("%s/%s is not read-only - refusing to merge", vg->name, image_lv->name); return 0; } if (!(lvl = find_lv_in_vg(vg, lv_name))) { log_error("Unable to find containing RAID array for %s/%s", vg->name, image_lv->name); return 0; } lv = lvl->lv; seg = first_seg(lv); for (s = 0; s < seg->area_count; s++) { if (seg_lv(seg, s) == image_lv) { meta_lv = seg_metalv(seg, s); } } if (!meta_lv) return_0; if (!deactivate_lv(vg->cmd, meta_lv)) { log_error("Failed to deactivate %s", meta_lv->name); return 0; } if (!deactivate_lv(vg->cmd, image_lv)) { log_error("Failed to deactivate %s/%s before merging", vg->name, image_lv->name); return 0; } lv_set_hidden(image_lv); image_lv->status |= (lv->status & LVM_WRITE); image_lv->status |= RAID_IMAGE; if (!vg_write(vg)) { log_error("Failed to write changes to %s in %s", lv->name, vg->name); return 0; } if (!suspend_lv(vg->cmd, lv)) { log_error("Failed to suspend %s/%s before committing changes", vg->name, lv->name); return 0; } if (!vg_commit(vg)) { log_error("Failed to commit changes to %s in %s", lv->name, vg->name); return 0; } if (!resume_lv(vg->cmd, lv)) { log_error("Failed to resume %s/%s after committing changes", vg->name, lv->name); return 0; } log_print_unless_silent("%s/%s successfully merged back into %s/%s", vg->name, image_lv->name, vg->name, lv->name); return 1; } static int _convert_mirror_to_raid1(struct logical_volume *lv, const struct segment_type *new_segtype) { uint32_t s; struct lv_segment *seg = first_seg(lv); struct lv_list lvl_array[seg->area_count], *lvl; struct dm_list meta_lvs; struct lv_segment_area *meta_areas; dm_list_init(&meta_lvs); if (!_raid_in_sync(lv)) { log_error("Unable to convert %s/%s while it is not in-sync", lv->vg->name, lv->name); return 0; } meta_areas = dm_pool_zalloc(lv->vg->vgmem, lv_mirror_count(lv) * sizeof(*meta_areas)); if (!meta_areas) { log_error("Failed to allocate memory"); return 0; } for (s = 0; s < seg->area_count; s++) { log_debug("Allocating new metadata LV for %s", seg_lv(seg, s)->name); if (!_alloc_rmeta_for_lv(seg_lv(seg, s), &(lvl_array[s].lv))) { log_error("Failed to allocate metadata LV for %s in %s", seg_lv(seg, s)->name, lv->name); return 0; } dm_list_add(&meta_lvs, &(lvl_array[s].list)); } log_debug("Clearing newly allocated metadata LVs"); if (!_clear_lvs(&meta_lvs)) { log_error("Failed to initialize metadata LVs"); return 0; } if (seg->log_lv) { log_debug("Removing mirror log, %s", seg->log_lv->name); if (!remove_mirror_log(lv->vg->cmd, lv, NULL, 0)) { log_error("Failed to remove mirror log"); return 0; } } seg->meta_areas = meta_areas; s = 0; dm_list_iterate_items(lvl, &meta_lvs) { log_debug("Adding %s to %s", lvl->lv->name, lv->name); /* Images are known to be in-sync */ lvl->lv->status &= ~LV_REBUILD; first_seg(lvl->lv)->status &= ~LV_REBUILD; lv_set_hidden(lvl->lv); if (!set_lv_segment_area_lv(seg, s, lvl->lv, 0, lvl->lv->status)) { log_error("Failed to add %s to %s", lvl->lv->name, lv->name); return 0; } s++; } for (s = 0; s < seg->area_count; s++) { char *new_name; new_name = dm_pool_zalloc(lv->vg->vgmem, strlen(lv->name) + strlen("_rimage_XXn")); if (!new_name) { log_error("Failed to rename mirror images"); return 0; } sprintf(new_name, "%s_rimage_%u", lv->name, s); log_debug("Renaming %s to %s", seg_lv(seg, s)->name, new_name); seg_lv(seg, s)->name = new_name; seg_lv(seg, s)->status &= ~MIRROR_IMAGE; seg_lv(seg, s)->status |= RAID_IMAGE; } init_mirror_in_sync(1); log_debug("Setting new segtype for %s", lv->name); seg->segtype = new_segtype; lv->status &= ~MIRRORED; lv->status |= RAID; seg->status |= RAID; if (!vg_write(lv->vg)) { log_error("Failed to write changes to %s in %s", lv->name, lv->vg->name); return 0; } if (!suspend_lv(lv->vg->cmd, lv)) { log_error("Failed to suspend %s/%s before committing changes", lv->vg->name, lv->name); return 0; } if (!vg_commit(lv->vg)) { log_error("Failed to commit changes to %s in %s", lv->name, lv->vg->name); return 0; } if (!resume_lv(lv->vg->cmd, lv)) { log_error("Failed to resume %s/%s after committing changes", lv->vg->name, lv->name); return 0; } return 1; } /* * lv_raid_reshape * @lv * @new_segtype * * Convert an LV from one RAID type (or 'mirror' segtype) to another. * * Returns: 1 on success, 0 on failure */ int lv_raid_reshape(struct logical_volume *lv, const struct segment_type *new_segtype) { struct lv_segment *seg = first_seg(lv); if (!new_segtype) { log_error(INTERNAL_ERROR "New segtype not specified"); return 0; } if (!strcmp(seg->segtype->name, "mirror") && (!strcmp(new_segtype->name, "raid1"))) return _convert_mirror_to_raid1(lv, new_segtype); log_error("Converting the segment type for %s/%s from %s to %s" " is not yet supported.", lv->vg->name, lv->name, seg->segtype->ops->name(seg), new_segtype->name); return 0; } /* * lv_raid_replace * @lv * @replace_pvs * @allocatable_pvs * * Replace the specified PVs. */ int lv_raid_replace(struct logical_volume *lv, struct dm_list *remove_pvs, struct dm_list *allocate_pvs) { uint32_t s, sd, match_count = 0; struct dm_list old_meta_lvs, old_data_lvs; struct dm_list new_meta_lvs, new_data_lvs; struct lv_segment *raid_seg = first_seg(lv); struct lv_list *lvl; char *tmp_names[raid_seg->area_count * 2]; dm_list_init(&old_meta_lvs); dm_list_init(&old_data_lvs); dm_list_init(&new_meta_lvs); dm_list_init(&new_data_lvs); /* * How many sub-LVs are being removed? */ for (s = 0; s < raid_seg->area_count; s++) { if ((seg_type(raid_seg, s) == AREA_UNASSIGNED) || (seg_metatype(raid_seg, s) == AREA_UNASSIGNED)) { log_error("Unable to replace RAID images while the " "array has unassigned areas"); return 0; } if (_lv_is_on_pvs(seg_lv(raid_seg, s), remove_pvs) || _lv_is_on_pvs(seg_metalv(raid_seg, s), remove_pvs)) match_count++; } if (!match_count) { log_verbose("%s/%s does not contain devices specified" " for replacement", lv->vg->name, lv->name); return 1; } else if (match_count == raid_seg->area_count) { log_error("Unable to remove all PVs from %s/%s at once.", lv->vg->name, lv->name); return 0; } else if (raid_seg->segtype->parity_devs && (match_count > raid_seg->segtype->parity_devs)) { log_error("Unable to replace more than %u PVs from (%s) %s/%s", raid_seg->segtype->parity_devs, raid_seg->segtype->ops->name(raid_seg), lv->vg->name, lv->name); return 0; } else if (!strcmp(raid_seg->segtype->name, "raid10")) { uint32_t i, rebuilds_per_group = 0; /* FIXME: We only support 2-way mirrors in RAID10 currently */ uint32_t copies = 2; for (i = 0; i < raid_seg->area_count * copies; i++) { s = i % raid_seg->area_count; if (!(i % copies)) rebuilds_per_group = 0; if (_lv_is_on_pvs(seg_lv(raid_seg, s), remove_pvs) || _lv_is_on_pvs(seg_metalv(raid_seg, s), remove_pvs)) rebuilds_per_group++; if (rebuilds_per_group >= copies) { log_error("Unable to replace all the devices " "in a RAID10 mirror group."); return 0; } } } /* * Allocate the new image components first * - This makes it easy to avoid all currently used devs * - We can immediately tell if there is enough space * * - We need to change the LV names when we insert them. */ try_again: if (!_alloc_image_components(lv, allocate_pvs, match_count, &new_meta_lvs, &new_data_lvs)) { log_error("Failed to allocate replacement images for %s/%s", lv->vg->name, lv->name); /* * If this is a repair, then try to * do better than all-or-nothing */ if (match_count > 1) { log_error("Attempting replacement of %u devices" " instead of %u", match_count - 1, match_count); match_count--; /* * Since we are replacing some but not all of the bad * devices, we must set partial_activation */ lv->vg->cmd->partial_activation = 1; goto try_again; } return 0; } /* * Remove the old images * - If we did this before the allocate, we wouldn't have to rename * the allocated images, but it'd be much harder to avoid the right * PVs during allocation. */ if (!_raid_extract_images(lv, raid_seg->area_count - match_count, remove_pvs, 0, &old_meta_lvs, &old_data_lvs)) { log_error("Failed to remove the specified images from %s/%s", lv->vg->name, lv->name); return 0; } /* * Skip metadata operation normally done to clear the metadata sub-LVs. * * The LV_REBUILD flag is set on the new sub-LVs, * so they will be rebuilt and we don't need to clear the metadata dev. */ for (s = 0; s < raid_seg->area_count; s++) { tmp_names[s] = NULL; sd = s + raid_seg->area_count; tmp_names[sd] = NULL; if ((seg_type(raid_seg, s) == AREA_UNASSIGNED) && (seg_metatype(raid_seg, s) == AREA_UNASSIGNED)) { /* Adjust the new metadata LV name */ lvl = dm_list_item(dm_list_first(&new_meta_lvs), struct lv_list); dm_list_del(&lvl->list); tmp_names[s] = dm_pool_alloc(lv->vg->vgmem, strlen(lvl->lv->name) + 1); if (!tmp_names[s]) return_0; if (dm_snprintf(tmp_names[s], strlen(lvl->lv->name) + 1, "%s_rmeta_%u", lv->name, s) < 0) return_0; if (!set_lv_segment_area_lv(raid_seg, s, lvl->lv, 0, lvl->lv->status)) { log_error("Failed to add %s to %s", lvl->lv->name, lv->name); return 0; } lv_set_hidden(lvl->lv); /* Adjust the new data LV name */ lvl = dm_list_item(dm_list_first(&new_data_lvs), struct lv_list); dm_list_del(&lvl->list); tmp_names[sd] = dm_pool_alloc(lv->vg->vgmem, strlen(lvl->lv->name) + 1); if (!tmp_names[sd]) return_0; if (dm_snprintf(tmp_names[sd], strlen(lvl->lv->name) + 1, "%s_rimage_%u", lv->name, s) < 0) return_0; if (!set_lv_segment_area_lv(raid_seg, s, lvl->lv, 0, lvl->lv->status)) { log_error("Failed to add %s to %s", lvl->lv->name, lv->name); return 0; } lv_set_hidden(lvl->lv); } } if (!vg_write(lv->vg)) { log_error("Failed to write changes to %s in %s", lv->name, lv->vg->name); return 0; } if (!suspend_lv_origin(lv->vg->cmd, lv)) { log_error("Failed to suspend %s/%s before committing changes", lv->vg->name, lv->name); return 0; } if (!vg_commit(lv->vg)) { log_error("Failed to commit changes to %s in %s", lv->name, lv->vg->name); return 0; } if (!resume_lv_origin(lv->vg->cmd, lv)) { log_error("Failed to resume %s/%s after committing changes", lv->vg->name, lv->name); return 0; } dm_list_iterate_items(lvl, &old_meta_lvs) { if (!deactivate_lv(lv->vg->cmd, lvl->lv)) return_0; if (!lv_remove(lvl->lv)) return_0; } dm_list_iterate_items(lvl, &old_data_lvs) { if (!deactivate_lv(lv->vg->cmd, lvl->lv)) return_0; if (!lv_remove(lvl->lv)) return_0; } /* Update new sub-LVs to correct name and clear REBUILD flag */ for (s = 0; s < raid_seg->area_count; s++) { sd = s + raid_seg->area_count; if (tmp_names[s] && tmp_names[sd]) { seg_metalv(raid_seg, s)->name = tmp_names[s]; seg_lv(raid_seg, s)->name = tmp_names[sd]; seg_metalv(raid_seg, s)->status &= ~LV_REBUILD; seg_lv(raid_seg, s)->status &= ~LV_REBUILD; } } if (!vg_write(lv->vg)) { log_error("Failed to write changes to %s in %s", lv->name, lv->vg->name); return 0; } if (!suspend_lv_origin(lv->vg->cmd, lv)) { log_error("Failed to suspend %s/%s before committing changes", lv->vg->name, lv->name); return 0; } if (!vg_commit(lv->vg)) { log_error("Failed to commit changes to %s in %s", lv->name, lv->vg->name); return 0; } if (!resume_lv_origin(lv->vg->cmd, lv)) { log_error("Failed to resume %s/%s after committing changes", lv->vg->name, lv->name); return 0; } return 1; } lvm2-2.02.98/lib/metadata/pv_alloc.h0000640000175000017500000000242412037016272016010 0ustar blankblank/* * Copyright (C) 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_PV_ALLOC_H int alloc_pv_segment_whole_pv(struct dm_pool *mem, struct physical_volume *pv); int peg_dup(struct dm_pool *mem, struct dm_list *peg_new, struct dm_list *peg_old); struct pv_segment *assign_peg_to_lvseg(struct physical_volume *pv, uint32_t pe, uint32_t area_len, struct lv_segment *seg, uint32_t area_num); int pv_split_segment(struct dm_pool *mem, struct physical_volume *pv, uint32_t pe, struct pv_segment **pvseg_allocated); int discard_pv_segment(struct pv_segment *peg, uint32_t discard_area_reduction); int release_pv_segment(struct pv_segment *peg, uint32_t area_reduction); int check_pv_segments(struct volume_group *vg); void merge_pv_segments(struct pv_segment *peg1, struct pv_segment *peg2); #endif lvm2-2.02.98/lib/metadata/segtype.h0000640000175000017500000001461112037016272015672 0ustar blankblank/* * 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 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 _SEGTYPES_H #define _SEGTYPES_H #include "metadata-exported.h" struct segtype_handler; struct cmd_context; struct dm_config_tree; struct lv_segment; struct lv_activate_opts; struct formatter; struct dm_config_node; struct dev_manager; /* Feature flags */ #define SEG_CAN_SPLIT 0x00000001U #define SEG_AREAS_STRIPED 0x00000002U #define SEG_AREAS_MIRRORED 0x00000004U #define SEG_SNAPSHOT 0x00000008U #define SEG_FORMAT1_SUPPORT 0x00000010U #define SEG_VIRTUAL 0x00000020U #define SEG_CANNOT_BE_ZEROED 0x00000040U #define SEG_MONITORED 0x00000080U #define SEG_REPLICATOR 0x00000100U #define SEG_REPLICATOR_DEV 0x00000200U #define SEG_RAID 0x00000400U #define SEG_THIN_POOL 0x00000800U #define SEG_THIN_VOLUME 0x00001000U #define SEG_UNKNOWN 0x80000000U #define seg_is_mirrored(seg) ((seg)->segtype->flags & SEG_AREAS_MIRRORED ? 1 : 0) #define seg_is_replicator(seg) ((seg)->segtype->flags & SEG_REPLICATOR ? 1 : 0) #define seg_is_replicator_dev(seg) ((seg)->segtype->flags & SEG_REPLICATOR_DEV ? 1 : 0) #define seg_is_striped(seg) ((seg)->segtype->flags & SEG_AREAS_STRIPED ? 1 : 0) #define seg_is_linear(seg) (seg_is_striped(seg) && ((seg)->area_count == 1)) #define seg_is_snapshot(seg) ((seg)->segtype->flags & SEG_SNAPSHOT ? 1 : 0) #define seg_is_virtual(seg) ((seg)->segtype->flags & SEG_VIRTUAL ? 1 : 0) #define seg_is_raid(seg) ((seg)->segtype->flags & SEG_RAID ? 1 : 0) #define seg_is_thin(seg) ((seg)->segtype->flags & (SEG_THIN_POOL|SEG_THIN_VOLUME) ? 1 : 0) #define seg_is_thin_pool(seg) ((seg)->segtype->flags & SEG_THIN_POOL ? 1 : 0) #define seg_is_thin_volume(seg) ((seg)->segtype->flags & SEG_THIN_VOLUME ? 1 : 0) #define seg_can_split(seg) ((seg)->segtype->flags & SEG_CAN_SPLIT ? 1 : 0) #define seg_cannot_be_zeroed(seg) ((seg)->segtype->flags & SEG_CANNOT_BE_ZEROED ? 1 : 0) #define seg_monitored(seg) ((seg)->segtype->flags & SEG_MONITORED ? 1 : 0) #define seg_unknown(seg) ((seg)->segtype->flags & SEG_UNKNOWN ? 1 : 0) #define segtype_is_striped(segtype) ((segtype)->flags & SEG_AREAS_STRIPED ? 1 : 0) #define segtype_is_mirrored(segtype) ((segtype)->flags & SEG_AREAS_MIRRORED ? 1 : 0) #define segtype_is_raid(segtype) ((segtype)->flags & SEG_RAID ? 1 : 0) #define segtype_is_thin(segtype) ((segtype)->flags & (SEG_THIN_POOL|SEG_THIN_VOLUME) ? 1 : 0) #define segtype_is_thin_pool(segtype) ((segtype)->flags & SEG_THIN_POOL ? 1 : 0) #define segtype_is_thin_volume(segtype) ((segtype)->flags & SEG_THIN_VOLUME ? 1 : 0) #define segtype_is_virtual(segtype) ((segtype)->flags & SEG_VIRTUAL ? 1 : 0) struct segment_type { struct dm_list list; /* Internal */ struct cmd_context *cmd; /* lvm_register_segtype() sets this. */ uint32_t flags; uint32_t parity_devs; /* Parity drives required by segtype */ struct segtype_handler *ops; const char *name; void *library; /* lvm_register_segtype() sets this. */ void *private; /* For the segtype handler to use. */ }; struct segtype_handler { const char *(*name) (const struct lv_segment * seg); const char *(*target_name) (const struct lv_segment *seg, const struct lv_activate_opts *laopts); void (*display) (const struct lv_segment * seg); int (*text_export) (const struct lv_segment * seg, struct formatter * f); int (*text_import_area_count) (const struct dm_config_node * sn, uint32_t *area_count); int (*text_import) (struct lv_segment * seg, const struct dm_config_node * sn, struct dm_hash_table * pv_hash); int (*merge_segments) (struct lv_segment * seg1, struct lv_segment * seg2); int (*add_target_line) (struct dev_manager *dm, struct dm_pool *mem, struct cmd_context *cmd, void **target_state, struct lv_segment *seg, const struct lv_activate_opts *laopts, struct dm_tree_node *node, uint64_t len, uint32_t *pvmove_mirror_count); int (*target_status_compatible) (const char *type); int (*check_transient_status) (struct lv_segment *seg, char *params); int (*target_percent) (void **target_state, percent_t *percent, struct dm_pool * mem, struct cmd_context *cmd, struct lv_segment *seg, char *params, uint64_t *total_numerator, uint64_t *total_denominator); int (*target_present) (struct cmd_context *cmd, const struct lv_segment *seg, unsigned *attributes); int (*modules_needed) (struct dm_pool *mem, const struct lv_segment *seg, struct dm_list *modules); void (*destroy) (struct segment_type * segtype); int (*target_monitored) (struct lv_segment *seg, int *pending); int (*target_monitor_events) (struct lv_segment *seg, int events); int (*target_unmonitor_events) (struct lv_segment *seg, int events); }; struct segment_type *get_segtype_from_string(struct cmd_context *cmd, const char *str); struct segtype_library; int lvm_register_segtype(struct segtype_library *seglib, struct segment_type *segtype); struct segment_type *init_striped_segtype(struct cmd_context *cmd); struct segment_type *init_zero_segtype(struct cmd_context *cmd); struct segment_type *init_error_segtype(struct cmd_context *cmd); struct segment_type *init_free_segtype(struct cmd_context *cmd); struct segment_type *init_unknown_segtype(struct cmd_context *cmd, const char *name); #ifdef RAID_INTERNAL int init_raid_segtypes(struct cmd_context *cmd, struct segtype_library *seglib); #endif #ifdef REPLICATOR_INTERNAL int init_replicator_segtype(struct cmd_context *cmd, struct segtype_library *seglib); #endif #ifdef THIN_INTERNAL int init_thin_segtypes(struct cmd_context *cmd, struct segtype_library *seglib); #endif #ifdef SNAPSHOT_INTERNAL struct segment_type *init_snapshot_segtype(struct cmd_context *cmd); #endif #ifdef MIRRORED_INTERNAL struct segment_type *init_mirrored_segtype(struct cmd_context *cmd); #endif #ifdef CRYPT_INTERNAL struct segment_type *init_crypt_segtype(struct cmd_context *cmd); #endif #endif lvm2-2.02.98/lib/metadata/metadata-exported.h0000640000175000017500000007563012037016272017632 0ustar blankblank/* * 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 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 is the representation of LVM metadata that is being adapted * for library export. */ #ifndef _LVM_METADATA_EXPORTED_H #define _LVM_METADATA_EXPORTED_H #include "uuid.h" #include "pv.h" #include "vg.h" #include "lv.h" #include "lvm-percent.h" #define MAX_STRIPES 128U #define SECTOR_SHIFT 9L #define SECTOR_SIZE ( 1L << SECTOR_SHIFT ) #define STRIPE_SIZE_MIN ( (unsigned) lvm_getpagesize() >> SECTOR_SHIFT) /* PAGESIZE in sectors */ #define STRIPE_SIZE_MAX ( 512L * 1024L >> SECTOR_SHIFT) /* 512 KB in sectors */ #define STRIPE_SIZE_LIMIT ((UINT_MAX >> 2) + 1) #define MAX_RESTRICTED_LVS 255 /* Used by FMT_RESTRICTED_LVIDS */ #define MAX_EXTENT_SIZE ((uint32_t) -1) /* Layer suffix */ #define MIRROR_SYNC_LAYER "_mimagetmp" /* Various flags */ /* Note that the bits no longer necessarily correspond to LVM1 disk format */ #define PARTIAL_VG UINT64_C(0x00000001) /* VG */ #define EXPORTED_VG UINT64_C(0x00000002) /* VG PV */ #define RESIZEABLE_VG UINT64_C(0x00000004) /* VG */ /* May any free extents on this PV be used or must they be left free? */ #define ALLOCATABLE_PV UINT64_C(0x00000008) /* PV */ //#define SPINDOWN_LV UINT64_C(0x00000010) /* LV */ //#define BADBLOCK_ON UINT64_C(0x00000020) /* LV */ #define VISIBLE_LV UINT64_C(0x00000040) /* LV */ #define FIXED_MINOR UINT64_C(0x00000080) /* LV */ /* FIXME Remove when metadata restructuring is completed */ #define SNAPSHOT UINT64_C(0x00001000) /* LV - internal use only */ #define PVMOVE UINT64_C(0x00002000) /* VG LV SEG */ #define LOCKED UINT64_C(0x00004000) /* LV */ #define MIRRORED UINT64_C(0x00008000) /* LV - internal use only */ //#define VIRTUAL UINT64_C(0x00010000) /* LV - internal use only */ #define MIRROR_LOG UINT64_C(0x00020000) /* LV */ #define MIRROR_IMAGE UINT64_C(0x00040000) /* LV */ #define LV_NOTSYNCED UINT64_C(0x00080000) /* LV */ #define LV_REBUILD UINT64_C(0x00100000) /* LV */ //#define PRECOMMITTED UINT64_C(0x00200000) /* VG - internal use only */ #define CONVERTING UINT64_C(0x00400000) /* LV */ #define MISSING_PV UINT64_C(0x00800000) /* PV */ #define PARTIAL_LV UINT64_C(0x01000000) /* LV - derived flag, not written out in metadata*/ //#define POSTORDER_FLAG UINT64_C(0x02000000) /* Not real flags, reserved for //#define POSTORDER_OPEN_FLAG UINT64_C(0x04000000) temporary use inside vg_read_internal. */ //#define VIRTUAL_ORIGIN UINT64_C(0x08000000) /* LV - internal use only */ #define MERGING UINT64_C(0x10000000) /* LV SEG */ #define REPLICATOR UINT64_C(0x20000000) /* LV -internal use only for replicator */ #define REPLICATOR_LOG UINT64_C(0x40000000) /* LV -internal use only for replicator-dev */ #define UNLABELLED_PV UINT64_C(0x80000000) /* PV -this PV had no label written yet */ #define RAID UINT64_C(0x0000000100000000) /* LV */ #define RAID_META UINT64_C(0x0000000200000000) /* LV */ #define RAID_IMAGE UINT64_C(0x0000000400000000) /* LV */ #define THIN_VOLUME UINT64_C(0x0000001000000000) /* LV */ #define THIN_POOL UINT64_C(0x0000002000000000) /* LV */ #define THIN_POOL_DATA UINT64_C(0x0000004000000000) /* LV */ #define THIN_POOL_METADATA UINT64_C(0x0000008000000000) /* LV */ #define LVM_READ UINT64_C(0x00000100) /* LV, VG */ #define LVM_WRITE UINT64_C(0x00000200) /* LV, VG */ #define CLUSTERED UINT64_C(0x00000400) /* VG */ //#define SHARED UINT64_C(0x00000800) /* VG */ /* Format features flags */ #define FMT_SEGMENTS 0x00000001U /* Arbitrary segment params? */ #define FMT_MDAS 0x00000002U /* Proper metadata areas? */ #define FMT_TAGS 0x00000004U /* Tagging? */ #define FMT_UNLIMITED_VOLS 0x00000008U /* Unlimited PVs/LVs? */ #define FMT_RESTRICTED_LVIDS 0x00000010U /* LVID <= 255 */ #define FMT_ORPHAN_ALLOCATABLE 0x00000020U /* Orphan PV allocatable? */ //#define FMT_PRECOMMIT 0x00000040U /* Supports pre-commit? */ #define FMT_RESIZE_PV 0x00000080U /* Supports pvresize? */ #define FMT_UNLIMITED_STRIPESIZE 0x00000100U /* Unlimited stripe size? */ #define FMT_RESTRICTED_READAHEAD 0x00000200U /* Readahead restricted to 2-120? */ /* Mirror conversion type flags */ #define MIRROR_BY_SEG 0x00000001U /* segment-by-segment mirror */ #define MIRROR_BY_LV 0x00000002U /* mirror using whole mimage LVs */ #define MIRROR_SKIP_INIT_SYNC 0x00000010U /* skip initial sync */ /* vg_read and vg_read_for_update flags */ #define READ_ALLOW_INCONSISTENT 0x00010000U #define READ_ALLOW_EXPORTED 0x00020000U #define READ_WITHOUT_LOCK 0x00040000U /* A meta-flag, useful with toollib for_each_* functions. */ #define READ_FOR_UPDATE 0x00100000U /* vg's "read_status" field */ #define FAILED_INCONSISTENT 0x00000001U #define FAILED_LOCKING 0x00000002U #define FAILED_NOTFOUND 0x00000004U #define FAILED_READ_ONLY 0x00000008U #define FAILED_EXPORTED 0x00000010U #define FAILED_RESIZEABLE 0x00000020U #define FAILED_CLUSTERED 0x00000040U #define FAILED_ALLOCATION 0x00000080U #define FAILED_EXIST 0x00000100U #define SUCCESS 0x00000000U #define VGMETADATACOPIES_ALL UINT32_MAX #define VGMETADATACOPIES_UNMANAGED 0 #define lv_is_thin_volume(lv) ((lv)->status & THIN_VOLUME ? 1 : 0) #define lv_is_thin_pool(lv) ((lv)->status & THIN_POOL ? 1 : 0) #define lv_is_used_thin_pool(lv) (lv_is_thin_pool(lv) && !dm_list_empty(&(lv)->segs_using_this_lv)) #define lv_is_thin_pool_data(lv) ((lv)->status & THIN_POOL_DATA ? 1 : 0) #define lv_is_thin_pool_metadata(lv) ((lv)->status & THIN_POOL_METADATA ? 1 : 0) #define lv_is_mirrored(lv) ((lv)->status & MIRRORED ? 1 : 0) #define lv_is_rlog(lv) ((lv)->status & REPLICATOR_LOG ? 1 : 0) #define lv_is_thin_type(lv) ((lv)->status & (THIN_POOL | THIN_VOLUME | THIN_POOL_DATA | THIN_POOL_METADATA) ? 1 : 0) #define lv_is_mirror_type(lv) ((lv)->status & (MIRROR_LOG | MIRROR_IMAGE | MIRRORED | PVMOVE) ? 1 : 0) #define lv_is_raid_type(lv) ((lv)->status & (RAID | RAID_IMAGE | RAID_META)) #define lv_is_virtual(lv) ((lv)->status & VIRTUAL) /* Ordered list - see lv_manip.c */ typedef enum { AREA_UNASSIGNED, AREA_PV, AREA_LV } area_type_t; /* * Whether or not to force an operation. */ typedef enum { PROMPT = 0, /* Issue yes/no prompt to confirm operation */ DONT_PROMPT = 1, /* Skip yes/no prompt */ DONT_PROMPT_OVERRIDE = 2 /* Skip prompt + override a second condition */ } force_t; typedef enum { THIN_DISCARDS_IGNORE, THIN_DISCARDS_NO_PASSDOWN, THIN_DISCARDS_PASSDOWN, } thin_discards_t; struct cmd_context; struct format_handler; struct labeller; struct format_type { struct dm_list list; struct cmd_context *cmd; struct format_handler *ops; struct dm_list mda_ops; /* List of permissible mda ops. */ struct labeller *labeller; const char *name; const char *alias; const char *orphan_vg_name; struct volume_group *orphan_vg; /* Only one ever exists. */ uint32_t features; void *library; void *private; }; struct pv_segment { struct dm_list list; /* Member of pv->segments: ordered list * covering entire data area on this PV */ struct physical_volume *pv; uint32_t pe; uint32_t len; struct lv_segment *lvseg; /* NULL if free space */ uint32_t lv_area; /* Index to area in LV segment */ }; #define pvseg_is_allocated(pvseg) ((pvseg)->lvseg) /* * Properties of each format instance type. * The primary role of the format_instance is to temporarily store metadata * area information we are working with. */ /* Include any existing PV ("on-disk") mdas during format_instance initialisation. */ #define FMT_INSTANCE_MDAS 0x00000002U /* * Include any auxiliary mdas during format_instance intialisation. * Currently, this includes metadata areas as defined by * metadata/dirs and metadata/raws setting. */ #define FMT_INSTANCE_AUX_MDAS 0x00000004U /* * Include any other format-specific mdas during format_instance initialisation. * For example metadata areas used during backup/restore/archive handling. */ #define FMT_INSTANCE_PRIVATE_MDAS 0x00000008U struct format_instance { unsigned ref_count; /* Refs to this fid from VG and PV structs */ struct dm_pool *mem; uint32_t type; const struct format_type *fmt; /* * Each mda in a vg is on exactly one of the below lists. * MDAs on the 'in_use' list will be read from / written to * disk, while MDAs on the 'ignored' list will not be read * or written to. */ /* FIXME: Try to use the index only. Remove these lists. */ struct dm_list metadata_areas_in_use; struct dm_list metadata_areas_ignored; struct dm_hash_table *metadata_areas_index; void *private; }; /* There will be one area for each stripe */ struct lv_segment_area { area_type_t type; union { struct { struct pv_segment *pvseg; } pv; struct { struct logical_volume *lv; uint32_t le; } lv; } u; }; struct lv_thin_message { struct dm_list list; /* Chained list of messages */ dm_thin_message_t type; /* Use dm thin message datatype */ union { struct logical_volume *lv; /* For: create_thin, create_snap, trim */ uint32_t delete_id; /* For delete, needs device_id */ } u; }; struct segment_type; /* List with vg_name, vgid and flags */ struct cmd_vg { struct dm_list list; const char *vg_name; const char *vgid; uint32_t flags; struct volume_group *vg; }; /* ++ Replicator datatypes */ typedef enum { REPLICATOR_STATE_PASSIVE, REPLICATOR_STATE_ACTIVE, NUM_REPLICATOR_STATE } replicator_state_t; struct replicator_site { struct dm_list list; /* Chained list of sites */ struct dm_list rdevices; /* Device list */ struct logical_volume *replicator; /* Reference to replicator */ const char *name; /* Site name */ const char *vg_name; /* VG name */ struct volume_group *vg; /* resolved vg (activate/deactive) */ unsigned site_index; replicator_state_t state; /* Active or pasive state of site */ dm_replicator_mode_t op_mode; /* Operation mode sync or async fail|warn|drop|stall */ uint64_t fall_behind_data; /* Bytes */ uint32_t fall_behind_ios; /* IO operations */ uint32_t fall_behind_timeout; /* Seconds */ }; struct replicator_device { struct dm_list list; /* Chained list of devices from same site */ struct lv_segment *replicator_dev; /* Reference to replicator-dev segment */ struct replicator_site *rsite; /* Reference to site parameters */ uint64_t device_index; const char *name; /* Device LV name */ struct logical_volume *lv; /* LV from replicator site's VG */ struct logical_volume *slog; /* Synclog lv from VG */ const char *slog_name; /* Debug - specify size of core synclog */ }; /* -- Replicator datatypes */ struct lv_segment { struct dm_list list; struct logical_volume *lv; const struct segment_type *segtype; uint32_t le; uint32_t len; uint64_t status; /* FIXME Fields depend on segment type */ uint32_t stripe_size; /* For stripe and RAID - in sectors */ uint32_t area_count; uint32_t area_len; uint32_t chunk_size; /* For snapshots/thin_pool. In sectors. */ /* For thin_pool, 128..2097152. */ struct logical_volume *origin; /* snap and thin */ struct logical_volume *cow; struct dm_list origin_list; uint32_t region_size; /* For mirrors, replicators - in sectors */ uint32_t extents_copied; struct logical_volume *log_lv; struct lv_segment *pvmove_source_seg; void *segtype_private; struct dm_list tags; struct lv_segment_area *areas; struct lv_segment_area *meta_areas; /* For RAID */ struct logical_volume *metadata_lv; /* For thin_pool */ uint64_t transaction_id; /* For thin_pool, thin */ uint64_t low_water_mark; /* For thin_pool */ unsigned zero_new_blocks; /* For thin_pool */ thin_discards_t discards; /* For thin_pool */ struct dm_list thin_messages; /* For thin_pool */ struct logical_volume *pool_lv; /* For thin */ uint32_t device_id; /* For thin, 24bit */ struct logical_volume *replicator;/* For replicator-devs - link to replicator LV */ struct logical_volume *rlog_lv; /* For replicators */ const char *rlog_type; /* For replicators */ uint64_t rdevice_index_highest; /* For replicators */ unsigned rsite_index_highest; /* For replicators */ }; #define seg_type(seg, s) (seg)->areas[(s)].type #define seg_pv(seg, s) (seg)->areas[(s)].u.pv.pvseg->pv #define seg_lv(seg, s) (seg)->areas[(s)].u.lv.lv #define seg_metalv(seg, s) (seg)->meta_areas[(s)].u.lv.lv #define seg_metatype(seg, s) (seg)->meta_areas[(s)].type struct pe_range { struct dm_list list; uint32_t start; /* PEs */ uint32_t count; /* PEs */ }; struct pv_list { struct dm_list list; struct physical_volume *pv; struct dm_list *mdas; /* Metadata areas */ struct dm_list *pe_ranges; /* Ranges of PEs e.g. for allocation */ }; struct lv_list { struct dm_list list; struct logical_volume *lv; }; struct pvcreate_params { int zero; uint64_t size; uint64_t data_alignment; uint64_t data_alignment_offset; int pvmetadatacopies; uint64_t pvmetadatasize; int64_t labelsector; struct id id; /* FIXME: redundant */ struct id *idp; /* 0 if no --uuid option */ uint64_t pe_start; uint32_t extent_count; uint32_t extent_size; const char *restorefile; /* 0 if no --restorefile option */ force_t force; unsigned yes; unsigned metadataignore; }; struct physical_volume *pvcreate_single(struct cmd_context *cmd, const char *pv_name, struct pvcreate_params *pp, int write_now); void pvcreate_params_set_defaults(struct pvcreate_params *pp); /* * Utility functions */ int vg_write(struct volume_group *vg); int vg_commit(struct volume_group *vg); void vg_revert(struct volume_group *vg); struct volume_group *vg_read_internal(struct cmd_context *cmd, const char *vg_name, const char *vgid, int warnings, int *consistent); struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name, int warnings, int scan_label_only); struct dm_list *get_pvs(struct cmd_context *cmd); /* * Add/remove LV to/from volume group */ int link_lv_to_vg(struct volume_group *vg, struct logical_volume *lv); int unlink_lv_from_vg(struct logical_volume *lv); void lv_set_visible(struct logical_volume *lv); void lv_set_hidden(struct logical_volume *lv); struct dm_list *get_vgnames(struct cmd_context *cmd, int include_internal); struct dm_list *get_vgids(struct cmd_context *cmd, int include_internal); int scan_vgs_for_pvs(struct cmd_context *cmd, int warnings); int pv_write(struct cmd_context *cmd, struct physical_volume *pv, int allow_non_orphan); int move_pv(struct volume_group *vg_from, struct volume_group *vg_to, const char *pv_name); int move_pvs_used_by_lv(struct volume_group *vg_from, struct volume_group *vg_to, const char *lv_name); int is_global_vg(const char *vg_name); int is_orphan_vg(const char *vg_name); int is_real_vg(const char *vg_name); int vg_missing_pv_count(const struct volume_group *vg); int vgs_are_compatible(struct cmd_context *cmd, struct volume_group *vg_from, struct volume_group *vg_to); uint32_t vg_lock_newname(struct cmd_context *cmd, const char *vgname); /* * Return a handle to VG metadata. */ struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name, const char *vgid, uint32_t flags); struct volume_group *vg_read_for_update(struct cmd_context *cmd, const char *vg_name, const char *vgid, uint32_t flags); /* * Test validity of a VG handle. */ uint32_t vg_read_error(struct volume_group *vg_handle); /* pe_start and pe_end relate to any existing data so that new metadata * areas can avoid overlap */ struct physical_volume *pv_create(const struct cmd_context *cmd, struct device *dev, struct id *id, uint64_t size, unsigned long data_alignment, unsigned long data_alignment_offset, uint64_t pe_start, uint32_t existing_extent_count, uint32_t existing_extent_size, uint64_t label_sector, unsigned pvmetadatacopies, uint64_t pvmetadatasize, unsigned metadataignore); int pv_resize(struct physical_volume *pv, struct volume_group *vg, uint64_t size); int pv_analyze(struct cmd_context *cmd, const char *pv_name, uint64_t label_sector); /* FIXME: move internal to library */ uint32_t pv_list_extents_free(const struct dm_list *pvh); struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name); int vg_remove_mdas(struct volume_group *vg); int vg_remove_check(struct volume_group *vg); void vg_remove_pvs(struct volume_group *vg); int vg_remove(struct volume_group *vg); int vg_rename(struct cmd_context *cmd, struct volume_group *vg, const char *new_name); int vg_extend(struct volume_group *vg, int pv_count, const char *const *pv_names, struct pvcreate_params *pp); int vg_reduce(struct volume_group *vg, const char *pv_name); int vg_change_tag(struct volume_group *vg, const char *tag, int add_tag); int vg_split_mdas(struct cmd_context *cmd, struct volume_group *vg_from, struct volume_group *vg_to); /* FIXME: Investigate refactoring these functions to take a pv ISO pv_list */ void add_pvl_to_vgs(struct volume_group *vg, struct pv_list *pvl); void del_pvl_from_vgs(struct volume_group *vg, struct pv_list *pvl); /* FIXME: refactor / unexport when lvremove liblvm refactoring dones */ int remove_lvs_in_vg(struct cmd_context *cmd, struct volume_group *vg, force_t force); /* * free_pv_fid() must be called on every struct physical_volume allocated * by pv_create, pv_read, find_pv_by_name or pv_by_path to free it when * no longer required. */ void free_pv_fid(struct physical_volume *pv); /* Manipulate LVs */ struct logical_volume *lv_create_empty(const char *name, union lvid *lvid, uint64_t status, alloc_policy_t alloc, struct volume_group *vg); /* Write out LV contents */ int set_lv(struct cmd_context *cmd, struct logical_volume *lv, uint64_t sectors, int value); int lv_change_tag(struct logical_volume *lv, const char *tag, int add_tag); /* Reduce the size of an LV by extents */ int lv_reduce(struct logical_volume *lv, uint32_t extents); /* Empty an LV prior to deleting it */ int lv_empty(struct logical_volume *lv); /* Empty an LV and add error segment */ int replace_lv_with_error_segment(struct logical_volume *lv); /* Entry point for all LV extent allocations */ int lv_extend(struct logical_volume *lv, const struct segment_type *segtype, uint32_t stripes, uint32_t stripe_size, uint32_t mirrors, uint32_t region_size, uint32_t extents, const char *thin_pool_name, struct dm_list *allocatable_pvs, alloc_policy_t alloc); /* lv must be part of lv->vg->lvs */ int lv_remove(struct logical_volume *lv); int lv_remove_single(struct cmd_context *cmd, struct logical_volume *lv, force_t force); int lv_remove_with_dependencies(struct cmd_context *cmd, struct logical_volume *lv, force_t force, unsigned level); int lv_rename(struct cmd_context *cmd, struct logical_volume *lv, const char *new_name); int lv_rename_update(struct cmd_context *cmd, struct logical_volume *lv, const char *new_name, int update_mda); uint64_t extents_from_size(struct cmd_context *cmd, uint64_t size, uint32_t extent_size); int update_pool_lv(struct logical_volume *lv, int activate); int get_pool_discards(const char *str, thin_discards_t *discards); const char *get_pool_discards_name(thin_discards_t discards); /* * Activation options */ typedef enum activation_change { CHANGE_AY = 0, /* activate */ CHANGE_AN = 1, /* deactivate */ CHANGE_AE = 2, /* activate exclusively */ CHANGE_ALY = 3, /* activate locally */ CHANGE_ALN = 4, /* deactivate locally */ CHANGE_AAY = 5 /* automatic activation */ } activation_change_t; /* FIXME: refactor and reduce the size of this struct! */ struct lvcreate_params { /* flags */ int snapshot; /* snap */ int thin; /* thin */ int create_thin_pool; /* thin */ int zero; /* all */ int major; /* all */ int minor; /* all */ int log_count; /* mirror */ int nosync; /* mirror */ activation_change_t activate; /* non-snapshot, non-mirror */ thin_discards_t discards; /* thin */ const char *origin; /* snap */ const char *pool; /* thin */ const char *vg_name; /* all */ const char *lv_name; /* all */ uint32_t stripes; /* striped */ uint32_t stripe_size; /* striped */ uint32_t chunk_size; /* snapshot */ uint32_t region_size; /* mirror */ uint32_t mirrors; /* mirror */ const struct segment_type *segtype; /* all */ /* size */ uint32_t extents; /* all */ uint32_t voriginextents; /* snapshot */ uint64_t voriginsize; /* snapshot */ uint32_t poolmetadataextents; /* thin pool */ uint64_t poolmetadatasize; /* thin pool */ struct dm_list *pvh; /* all */ uint32_t permission; /* all */ uint32_t read_ahead; /* all */ alloc_policy_t alloc; /* all */ struct dm_list tags; /* all */ }; int lv_create_single(struct volume_group *vg, struct lvcreate_params *lp); /* * Functions for layer manipulation */ int insert_layer_for_segments_on_pv(struct cmd_context *cmd, struct logical_volume *lv_where, struct logical_volume *layer_lv, uint64_t status, struct pv_list *pv, struct dm_list *lvs_changed); int remove_layers_for_segments(struct cmd_context *cmd, struct logical_volume *lv, struct logical_volume *layer_lv, uint64_t status_mask, struct dm_list *lvs_changed); int remove_layers_for_segments_all(struct cmd_context *cmd, struct logical_volume *layer_lv, uint64_t status_mask, struct dm_list *lvs_changed); int split_parent_segments_for_layer(struct cmd_context *cmd, struct logical_volume *layer_lv); int remove_layer_from_lv(struct logical_volume *lv, struct logical_volume *layer_lv); struct logical_volume *insert_layer_for_lv(struct cmd_context *cmd, struct logical_volume *lv_where, uint64_t status, const char *layer_suffix); /* Find a PV within a given VG */ struct pv_list *find_pv_in_vg(const struct volume_group *vg, const char *pv_name); struct pv_list *find_pv_in_vg_by_uuid(const struct volume_group *vg, const struct id *id); /* Find an LV within a given VG */ struct lv_list *find_lv_in_vg(const struct volume_group *vg, const char *lv_name); /* FIXME Merge these functions with ones above */ struct logical_volume *find_lv(const struct volume_group *vg, const char *lv_name); struct physical_volume *find_pv_by_name(struct cmd_context *cmd, const char *pv_name); const char *find_vgname_from_pvname(struct cmd_context *cmd, const char *pvname); const char *find_vgname_from_pvid(struct cmd_context *cmd, const char *pvid); /* Find LV segment containing given LE */ struct lv_segment *first_seg(const struct logical_volume *lv); struct lv_segment *last_seg(const struct logical_volume *lv); /* * Useful functions for managing snapshots. */ int lv_is_origin(const struct logical_volume *lv); int lv_is_virtual_origin(const struct logical_volume *lv); int lv_is_cow(const struct logical_volume *lv); int lv_is_merging_origin(const struct logical_volume *origin); int lv_is_merging_cow(const struct logical_volume *snapshot); /* Test if given LV is visible from user's perspective */ int lv_is_visible(const struct logical_volume *lv); int pv_is_in_vg(struct volume_group *vg, struct physical_volume *pv); struct lv_segment *find_merging_cow(const struct logical_volume *origin); /* Given a cow LV, return return the snapshot lv_segment that uses it */ struct lv_segment *find_cow(const struct logical_volume *lv); /* Given a cow LV, return its origin */ struct logical_volume *origin_from_cow(const struct logical_volume *lv); void init_snapshot_seg(struct lv_segment *seg, struct logical_volume *origin, struct logical_volume *cow, uint32_t chunk_size, int merge); void init_snapshot_merge(struct lv_segment *cow_seg, struct logical_volume *origin); void clear_snapshot_merge(struct logical_volume *origin); int vg_add_snapshot(struct logical_volume *origin, struct logical_volume *cow, union lvid *lvid, uint32_t extent_count, uint32_t chunk_size); int vg_remove_snapshot(struct logical_volume *cow); int vg_check_status(const struct volume_group *vg, uint64_t status); /* * Check if the VG reached maximal LVs count (if set) */ int vg_max_lv_reached(struct volume_group *vg); /* * Mirroring functions */ struct lv_segment *find_mirror_seg(struct lv_segment *seg); int lv_add_mirrors(struct cmd_context *cmd, struct logical_volume *lv, uint32_t mirrors, uint32_t stripes, uint32_t stripe_size, uint32_t region_size, uint32_t log_count, struct dm_list *pvs, alloc_policy_t alloc, uint32_t flags); int lv_split_mirror_images(struct logical_volume *lv, const char *split_lv_name, uint32_t split_count, struct dm_list *removable_pvs); int lv_remove_mirrors(struct cmd_context *cmd, struct logical_volume *lv, uint32_t mirrors, uint32_t log_count, int (*is_removable)(struct logical_volume *, void *), void *removable_baton, uint64_t status_mask); int is_temporary_mirror_layer(const struct logical_volume *lv); struct logical_volume * find_temporary_mirror(const struct logical_volume *lv); uint32_t lv_mirror_count(const struct logical_volume *lv); uint32_t adjusted_mirror_region_size(uint32_t extent_size, uint32_t extents, uint32_t region_size); int remove_mirrors_from_segments(struct logical_volume *lv, uint32_t new_mirrors, uint64_t status_mask); int add_mirrors_to_segments(struct cmd_context *cmd, struct logical_volume *lv, uint32_t mirrors, uint32_t region_size, struct dm_list *allocatable_pvs, alloc_policy_t alloc); int remove_mirror_images(struct logical_volume *lv, uint32_t num_mirrors, int (*is_removable)(struct logical_volume *, void *), void *removable_baton, unsigned remove_log); int add_mirror_images(struct cmd_context *cmd, struct logical_volume *lv, uint32_t mirrors, uint32_t stripes, uint32_t stripe_size, uint32_t region_size, struct dm_list *allocatable_pvs, alloc_policy_t alloc, uint32_t log_count); struct logical_volume *detach_mirror_log(struct lv_segment *seg); int attach_mirror_log(struct lv_segment *seg, struct logical_volume *lv); int remove_mirror_log(struct cmd_context *cmd, struct logical_volume *lv, struct dm_list *removable_pvs, int force); int add_mirror_log(struct cmd_context *cmd, struct logical_volume *lv, uint32_t log_count, uint32_t region_size, struct dm_list *allocatable_pvs, alloc_policy_t alloc); #if 0 /* FIXME: reconfigure_mirror_images: remove this code? */ int reconfigure_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirrors, struct dm_list *removable_pvs, unsigned remove_log); #endif int collapse_mirrored_lv(struct logical_volume *lv); int shift_mirror_images(struct lv_segment *mirrored_seg, unsigned mimage); /* ++ metadata/replicator_manip.c */ int replicator_add_replicator_dev(struct logical_volume *replicator_lv, struct lv_segment *rdev_seg); struct logical_volume *replicator_remove_replicator_dev(struct lv_segment *rdev_seg); int replicator_add_rlog(struct lv_segment *replicator_seg, struct logical_volume *rlog_lv); struct logical_volume *replicator_remove_rlog(struct lv_segment *replicator_seg); int replicator_dev_add_slog(struct replicator_device *rdev, struct logical_volume *slog_lv); struct logical_volume *replicator_dev_remove_slog(struct replicator_device *rdev); int replicator_dev_add_rimage(struct replicator_device *rdev, struct logical_volume *lv); struct logical_volume *replicator_dev_remove_rimage(struct replicator_device *rdev); int lv_is_active_replicator_dev(const struct logical_volume *lv); int lv_is_replicator(const struct logical_volume *lv); int lv_is_replicator_dev(const struct logical_volume *lv); int lv_is_rimage(const struct logical_volume *lv); int lv_is_slog(const struct logical_volume *lv); struct logical_volume *first_replicator_dev(const struct logical_volume *lv); /* -- metadata/replicator_manip.c */ /* ++ metadata/raid_manip.c */ int lv_is_raid_with_tracking(const struct logical_volume *lv); uint32_t lv_raid_image_count(const struct logical_volume *lv); int lv_raid_change_image_count(struct logical_volume *lv, uint32_t new_count, struct dm_list *pvs); int lv_raid_split(struct logical_volume *lv, const char *split_name, uint32_t new_count, struct dm_list *splittable_pvs); int lv_raid_split_and_track(struct logical_volume *lv, struct dm_list *splittable_pvs); int lv_raid_merge(struct logical_volume *lv); int lv_raid_reshape(struct logical_volume *lv, const struct segment_type *new_segtype); int lv_raid_replace(struct logical_volume *lv, struct dm_list *remove_pvs, struct dm_list *allocate_pvs); /* -- metadata/raid_manip.c */ struct cmd_vg *cmd_vg_add(struct dm_pool *mem, struct dm_list *cmd_vgs, const char *vg_name, const char *vgid, uint32_t flags); struct cmd_vg *cmd_vg_lookup(struct dm_list *cmd_vgs, const char *vg_name, const char *vgid); int cmd_vg_read(struct cmd_context *cmd, struct dm_list *cmd_vgs); void free_cmd_vgs(struct dm_list *cmd_vgs); int find_replicator_vgs(struct logical_volume *lv); int lv_read_replicator_vgs(struct logical_volume *lv); void lv_release_replicator_vgs(struct logical_volume *lv); struct logical_volume *find_pvmove_lv(struct volume_group *vg, struct device *dev, uint64_t lv_type); struct logical_volume *find_pvmove_lv_from_pvname(struct cmd_context *cmd, struct volume_group *vg, const char *name, const char *uuid, uint64_t lv_type); struct logical_volume *find_pvmove_lv_in_lv(struct logical_volume *lv); const char *get_pvmove_pvname_from_lv(struct logical_volume *lv); const char *get_pvmove_pvname_from_lv_mirr(struct logical_volume *lv_mirr); percent_t copy_percent(const struct logical_volume *lv_mirr); struct dm_list *lvs_using_lv(struct cmd_context *cmd, struct volume_group *vg, struct logical_volume *lv); uint32_t find_free_lvnum(struct logical_volume *lv); char *generate_lv_name(struct volume_group *vg, const char *format, char *buffer, size_t len); /* * Begin skeleton for external LVM library */ int pv_change_metadataignore(struct physical_volume *pv, uint32_t mda_ignore); int vg_check_write_mode(struct volume_group *vg); #define vg_is_clustered(vg) (vg_status((vg)) & CLUSTERED) #define vg_is_exported(vg) (vg_status((vg)) & EXPORTED_VG) #define vg_is_resizeable(vg) (vg_status((vg)) & RESIZEABLE_VG) int lv_has_unknown_segments(const struct logical_volume *lv); int vg_has_unknown_segments(const struct volume_group *vg); int vg_mark_partial_lvs(struct volume_group *vg, int clear); struct vgcreate_params { const char *vg_name; uint32_t extent_size; size_t max_pv; size_t max_lv; alloc_policy_t alloc; int clustered; /* FIXME: put this into a 'status' variable instead? */ uint32_t vgmetadatacopies; }; int vgcreate_params_validate(struct cmd_context *cmd, struct vgcreate_params *vp); int validate_vg_rename_params(struct cmd_context *cmd, const char *vg_name_old, const char *vg_name_new); #endif lvm2-2.02.98/lib/metadata/metadata.c0000640000175000017500000034471712037016272016002 0ustar blankblank/* * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU 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 "device.h" #include "metadata.h" #include "toolcontext.h" #include "lvm-string.h" #include "lvm-file.h" #include "lvmcache.h" #include "lvmetad.h" #include "memlock.h" #include "str_list.h" #include "pv_alloc.h" #include "segtype.h" #include "activate.h" #include "display.h" #include "locking.h" #include "archiver.h" #include "defaults.h" #include #include static struct physical_volume *_pv_read(struct cmd_context *cmd, struct dm_pool *pvmem, const char *pv_name, struct format_instance *fid, int warnings, int scan_label_only); static struct physical_volume *_find_pv_by_name(struct cmd_context *cmd, const char *pv_name); static struct pv_list *_find_pv_in_vg(const struct volume_group *vg, const char *pv_name); static struct pv_list *_find_pv_in_vg_by_uuid(const struct volume_group *vg, const struct id *id); static uint32_t _vg_bad_status_bits(const struct volume_group *vg, uint64_t status); const char _really_init[] = "Really INITIALIZE physical volume \"%s\" of volume group \"%s\" [y/n]? "; static int _alignment_overrides_default(unsigned long data_alignment, unsigned long default_pe_align) { return data_alignment && (default_pe_align % data_alignment); } unsigned long set_pe_align(struct physical_volume *pv, unsigned long data_alignment) { unsigned long default_pe_align, temp_pe_align; if (pv->pe_align) goto out; if (data_alignment) { /* Always use specified data_alignment */ pv->pe_align = data_alignment; goto out; } default_pe_align = find_config_tree_int(pv->fmt->cmd, "devices/default_data_alignment", DEFAULT_DATA_ALIGNMENT); if (default_pe_align) /* align on 1 MiB multiple */ default_pe_align *= DEFAULT_PE_ALIGN; else /* align on 64 KiB multiple (old default) */ default_pe_align = DEFAULT_PE_ALIGN_OLD; pv->pe_align = MAX((default_pe_align << SECTOR_SHIFT), lvm_getpagesize()) >> SECTOR_SHIFT; if (!pv->dev) goto out; /* * Align to stripe-width of underlying md device if present */ if (find_config_tree_bool(pv->fmt->cmd, "devices/md_chunk_alignment", DEFAULT_MD_CHUNK_ALIGNMENT)) { temp_pe_align = dev_md_stripe_width(pv->fmt->cmd->sysfs_dir, pv->dev); if (_alignment_overrides_default(temp_pe_align, default_pe_align)) pv->pe_align = MAX(pv->pe_align, temp_pe_align); } /* * Align to topology's minimum_io_size or optimal_io_size if present * - 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) */ if (find_config_tree_bool(pv->fmt->cmd, "devices/data_alignment_detection", DEFAULT_DATA_ALIGNMENT_DETECTION)) { temp_pe_align = dev_minimum_io_size(pv->fmt->cmd->sysfs_dir, pv->dev); if (_alignment_overrides_default(temp_pe_align, default_pe_align)) pv->pe_align = MAX(pv->pe_align, temp_pe_align); temp_pe_align = dev_optimal_io_size(pv->fmt->cmd->sysfs_dir, pv->dev); if (_alignment_overrides_default(temp_pe_align, default_pe_align)) pv->pe_align = MAX(pv->pe_align, temp_pe_align); } out: log_very_verbose("%s: Setting PE alignment to %lu sectors.", dev_name(pv->dev), pv->pe_align); return pv->pe_align; } unsigned long set_pe_align_offset(struct physical_volume *pv, unsigned long data_alignment_offset) { if (pv->pe_align_offset) goto out; if (data_alignment_offset) { /* Always use specified data_alignment_offset */ pv->pe_align_offset = data_alignment_offset; goto out; } if (!pv->dev) goto out; if (find_config_tree_bool(pv->fmt->cmd, "devices/data_alignment_offset_detection", DEFAULT_DATA_ALIGNMENT_OFFSET_DETECTION)) { int align_offset = dev_alignment_offset(pv->fmt->cmd->sysfs_dir, pv->dev); /* must handle a -1 alignment_offset; means dev is misaligned */ if (align_offset < 0) align_offset = 0; pv->pe_align_offset = MAX(pv->pe_align_offset, align_offset); } out: log_very_verbose("%s: Setting PE alignment offset to %lu sectors.", dev_name(pv->dev), pv->pe_align_offset); return pv->pe_align_offset; } void add_pvl_to_vgs(struct volume_group *vg, struct pv_list *pvl) { dm_list_add(&vg->pvs, &pvl->list); vg->pv_count++; pvl->pv->vg = vg; pv_set_fid(pvl->pv, vg->fid); } void del_pvl_from_vgs(struct volume_group *vg, struct pv_list *pvl) { struct lvmcache_info *info; vg->pv_count--; dm_list_del(&pvl->list); pvl->pv->vg = vg->fid->fmt->orphan_vg; /* orphan */ if ((info = lvmcache_info_from_pvid((const char *) &pvl->pv->id, 0))) lvmcache_fid_add_mdas(info, vg->fid->fmt->orphan_vg->fid, (const char *) &pvl->pv->id, ID_LEN); pv_set_fid(pvl->pv, vg->fid->fmt->orphan_vg->fid); } /** * add_pv_to_vg - Add a physical volume to a volume group * @vg - volume group to add to * @pv_name - name of the pv (to be removed) * @pv - physical volume to add to volume group * @pp - physical volume creation params (OPTIONAL) * * Returns: * 0 - failure * 1 - success * FIXME: remove pv_name - obtain safely from pv */ int add_pv_to_vg(struct volume_group *vg, const char *pv_name, struct physical_volume *pv, struct pvcreate_params *pp) { struct pv_to_create *pvc; struct pv_list *pvl; struct format_instance *fid = vg->fid; struct dm_pool *mem = vg->vgmem; char uuid[64] __attribute__((aligned(8))); log_verbose("Adding physical volume '%s' to volume group '%s'", pv_name, vg->name); if (!(pvl = dm_pool_zalloc(mem, sizeof(*pvl)))) { log_error("pv_list allocation for '%s' failed", pv_name); return 0; } if (!is_orphan_vg(pv->vg_name)) { log_error("Physical volume '%s' is already in volume group " "'%s'", pv_name, pv->vg_name); return 0; } if (pv->fmt != fid->fmt) { log_error("Physical volume %s is of different format type (%s)", pv_name, pv->fmt->name); return 0; } /* Ensure PV doesn't depend on another PV already in the VG */ if (pv_uses_vg(pv, vg)) { log_error("Physical volume %s might be constructed from same " "volume group %s", pv_name, vg->name); return 0; } if (!(pv->vg_name = dm_pool_strdup(mem, vg->name))) { log_error("vg->name allocation failed for '%s'", pv_name); return 0; } memcpy(&pv->vgid, &vg->id, sizeof(vg->id)); /* Units of 512-byte sectors */ pv->pe_size = vg->extent_size; /* * pe_count must always be calculated by pv_setup */ pv->pe_alloc_count = 0; if (!fid->fmt->ops->pv_setup(fid->fmt, pv, vg)) { log_error("Format-specific setup of physical volume '%s' " "failed.", pv_name); return 0; } if (_find_pv_in_vg(vg, pv_name) || _find_pv_in_vg_by_uuid(vg, &pv->id)) { if (!id_write_format(&pv->id, uuid, sizeof(uuid))) { stack; uuid[0] = '\0'; } log_error("Physical volume '%s (%s)' already in the VG.", pv_name, uuid); return 0; } if (vg->pv_count && (vg->pv_count == vg->max_pv)) { log_error("No space for '%s' - volume group '%s' " "holds max %d physical volume(s).", pv_name, vg->name, vg->max_pv); return 0; } if (!alloc_pv_segment_whole_pv(mem, pv)) return_0; if ((uint64_t) vg->extent_count + pv->pe_count > MAX_EXTENT_COUNT) { log_error("Unable to add %s to %s: new extent count (%" PRIu64 ") exceeds limit (%" PRIu32 ").", pv_name, vg->name, (uint64_t) vg->extent_count + pv->pe_count, MAX_EXTENT_COUNT); return 0; } pvl->pv = pv; add_pvl_to_vgs(vg, pvl); vg->extent_count += pv->pe_count; vg->free_count += pv->pe_count; if (pv->status & UNLABELLED_PV) { if (!(pvc = dm_pool_zalloc(mem, sizeof(*pvc)))) { log_error("pv_to_create allocation for '%s' failed", pv_name); return 0; } pvc->pv = pv; pvc->pp = pp; dm_list_add(&vg->pvs_to_create, &pvc->list); } return 1; } static int _copy_pv(struct dm_pool *pvmem, struct physical_volume *pv_to, struct physical_volume *pv_from) { memcpy(pv_to, pv_from, sizeof(*pv_to)); /* We must use pv_set_fid here to update the reference counter! */ pv_to->fid = NULL; pv_set_fid(pv_to, pv_from->fid); if (!(pv_to->vg_name = dm_pool_strdup(pvmem, pv_from->vg_name))) return_0; if (!str_list_dup(pvmem, &pv_to->tags, &pv_from->tags)) return_0; if (!peg_dup(pvmem, &pv_to->segments, &pv_from->segments)) return_0; return 1; } static struct pv_list *_copy_pvl(struct dm_pool *pvmem, struct pv_list *pvl_from) { struct pv_list *pvl_to = NULL; if (!(pvl_to = dm_pool_zalloc(pvmem, sizeof(*pvl_to)))) return_NULL; if (!(pvl_to->pv = dm_pool_alloc(pvmem, sizeof(*pvl_to->pv)))) goto_bad; if(!_copy_pv(pvmem, pvl_to->pv, pvl_from->pv)) goto_bad; return pvl_to; bad: dm_pool_free(pvmem, pvl_to); return NULL; } int get_pv_from_vg_by_id(const struct format_type *fmt, const char *vg_name, const char *vgid, const char *pvid, struct physical_volume *pv) { struct volume_group *vg; struct pv_list *pvl; int r = 0, consistent = 0; if (!(vg = vg_read_internal(fmt->cmd, vg_name, vgid, 1, &consistent))) { log_error("get_pv_from_vg_by_id: vg_read_internal failed to read VG %s", vg_name); return 0; } if (!consistent) log_warn("WARNING: Volume group %s is not consistent", vg_name); dm_list_iterate_items(pvl, &vg->pvs) { if (id_equal(&pvl->pv->id, (const struct id *) pvid)) { if (!_copy_pv(fmt->cmd->mem, pv, pvl->pv)) { log_error("internal PV duplication failed"); r = 0; goto out; } r = 1; goto out; } } out: release_vg(vg); return r; } int move_pv(struct volume_group *vg_from, struct volume_group *vg_to, const char *pv_name) { struct physical_volume *pv; struct pv_list *pvl; /* FIXME: handle tags */ if (!(pvl = find_pv_in_vg(vg_from, pv_name))) { log_error("Physical volume %s not in volume group %s", pv_name, vg_from->name); return 0; } if (_vg_bad_status_bits(vg_from, RESIZEABLE_VG) || _vg_bad_status_bits(vg_to, RESIZEABLE_VG)) return 0; del_pvl_from_vgs(vg_from, pvl); add_pvl_to_vgs(vg_to, pvl); pv = pvl->pv; vg_from->extent_count -= pv_pe_count(pv); vg_to->extent_count += pv_pe_count(pv); vg_from->free_count -= pv_pe_count(pv) - pv_pe_alloc_count(pv); vg_to->free_count += pv_pe_count(pv) - pv_pe_alloc_count(pv); return 1; } int move_pvs_used_by_lv(struct volume_group *vg_from, struct volume_group *vg_to, const char *lv_name) { struct lv_segment *lvseg; unsigned s; struct lv_list *lvl; struct logical_volume *lv; /* FIXME: handle tags */ if (!(lvl = find_lv_in_vg(vg_from, lv_name))) { log_error("Logical volume %s not in volume group %s", lv_name, vg_from->name); return 0; } if (_vg_bad_status_bits(vg_from, RESIZEABLE_VG) || _vg_bad_status_bits(vg_to, RESIZEABLE_VG)) return 0; dm_list_iterate_items(lvseg, &lvl->lv->segments) { if (lvseg->log_lv) if (!move_pvs_used_by_lv(vg_from, vg_to, lvseg->log_lv->name)) return_0; for (s = 0; s < lvseg->area_count; s++) { if (seg_type(lvseg, s) == AREA_PV) { if (!move_pv(vg_from, vg_to, pv_dev_name(seg_pv(lvseg, s)))) return_0; } else if (seg_type(lvseg, s) == AREA_LV) { lv = seg_lv(lvseg, s); if (!move_pvs_used_by_lv(vg_from, vg_to, lv->name)) return_0; } } } return 1; } static int validate_new_vg_name(struct cmd_context *cmd, const char *vg_name) { static char vg_path[PATH_MAX]; if (!validate_name(vg_name)) return_0; snprintf(vg_path, sizeof(vg_path), "%s%s", cmd->dev_dir, vg_name); if (path_exists(vg_path)) { log_error("%s: already exists in filesystem", vg_path); return 0; } return 1; } int validate_vg_rename_params(struct cmd_context *cmd, const char *vg_name_old, const char *vg_name_new) { unsigned length; char *dev_dir; dev_dir = cmd->dev_dir; length = strlen(dev_dir); /* Check sanity of new name */ if (strlen(vg_name_new) > NAME_LEN - length - 2) { log_error("New volume group path exceeds maximum length " "of %d!", NAME_LEN - length - 2); return 0; } if (!validate_new_vg_name(cmd, vg_name_new)) { log_error("New volume group name \"%s\" is invalid", vg_name_new); return 0; } if (!strcmp(vg_name_old, vg_name_new)) { log_error("Old and new volume group names must differ"); return 0; } return 1; } int vg_rename(struct cmd_context *cmd, struct volume_group *vg, const char *new_name) { struct dm_pool *mem = vg->vgmem; struct pv_list *pvl; vg->old_name = vg->name; if (!(vg->name = dm_pool_strdup(mem, new_name))) { log_error("vg->name allocation failed for '%s'", new_name); return 0; } dm_list_iterate_items(pvl, &vg->pvs) { if (!(pvl->pv->vg_name = dm_pool_strdup(mem, new_name))) { log_error("pv->vg_name allocation failed for '%s'", pv_dev_name(pvl->pv)); return 0; } } return 1; } int remove_lvs_in_vg(struct cmd_context *cmd, struct volume_group *vg, force_t force) { struct dm_list *lst; struct lv_list *lvl; while ((lst = dm_list_first(&vg->lvs))) { lvl = dm_list_item(lst, struct lv_list); if (!lv_remove_with_dependencies(cmd, lvl->lv, force, 0)) return 0; } return 1; } int vg_remove_check(struct volume_group *vg) { unsigned lv_count; if (vg_read_error(vg) || vg_missing_pv_count(vg)) { log_error("Volume group \"%s\" not found, is inconsistent " "or has PVs missing.", vg ? vg->name : ""); log_error("Consider vgreduce --removemissing if metadata " "is inconsistent."); return 0; } if (!vg_check_status(vg, EXPORTED_VG)) return 0; lv_count = vg_visible_lvs(vg); if (lv_count) { log_error("Volume group \"%s\" still contains %u " "logical volume(s)", vg->name, lv_count); return 0; } if (!archive(vg)) return 0; return 1; } void vg_remove_pvs(struct volume_group *vg) { struct pv_list *pvl, *tpvl; dm_list_iterate_items_safe(pvl, tpvl, &vg->pvs) { del_pvl_from_vgs(vg, pvl); dm_list_add(&vg->removed_pvs, &pvl->list); } } int vg_remove(struct volume_group *vg) { struct physical_volume *pv; struct pv_list *pvl; int ret = 1; if (!lock_vol(vg->cmd, VG_ORPHANS, LCK_VG_WRITE)) { log_error("Can't get lock for orphan PVs"); return 0; } if (!vg_remove_mdas(vg)) { log_error("vg_remove_mdas %s failed", vg->name); unlock_vg(vg->cmd, VG_ORPHANS); return 0; } /* init physical volumes */ dm_list_iterate_items(pvl, &vg->removed_pvs) { pv = pvl->pv; if (is_missing_pv(pv)) continue; log_verbose("Removing physical volume \"%s\" from " "volume group \"%s\"", pv_dev_name(pv), vg->name); pv->vg_name = vg->fid->fmt->orphan_vg_name; pv->status = ALLOCATABLE_PV; if (!dev_get_size(pv_dev(pv), &pv->size)) { log_error("%s: Couldn't get size.", pv_dev_name(pv)); ret = 0; continue; } /* FIXME Write to same sector label was read from */ if (!pv_write(vg->cmd, pv, 0)) { log_error("Failed to remove physical volume \"%s\"" " from volume group \"%s\"", pv_dev_name(pv), vg->name); ret = 0; } } /* FIXME Handle partial failures from above. */ if (!lvmetad_vg_remove(vg)) stack; if (!backup_remove(vg->cmd, vg->name)) stack; if (ret) log_print_unless_silent("Volume group \"%s\" successfully removed", vg->name); else log_error("Volume group \"%s\" not properly removed", vg->name); unlock_vg(vg->cmd, VG_ORPHANS); return ret; } /* * Extend a VG by a single PV / device path * * Parameters: * - vg: handle of volume group to extend by 'pv_name' * - pv_name: device path of PV to add to VG * - pp: parameters to pass to implicit pvcreate; if NULL, do not pvcreate * */ static int vg_extend_single_pv(struct volume_group *vg, char *pv_name, struct pvcreate_params *pp) { struct physical_volume *pv; if (!(pv = pv_by_path(vg->fid->fmt->cmd, pv_name))) stack; if (!pv && !pp) { log_error("%s not identified as an existing " "physical volume", pv_name); return 0; } else if (!pv && pp) { if (!(pv = pvcreate_single(vg->cmd, pv_name, pp, 0))) return_0; } if (!add_pv_to_vg(vg, pv_name, pv, pp)) { free_pv_fid(pv); return_0; } return 1; } /* * Extend a VG by a single PV / device path * * Parameters: * - vg: handle of volume group to extend by 'pv_name' * - pv_count: count of device paths of PVs * - pv_names: device paths of PVs to add to VG * - pp: parameters to pass to implicit pvcreate; if NULL, do not pvcreate * */ int vg_extend(struct volume_group *vg, int pv_count, const char *const *pv_names, struct pvcreate_params *pp) { int i; char *pv_name; if (_vg_bad_status_bits(vg, RESIZEABLE_VG)) return_0; /* attach each pv */ for (i = 0; i < pv_count; i++) { if (!(pv_name = dm_strdup(pv_names[i]))) { log_error("Failed to duplicate pv name %s.", pv_names[i]); return 0; } dm_unescape_colons_and_at_signs(pv_name, NULL, NULL); if (!vg_extend_single_pv(vg, pv_name, pp)) { log_error("Unable to add physical volume '%s' to " "volume group '%s'.", pv_name, vg->name); dm_free(pv_name); return 0; } dm_free(pv_name); } /* FIXME Decide whether to initialise and add new mdahs to format instance */ return 1; } /* FIXME: use this inside vgreduce_single? */ int vg_reduce(struct volume_group *vg, const char *pv_name) { struct physical_volume *pv; struct pv_list *pvl; if (_vg_bad_status_bits(vg, RESIZEABLE_VG)) return 0; if (!archive(vg)) goto bad; /* remove each pv */ if (!(pvl = find_pv_in_vg(vg, pv_name))) { log_error("Physical volume %s not in volume group %s.", pv_name, vg->name); goto bad; } pv = pvl->pv; if (pv_pe_alloc_count(pv)) { log_error("Physical volume %s still in use.", pv_name); goto bad; } if (!dev_get_size(pv_dev(pv), &pv->size)) { log_error("%s: Couldn't get size.", pv_name); goto bad; } vg->free_count -= pv_pe_count(pv) - pv_pe_alloc_count(pv); vg->extent_count -= pv_pe_count(pv); del_pvl_from_vgs(vg, pvl); /* add pv to the remove_pvs list */ dm_list_add(&vg->removed_pvs, &pvl->list); return 1; bad: log_error("Unable to remove physical volume '%s' from " "volume group '%s'.", pv_name, vg->name); return 0; } int lv_change_tag(struct logical_volume *lv, const char *tag, int add_tag) { char *tag_new; if (!(lv->vg->fid->fmt->features & FMT_TAGS)) { log_error("Logical volume %s/%s does not support tags", lv->vg->name, lv->name); return 0; } if (add_tag) { if (!(tag_new = dm_pool_strdup(lv->vg->vgmem, tag))) { log_error("Failed to duplicate tag %s from %s/%s", tag, lv->vg->name, lv->name); return 0; } if (!str_list_add(lv->vg->vgmem, &lv->tags, tag_new)) { log_error("Failed to add tag %s to %s/%s", tag, lv->vg->name, lv->name); return 0; } } else str_list_del(&lv->tags, tag); return 1; } int vg_change_tag(struct volume_group *vg, const char *tag, int add_tag) { char *tag_new; if (!(vg->fid->fmt->features & FMT_TAGS)) { log_error("Volume group %s does not support tags", vg->name); return 0; } if (add_tag) { if (!(tag_new = dm_pool_strdup(vg->vgmem, tag))) { log_error("Failed to duplicate tag %s from %s", tag, vg->name); return 0; } if (!str_list_add(vg->vgmem, &vg->tags, tag_new)) { log_error("Failed to add tag %s to volume group %s", tag, vg->name); return 0; } } else str_list_del(&vg->tags, tag); return 1; } const char *strip_dir(const char *vg_name, const char *dev_dir) { size_t len = strlen(dev_dir); if (!strncmp(vg_name, dev_dir, len)) vg_name += len; return vg_name; } /* * Validate parameters to vg_create() before calling. * FIXME: Move inside vg_create library function. * FIXME: Change vgcreate_params struct to individual gets/sets */ int vgcreate_params_validate(struct cmd_context *cmd, struct vgcreate_params *vp) { if (!validate_new_vg_name(cmd, vp->vg_name)) { log_error("New volume group name \"%s\" is invalid", vp->vg_name); return 1; } if (vp->alloc == ALLOC_INHERIT) { log_error("Volume Group allocation policy cannot inherit " "from anything"); return 1; } if (!vp->extent_size) { log_error("Physical extent size may not be zero"); return 1; } if (!(cmd->fmt->features & FMT_UNLIMITED_VOLS)) { if (!vp->max_lv) vp->max_lv = 255; if (!vp->max_pv) vp->max_pv = 255; if (vp->max_lv > 255 || vp->max_pv > 255) { log_error("Number of volumes may not exceed 255"); return 1; } } return 0; } /* * Create a (struct volume_group) volume group handle from a struct volume_group pointer and a * possible failure code or zero for success. */ static struct volume_group *_vg_make_handle(struct cmd_context *cmd, struct volume_group *vg, uint32_t failure) { /* Never return a cached VG structure for a failure */ if (vg && vg->vginfo && failure != SUCCESS) { release_vg(vg); vg = NULL; } if (!vg && !(vg = alloc_vg("vg_make_handle", cmd, NULL))) return_NULL; if (vg->read_status != failure) vg->read_status = failure; return vg; } int lv_has_unknown_segments(const struct logical_volume *lv) { struct lv_segment *seg; /* foreach segment */ dm_list_iterate_items(seg, &lv->segments) if (seg_unknown(seg)) return 1; return 0; } int vg_has_unknown_segments(const struct volume_group *vg) { struct lv_list *lvl; /* foreach LV */ dm_list_iterate_items(lvl, &vg->lvs) if (lv_has_unknown_segments(lvl->lv)) return 1; return 0; } /* * Create a VG with default parameters. * Returns: * - struct volume_group* with SUCCESS code: VG structure created * - NULL or struct volume_group* with FAILED_* code: error creating VG structure * Use vg_read_error() to determine success or failure. * FIXME: cleanup usage of _vg_make_handle() */ struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name) { struct volume_group *vg; struct format_instance_ctx fic; struct format_instance *fid; int consistent = 0; uint32_t rc; if (!validate_name(vg_name)) { log_error("Invalid vg name %s", vg_name); /* FIXME: use _vg_make_handle() w/proper error code */ return NULL; } rc = vg_lock_newname(cmd, vg_name); if (rc != SUCCESS) /* NOTE: let caller decide - this may be check for existence */ return _vg_make_handle(cmd, NULL, rc); /* FIXME: Is this vg_read_internal necessary? Move it inside vg_lock_newname? */ /* is this vg name already in use ? */ if ((vg = vg_read_internal(cmd, vg_name, NULL, 1, &consistent))) { log_error("A volume group called '%s' already exists.", vg_name); unlock_and_release_vg(cmd, vg, vg_name); return _vg_make_handle(cmd, NULL, FAILED_EXIST); } /* Strip dev_dir if present */ vg_name = strip_dir(vg_name, cmd->dev_dir); if (!(vg = alloc_vg("vg_create", cmd, vg_name))) goto_bad; if (!id_create(&vg->id)) { log_error("Couldn't create uuid for volume group '%s'.", vg_name); goto bad; } vg->status = (RESIZEABLE_VG | LVM_READ | LVM_WRITE); if (!(vg->system_id = dm_pool_zalloc(vg->vgmem, NAME_LEN + 1))) goto_bad; *vg->system_id = '\0'; vg->extent_size = DEFAULT_EXTENT_SIZE * 2; vg->extent_count = 0; vg->free_count = 0; vg->max_lv = DEFAULT_MAX_LV; vg->max_pv = DEFAULT_MAX_PV; vg->alloc = DEFAULT_ALLOC_POLICY; vg->mda_copies = DEFAULT_VGMETADATACOPIES; vg->pv_count = 0; fic.type = FMT_INSTANCE_MDAS | FMT_INSTANCE_AUX_MDAS; fic.context.vg_ref.vg_name = vg_name; fic.context.vg_ref.vg_id = NULL; if (!(fid = cmd->fmt->ops->create_instance(cmd->fmt, &fic))) { log_error("Failed to create format instance"); goto bad; } vg_set_fid(vg, fid); if (vg->fid->fmt->ops->vg_setup && !vg->fid->fmt->ops->vg_setup(vg->fid, vg)) { log_error("Format specific setup of volume group '%s' failed.", vg_name); goto bad; } return _vg_make_handle(cmd, vg, SUCCESS); bad: unlock_and_release_vg(cmd, vg, vg_name); /* FIXME: use _vg_make_handle() w/proper error code */ return NULL; } uint64_t extents_from_size(struct cmd_context *cmd, uint64_t size, uint32_t extent_size) { if (size % extent_size) { size += extent_size - size % extent_size; log_print_unless_silent("Rounding up size to full physical extent %s", display_size(cmd, size)); } if (size > (uint64_t) MAX_EXTENT_COUNT * extent_size) { log_error("Volume too large (%s) for extent size %s. " "Upper limit is %s.", display_size(cmd, size), display_size(cmd, (uint64_t) extent_size), display_size(cmd, (uint64_t) MAX_EXTENT_COUNT * extent_size)); return 0; } return (uint64_t) size / extent_size; } /* * Return random integer in [0,max) interval * * The loop rejects numbers that come from an "incomplete" slice of the * RAND_MAX space (considering the number space [0, RAND_MAX] is divided * into some "max"-sized slices and at most a single smaller slice, * between [n*max, RAND_MAX] for suitable n -- numbers from this last slice * are discarded because they could distort the distribution in favour of * smaller numbers. */ static unsigned _even_rand( unsigned *seed, unsigned max ) { unsigned r, ret; /* make sure distribution is even */ do { r = (unsigned) rand_r( seed ); ret = r % max; } while ( r - ret > RAND_MAX - max ); return ret; } static dm_bitset_t _bitset_with_random_bits(struct dm_pool *mem, uint32_t num_bits, uint32_t num_set_bits, unsigned *seed) { dm_bitset_t bs; unsigned bit_selected; char buf[32]; uint32_t i = num_bits - num_set_bits; if (!(bs = dm_bitset_create(mem, (unsigned) num_bits))) { log_error("Failed to allocate bitset for setting random bits."); return NULL; } if (!dm_pool_begin_object(mem, 512)) { log_error("dm_pool_begin_object failed for random list of bits."); dm_pool_free(mem, bs); return NULL; } /* Perform loop num_set_bits times, selecting one bit each time */ while (i++ < num_bits) { /* Select a random bit between 0 and (i-1) inclusive. */ bit_selected = _even_rand(seed, i); /* * If the bit was already set, set the new bit that became * choosable for the first time during this pass. * This maintains a uniform probability distribution by compensating * for being unable to select it until this pass. */ if (dm_bit(bs, bit_selected)) bit_selected = i - 1; dm_bit_set(bs, bit_selected); if (dm_snprintf(buf, sizeof(buf), "%u ", bit_selected) < 0) { log_error("snprintf random bit failed."); dm_pool_free(mem, bs); return NULL; } if (!dm_pool_grow_object(mem, buf, strlen(buf))) { log_error("Failed to generate list of random bits."); dm_pool_free(mem, bs); return NULL; } } if (!dm_pool_grow_object(mem, "\0", 1)) { log_error("Failed to finish list of random bits."); dm_pool_free(mem, bs); return NULL; } log_debug("Selected %" PRIu32 " random bits from %" PRIu32 ": %s", num_set_bits, num_bits, (char *) dm_pool_end_object(mem)); return bs; } static int _vg_ignore_mdas(struct volume_group *vg, uint32_t num_to_ignore) { struct metadata_area *mda; uint32_t mda_used_count = vg_mda_used_count(vg); dm_bitset_t mda_to_ignore_bs; int r = 1; log_debug("Adjusting ignored mdas for %s: %" PRIu32 " of %" PRIu32 " mdas in use " "but %" PRIu32 " required. Changing %" PRIu32 " mda.", vg->name, mda_used_count, vg_mda_count(vg), vg_mda_copies(vg), num_to_ignore); if (!num_to_ignore) return 1; if (!(mda_to_ignore_bs = _bitset_with_random_bits(vg->vgmem, mda_used_count, num_to_ignore, &vg->cmd->rand_seed))) return_0; dm_list_iterate_items(mda, &vg->fid->metadata_areas_in_use) if (!mda_is_ignored(mda) && (--mda_used_count, dm_bit(mda_to_ignore_bs, mda_used_count))) { mda_set_ignored(mda, 1); if (!--num_to_ignore) goto out; } log_error(INTERNAL_ERROR "Unable to find %"PRIu32" metadata areas to ignore " "on volume group %s", num_to_ignore, vg->name); r = 0; out: dm_pool_free(vg->vgmem, mda_to_ignore_bs); return r; } static int _vg_unignore_mdas(struct volume_group *vg, uint32_t num_to_unignore) { struct metadata_area *mda, *tmda; uint32_t mda_used_count = vg_mda_used_count(vg); uint32_t mda_count = vg_mda_count(vg); uint32_t mda_free_count = mda_count - mda_used_count; dm_bitset_t mda_to_unignore_bs; int r = 1; if (!num_to_unignore) return 1; log_debug("Adjusting ignored mdas for %s: %" PRIu32 " of %" PRIu32 " mdas in use " "but %" PRIu32 " required. Changing %" PRIu32 " mda.", vg->name, mda_used_count, mda_count, vg_mda_copies(vg), num_to_unignore); if (!(mda_to_unignore_bs = _bitset_with_random_bits(vg->vgmem, mda_free_count, num_to_unignore, &vg->cmd->rand_seed))) return_0; dm_list_iterate_items_safe(mda, tmda, &vg->fid->metadata_areas_ignored) if (mda_is_ignored(mda) && (--mda_free_count, dm_bit(mda_to_unignore_bs, mda_free_count))) { mda_set_ignored(mda, 0); dm_list_move(&vg->fid->metadata_areas_in_use, &mda->list); if (!--num_to_unignore) goto out; } dm_list_iterate_items(mda, &vg->fid->metadata_areas_in_use) if (mda_is_ignored(mda) && (--mda_free_count, dm_bit(mda_to_unignore_bs, mda_free_count))) { mda_set_ignored(mda, 0); if (!--num_to_unignore) goto out; } log_error(INTERNAL_ERROR "Unable to find %"PRIu32" metadata areas to unignore " "on volume group %s", num_to_unignore, vg->name); r = 0; out: dm_pool_free(vg->vgmem, mda_to_unignore_bs); return r; } static int _vg_adjust_ignored_mdas(struct volume_group *vg) { uint32_t mda_copies_used = vg_mda_used_count(vg); if (vg->mda_copies == VGMETADATACOPIES_UNMANAGED) { /* Ensure at least one mda is in use. */ if (!mda_copies_used && vg_mda_count(vg) && !_vg_unignore_mdas(vg, 1)) return_0; else return 1; } /* Not an error to have vg_mda_count larger than total mdas. */ if (vg->mda_copies == VGMETADATACOPIES_ALL || vg->mda_copies >= vg_mda_count(vg)) { /* Use all */ if (!_vg_unignore_mdas(vg, vg_mda_count(vg) - mda_copies_used)) return_0; } else if (mda_copies_used < vg->mda_copies) { if (!_vg_unignore_mdas(vg, vg->mda_copies - mda_copies_used)) return_0; } else if (mda_copies_used > vg->mda_copies) if (!_vg_ignore_mdas(vg, mda_copies_used - vg->mda_copies)) return_0; /* * The VGMETADATACOPIES_ALL value will never be written disk. * It is a special cmdline value that means 2 things: * 1. clear all ignore bits in all mdas in this vg * 2. set the "unmanaged" policy going forward for metadata balancing */ if (vg->mda_copies == VGMETADATACOPIES_ALL) vg->mda_copies = VGMETADATACOPIES_UNMANAGED; return 1; } uint64_t find_min_mda_size(struct dm_list *mdas) { uint64_t min_mda_size = UINT64_MAX, mda_size; struct metadata_area *mda; dm_list_iterate_items(mda, mdas) { if (!mda->ops->mda_total_sectors) continue; mda_size = mda->ops->mda_total_sectors(mda); if (mda_size < min_mda_size) min_mda_size = mda_size; } if (min_mda_size == UINT64_MAX) min_mda_size = UINT64_C(0); return min_mda_size; } static int _move_mdas(struct volume_group *vg_from, struct volume_group *vg_to, struct dm_list *mdas_from, struct dm_list *mdas_to) { struct metadata_area *mda, *mda2; int common_mda = 0; dm_list_iterate_items_safe(mda, mda2, mdas_from) { if (!mda->ops->mda_in_vg) { common_mda = 1; continue; } if (!mda->ops->mda_in_vg(vg_from->fid, vg_from, mda)) { if (is_orphan_vg(vg_to->name)) dm_list_del(&mda->list); else dm_list_move(mdas_to, &mda->list); } } return common_mda; } /* * Separate metadata areas after splitting a VG. * Also accepts orphan VG as destination (for vgreduce). */ int vg_split_mdas(struct cmd_context *cmd __attribute__((unused)), struct volume_group *vg_from, struct volume_group *vg_to) { struct dm_list *mdas_from_in_use, *mdas_to_in_use; struct dm_list *mdas_from_ignored, *mdas_to_ignored; int common_mda = 0; mdas_from_in_use = &vg_from->fid->metadata_areas_in_use; mdas_from_ignored = &vg_from->fid->metadata_areas_ignored; mdas_to_in_use = &vg_to->fid->metadata_areas_in_use; mdas_to_ignored = &vg_to->fid->metadata_areas_ignored; common_mda = _move_mdas(vg_from, vg_to, mdas_from_in_use, mdas_to_in_use); common_mda = _move_mdas(vg_from, vg_to, mdas_from_ignored, mdas_to_ignored); if ((dm_list_empty(mdas_from_in_use) && dm_list_empty(mdas_from_ignored)) || ((!is_orphan_vg(vg_to->name) && dm_list_empty(mdas_to_in_use) && dm_list_empty(mdas_to_ignored)))) return common_mda; return 1; } static int _wipe_sb(struct device *dev, const char *type, const char *name, int wipe_len, struct pvcreate_params *pp, int (*func)(struct device *dev, uint64_t *signature)) { int wipe; uint64_t superblock; wipe = func(dev, &superblock); if (wipe == -1) { log_error("Fatal error while trying to detect %s on %s.", type, name); return 0; } if (wipe == 0) return 1; /* Specifying --yes => do not ask. */ if (!pp->yes && (pp->force == PROMPT) && yes_no_prompt("WARNING: %s detected on %s. Wipe it? [y/n] ", type, name) != 'y') { log_error("Aborting pvcreate on %s.", name); return 0; } log_print_unless_silent("Wiping %s on %s.", type, name); if (!dev_set(dev, superblock, wipe_len, 0)) { log_error("Failed to wipe %s on %s.", type, name); return 0; } return 1; } /* * See if we may pvcreate on this device. * 0 indicates we may not. */ static int pvcreate_check(struct cmd_context *cmd, const char *name, struct pvcreate_params *pp) { struct physical_volume *pv; struct device *dev; /* FIXME Check partition type is LVM unless --force is given */ /* Is there a pv here already? */ if (!(pv = pv_read(cmd, name, 0, 0))) stack; /* * If a PV has no MDAs it may appear to be an orphan until the * metadata is read off another PV in the same VG. Detecting * this means checking every VG by scanning every PV on the * system. */ if (pv && is_orphan(pv) && !dm_list_size(&pv->fid->metadata_areas_in_use)) { free_pv_fid(pv); if (!scan_vgs_for_pvs(cmd, 0)) return_0; if (!(pv = pv_read(cmd, name, 0, 0))) stack; } /* Allow partial & exported VGs to be destroyed. */ /* We must have -ff to overwrite a non orphan */ if (pv && !is_orphan(pv) && pp->force != DONT_PROMPT_OVERRIDE) { log_error("Can't initialize physical volume \"%s\" of " "volume group \"%s\" without -ff", name, pv_vg_name(pv)); goto bad; } /* prompt */ if (pv && !is_orphan(pv) && !pp->yes && yes_no_prompt(_really_init, name, pv_vg_name(pv)) == 'n') { log_error("%s: physical volume not initialized", name); goto bad; } if (sigint_caught()) goto_bad; dev = dev_cache_get(name, cmd->filter); /* Is there an md superblock here? */ /* FIXME: still possible issues here - rescan cache? */ if (!dev && md_filtering()) { if (!refresh_filters(cmd)) goto_bad; init_md_filtering(0); dev = dev_cache_get(name, cmd->filter); init_md_filtering(1); } if (!dev) { log_error("Device %s not found (or ignored by filtering).", name); goto bad; } /* * This test will fail if the device belongs to an MD array. */ if (!dev_test_excl(dev)) { /* FIXME Detect whether device-mapper itself is still using it */ log_error("Can't open %s exclusively. Mounted filesystem?", name); goto bad; } if (!_wipe_sb(dev, "software RAID md superblock", name, 4, pp, dev_is_md)) goto_bad; if (!_wipe_sb(dev, "swap signature", name, 10, pp, dev_is_swap)) goto_bad; if (!_wipe_sb(dev, "LUKS signature", name, 8, pp, dev_is_luks)) goto_bad; if (sigint_caught()) goto_bad; if (pv && !is_orphan(pv) && pp->force) { log_warn("WARNING: Forcing physical volume creation on " "%s%s%s%s", name, !is_orphan(pv) ? " of volume group \"" : "", !is_orphan(pv) ? pv_vg_name(pv) : "", !is_orphan(pv) ? "\"" : ""); } free_pv_fid(pv); return 1; bad: free_pv_fid(pv); return 0; } void pvcreate_params_set_defaults(struct pvcreate_params *pp) { memset(pp, 0, sizeof(*pp)); pp->zero = 1; pp->size = 0; pp->data_alignment = UINT64_C(0); pp->data_alignment_offset = UINT64_C(0); pp->pvmetadatacopies = DEFAULT_PVMETADATACOPIES; pp->pvmetadatasize = DEFAULT_PVMETADATASIZE; pp->labelsector = DEFAULT_LABELSECTOR; pp->idp = 0; pp->pe_start = 0; pp->extent_count = 0; pp->extent_size = 0; pp->restorefile = 0; pp->force = PROMPT; pp->yes = 0; pp->metadataignore = DEFAULT_PVMETADATAIGNORE; } static int _pvcreate_write(struct cmd_context *cmd, struct pv_to_create *pvc) { int zero = pvc->pp->zero; struct physical_volume *pv = pvc->pv; struct device *dev = pv->dev; const char *pv_name = dev_name(dev); /* Wipe existing label first */ if (!label_remove(pv_dev(pv))) { log_error("Failed to wipe existing label on %s", pv_name); return 0; } if (zero) { log_verbose("Zeroing start of device %s", pv_name); if (!dev_open_quiet(dev)) { log_error("%s not opened: device not zeroed", pv_name); return 0; } if (!dev_set(dev, UINT64_C(0), (size_t) 2048, 0)) { log_error("%s not wiped: aborting", pv_name); if (!dev_close(dev)) stack; return 0; } if (!dev_close(dev)) stack; } log_verbose("Writing physical volume data to disk \"%s\"", pv_name); if (!(pv_write(cmd, pv, 1))) { log_error("Failed to write physical volume \"%s\"", pv_name); return 0; } log_print_unless_silent("Physical volume \"%s\" successfully created", pv_name); return 1; } /* * pvcreate_single() - initialize a device with PV label and metadata area * * Parameters: * - pv_name: device path to initialize * - pp: parameters to pass to pv_create; if NULL, use default values * * Returns: * NULL: error * struct physical_volume * (non-NULL): handle to physical volume created */ struct physical_volume * pvcreate_single(struct cmd_context *cmd, const char *pv_name, struct pvcreate_params *pp, int write_now) { struct physical_volume *pv = NULL; struct device *dev; struct dm_list mdas; struct pvcreate_params default_pp; char buffer[64] __attribute__((aligned(8))); pvcreate_params_set_defaults(&default_pp); if (!pp) pp = &default_pp; if (pp->idp) { if ((dev = lvmcache_device_from_pvid(cmd, pp->idp, NULL, NULL)) && (dev != dev_cache_get(pv_name, cmd->filter))) { if (!id_write_format((const struct id*)&pp->idp->uuid, buffer, sizeof(buffer))) goto_bad; log_error("uuid %s already in use on \"%s\"", buffer, dev_name(dev)); goto bad; } } if (!pvcreate_check(cmd, pv_name, pp)) goto_bad; if (sigint_caught()) goto_bad; if (!(dev = dev_cache_get(pv_name, cmd->filter))) { log_error("%s: Couldn't find device. Check your filters?", pv_name); goto bad; } dm_list_init(&mdas); if (!(pv = pv_create(cmd, dev, pp->idp, pp->size, pp->data_alignment, pp->data_alignment_offset, pp->pe_start ? pp->pe_start : PV_PE_START_CALC, pp->extent_count, pp->extent_size, pp->labelsector, pp->pvmetadatacopies, pp->pvmetadatasize, pp->metadataignore))) { log_error("Failed to setup physical volume \"%s\"", pv_name); goto bad; } log_verbose("Set up physical volume for \"%s\" with %" PRIu64 " available sectors", pv_name, pv_size(pv)); if (write_now) { struct pv_to_create pvc; pvc.pp = pp; pvc.pv = pv; if (!_pvcreate_write(cmd, &pvc)) goto bad; } else { pv->status |= UNLABELLED_PV; } return pv; bad: return NULL; } static struct physical_volume *_alloc_pv(struct dm_pool *mem, struct device *dev) { struct physical_volume *pv; if (!(pv = dm_pool_zalloc(mem, sizeof(*pv)))) { log_error("Failed to allocate pv structure."); return NULL; } pv->dev = dev; pv->status = ALLOCATABLE_PV; dm_list_init(&pv->tags); dm_list_init(&pv->segments); return pv; } /** * pv_create - initialize a physical volume for use with a volume group * created PV belongs to Orphan VG. * * @fmt: format type * @dev: PV device to initialize * @size: size of the PV in sectors * @data_alignment: requested alignment of data * @data_alignment_offset: requested offset to aligned data * @pe_start: physical extent start * @existing_extent_count * @existing_extent_size * @pvmetadatacopies * @pvmetadatasize * @mdas * * Returns: * PV handle - physical volume initialized successfully * NULL - invalid parameter or problem initializing the physical volume * * Note: * FIXME: shorten argument list and replace with explict 'set' functions */ struct physical_volume *pv_create(const struct cmd_context *cmd, struct device *dev, struct id *id, uint64_t size, unsigned long data_alignment, unsigned long data_alignment_offset, uint64_t pe_start, uint32_t existing_extent_count, uint32_t existing_extent_size, uint64_t label_sector, unsigned pvmetadatacopies, uint64_t pvmetadatasize, unsigned metadataignore) { const struct format_type *fmt = cmd->fmt; struct dm_pool *mem = fmt->orphan_vg->vgmem; struct physical_volume *pv = _alloc_pv(mem, dev); unsigned mda_index; struct pv_list *pvl; if (!pv) return_NULL; if (id) memcpy(&pv->id, id, sizeof(*id)); else if (!id_create(&pv->id)) { log_error("Failed to create random uuid for %s.", dev_name(dev)); goto bad; } if (!dev_get_size(pv->dev, &pv->size)) { log_error("%s: Couldn't get size.", pv_dev_name(pv)); goto bad; } if (size) { if (size > pv->size) log_warn("WARNING: %s: Overriding real size. " "You could lose data.", pv_dev_name(pv)); log_verbose("%s: Pretending size is %" PRIu64 " sectors.", pv_dev_name(pv), size); pv->size = size; } if (pv->size < pv_min_size()) { log_error("%s: Size must exceed minimum of %" PRIu64 " sectors.", pv_dev_name(pv), pv_min_size()); goto bad; } if (pv->size < data_alignment) { log_error("%s: Data alignment must not exceed device size.", pv_dev_name(pv)); goto bad; } if (!(pvl = dm_pool_zalloc(mem, sizeof(*pvl)))) { log_error("pv_list allocation in pv_create failed"); goto bad; } pvl->pv = pv; add_pvl_to_vgs(fmt->orphan_vg, pvl); fmt->orphan_vg->extent_count += pv->pe_count; fmt->orphan_vg->free_count += pv->pe_count; pv->fmt = fmt; pv->vg_name = fmt->orphan_vg_name; if (!fmt->ops->pv_initialise(fmt, label_sector, pe_start, existing_extent_count, existing_extent_size, data_alignment, data_alignment_offset, pv)) { log_error("Format-specific initialisation of physical " "volume %s failed.", pv_dev_name(pv)); goto bad; } for (mda_index = 0; mda_index < pvmetadatacopies; mda_index++) { if (pv->fmt->ops->pv_add_metadata_area && !pv->fmt->ops->pv_add_metadata_area(pv->fmt, pv, pe_start != PV_PE_START_CALC, mda_index, pvmetadatasize, metadataignore)) { log_error("Failed to add metadata area for " "new physical volume %s", pv_dev_name(pv)); goto bad; } } return pv; bad: // FIXME: detach from orphan in error path //free_pv_fid(pv); //dm_pool_free(mem, pv); return NULL; } /* FIXME: liblvm todo - make into function that returns handle */ struct pv_list *find_pv_in_vg(const struct volume_group *vg, const char *pv_name) { return _find_pv_in_vg(vg, pv_name); } static struct pv_list *_find_pv_in_vg(const struct volume_group *vg, const char *pv_name) { struct pv_list *pvl; dm_list_iterate_items(pvl, &vg->pvs) if (pvl->pv->dev == dev_cache_get(pv_name, vg->cmd->filter)) return pvl; return NULL; } struct pv_list *find_pv_in_pv_list(const struct dm_list *pl, const struct physical_volume *pv) { struct pv_list *pvl; dm_list_iterate_items(pvl, pl) if (pvl->pv == pv) return pvl; return NULL; } int pv_is_in_vg(struct volume_group *vg, struct physical_volume *pv) { struct pv_list *pvl; dm_list_iterate_items(pvl, &vg->pvs) if (pv == pvl->pv) return 1; return 0; } static struct pv_list *_find_pv_in_vg_by_uuid(const struct volume_group *vg, const struct id *id) { struct pv_list *pvl; dm_list_iterate_items(pvl, &vg->pvs) if (id_equal(&pvl->pv->id, id)) return pvl; return NULL; } /** * find_pv_in_vg_by_uuid - Find PV in VG by PV UUID * @vg: volume group to search * @id: UUID of the PV to match * * Returns: * struct pv_list within owning struct volume_group - if UUID of PV found in VG * NULL - invalid parameter or UUID of PV not found in VG * * Note * FIXME - liblvm todo - make into function that takes VG handle */ struct pv_list *find_pv_in_vg_by_uuid(const struct volume_group *vg, const struct id *id) { return _find_pv_in_vg_by_uuid(vg, id); } struct lv_list *find_lv_in_vg(const struct volume_group *vg, const char *lv_name) { struct lv_list *lvl; const char *ptr; /* Use last component */ if ((ptr = strrchr(lv_name, '/'))) ptr++; else ptr = lv_name; dm_list_iterate_items(lvl, &vg->lvs) if (!strcmp(lvl->lv->name, ptr)) return lvl; return NULL; } struct lv_list *find_lv_in_lv_list(const struct dm_list *ll, const struct logical_volume *lv) { struct lv_list *lvl; dm_list_iterate_items(lvl, ll) if (lvl->lv == lv) return lvl; return NULL; } struct lv_list *find_lv_in_vg_by_lvid(struct volume_group *vg, const union lvid *lvid) { struct lv_list *lvl; dm_list_iterate_items(lvl, &vg->lvs) if (!strncmp(lvl->lv->lvid.s, lvid->s, sizeof(*lvid))) return lvl; return NULL; } struct logical_volume *find_lv(const struct volume_group *vg, const char *lv_name) { struct lv_list *lvl = find_lv_in_vg(vg, lv_name); return lvl ? lvl->lv : NULL; } struct physical_volume *find_pv(struct volume_group *vg, struct device *dev) { struct pv_list *pvl; dm_list_iterate_items(pvl, &vg->pvs) if (dev == pvl->pv->dev) return pvl->pv; return NULL; } /* FIXME: liblvm todo - make into function that returns handle */ struct physical_volume *find_pv_by_name(struct cmd_context *cmd, const char *pv_name) { return _find_pv_by_name(cmd, pv_name); } static struct physical_volume *_find_pv_by_name(struct cmd_context *cmd, const char *pv_name) { struct physical_volume *pv; if (!(pv = _pv_read(cmd, cmd->mem, pv_name, NULL, 1, 0))) { log_error("Physical volume %s not found", pv_name); goto bad; } if (is_orphan_vg(pv->vg_name) && !dm_list_size(&pv->fid->metadata_areas_in_use)) { /* If a PV has no MDAs - need to search all VGs for it */ if (!scan_vgs_for_pvs(cmd, 1)) goto_bad; free_pv_fid(pv); if (!(pv = _pv_read(cmd, cmd->mem, pv_name, NULL, 1, 0))) { log_error("Physical volume %s not found", pv_name); goto bad; } } if (is_orphan_vg(pv->vg_name)) { log_error("Physical volume %s not in a volume group", pv_name); goto bad; } return pv; bad: free_pv_fid(pv); return NULL; } /* Find segment at a given logical extent in an LV */ struct lv_segment *find_seg_by_le(const struct logical_volume *lv, uint32_t le) { struct lv_segment *seg; dm_list_iterate_items(seg, &lv->segments) if (le >= seg->le && le < seg->le + seg->len) return seg; return NULL; } struct lv_segment *first_seg(const struct logical_volume *lv) { struct lv_segment *seg; dm_list_iterate_items(seg, &lv->segments) return seg; return NULL; } struct lv_segment *last_seg(const struct logical_volume *lv) { struct lv_segment *seg; dm_list_iterate_back_items(seg, &lv->segments) return seg; return NULL; } int vg_remove_mdas(struct volume_group *vg) { struct metadata_area *mda; /* FIXME Improve recovery situation? */ /* Remove each copy of the metadata */ dm_list_iterate_items(mda, &vg->fid->metadata_areas_in_use) { if (mda->ops->vg_remove && !mda->ops->vg_remove(vg->fid, vg, mda)) return_0; } return 1; } /* * Determine whether two vgs are compatible for merging. */ int vgs_are_compatible(struct cmd_context *cmd __attribute__((unused)), struct volume_group *vg_from, struct volume_group *vg_to) { struct lv_list *lvl1, *lvl2; struct pv_list *pvl; const char *name1, *name2; if (lvs_in_vg_activated(vg_from)) { log_error("Logical volumes in \"%s\" must be inactive", vg_from->name); return 0; } /* Check compatibility */ if (vg_to->extent_size != vg_from->extent_size) { log_error("Extent sizes differ: %d (%s) and %d (%s)", vg_to->extent_size, vg_to->name, vg_from->extent_size, vg_from->name); return 0; } if (vg_to->max_pv && (vg_to->max_pv < vg_to->pv_count + vg_from->pv_count)) { log_error("Maximum number of physical volumes (%d) exceeded " " for \"%s\" and \"%s\"", vg_to->max_pv, vg_to->name, vg_from->name); return 0; } if (vg_to->max_lv && (vg_to->max_lv < vg_visible_lvs(vg_to) + vg_visible_lvs(vg_from))) { log_error("Maximum number of logical volumes (%d) exceeded " " for \"%s\" and \"%s\"", vg_to->max_lv, vg_to->name, vg_from->name); return 0; } /* Metadata types must be the same */ if (vg_to->fid->fmt != vg_from->fid->fmt) { log_error("Metadata types differ for \"%s\" and \"%s\"", vg_to->name, vg_from->name); return 0; } /* Clustering attribute must be the same */ if (vg_is_clustered(vg_to) != vg_is_clustered(vg_from)) { log_error("Clustered attribute differs for \"%s\" and \"%s\"", vg_to->name, vg_from->name); return 0; } /* Check no conflicts with LV names */ dm_list_iterate_items(lvl1, &vg_to->lvs) { name1 = lvl1->lv->name; dm_list_iterate_items(lvl2, &vg_from->lvs) { name2 = lvl2->lv->name; if (!strcmp(name1, name2)) { log_error("Duplicate logical volume " "name \"%s\" " "in \"%s\" and \"%s\"", name1, vg_to->name, vg_from->name); return 0; } } } /* Check no PVs are constructed from either VG */ dm_list_iterate_items(pvl, &vg_to->pvs) { if (pv_uses_vg(pvl->pv, vg_from)) { log_error("Physical volume %s might be constructed " "from same volume group %s.", pv_dev_name(pvl->pv), vg_from->name); return 0; } } dm_list_iterate_items(pvl, &vg_from->pvs) { if (pv_uses_vg(pvl->pv, vg_to)) { log_error("Physical volume %s might be constructed " "from same volume group %s.", pv_dev_name(pvl->pv), vg_to->name); return 0; } } return 1; } struct _lv_postorder_baton { int (*fn)(struct logical_volume *lv, void *data); void *data; }; static int _lv_postorder_visit(struct logical_volume *, int (*fn)(struct logical_volume *lv, void *data), void *data); static int _lv_each_dependency(struct logical_volume *lv, int (*fn)(struct logical_volume *lv, void *data), void *data) { unsigned i, s; struct lv_segment *lvseg; struct logical_volume *deps[] = { (lv->rdevice && lv != lv->rdevice->lv) ? lv->rdevice->lv : 0, (lv->rdevice && lv != lv->rdevice->slog) ? lv->rdevice->slog : 0, lv->snapshot ? lv->snapshot->origin : 0, lv->snapshot ? lv->snapshot->cow : 0 }; for (i = 0; i < sizeof(deps) / sizeof(*deps); ++i) { if (deps[i] && !fn(deps[i], data)) return_0; } dm_list_iterate_items(lvseg, &lv->segments) { if (lvseg->log_lv && !fn(lvseg->log_lv, data)) return_0; if (lvseg->rlog_lv && !fn(lvseg->rlog_lv, data)) return_0; if (lvseg->pool_lv && !fn(lvseg->pool_lv, data)) return_0; if (lvseg->metadata_lv && !fn(lvseg->metadata_lv, data)) return_0; for (s = 0; s < lvseg->area_count; ++s) { if (seg_type(lvseg, s) == AREA_LV && !fn(seg_lv(lvseg,s), data)) return_0; } } return 1; } static int _lv_postorder_cleanup(struct logical_volume *lv, void *data) { if (!(lv->status & POSTORDER_FLAG)) return 1; lv->status &= ~POSTORDER_FLAG; if (!_lv_each_dependency(lv, _lv_postorder_cleanup, data)) return_0; return 1; } static int _lv_postorder_level(struct logical_volume *lv, void *data) { struct _lv_postorder_baton *baton = data; return _lv_postorder_visit(lv, baton->fn, baton->data); }; static int _lv_postorder_visit(struct logical_volume *lv, int (*fn)(struct logical_volume *lv, void *data), void *data) { struct _lv_postorder_baton baton; int r; if (lv->status & POSTORDER_FLAG) return 1; if (lv->status & POSTORDER_OPEN_FLAG) return 1; // a data structure loop has closed... lv->status |= POSTORDER_OPEN_FLAG; baton.fn = fn; baton.data = data; r = _lv_each_dependency(lv, _lv_postorder_level, &baton); if (r) r = fn(lv, data); lv->status &= ~POSTORDER_OPEN_FLAG; lv->status |= POSTORDER_FLAG; return r; } /* * This will walk the LV dependency graph in depth-first order and in the * postorder, call a callback function "fn". The void *data is passed along all * the calls. The callback may return zero to indicate an error and terminate * the depth-first walk. The error is propagated to return value of * _lv_postorder. */ static int _lv_postorder(struct logical_volume *lv, int (*fn)(struct logical_volume *lv, void *data), void *data) { int r; int pool_locked = dm_pool_locked(lv->vg->vgmem); if (pool_locked && !dm_pool_unlock(lv->vg->vgmem, 0)) return_0; r = _lv_postorder_visit(lv, fn, data); _lv_postorder_cleanup(lv, 0); if (pool_locked && !dm_pool_lock(lv->vg->vgmem, 0)) return_0; return r; } /* * Calls _lv_postorder() on each LV from VG. Avoids duplicate transitivity visits. * Clears with _lv_postorder_cleanup() when all LVs were visited by postorder. */ static int _lv_postorder_vg(struct volume_group *vg, int (*fn)(struct logical_volume *lv, void *data), void *data) { struct lv_list *lvl; int r = 1; int pool_locked = dm_pool_locked(vg->vgmem); if (pool_locked && !dm_pool_unlock(vg->vgmem, 0)) return_0; dm_list_iterate_items(lvl, &vg->lvs) if (!_lv_postorder_visit(lvl->lv, fn, data)) { stack; r = 0; } dm_list_iterate_items(lvl, &vg->lvs) _lv_postorder_cleanup(lvl->lv, 0); if (pool_locked && !dm_pool_lock(vg->vgmem, 0)) return_0; return r; } struct _lv_mark_if_partial_baton { int partial; }; static int _lv_mark_if_partial_collect(struct logical_volume *lv, void *data) { struct _lv_mark_if_partial_baton *baton = data; if (lv->status & PARTIAL_LV) baton->partial = 1; return 1; } static int _lv_mark_if_partial_single(struct logical_volume *lv, void *data) { unsigned s; struct _lv_mark_if_partial_baton baton; struct lv_segment *lvseg; dm_list_iterate_items(lvseg, &lv->segments) { for (s = 0; s < lvseg->area_count; ++s) { if (seg_type(lvseg, s) == AREA_PV) { if (is_missing_pv(seg_pv(lvseg, s))) lv->status |= PARTIAL_LV; } } } baton.partial = 0; if (!_lv_each_dependency(lv, _lv_mark_if_partial_collect, &baton)) return_0; if (baton.partial) lv->status |= PARTIAL_LV; return 1; } /* * Mark LVs with missing PVs using PARTIAL_LV status flag. The flag is * propagated transitively, so LVs referencing other LVs are marked * partial as well, if any of their referenced LVs are marked partial. */ int vg_mark_partial_lvs(struct volume_group *vg, int clear) { struct lv_list *lvl; if (clear) dm_list_iterate_items(lvl, &vg->lvs) lvl->lv->status &= ~PARTIAL_LV; if (!_lv_postorder_vg(vg, _lv_mark_if_partial_single, NULL)) return_0; return 1; } /* * Be sure that all PV devices have cached read ahead in dev-cache * Currently it takes read_ahead from first PV segment only */ static int _lv_read_ahead_single(struct logical_volume *lv, void *data) { struct lv_segment *seg = first_seg(lv); uint32_t seg_read_ahead = 0, *read_ahead = data; if (!read_ahead) { log_error(INTERNAL_ERROR "Read ahead data missing."); return 0; } if (seg && seg->area_count && seg_type(seg, 0) == AREA_PV) dev_get_read_ahead(seg_pv(seg, 0)->dev, &seg_read_ahead); if (seg_read_ahead > *read_ahead) *read_ahead = seg_read_ahead; return 1; } /* * Calculate readahead for logical volume from underlying PV devices. * If read_ahead is NULL, only ensure that readahead of PVs are preloaded * into PV struct device in dev cache. */ void lv_calculate_readahead(const struct logical_volume *lv, uint32_t *read_ahead) { uint32_t _read_ahead = 0; if (lv->read_ahead == DM_READ_AHEAD_AUTO) _lv_postorder((struct logical_volume *)lv, _lv_read_ahead_single, &_read_ahead); if (read_ahead) { log_debug("Calculated readahead of LV %s is %u", lv->name, _read_ahead); *read_ahead = _read_ahead; } } struct validate_hash { struct dm_hash_table *lvname; struct dm_hash_table *lvid; struct dm_hash_table *pvid; }; /* * Check that an LV and all its PV references are correctly listed in vg->lvs * and vg->pvs, respectively. This only looks at a single LV, but *not* at the * LVs it is using. To do the latter, you should use _lv_postorder with this * function. C.f. vg_validate. */ static int _lv_validate_references_single(struct logical_volume *lv, void *data) { struct volume_group *vg = lv->vg; struct validate_hash *vhash = data; struct lv_segment *lvseg; struct physical_volume *pv; unsigned s; int r = 1; if (lv != dm_hash_lookup_binary(vhash->lvid, &lv->lvid.id[1], sizeof(lv->lvid.id[1]))) { log_error(INTERNAL_ERROR "Referenced LV %s not listed in VG %s.", lv->name, vg->name); r = 0; } dm_list_iterate_items(lvseg, &lv->segments) { for (s = 0; s < lvseg->area_count; ++s) { if (seg_type(lvseg, s) != AREA_PV) continue; pv = seg_pv(lvseg, s); /* look up the reference in vg->pvs */ if (pv != dm_hash_lookup_binary(vhash->pvid, &pv->id, sizeof(pv->id))) { log_error(INTERNAL_ERROR "Referenced PV %s not listed in VG %s.", pv_dev_name(pv), vg->name); r = 0; } } } return r; } int vg_validate(struct volume_group *vg) { struct pv_list *pvl; struct lv_list *lvl; struct lv_segment *seg; struct str_list *sl; char uuid[64] __attribute__((aligned(8))); int r = 1; uint32_t hidden_lv_count = 0, lv_count = 0, lv_visible_count = 0; uint32_t pv_count = 0; uint32_t num_snapshots = 0; struct validate_hash vhash = { NULL }; if (vg->alloc == ALLOC_CLING_BY_TAGS) { log_error(INTERNAL_ERROR "VG %s allocation policy set to invalid cling_by_tags.", vg->name); r = 0; } /* FIXME Also check there's no data/metadata overlap */ if (!(vhash.pvid = dm_hash_create(vg->pv_count))) { log_error("Failed to allocate pvid hash."); return 0; } dm_list_iterate_items(sl, &vg->tags) if (!validate_tag(sl->str)) { log_error(INTERNAL_ERROR "VG %s tag %s has invalid form.", vg->name, sl->str); r = 0; } dm_list_iterate_items(pvl, &vg->pvs) { if (++pv_count > vg->pv_count) { log_error(INTERNAL_ERROR "PV list corruption detected in VG %s.", vg->name); /* FIXME Dump list structure? */ r = 0; } if (pvl->pv->vg != vg) { log_error(INTERNAL_ERROR "VG %s PV list entry points " "to different VG %s.", vg->name, pvl->pv->vg ? pvl->pv->vg->name : "NULL"); r = 0; } if (strcmp(pvl->pv->vg_name, vg->name)) { log_error(INTERNAL_ERROR "VG name for PV %s is corrupted.", pv_dev_name(pvl->pv)); r = 0; } if (dm_hash_lookup_binary(vhash.pvid, &pvl->pv->id, sizeof(pvl->pv->id))) { if (!id_write_format(&pvl->pv->id, uuid, sizeof(uuid))) stack; log_error(INTERNAL_ERROR "Duplicate PV id " "%s detected for %s in %s.", uuid, pv_dev_name(pvl->pv), vg->name); r = 0; } dm_list_iterate_items(sl, &pvl->pv->tags) if (!validate_tag(sl->str)) { log_error(INTERNAL_ERROR "PV %s tag %s has invalid form.", pv_dev_name(pvl->pv), sl->str); r = 0; } if (!dm_hash_insert_binary(vhash.pvid, &pvl->pv->id, sizeof(pvl->pv->id), pvl->pv)) { log_error("Failed to hash pvid."); r = 0; break; } } if (!check_pv_segments(vg)) { log_error(INTERNAL_ERROR "PV segments corrupted in %s.", vg->name); r = 0; } /* * Count all non-snapshot invisible LVs */ dm_list_iterate_items(lvl, &vg->lvs) { lv_count++; if (lv_is_cow(lvl->lv)) num_snapshots++; if (lv_is_visible(lvl->lv)) lv_visible_count++; if (!check_lv_segments(lvl->lv, 0)) { log_error(INTERNAL_ERROR "LV segments corrupted in %s.", lvl->lv->name); r = 0; } if (lvl->lv->alloc == ALLOC_CLING_BY_TAGS) { log_error(INTERNAL_ERROR "LV %s allocation policy set to invalid cling_by_tags.", lvl->lv->name); r = 0; } if (!validate_name(lvl->lv->name)) { log_error(INTERNAL_ERROR "LV name %s has invalid form.", lvl->lv->name); r = 0; } dm_list_iterate_items(sl, &lvl->lv->tags) if (!validate_tag(sl->str)) { log_error(INTERNAL_ERROR "LV %s tag %s has invalid form.", lvl->lv->name, sl->str); r = 0; } if (lvl->lv->status & VISIBLE_LV) continue; /* snapshots */ if (lv_is_cow(lvl->lv)) continue; /* virtual origins are always hidden */ if (lv_is_origin(lvl->lv) && !lv_is_virtual_origin(lvl->lv)) continue; /* count other non-snapshot invisible volumes */ hidden_lv_count++; /* * FIXME: add check for unreferenced invisible LVs * - snapshot cow & origin * - mirror log & images * - mirror conversion volumes (_mimagetmp*) */ } /* * all volumes = visible LVs + snapshot_cows + invisible LVs */ if (lv_count != lv_visible_count + num_snapshots + hidden_lv_count) { log_error(INTERNAL_ERROR "#internal LVs (%u) != #LVs (%" PRIu32 ") + #snapshots (%" PRIu32 ") + #internal LVs (%u) in VG %s", lv_count, lv_visible_count, num_snapshots, hidden_lv_count, vg->name); r = 0; } /* Avoid endless loop if lv->segments list is corrupt */ if (!r) goto out; if (!(vhash.lvname = dm_hash_create(lv_count))) { log_error("Failed to allocate lv_name hash"); r = 0; goto out; } if (!(vhash.lvid = dm_hash_create(lv_count))) { log_error("Failed to allocate uuid hash"); r = 0; goto out; } dm_list_iterate_items(lvl, &vg->lvs) { if (dm_hash_lookup(vhash.lvname, lvl->lv->name)) { log_error(INTERNAL_ERROR "Duplicate LV name %s detected in %s.", lvl->lv->name, vg->name); r = 0; } if (dm_hash_lookup_binary(vhash.lvid, &lvl->lv->lvid.id[1], sizeof(lvl->lv->lvid.id[1]))) { if (!id_write_format(&lvl->lv->lvid.id[1], uuid, sizeof(uuid))) stack; log_error(INTERNAL_ERROR "Duplicate LV id " "%s detected for %s in %s.", uuid, lvl->lv->name, vg->name); r = 0; } if (!check_lv_segments(lvl->lv, 1)) { log_error(INTERNAL_ERROR "LV segments corrupted in %s.", lvl->lv->name); r = 0; } if (!dm_hash_insert(vhash.lvname, lvl->lv->name, lvl)) { log_error("Failed to hash lvname."); r = 0; break; } if (!dm_hash_insert_binary(vhash.lvid, &lvl->lv->lvid.id[1], sizeof(lvl->lv->lvid.id[1]), lvl->lv)) { log_error("Failed to hash lvid."); r = 0; break; } } if (!_lv_postorder_vg(vg, _lv_validate_references_single, &vhash)) { stack; r = 0; } dm_list_iterate_items(lvl, &vg->lvs) { if (!(lvl->lv->status & PVMOVE)) continue; dm_list_iterate_items(seg, &lvl->lv->segments) { if (seg_is_mirrored(seg)) { if (seg->area_count != 2) { log_error(INTERNAL_ERROR "Segment in %s is not 2-way.", lvl->lv->name); r = 0; } } else if (seg->area_count != 1) { log_error(INTERNAL_ERROR "Segment in %s has wrong number of areas: %d.", lvl->lv->name, seg->area_count); r = 0; } } } if (!(vg->fid->fmt->features & FMT_UNLIMITED_VOLS) && (!vg->max_lv || !vg->max_pv)) { log_error(INTERNAL_ERROR "Volume group %s has limited PV/LV count" " but limit is not set.", vg->name); r = 0; } if (vg_max_lv_reached(vg)) stack; out: if (vhash.lvid) dm_hash_destroy(vhash.lvid); if (vhash.lvname) dm_hash_destroy(vhash.lvname); if (vhash.pvid) dm_hash_destroy(vhash.pvid); return r; } /* * After vg_write() returns success, * caller MUST call either vg_commit() or vg_revert() */ int vg_write(struct volume_group *vg) { struct dm_list *mdah; struct pv_to_create *pv_to_create; struct metadata_area *mda; if (!vg_validate(vg)) return_0; if (vg->status & PARTIAL_VG) { log_error("Cannot update partial volume group %s.", vg->name); return 0; } if (vg_missing_pv_count(vg) && !vg->cmd->handles_missing_pvs) { log_error("Cannot update volume group %s while physical " "volumes are missing.", vg->name); return 0; } if (vg_has_unknown_segments(vg) && !vg->cmd->handles_unknown_segments) { log_error("Cannot update volume group %s with unknown segments in it!", vg->name); return 0; } if ((vg->fid->fmt->features & FMT_MDAS) && !_vg_adjust_ignored_mdas(vg)) return_0; if (!vg_mda_used_count(vg)) { log_error("Aborting vg_write: No metadata areas to write to!"); return 0; } if (!drop_cached_metadata(vg)) { log_error("Unable to drop cached metadata for VG %s.", vg->name); return 0; } if (critical_section()) log_error(INTERNAL_ERROR "Writing metadata in critical section."); /* Unlock memory if possible */ memlock_unlock(vg->cmd); vg->seqno++; dm_list_iterate_items(pv_to_create, &vg->pvs_to_create) { if (!_pvcreate_write(vg->cmd, pv_to_create)) return 0; pv_to_create->pv->status &= ~UNLABELLED_PV; } /* Write to each copy of the metadata area */ dm_list_iterate_items(mda, &vg->fid->metadata_areas_in_use) { if (!mda->ops->vg_write) { log_error("Format does not support writing volume" "group metadata areas"); /* Revert */ dm_list_uniterate(mdah, &vg->fid->metadata_areas_in_use, &mda->list) { mda = dm_list_item(mdah, struct metadata_area); if (mda->ops->vg_revert && !mda->ops->vg_revert(vg->fid, vg, mda)) { stack; } } return 0; } if (!mda->ops->vg_write(vg->fid, vg, mda)) { stack; /* Revert */ dm_list_uniterate(mdah, &vg->fid->metadata_areas_in_use, &mda->list) { mda = dm_list_item(mdah, struct metadata_area); if (mda->ops->vg_revert && !mda->ops->vg_revert(vg->fid, vg, mda)) { stack; } } return 0; } } /* Now pre-commit each copy of the new metadata */ dm_list_iterate_items(mda, &vg->fid->metadata_areas_in_use) { if (mda->ops->vg_precommit && !mda->ops->vg_precommit(vg->fid, vg, mda)) { stack; /* Revert */ dm_list_iterate_items(mda, &vg->fid->metadata_areas_in_use) { if (mda->ops->vg_revert && !mda->ops->vg_revert(vg->fid, vg, mda)) { stack; } } return 0; } } return 1; } static int _vg_commit_mdas(struct volume_group *vg) { struct metadata_area *mda, *tmda; struct dm_list ignored; int failed = 0; int cache_updated = 0; /* Rearrange the metadata_areas_in_use so ignored mdas come first. */ dm_list_init(&ignored); dm_list_iterate_items_safe(mda, tmda, &vg->fid->metadata_areas_in_use) if (mda_is_ignored(mda)) dm_list_move(&ignored, &mda->list); dm_list_iterate_items_safe(mda, tmda, &ignored) dm_list_move(&vg->fid->metadata_areas_in_use, &mda->list); /* Commit to each copy of the metadata area */ dm_list_iterate_items(mda, &vg->fid->metadata_areas_in_use) { failed = 0; if (mda->ops->vg_commit && !mda->ops->vg_commit(vg->fid, vg, mda)) { stack; failed = 1; } /* Update cache first time we succeed */ if (!failed && !cache_updated) { lvmcache_update_vg(vg, 0); // lvmetad_vg_commit(vg); cache_updated = 1; } } return cache_updated; } /* Commit pending changes */ int vg_commit(struct volume_group *vg) { int cache_updated = 0; if (!lvmcache_vgname_is_locked(vg->name)) { log_error(INTERNAL_ERROR "Attempt to write new VG metadata " "without locking %s", vg->name); return cache_updated; } if (!lvmetad_vg_update(vg)) return 0; cache_updated = _vg_commit_mdas(vg); if (cache_updated) { /* Instruct remote nodes to upgrade cached metadata. */ if (!remote_commit_cached_metadata(vg)) stack; // FIXME: What should we do? /* * We need to clear old_name after a successful commit. * The volume_group structure could be reused later. */ vg->old_name = NULL; } /* If update failed, remove any cached precommitted metadata. */ if (!cache_updated && !drop_cached_metadata(vg)) log_error("Attempt to drop cached metadata failed " "after commit for VG %s.", vg->name); /* If at least one mda commit succeeded, it was committed */ return cache_updated; } /* Don't commit any pending changes */ void vg_revert(struct volume_group *vg) { struct metadata_area *mda; dm_list_iterate_items(mda, &vg->fid->metadata_areas_in_use) { if (mda->ops->vg_revert && !mda->ops->vg_revert(vg->fid, vg, mda)) { stack; } } if (!drop_cached_metadata(vg)) log_error("Attempt to drop cached metadata failed " "after reverted update for VG %s.", vg->name); if (!remote_revert_cached_metadata(vg)) stack; // FIXME: What should we do? } struct _vg_read_orphan_baton { struct volume_group *vg; int warnings; }; static int _vg_read_orphan_pv(struct lvmcache_info *info, void *baton) { struct _vg_read_orphan_baton *b = baton; struct physical_volume *pv = NULL; struct pv_list *pvl; if (!(pv = _pv_read(b->vg->cmd, b->vg->vgmem, dev_name(lvmcache_device(info)), b->vg->fid, b->warnings, 0))) { stack; return 1; } if (!(pvl = dm_pool_zalloc(b->vg->vgmem, sizeof(*pvl)))) { log_error("pv_list allocation failed"); free_pv_fid(pv); return 0; } pvl->pv = pv; add_pvl_to_vgs(b->vg, pvl); return 1; } /* Make orphan PVs look like a VG. */ static struct volume_group *_vg_read_orphans(struct cmd_context *cmd, int warnings, const char *orphan_vgname) { const struct format_type *fmt; struct lvmcache_vginfo *vginfo; struct volume_group *vg = NULL; struct _vg_read_orphan_baton baton; struct pv_list *pvl; lvmcache_label_scan(cmd, 0); lvmcache_seed_infos_from_lvmetad(cmd); if (!(vginfo = lvmcache_vginfo_from_vgname(orphan_vgname, NULL))) return_NULL; if (!(fmt = lvmcache_fmt_from_vgname(cmd, orphan_vgname, NULL, 0))) return_NULL; vg = fmt->orphan_vg; dm_list_iterate_items(pvl, &vg->pvs) pv_set_fid(pvl->pv, NULL); dm_list_init(&vg->pvs); vg->pv_count = 0; baton.warnings = warnings; baton.vg = vg; if (!lvmcache_foreach_pv(vginfo, _vg_read_orphan_pv, &baton)) return_NULL; return vg; } static int _update_pv_list(struct dm_pool *pvmem, struct dm_list *all_pvs, struct volume_group *vg) { struct pv_list *pvl, *pvl2; dm_list_iterate_items(pvl, &vg->pvs) { dm_list_iterate_items(pvl2, all_pvs) { if (pvl->pv->dev == pvl2->pv->dev) goto next_pv; } /* * PV is not on list so add it. */ if (!(pvl2 = _copy_pvl(pvmem, pvl))) { log_error("pv_list allocation for '%s' failed", pv_dev_name(pvl->pv)); return 0; } dm_list_add(all_pvs, &pvl2->list); next_pv: ; } return 1; } static void _free_pv_list(struct dm_list *all_pvs) { struct pv_list *pvl; dm_list_iterate_items(pvl, all_pvs) pvl->pv->fid->fmt->ops->destroy_instance(pvl->pv->fid); } static void _destroy_fid(struct format_instance **fid) { if (*fid) { (*fid)->fmt->ops->destroy_instance(*fid); *fid = NULL; } } int vg_missing_pv_count(const struct volume_group *vg) { int ret = 0; struct pv_list *pvl; dm_list_iterate_items(pvl, &vg->pvs) { if (is_missing_pv(pvl->pv)) ++ ret; } return ret; } static void check_reappeared_pv(struct volume_group *correct_vg, struct physical_volume *pv) { struct pv_list *pvl; /* * Skip these checks in case the tool is going to deal with missing * PVs, especially since the resulting messages can be pretty * confusing. */ if (correct_vg->cmd->handles_missing_pvs) return; dm_list_iterate_items(pvl, &correct_vg->pvs) if (pv->dev == pvl->pv->dev && is_missing_pv(pvl->pv)) { log_warn("Missing device %s reappeared, updating " "metadata for VG %s to version %u.", pv_dev_name(pvl->pv), pv_vg_name(pvl->pv), correct_vg->seqno); if (pvl->pv->pe_alloc_count == 0) { pv->status &= ~MISSING_PV; pvl->pv->status &= ~MISSING_PV; } else log_warn("Device still marked missing because of allocated data " "on it, remove volumes and consider vgreduce --removemissing."); } } static int _check_mda_in_use(struct metadata_area *mda, void *_in_use) { int *in_use = _in_use; if (!mda_is_ignored(mda)) *in_use = 1; return 1; } /* Caller sets consistent to 1 if it's safe for vg_read_internal to correct * inconsistent metadata on disk (i.e. the VG write lock is held). * This guarantees only consistent metadata is returned. * If consistent is 0, caller must check whether consistent == 1 on return * and take appropriate action if it isn't (e.g. abort; get write lock * and call vg_read_internal again). * * If precommitted is set, use precommitted metadata if present. * * Either of vgname or vgid may be NULL. * * Note: vginfo structs must not be held or used as parameters * across the call to this function. */ static struct volume_group *_vg_read(struct cmd_context *cmd, const char *vgname, const char *vgid, int warnings, int *consistent, unsigned precommitted) { struct format_instance *fid = NULL; struct format_instance_ctx fic; const struct format_type *fmt; struct volume_group *vg, *correct_vg = NULL; struct metadata_area *mda; struct lvmcache_info *info; int inconsistent = 0; int inconsistent_vgid = 0; int inconsistent_pvs = 0; int inconsistent_mdas = 0; int inconsistent_mda_count = 0; unsigned use_precommitted = precommitted; unsigned saved_handles_missing_pvs = cmd->handles_missing_pvs; struct dm_list *pvids; struct pv_list *pvl, *pvl2; struct dm_list all_pvs; char uuid[64] __attribute__((aligned(8))); unsigned seqno = 0; if (is_orphan_vg(vgname)) { if (use_precommitted) { log_error(INTERNAL_ERROR "vg_read_internal requires vgname " "with pre-commit."); return NULL; } *consistent = 1; return _vg_read_orphans(cmd, warnings, vgname); } if (lvmetad_active() && !use_precommitted) { *consistent = 1; return lvmcache_get_vg(cmd, vgname, vgid, precommitted); } /* * If cached metadata was inconsistent and *consistent is set * then repair it now. Otherwise just return it. * Also return if use_precommitted is set due to the FIXME in * the missing PV logic below. */ if ((correct_vg = lvmcache_get_vg(cmd, vgname, vgid, precommitted)) && (use_precommitted || !*consistent)) { *consistent = 1; return correct_vg; } else { if (correct_vg && correct_vg->seqno > seqno) seqno = correct_vg->seqno; release_vg(correct_vg); correct_vg = NULL; } /* Find the vgname in the cache */ /* If it's not there we must do full scan to be completely sure */ if (!(fmt = lvmcache_fmt_from_vgname(cmd, vgname, vgid, 1))) { lvmcache_label_scan(cmd, 0); if (!(fmt = lvmcache_fmt_from_vgname(cmd, vgname, vgid, 1))) { /* Independent MDAs aren't supported under low memory */ if (!cmd->independent_metadata_areas && critical_section()) return_NULL; lvmcache_label_scan(cmd, 2); if (!(fmt = lvmcache_fmt_from_vgname(cmd, vgname, vgid, 0))) return_NULL; } } /* Now determine the correct vgname if none was supplied */ if (!vgname && !(vgname = lvmcache_vgname_from_vgid(cmd->mem, vgid))) return_NULL; if (use_precommitted && !(fmt->features & FMT_PRECOMMIT)) use_precommitted = 0; /* create format instance with appropriate metadata area */ fic.type = FMT_INSTANCE_MDAS | FMT_INSTANCE_AUX_MDAS; fic.context.vg_ref.vg_name = vgname; fic.context.vg_ref.vg_id = vgid; if (!(fid = fmt->ops->create_instance(fmt, &fic))) { log_error("Failed to create format instance"); return NULL; } /* Store pvids for later so we can check if any are missing */ if (!(pvids = lvmcache_get_pvids(cmd, vgname, vgid))) { _destroy_fid(&fid); return_NULL; } /* * We use the fid globally here so prevent the release_vg * call to destroy the fid - we may want to reuse it! */ fid->ref_count++; /* Ensure contents of all metadata areas match - else do recovery */ inconsistent_mda_count=0; dm_list_iterate_items(mda, &fid->metadata_areas_in_use) { if ((use_precommitted && !(vg = mda->ops->vg_read_precommit(fid, vgname, mda))) || (!use_precommitted && !(vg = mda->ops->vg_read(fid, vgname, mda, 0)))) { inconsistent = 1; continue; } if (!correct_vg) { correct_vg = vg; continue; } /* FIXME Also ensure contents same - checksum compare? */ if (correct_vg->seqno != vg->seqno) { if (cmd->metadata_read_only) log_very_verbose("Not repairing VG %s metadata seqno (%d != %d) " "as global/metadata_read_only is set.", vgname, vg->seqno, correct_vg->seqno); else inconsistent = 1; if (vg->seqno > correct_vg->seqno) { release_vg(correct_vg); correct_vg = vg; } else { mda->status |= MDA_INCONSISTENT; ++inconsistent_mda_count; } } if (vg != correct_vg) release_vg(vg); } fid->ref_count--; /* Ensure every PV in the VG was in the cache */ if (correct_vg) { /* * Update the seqno from the cache, for the benefit of * retro-style metadata formats like LVM1. */ // correct_vg->seqno = seqno > correct_vg->seqno ? seqno : correct_vg->seqno; /* * If the VG has PVs without mdas, or ignored mdas, they may * still be orphans in the cache: update the cache state here, * and update the metadata lists in the vg. */ if (!inconsistent && dm_list_size(&correct_vg->pvs) > dm_list_size(pvids)) { dm_list_iterate_items(pvl, &correct_vg->pvs) { if (!pvl->pv->dev) { inconsistent_pvs = 1; break; } if (str_list_match_item(pvids, pvl->pv->dev->pvid)) continue; /* * PV not marked as belonging to this VG in cache. * Check it's an orphan without metadata area * not ignored. */ if (!(info = lvmcache_info_from_pvid(pvl->pv->dev->pvid, 1)) || !lvmcache_is_orphan(info)) { inconsistent_pvs = 1; break; } if (lvmcache_mda_count(info)) { if (!lvmcache_fid_add_mdas_pv(info, fid)) { release_vg(correct_vg); return_NULL; } log_debug("Empty mda found for VG %s.", vgname); if (inconsistent_mdas) continue; /* * If any newly-added mdas are in-use then their * metadata needs updating. */ lvmcache_foreach_mda(info, _check_mda_in_use, &inconsistent_mdas); } } /* If the check passed, let's update VG and recalculate pvids */ if (!inconsistent_pvs) { log_debug("Updating cache for PVs without mdas " "in VG %s.", vgname); /* * If there is no precommitted metadata, committed metadata * is read and stored in the cache even if use_precommitted is set */ lvmcache_update_vg(correct_vg, correct_vg->status & PRECOMMITTED); if (!(pvids = lvmcache_get_pvids(cmd, vgname, vgid))) { release_vg(correct_vg); return_NULL; } } } fid->ref_count++; if (dm_list_size(&correct_vg->pvs) != dm_list_size(pvids) + vg_missing_pv_count(correct_vg)) { log_debug("Cached VG %s had incorrect PV list", vgname); if (critical_section()) inconsistent = 1; else { release_vg(correct_vg); correct_vg = NULL; } } else dm_list_iterate_items(pvl, &correct_vg->pvs) { if (is_missing_pv(pvl->pv)) continue; if (!str_list_match_item(pvids, pvl->pv->dev->pvid)) { log_debug("Cached VG %s had incorrect PV list", vgname); release_vg(correct_vg); correct_vg = NULL; break; } } if (correct_vg && inconsistent_mdas) { release_vg(correct_vg); correct_vg = NULL; } fid->ref_count--; } dm_list_init(&all_pvs); /* Failed to find VG where we expected it - full scan and retry */ if (!correct_vg) { /* * Free outstanding format instance that remained unassigned * from previous step where we tried to get the "correct_vg", * but we failed to do so (so there's a dangling fid now). */ _destroy_fid(&fid); inconsistent = 0; /* Independent MDAs aren't supported under low memory */ if (!cmd->independent_metadata_areas && critical_section()) return_NULL; lvmcache_label_scan(cmd, 2); if (!(fmt = lvmcache_fmt_from_vgname(cmd, vgname, vgid, 0))) return_NULL; if (precommitted && !(fmt->features & FMT_PRECOMMIT)) use_precommitted = 0; /* create format instance with appropriate metadata area */ fic.type = FMT_INSTANCE_MDAS | FMT_INSTANCE_AUX_MDAS; fic.context.vg_ref.vg_name = vgname; fic.context.vg_ref.vg_id = vgid; if (!(fid = fmt->ops->create_instance(fmt, &fic))) { log_error("Failed to create format instance"); return NULL; } /* * We use the fid globally here so prevent the release_vg * call to destroy the fid - we may want to reuse it! */ fid->ref_count++; /* Ensure contents of all metadata areas match - else recover */ inconsistent_mda_count=0; dm_list_iterate_items(mda, &fid->metadata_areas_in_use) { if ((use_precommitted && !(vg = mda->ops->vg_read_precommit(fid, vgname, mda))) || (!use_precommitted && !(vg = mda->ops->vg_read(fid, vgname, mda, 0)))) { inconsistent = 1; continue; } if (!correct_vg) { correct_vg = vg; if (!_update_pv_list(cmd->mem, &all_pvs, correct_vg)) { _free_pv_list(&all_pvs); fid->ref_count--; release_vg(vg); return_NULL; } continue; } if (!id_equal(&vg->id, &correct_vg->id)) { inconsistent = 1; inconsistent_vgid = 1; } /* FIXME Also ensure contents same - checksums same? */ if (correct_vg->seqno != vg->seqno) { /* Ignore inconsistent seqno if told to skip repair logic */ if (cmd->metadata_read_only) log_very_verbose("Not repairing VG %s metadata seqno (%d != %d) " "as global/metadata_read_only is set.", vgname, vg->seqno, correct_vg->seqno); else inconsistent = 1; if (!_update_pv_list(cmd->mem, &all_pvs, vg)) { _free_pv_list(&all_pvs); fid->ref_count--; release_vg(vg); release_vg(correct_vg); return_NULL; } if (vg->seqno > correct_vg->seqno) { release_vg(correct_vg); correct_vg = vg; } else { mda->status |= MDA_INCONSISTENT; ++inconsistent_mda_count; } } if (vg != correct_vg) release_vg(vg); } fid->ref_count--; /* Give up looking */ if (!correct_vg) { _free_pv_list(&all_pvs); _destroy_fid(&fid); return_NULL; } } /* * If there is no precommitted metadata, committed metadata * is read and stored in the cache even if use_precommitted is set */ lvmcache_update_vg(correct_vg, (correct_vg->status & PRECOMMITTED)); if (inconsistent) { /* FIXME Test should be if we're *using* precommitted metadata not if we were searching for it */ if (use_precommitted) { log_error("Inconsistent pre-commit metadata copies " "for volume group %s", vgname); /* * Check whether all of the inconsistent MDAs were on * MISSING PVs -- in that case, we should be safe. */ dm_list_iterate_items(mda, &fid->metadata_areas_in_use) { if (mda->status & MDA_INCONSISTENT) { log_debug("Checking inconsistent MDA: %s", dev_name(mda_get_device(mda))); dm_list_iterate_items(pvl, &correct_vg->pvs) { if (mda_get_device(mda) == pvl->pv->dev && (pvl->pv->status & MISSING_PV)) --inconsistent_mda_count; } } } if (inconsistent_mda_count < 0) log_error(INTERNAL_ERROR "Too many inconsistent MDAs."); if (!inconsistent_mda_count) { *consistent = 0; _free_pv_list(&all_pvs); return correct_vg; } _free_pv_list(&all_pvs); release_vg(correct_vg); return NULL; } if (!*consistent) { _free_pv_list(&all_pvs); return correct_vg; } /* Don't touch if vgids didn't match */ if (inconsistent_vgid) { log_error("Inconsistent metadata UUIDs found for " "volume group %s", vgname); *consistent = 0; _free_pv_list(&all_pvs); return correct_vg; } log_warn("WARNING: Inconsistent metadata found for VG %s - updating " "to use version %u", vgname, correct_vg->seqno); /* * If PV is marked missing but we found it, * update metadata and remove MISSING flag */ dm_list_iterate_items(pvl, &all_pvs) check_reappeared_pv(correct_vg, pvl->pv); cmd->handles_missing_pvs = 1; if (!vg_write(correct_vg)) { log_error("Automatic metadata correction failed"); _free_pv_list(&all_pvs); release_vg(correct_vg); cmd->handles_missing_pvs = saved_handles_missing_pvs; return NULL; } cmd->handles_missing_pvs = saved_handles_missing_pvs; if (!vg_commit(correct_vg)) { log_error("Automatic metadata correction commit " "failed"); release_vg(correct_vg); return NULL; } dm_list_iterate_items(pvl, &all_pvs) { dm_list_iterate_items(pvl2, &correct_vg->pvs) { if (pvl->pv->dev == pvl2->pv->dev) goto next_pv; } if (!id_write_format(&pvl->pv->id, uuid, sizeof(uuid))) { _free_pv_list(&all_pvs); release_vg(correct_vg); return_NULL; } log_error("Removing PV %s (%s) that no longer belongs to VG %s", pv_dev_name(pvl->pv), uuid, correct_vg->name); if (!pv_write_orphan(cmd, pvl->pv)) { _free_pv_list(&all_pvs); release_vg(correct_vg); return_NULL; } /* Refresh metadata after orphan write */ drop_cached_metadata(correct_vg); next_pv: ; } } _free_pv_list(&all_pvs); if (vg_missing_pv_count(correct_vg)) { log_verbose("There are %d physical volumes missing.", vg_missing_pv_count(correct_vg)); vg_mark_partial_lvs(correct_vg, 1); } if ((correct_vg->status & PVMOVE) && !pvmove_mode()) { log_error("WARNING: Interrupted pvmove detected in " "volume group %s", correct_vg->name); log_error("Please restore the metadata by running " "vgcfgrestore."); release_vg(correct_vg); return NULL; } *consistent = 1; return correct_vg; } struct volume_group *vg_read_internal(struct cmd_context *cmd, const char *vgname, const char *vgid, int warnings, int *consistent) { struct volume_group *vg; struct lv_list *lvl; if (!(vg = _vg_read(cmd, vgname, vgid, warnings, consistent, 0))) return NULL; if (!check_pv_segments(vg)) { log_error(INTERNAL_ERROR "PV segments corrupted in %s.", vg->name); release_vg(vg); return NULL; } dm_list_iterate_items(lvl, &vg->lvs) { if (!check_lv_segments(lvl->lv, 0)) { log_error(INTERNAL_ERROR "LV segments corrupted in %s.", lvl->lv->name); release_vg(vg); return NULL; } } dm_list_iterate_items(lvl, &vg->lvs) { /* * Checks that cross-reference other LVs. */ if (!check_lv_segments(lvl->lv, 1)) { log_error(INTERNAL_ERROR "LV segments corrupted in %s.", lvl->lv->name); release_vg(vg); return NULL; } } return vg; } void free_pv_fid(struct physical_volume *pv) { if (!pv) return; if (pv->fid) pv->fid->fmt->ops->destroy_instance(pv->fid); } /* This is only called by lv_from_lvid, which is only called from * activate.c so we know the appropriate VG lock is already held and * the vg_read_internal is therefore safe. */ static struct volume_group *_vg_read_by_vgid(struct cmd_context *cmd, const char *vgid, unsigned precommitted) { const char *vgname; struct dm_list *vgnames; struct volume_group *vg; struct str_list *strl; int consistent = 0; /* Is corresponding vgname already cached? */ if (lvmcache_vgid_is_cached(vgid)) { if ((vg = _vg_read(cmd, NULL, vgid, 1, &consistent, precommitted)) && id_equal(&vg->id, (const struct id *)vgid)) { if (!consistent) log_error("Volume group %s metadata is " "inconsistent", vg->name); return vg; } release_vg(vg); } /* Mustn't scan if memory locked: ensure cache gets pre-populated! */ if (critical_section()) return_NULL; /* FIXME Need a genuine read by ID here - don't vg_read_internal by name! */ /* FIXME Disabled vgrenames while active for now because we aren't * allowed to do a full scan here any more. */ // The slow way - full scan required to cope with vgrename lvmcache_label_scan(cmd, 2); if (!(vgnames = get_vgnames(cmd, 0))) { log_error("vg_read_by_vgid: get_vgnames failed"); return NULL; } dm_list_iterate_items(strl, vgnames) { vgname = strl->str; if (!vgname) continue; // FIXME Unnecessary? consistent = 0; if ((vg = _vg_read(cmd, vgname, vgid, 1, &consistent, precommitted)) && id_equal(&vg->id, (const struct id *)vgid)) { if (!consistent) { log_error("Volume group %s metadata is " "inconsistent", vgname); release_vg(vg); return NULL; } return vg; } release_vg(vg); } return NULL; } /* Only called by activate.c */ struct logical_volume *lv_from_lvid(struct cmd_context *cmd, const char *lvid_s, unsigned precommitted) { struct lv_list *lvl; struct volume_group *vg; const union lvid *lvid; lvid = (const union lvid *) lvid_s; log_very_verbose("Finding volume group for uuid %s", lvid_s); if (!(vg = _vg_read_by_vgid(cmd, (const char *)lvid->id[0].uuid, precommitted))) { log_error("Volume group for uuid not found: %s", lvid_s); return NULL; } log_verbose("Found volume group \"%s\"", vg->name); if (vg->status & EXPORTED_VG) { log_error("Volume group \"%s\" is exported", vg->name); goto out; } if (!(lvl = find_lv_in_vg_by_lvid(vg, lvid))) { log_very_verbose("Can't find logical volume id %s", lvid_s); goto out; } return lvl->lv; out: release_vg(vg); return NULL; } const char *find_vgname_from_pvid(struct cmd_context *cmd, const char *pvid) { char *vgname; struct lvmcache_info *info; vgname = lvmcache_vgname_from_pvid(cmd, pvid); if (is_orphan_vg(vgname)) { if (!(info = lvmcache_info_from_pvid(pvid, 0))) { return_NULL; } /* * If an orphan PV has no MDAs, or it has MDAs but the * MDA is ignored, it may appear to be an orphan until * the metadata is read off another PV in the same VG. * Detecting this means checking every VG by scanning * every PV on the system. */ if (lvmcache_uncertain_ownership(info)) { if (!scan_vgs_for_pvs(cmd, 1)) { log_error("Rescan for PVs without " "metadata areas failed."); return NULL; } /* * Ask lvmcache again - we may have a non-orphan * name now */ vgname = lvmcache_vgname_from_pvid(cmd, pvid); } } return vgname; } const char *find_vgname_from_pvname(struct cmd_context *cmd, const char *pvname) { const char *pvid; pvid = lvmcache_pvid_from_devname(cmd, pvname); if (!pvid) /* Not a PV */ return NULL; return find_vgname_from_pvid(cmd, pvid); } /** * pv_read - read and return a handle to a physical volume * @cmd: LVM command initiating the pv_read * @pv_name: full device name of the PV, including the path * @mdas: list of metadata areas of the PV * @label_sector: sector number where the PV label is stored on @pv_name * @warnings: * * Returns: * PV handle - valid pv_name and successful read of the PV, or * NULL - invalid parameter or error in reading the PV * * Note: * FIXME - liblvm todo - make into function that returns handle */ struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name, int warnings, int scan_label_only) { return _pv_read(cmd, cmd->mem, pv_name, NULL, warnings, scan_label_only); } /* FIXME Use label functions instead of PV functions */ static struct physical_volume *_pv_read(struct cmd_context *cmd, struct dm_pool *pvmem, const char *pv_name, struct format_instance *fid, int warnings, int scan_label_only) { struct physical_volume *pv; struct label *label; struct lvmcache_info *info; struct device *dev; const struct format_type *fmt; int found; if (!(dev = dev_cache_get(pv_name, cmd->filter))) return_NULL; if (lvmetad_active()) { info = lvmcache_info_from_pvid(dev->pvid, 0); if (!info) { if (!lvmetad_pv_lookup_by_dev(cmd, dev, &found)) return_NULL; if (!found) { if (warnings) log_error("No physical volume found in lvmetad cache for %s", pv_name); return NULL; } } info = lvmcache_info_from_pvid(dev->pvid, 0); label = lvmcache_get_label(info); } else { if (!(label_read(dev, &label, UINT64_C(0)))) { if (warnings) log_error("No physical volume label read from %s", pv_name); return NULL; } info = (struct lvmcache_info *) label->info; } fmt = lvmcache_fmt(info); pv = _alloc_pv(pvmem, dev); if (!pv) { log_error("pv allocation for '%s' failed", pv_name); return NULL; } pv->label_sector = label->sector; /* FIXME Move more common code up here */ if (!(lvmcache_fmt(info)->ops->pv_read(lvmcache_fmt(info), pv_name, pv, scan_label_only))) { log_error("Failed to read existing physical volume '%s'", pv_name); goto bad; } if (!pv->size) goto bad; if (!alloc_pv_segment_whole_pv(pvmem, pv)) goto_bad; if (fid) lvmcache_fid_add_mdas(info, fid, (const char *) &pv->id, ID_LEN); else { lvmcache_fid_add_mdas(info, fmt->orphan_vg->fid, (const char *) &pv->id, ID_LEN); pv_set_fid(pv, fmt->orphan_vg->fid); } return pv; bad: free_pv_fid(pv); dm_pool_free(pvmem, pv); return NULL; } /* May return empty list */ struct dm_list *get_vgnames(struct cmd_context *cmd, int include_internal) { return lvmcache_get_vgnames(cmd, include_internal); } struct dm_list *get_vgids(struct cmd_context *cmd, int include_internal) { return lvmcache_get_vgids(cmd, include_internal); } static int _get_pvs(struct cmd_context *cmd, int warnings, struct dm_list **pvslist) { struct str_list *strl; struct dm_list * uninitialized_var(results); const char *vgname, *vgid; struct pv_list *pvl, *pvl_copy; struct dm_list *vgids; struct volume_group *vg; int consistent = 0; int old_pvmove; lvmcache_label_scan(cmd, 0); if (pvslist) { if (!(results = dm_pool_alloc(cmd->mem, sizeof(*results)))) { log_error("PV list allocation failed"); return 0; } dm_list_init(results); } /* Get list of VGs */ if (!(vgids = get_vgids(cmd, 1))) { log_error("get_pvs: get_vgids failed"); return 0; } /* Read every VG to ensure cache consistency */ /* Orphan VG is last on list */ old_pvmove = pvmove_mode(); init_pvmove(1); dm_list_iterate_items(strl, vgids) { vgid = strl->str; if (!vgid) continue; /* FIXME Unnecessary? */ consistent = 0; if (!(vgname = lvmcache_vgname_from_vgid(NULL, vgid))) { stack; continue; } if (!(vg = vg_read_internal(cmd, vgname, vgid, warnings, &consistent))) { stack; continue; } if (!consistent) log_warn("WARNING: Volume Group %s is not consistent", vgname); /* Move PVs onto results list */ if (pvslist) dm_list_iterate_items(pvl, &vg->pvs) { if (!(pvl_copy = _copy_pvl(cmd->mem, pvl))) { log_error("PV list allocation failed"); release_vg(vg); return 0; } dm_list_add(results, &pvl_copy->list); } release_vg(vg); } init_pvmove(old_pvmove); if (pvslist) *pvslist = results; else dm_pool_free(cmd->mem, vgids); return 1; } struct dm_list *get_pvs(struct cmd_context *cmd) { struct dm_list *results; if (!_get_pvs(cmd, 1, &results)) return NULL; return results; } int scan_vgs_for_pvs(struct cmd_context *cmd, int warnings) { return _get_pvs(cmd, warnings, NULL); } int pv_write(struct cmd_context *cmd __attribute__((unused)), struct physical_volume *pv, int allow_non_orphan) { if (!pv->fmt->ops->pv_write) { log_error("Format does not support writing physical volumes"); return 0; } /* * FIXME: Try to remove this restriction. This requires checking * that the PV and the VG are in a consistent state. We need * to provide some revert mechanism since PV label together * with VG metadata write is not atomic. */ if (!allow_non_orphan && (!is_orphan_vg(pv->vg_name) || pv->pe_alloc_count)) { log_error("Assertion failed: can't _pv_write non-orphan PV " "(in VG %s)", pv->vg_name); return 0; } if (!pv->fmt->ops->pv_write(pv->fmt, pv)) return_0; if (!lvmetad_pv_found(&pv->id, pv->dev, pv->fmt, pv->label_sector, NULL, NULL)) return_0; return 1; } int pv_write_orphan(struct cmd_context *cmd, struct physical_volume *pv) { const char *old_vg_name = pv->vg_name; pv->vg_name = cmd->fmt->orphan_vg_name; pv->status = ALLOCATABLE_PV; pv->pe_alloc_count = 0; if (!dev_get_size(pv->dev, &pv->size)) { log_error("%s: Couldn't get size.", pv_dev_name(pv)); return 0; } if (!pv_write(cmd, pv, 0)) { log_error("Failed to clear metadata from physical " "volume \"%s\" after removal from \"%s\"", pv_dev_name(pv), old_vg_name); return 0; } return 1; } int is_global_vg(const char *vg_name) { return (vg_name && !strcmp(vg_name, VG_GLOBAL)) ? 1 : 0; } /** * is_orphan_vg - Determine whether a vg_name is an orphan * @vg_name: pointer to the vg_name */ int is_orphan_vg(const char *vg_name) { return (vg_name && !strncmp(vg_name, ORPHAN_PREFIX, sizeof(ORPHAN_PREFIX) - 1)) ? 1 : 0; } /* * Exclude pseudo VG names used for locking. */ int is_real_vg(const char *vg_name) { return (vg_name && *vg_name != '#'); } static int _analyze_mda(struct metadata_area *mda, void *baton) { const struct format_type *fmt = baton; mda->ops->pv_analyze_mda(fmt, mda); return 1; } /* * Returns: * 0 - fail * 1 - success */ int pv_analyze(struct cmd_context *cmd, const char *pv_name, uint64_t label_sector) { struct label *label; struct device *dev; struct lvmcache_info *info; dev = dev_cache_get(pv_name, cmd->filter); if (!dev) { log_error("Device %s not found (or ignored by filtering).", pv_name); return 0; } /* * First, scan for LVM labels. */ if (!label_read(dev, &label, label_sector)) { log_error("Could not find LVM label on %s", pv_name); return 0; } log_print("Found label on %s, sector %"PRIu64", type=%.8s", pv_name, label->sector, label->type); /* * Next, loop through metadata areas */ info = label->info; lvmcache_foreach_mda(info, _analyze_mda, (void *)lvmcache_fmt(info)); return 1; } /* FIXME: remove / combine this with locking? */ int vg_check_write_mode(struct volume_group *vg) { if (vg->open_mode != 'w') { log_errno(EPERM, "Attempt to modify a read-only VG"); return 0; } return 1; } /* * Performs a set of checks against a VG according to bits set in status * and returns FAILED_* bits for those that aren't acceptable. * * FIXME Remove the unnecessary duplicate definitions and return bits directly. */ static uint32_t _vg_bad_status_bits(const struct volume_group *vg, uint64_t status) { uint32_t failure = 0; if ((status & CLUSTERED) && (vg_is_clustered(vg)) && !locking_is_clustered()) { log_error("Skipping clustered volume group %s", vg->name); /* Return because other flags are considered undefined. */ return FAILED_CLUSTERED; } if ((status & EXPORTED_VG) && vg_is_exported(vg)) { log_error("Volume group %s is exported", vg->name); failure |= FAILED_EXPORTED; } if ((status & LVM_WRITE) && !(vg->status & LVM_WRITE)) { log_error("Volume group %s is read-only", vg->name); failure |= FAILED_READ_ONLY; } if ((status & RESIZEABLE_VG) && !vg_is_resizeable(vg)) { log_error("Volume group %s is not resizeable.", vg->name); failure |= FAILED_RESIZEABLE; } return failure; } /** * vg_check_status - check volume group status flags and log error * @vg - volume group to check status flags * @status - specific status flags to check (e.g. EXPORTED_VG) */ int vg_check_status(const struct volume_group *vg, uint64_t status) { return !_vg_bad_status_bits(vg, status); } static struct volume_group *_recover_vg(struct cmd_context *cmd, const char *vg_name, const char *vgid) { int consistent = 1; struct volume_group *vg; unlock_vg(cmd, vg_name); dev_close_all(); if (!lock_vol(cmd, vg_name, LCK_VG_WRITE)) return_NULL; if (!(vg = vg_read_internal(cmd, vg_name, vgid, 1, &consistent))) return_NULL; if (!consistent) { release_vg(vg); return_NULL; } return (struct volume_group *)vg; } /* * Consolidated locking, reading, and status flag checking. * * If the metadata is inconsistent, setting READ_ALLOW_INCONSISTENT in * misc_flags will return it with FAILED_INCONSISTENT set instead of * giving you nothing. * * Use vg_read_error(vg) to determine the result. Nonzero means there were * problems reading the volume group. * Zero value means that the VG is open and appropriate locks are held. */ static struct volume_group *_vg_lock_and_read(struct cmd_context *cmd, const char *vg_name, const char *vgid, uint32_t lock_flags, uint64_t status_flags, uint32_t misc_flags) { struct volume_group *vg = NULL; int consistent = 1; int consistent_in; uint32_t failure = 0; int already_locked; if (misc_flags & READ_ALLOW_INCONSISTENT || lock_flags != LCK_VG_WRITE) consistent = 0; if (!validate_name(vg_name) && !is_orphan_vg(vg_name)) { log_error("Volume group name %s has invalid characters", vg_name); return NULL; } already_locked = lvmcache_vgname_is_locked(vg_name); if (!already_locked && !(misc_flags & READ_WITHOUT_LOCK) && !lock_vol(cmd, vg_name, lock_flags)) { log_error("Can't get lock for %s", vg_name); return _vg_make_handle(cmd, vg, FAILED_LOCKING); } if (is_orphan_vg(vg_name)) status_flags &= ~LVM_WRITE; consistent_in = consistent; /* If consistent == 1, we get NULL here if correction fails. */ if (!(vg = vg_read_internal(cmd, vg_name, vgid, 1, &consistent))) { if (consistent_in && !consistent) { log_error("Volume group \"%s\" inconsistent.", vg_name); failure |= FAILED_INCONSISTENT; goto_bad; } log_error("Volume group \"%s\" not found", vg_name); failure |= FAILED_NOTFOUND; goto bad; } if (vg_is_clustered(vg) && !locking_is_clustered()) { log_error("Skipping clustered volume group %s", vg->name); failure |= FAILED_CLUSTERED; goto bad; } /* consistent == 0 when VG is not found, but failed == FAILED_NOTFOUND */ if (!consistent && !failure) { release_vg(vg); if (!(vg = _recover_vg(cmd, vg_name, vgid))) { log_error("Recovery of volume group \"%s\" failed.", vg_name); failure |= FAILED_INCONSISTENT; goto_bad; } } /* * Check that the tool can handle tricky cases -- missing PVs and * unknown segment types. */ if (!cmd->handles_missing_pvs && vg_missing_pv_count(vg) && lock_flags == LCK_VG_WRITE) { log_error("Cannot change VG %s while PVs are missing.", vg->name); log_error("Consider vgreduce --removemissing."); failure |= FAILED_INCONSISTENT; /* FIXME new failure code here? */ goto_bad; } if (!cmd->handles_unknown_segments && vg_has_unknown_segments(vg) && lock_flags == LCK_VG_WRITE) { log_error("Cannot change VG %s with unknown segments in it!", vg->name); failure |= FAILED_INCONSISTENT; /* FIXME new failure code here? */ goto_bad; } failure |= _vg_bad_status_bits(vg, status_flags); if (failure) goto_bad; return _vg_make_handle(cmd, vg, failure); bad: if (!already_locked && !(misc_flags & READ_WITHOUT_LOCK)) unlock_vg(cmd, vg_name); return _vg_make_handle(cmd, vg, failure); } /* * vg_read: High-level volume group metadata read function. * * vg_read_error() must be used on any handle returned to check for errors. * * - metadata inconsistent and automatic correction failed: FAILED_INCONSISTENT * - VG is read-only: FAILED_READ_ONLY * - VG is EXPORTED, unless flags has READ_ALLOW_EXPORTED: FAILED_EXPORTED * - VG is not RESIZEABLE: FAILED_RESIZEABLE * - locking failed: FAILED_LOCKING * * On failures, all locks are released, unless one of the following applies: * - vgname_is_locked(lock_name) is true * FIXME: remove the above 2 conditions if possible and make an error always * release the lock. * * Volume groups are opened read-only unless flags contains READ_FOR_UPDATE. * * Checking for VG existence: * * FIXME: We want vg_read to attempt automatic recovery after acquiring a * temporary write lock: if that fails, we bail out as usual, with failed & * FAILED_INCONSISTENT. If it works, we are good to go. Code that's been in * toollib just set lock_flags to LCK_VG_WRITE and called vg_read_internal with * *consistent = 1. */ struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name, const char *vgid, uint32_t flags) { uint64_t status = UINT64_C(0); uint32_t lock_flags = LCK_VG_READ; if (flags & READ_FOR_UPDATE) { status |= EXPORTED_VG | LVM_WRITE; lock_flags = LCK_VG_WRITE; } if (flags & READ_ALLOW_EXPORTED) status &= ~EXPORTED_VG; return _vg_lock_and_read(cmd, vg_name, vgid, lock_flags, status, flags); } /* * A high-level volume group metadata reading function. Open a volume group for * later update (this means the user code can change the metadata and later * request the new metadata to be written and committed). */ struct volume_group *vg_read_for_update(struct cmd_context *cmd, const char *vg_name, const char *vgid, uint32_t flags) { return vg_read(cmd, vg_name, vgid, flags | READ_FOR_UPDATE); } /* * Test the validity of a VG handle returned by vg_read() or vg_read_for_update(). */ uint32_t vg_read_error(struct volume_group *vg_handle) { if (!vg_handle) return FAILED_ALLOCATION; return vg_handle->read_status; } /* * Lock a vgname and/or check for existence. * Takes a WRITE lock on the vgname before scanning. * If scanning fails or vgname found, release the lock. * NOTE: If you find the return codes confusing, you might think of this * function as similar to an open() call with O_CREAT and O_EXCL flags * (open returns fail with -EEXIST if file already exists). * * Returns: * FAILED_LOCKING - Cannot lock name * FAILED_EXIST - VG name already exists - cannot reserve * SUCCESS - VG name does not exist in system and WRITE lock held */ uint32_t vg_lock_newname(struct cmd_context *cmd, const char *vgname) { if (!lock_vol(cmd, vgname, LCK_VG_WRITE)) { return FAILED_LOCKING; } /* Find the vgname in the cache */ /* If it's not there we must do full scan to be completely sure */ if (!lvmcache_fmt_from_vgname(cmd, vgname, NULL, 1)) { lvmcache_label_scan(cmd, 0); if (!lvmcache_fmt_from_vgname(cmd, vgname, NULL, 1)) { /* Independent MDAs aren't supported under low memory */ if (!cmd->independent_metadata_areas && critical_section()) { /* * FIXME: Disallow calling this function if * critical_section() is true. */ unlock_vg(cmd, vgname); return FAILED_LOCKING; } lvmcache_label_scan(cmd, 2); if (!lvmcache_fmt_from_vgname(cmd, vgname, NULL, 0)) { /* vgname not found after scanning */ return SUCCESS; } } } /* Found vgname so cannot reserve. */ unlock_vg(cmd, vgname); return FAILED_EXIST; } struct format_instance *alloc_fid(const struct format_type *fmt, const struct format_instance_ctx *fic) { struct dm_pool *mem; struct format_instance *fid; if (!(mem = dm_pool_create("format_instance", 1024))) return_NULL; if (!(fid = dm_pool_zalloc(mem, sizeof(*fid)))) { log_error("Couldn't allocate format_instance object."); goto bad; } fid->ref_count = 1; fid->mem = mem; fid->type = fic->type; fid->fmt = fmt; dm_list_init(&fid->metadata_areas_in_use); dm_list_init(&fid->metadata_areas_ignored); return fid; bad: dm_pool_destroy(mem); return NULL; } void pv_set_fid(struct physical_volume *pv, struct format_instance *fid) { if (fid == pv->fid) return; if (fid) fid->ref_count++; if (pv->fid) pv->fid->fmt->ops->destroy_instance(pv->fid); pv->fid = fid; } void vg_set_fid(struct volume_group *vg, struct format_instance *fid) { struct pv_list *pvl; if (fid == vg->fid) return; if (fid) fid->ref_count++; dm_list_iterate_items(pvl, &vg->pvs) pv_set_fid(pvl->pv, fid); dm_list_iterate_items(pvl, &vg->removed_pvs) pv_set_fid(pvl->pv, fid); if (vg->fid) vg->fid->fmt->ops->destroy_instance(vg->fid); vg->fid = fid; } static int _convert_key_to_string(const char *key, size_t key_len, unsigned sub_key, char *buf, size_t buf_len) { memcpy(buf, key, key_len); buf += key_len; buf_len -= key_len; if ((dm_snprintf(buf, buf_len, "_%u", sub_key) == -1)) return_0; return 1; } int fid_add_mda(struct format_instance *fid, struct metadata_area *mda, const char *key, size_t key_len, const unsigned sub_key) { static char full_key[PATH_MAX]; dm_list_add(mda_is_ignored(mda) ? &fid->metadata_areas_ignored : &fid->metadata_areas_in_use, &mda->list); /* Return if the mda is not supposed to be indexed. */ if (!key) return 1; /* Add metadata area to index. */ if (!_convert_key_to_string(key, key_len, sub_key, full_key, sizeof(full_key))) return_0; if (!dm_hash_insert(fid->metadata_areas_index, full_key, mda)) { log_error("Failed to hash mda."); return 0; } return 1; } int fid_add_mdas(struct format_instance *fid, struct dm_list *mdas, const char *key, size_t key_len) { struct metadata_area *mda, *mda_new; unsigned mda_index = 0; dm_list_iterate_items(mda, mdas) { mda_new = mda_copy(fid->mem, mda); if (!mda_new) return_0; fid_remove_mda(fid, NULL, key, key_len, mda_index); fid_add_mda(fid, mda_new, key, key_len, mda_index); mda_index++; } return 1; } struct metadata_area *fid_get_mda_indexed(struct format_instance *fid, const char *key, size_t key_len, const unsigned sub_key) { static char full_key[PATH_MAX]; struct metadata_area *mda = NULL; if (!_convert_key_to_string(key, key_len, sub_key, full_key, sizeof(full_key))) return_NULL; mda = (struct metadata_area *) dm_hash_lookup(fid->metadata_areas_index, full_key); return mda; } int fid_remove_mda(struct format_instance *fid, struct metadata_area *mda, const char *key, size_t key_len, const unsigned sub_key) { static char full_key[PATH_MAX]; struct metadata_area *mda_indexed = NULL; /* At least one of mda or key must be specified. */ if (!mda && !key) return 1; if (key) { /* * If both mda and key specified, check given mda * with what we find using the index and return * immediately if these two do not match. */ if (!(mda_indexed = fid_get_mda_indexed(fid, key, key_len, sub_key)) || (mda && mda != mda_indexed)) return 1; mda = mda_indexed; if (!_convert_key_to_string(key, key_len, sub_key, full_key, sizeof(full_key))) return_0; dm_hash_remove(fid->metadata_areas_index, full_key); } dm_list_del(&mda->list); return 1; } /* * Copy constructor for a metadata_area. */ struct metadata_area *mda_copy(struct dm_pool *mem, struct metadata_area *mda) { struct metadata_area *mda_new; if (!(mda_new = dm_pool_alloc(mem, sizeof(*mda_new)))) { log_error("metadata_area allocation failed"); return NULL; } memcpy(mda_new, mda, sizeof(*mda)); if (mda->ops->mda_metadata_locn_copy && mda->metadata_locn) { mda_new->metadata_locn = mda->ops->mda_metadata_locn_copy(mem, mda->metadata_locn); if (!mda_new->metadata_locn) { dm_pool_free(mem, mda_new); return NULL; } } dm_list_init(&mda_new->list); return mda_new; } /* * This function provides a way to answer the question on a format specific * basis - does the format specfic context of these two metadata areas * match? * * A metatdata_area is defined to be independent of the underlying context. * This has the benefit that we can use the same abstraction to read disks * (see _metadata_text_raw_ops) or files (see _metadata_text_file_ops). * However, one downside is there is no format-independent way to determine * whether a given metadata_area is attached to a specific device - in fact, * it may not be attached to a device at all. * * Thus, LVM is structured such that an mda is not a member of struct * physical_volume. The location of the mda depends on whether * the PV is in a volume group. A PV not in a VG has an mda on the * 'info->mda' list in lvmcache, while a PV in a VG has an mda on * the vg->fid->metadata_areas_in_use list. For further details, see _vg_read(), * and the sequence of creating the format_instance with fid->metadata_areas_in_use * list, as well as the construction of the VG, with list of PVs (comes * after the construction of the fid and list of mdas). */ unsigned mda_locns_match(struct metadata_area *mda1, struct metadata_area *mda2) { if (!mda1->ops->mda_locns_match || !mda2->ops->mda_locns_match || mda1->ops->mda_locns_match != mda2->ops->mda_locns_match) return 0; return mda1->ops->mda_locns_match(mda1, mda2); } struct device *mda_get_device(struct metadata_area *mda) { if (!mda->ops->mda_get_device) return NULL; return mda->ops->mda_get_device(mda); } unsigned mda_is_ignored(struct metadata_area *mda) { return (mda->status & MDA_IGNORED); } void mda_set_ignored(struct metadata_area *mda, unsigned mda_ignored) { void *locn = mda->metadata_locn; unsigned old_mda_ignored = mda_is_ignored(mda); if (mda_ignored && !old_mda_ignored) mda->status |= MDA_IGNORED; else if (!mda_ignored && old_mda_ignored) mda->status &= ~MDA_IGNORED; else return; /* No change */ log_debug("%s ignored flag for mda %s at offset %" PRIu64 ".", mda_ignored ? "Setting" : "Clearing", mda->ops->mda_metadata_locn_name ? mda->ops->mda_metadata_locn_name(locn) : "", mda->ops->mda_metadata_locn_offset ? mda->ops->mda_metadata_locn_offset(locn) : UINT64_C(0)); } int mdas_empty_or_ignored(struct dm_list *mdas) { struct metadata_area *mda; if (!dm_list_size(mdas)) return 1; dm_list_iterate_items(mda, mdas) { if (mda_is_ignored(mda)) return 1; } return 0; } int pv_change_metadataignore(struct physical_volume *pv, uint32_t mda_ignored) { const char *pv_name = pv_dev_name(pv); if (mda_ignored && !pv_mda_used_count(pv)) { log_error("Metadata areas on physical volume \"%s\" already " "ignored.", pv_name); return 0; } if (!mda_ignored && (pv_mda_used_count(pv) == pv_mda_count(pv))) { log_error("Metadata areas on physical volume \"%s\" already " "marked as in-use.", pv_name); return 0; } if (!pv_mda_count(pv)) { log_error("Physical volume \"%s\" has no metadata " "areas.", pv_name); return 0; } log_verbose("Marking metadata areas on physical volume \"%s\" " "as %s.", pv_name, mda_ignored ? "ignored" : "in-use"); if (!pv_mda_set_ignored(pv, mda_ignored)) return_0; /* * Update vg_mda_copies based on the mdas in this PV. * This is most likely what the user would expect - if they * specify a specific PV to be ignored/un-ignored, they will * most likely not want LVM to turn around and change the * ignore / un-ignore value when it writes the VG to disk. * This does not guarantee this PV's ignore bits will be * preserved in future operations. */ if (!is_orphan(pv) && vg_mda_copies(pv->vg) != VGMETADATACOPIES_UNMANAGED) { log_warn("WARNING: Changing preferred number of copies of VG %s " "metadata from %"PRIu32" to %"PRIu32, pv_vg_name(pv), vg_mda_copies(pv->vg), vg_mda_used_count(pv->vg)); vg_set_mda_copies(pv->vg, vg_mda_used_count(pv->vg)); } return 1; } char *tags_format_and_copy(struct dm_pool *mem, const struct dm_list *tags) { struct str_list *sl; if (!dm_pool_begin_object(mem, 256)) { log_error("dm_pool_begin_object failed"); return NULL; } dm_list_iterate_items(sl, tags) { if (!dm_pool_grow_object(mem, sl->str, strlen(sl->str)) || (sl->list.n != tags && !dm_pool_grow_object(mem, ",", 1))) { log_error("dm_pool_grow_object failed"); return NULL; } } if (!dm_pool_grow_object(mem, "\0", 1)) { log_error("dm_pool_grow_object failed"); return NULL; } return dm_pool_end_object(mem); } /** * pv_by_path - Given a device path return a PV handle if it is a PV * @cmd - handle to the LVM command instance * @pv_name - device path to read for the PV * * Returns: * NULL - device path does not contain a valid PV * non-NULL - PV handle corresponding to device path * * FIXME: merge with find_pv_by_name ? */ struct physical_volume *pv_by_path(struct cmd_context *cmd, const char *pv_name) { return _pv_read(cmd, cmd->mem, pv_name, NULL, 1, 0); } lvm2-2.02.98/lib/metadata/pv.c0000640000175000017500000001763312037016272014641 0ustar blankblank/* * 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 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 "metadata.h" #include "lvmcache.h" /* * FIXME: Check for valid handle before dereferencing field or log error? */ #define pv_field(handle, field) ((handle)->field) char *pv_fmt_dup(const struct physical_volume *pv) { if (!pv->fmt) return NULL; return dm_pool_strdup(pv->vg->vgmem, pv->fmt->name); } char *pv_name_dup(const struct physical_volume *pv) { return dm_pool_strdup(pv->vg->vgmem, dev_name(pv->dev)); } /* * Gets/Sets for external LVM library */ struct id pv_id(const struct physical_volume *pv) { return pv_field(pv, id); } char *pv_uuid_dup(const struct physical_volume *pv) { return id_format_and_copy(pv->vg->vgmem, &pv->id); } char *pv_tags_dup(const struct physical_volume *pv) { return tags_format_and_copy(pv->vg->vgmem, &pv->tags); } const struct format_type *pv_format_type(const struct physical_volume *pv) { return pv_field(pv, fmt); } struct id pv_vgid(const struct physical_volume *pv) { return pv_field(pv, vgid); } struct device *pv_dev(const struct physical_volume *pv) { return pv_field(pv, dev); } const char *pv_vg_name(const struct physical_volume *pv) { return pv_field(pv, vg_name); } const char *pv_dev_name(const struct physical_volume *pv) { return dev_name(pv_dev(pv)); } uint64_t pv_size(const struct physical_volume *pv) { return pv_field(pv, size); } uint64_t pv_dev_size(const struct physical_volume *pv) { uint64_t size; if (!dev_get_size(pv->dev, &size)) size = 0; return size; } uint64_t pv_size_field(const struct physical_volume *pv) { uint64_t size; if (!pv->pe_count) size = pv->size; else size = (uint64_t) pv->pe_count * pv->pe_size; return size; } uint64_t pv_free(const struct physical_volume *pv) { uint64_t freespace; if (!pv->pe_count) freespace = pv->size; else freespace = (uint64_t) (pv->pe_count - pv->pe_alloc_count) * pv->pe_size; return freespace; } uint64_t pv_status(const struct physical_volume *pv) { return pv_field(pv, status); } uint32_t pv_pe_size(const struct physical_volume *pv) { return pv_field(pv, pe_size); } uint64_t pv_pe_start(const struct physical_volume *pv) { return pv_field(pv, pe_start); } uint32_t pv_pe_count(const struct physical_volume *pv) { return pv_field(pv, pe_count); } uint32_t pv_pe_alloc_count(const struct physical_volume *pv) { return pv_field(pv, pe_alloc_count); } uint32_t pv_mda_count(const struct physical_volume *pv) { struct lvmcache_info *info; info = lvmcache_info_from_pvid((const char *)&pv->id.uuid, 0); return info ? lvmcache_mda_count(info) : UINT64_C(0); } static int _count_unignored(struct metadata_area *mda, void *baton) { uint32_t *count = baton; if (!mda_is_ignored(mda)) (*count) ++; return 1; } uint32_t pv_mda_used_count(const struct physical_volume *pv) { struct lvmcache_info *info; uint32_t used_count=0; info = lvmcache_info_from_pvid((const char *)&pv->id.uuid, 0); if (!info) return 0; lvmcache_foreach_mda(info, _count_unignored, &used_count); return used_count; } /** * is_orphan - Determine whether a pv is an orphan based on its vg_name * @pv: handle to the physical volume */ int is_orphan(const struct physical_volume *pv) { return is_orphan_vg(pv_field(pv, vg_name)); } /** * is_pv - Determine whether a pv is a real pv or dummy one * @pv: handle to device */ int is_pv(const struct physical_volume *pv) { return (pv_field(pv, vg_name) ? 1 : 0); } int is_missing_pv(const struct physical_volume *pv) { return pv_field(pv, status) & MISSING_PV ? 1 : 0; } char *pv_attr_dup(struct dm_pool *mem, const struct physical_volume *pv) { char *repstr; if (!(repstr = dm_pool_zalloc(mem, 4))) { log_error("dm_pool_alloc failed"); return NULL; } repstr[0] = (pv->status & ALLOCATABLE_PV) ? 'a' : '-'; repstr[1] = (pv->status & EXPORTED_VG) ? 'x' : '-'; repstr[2] = (pv->status & MISSING_PV) ? 'm' : '-'; return repstr; } uint64_t pv_mda_size(const struct physical_volume *pv) { struct lvmcache_info *info; uint64_t min_mda_size = 0; const char *pvid = (const char *)(&pv->id.uuid); /* PVs could have 2 mdas of different sizes (rounding effect) */ if ((info = lvmcache_info_from_pvid(pvid, 0))) min_mda_size = lvmcache_smallest_mda_size(info); return min_mda_size; } static int _pv_mda_free(struct metadata_area *mda, void *baton) { uint64_t mda_free; uint64_t *freespace = baton; if (!mda->ops->mda_free_sectors) return 1; mda_free = mda->ops->mda_free_sectors(mda); if (mda_free < *freespace) *freespace = mda_free; return 1; } uint64_t pv_mda_free(const struct physical_volume *pv) { struct lvmcache_info *info; uint64_t freespace = UINT64_MAX; const char *pvid = (const char *)&pv->id.uuid; if ((info = lvmcache_info_from_pvid(pvid, 0))) lvmcache_foreach_mda(info, _pv_mda_free, &freespace); if (freespace == UINT64_MAX) freespace = UINT64_C(0); return freespace; } uint64_t pv_used(const struct physical_volume *pv) { uint64_t used; if (!pv->pe_count) used = 0LL; else used = (uint64_t) pv->pe_alloc_count * pv->pe_size; return used; } struct _pv_mda_set_ignored_baton { unsigned mda_ignored; struct dm_list *mdas_in_use, *mdas_ignored, *mdas_to_change; }; static int _pv_mda_set_ignored_one(struct metadata_area *mda, void *baton) { struct _pv_mda_set_ignored_baton *b = baton; struct metadata_area *vg_mda, *tmda; if (mda_is_ignored(mda) && !b->mda_ignored) { /* Changing an ignored mda to one in_use requires moving it */ dm_list_iterate_items_safe(vg_mda, tmda, b->mdas_ignored) if (mda_locns_match(mda, vg_mda)) { mda_set_ignored(vg_mda, b->mda_ignored); dm_list_move(b->mdas_in_use, &vg_mda->list); } } dm_list_iterate_items_safe(vg_mda, tmda, b->mdas_in_use) if (mda_locns_match(mda, vg_mda)) /* Don't move mda: needs writing to disk. */ mda_set_ignored(vg_mda, b->mda_ignored); mda_set_ignored(mda, b->mda_ignored); return 1; } unsigned pv_mda_set_ignored(const struct physical_volume *pv, unsigned mda_ignored) { struct lvmcache_info *info; struct _pv_mda_set_ignored_baton baton; struct metadata_area *mda; if (!(info = lvmcache_info_from_pvid((const char *)&pv->id.uuid, 0))) return_0; baton.mda_ignored = mda_ignored; baton.mdas_in_use = &pv->fid->metadata_areas_in_use; baton.mdas_ignored = &pv->fid->metadata_areas_ignored; baton.mdas_to_change = baton.mda_ignored ? baton.mdas_in_use : baton.mdas_ignored; if (is_orphan(pv)) { dm_list_iterate_items(mda, baton.mdas_to_change) mda_set_ignored(mda, baton.mda_ignored); return 1; } /* * Do not allow disabling of the the last PV in a VG. */ if (pv_mda_used_count(pv) == vg_mda_used_count(pv->vg)) { log_error("Cannot disable all metadata areas in volume group %s.", pv->vg->name); return 0; } /* * Non-orphan case is more complex. * If the PV's mdas are ignored, and we wish to un-ignore, * we clear the bit and move them from the ignored mda list to the * in_use list, ensuring the new state will get written to disk * in the vg_write() path. * If the PV's mdas are not ignored, and we are setting * them to ignored, we set the bit but leave them on the in_use * list, ensuring the new state will get written to disk in the * vg_write() path. */ /* FIXME: Try not to update the cache here! Also, try to iterate over * PV mdas only using the format instance's index somehow * (i.e. try to avoid using mda_locn_match call). */ lvmcache_foreach_mda(info, _pv_mda_set_ignored_one, &baton); return 1; } lvm2-2.02.98/lib/metadata/pv_map.c0000640000175000017500000001156112037016272015470 0ustar blankblank/* * Copyright (C) 2001-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 */ #include "lib.h" #include "pv_map.h" #include /* * Areas are maintained in size order, largest first. * * FIXME Cope with overlap. */ static void _insert_area(struct dm_list *head, struct pv_area *a, unsigned reduced) { struct pv_area *pva; uint32_t count = reduced ? a->unreserved : a->count; dm_list_iterate_items(pva, head) if (count > pva->count) break; dm_list_add(&pva->list, &a->list); a->map->pe_count += a->count; } static void _remove_area(struct pv_area *a) { dm_list_del(&a->list); a->map->pe_count -= a->count; } static int _create_single_area(struct dm_pool *mem, struct pv_map *pvm, uint32_t start, uint32_t length) { struct pv_area *pva; if (!(pva = dm_pool_zalloc(mem, sizeof(*pva)))) return_0; log_debug("Allowing allocation on %s start PE %" PRIu32 " length %" PRIu32, pv_dev_name(pvm->pv), start, length); pva->map = pvm; pva->start = start; pva->count = length; pva->unreserved = pva->count; _insert_area(&pvm->areas, pva, 0); return 1; } static int _create_alloc_areas_for_pv(struct dm_pool *mem, struct pv_map *pvm, uint32_t start, uint32_t count) { struct pv_segment *peg; uint32_t pe, end, area_len; /* Only select extents from start to end inclusive */ end = start + count - 1; if (end > pvm->pv->pe_count - 1) end = pvm->pv->pe_count - 1; pe = start; /* Walk through complete ordered list of device segments */ dm_list_iterate_items(peg, &pvm->pv->segments) { /* pe holds the next extent we want to check */ /* Beyond the range we're interested in? */ if (pe > end) break; /* Skip if we haven't reached the first seg we want yet */ if (pe > peg->pe + peg->len - 1) continue; /* Free? */ if (peg->lvseg) goto next; /* How much of this peg do we need? */ area_len = (end >= peg->pe + peg->len - 1) ? peg->len - (pe - peg->pe) : end - pe + 1; if (!_create_single_area(mem, pvm, pe, area_len)) return_0; next: pe = peg->pe + peg->len; } return 1; } static int _create_all_areas_for_pv(struct dm_pool *mem, struct pv_map *pvm, struct dm_list *pe_ranges) { struct pe_range *aa; if (!pe_ranges) { /* Use whole PV */ if (!_create_alloc_areas_for_pv(mem, pvm, UINT32_C(0), pvm->pv->pe_count)) return_0; return 1; } dm_list_iterate_items(aa, pe_ranges) { if (!_create_alloc_areas_for_pv(mem, pvm, aa->start, aa->count)) return_0; } return 1; } static int _create_maps(struct dm_pool *mem, struct dm_list *pvs, struct dm_list *pvms) { struct pv_map *pvm, *pvm2; struct pv_list *pvl; dm_list_iterate_items(pvl, pvs) { if (!(pvl->pv->status & ALLOCATABLE_PV)) continue; if (is_missing_pv(pvl->pv)) continue; assert(pvl->pv->dev); pvm = NULL; dm_list_iterate_items(pvm2, pvms) if (pvm2->pv->dev == pvl->pv->dev) { pvm = pvm2; break; } if (!pvm) { if (!(pvm = dm_pool_zalloc(mem, sizeof(*pvm)))) return_0; pvm->pv = pvl->pv; dm_list_init(&pvm->areas); dm_list_add(pvms, &pvm->list); } if (!_create_all_areas_for_pv(mem, pvm, pvl->pe_ranges)) return_0; } return 1; } /* * Create list of PV areas available for this particular allocation */ struct dm_list *create_pv_maps(struct dm_pool *mem, struct volume_group *vg, struct dm_list *allocatable_pvs) { struct dm_list *pvms; if (!(pvms = dm_pool_zalloc(mem, sizeof(*pvms)))) { log_error("create_pv_maps alloc failed"); return NULL; } dm_list_init(pvms); if (!_create_maps(mem, allocatable_pvs, pvms)) { log_error("Couldn't create physical volume maps in %s", vg->name); dm_pool_free(mem, pvms); return NULL; } return pvms; } void consume_pv_area(struct pv_area *pva, uint32_t to_go) { _remove_area(pva); assert(to_go <= pva->count); if (to_go < pva->count) { /* split the area */ pva->start += to_go; pva->count -= to_go; pva->unreserved = pva->count; _insert_area(&pva->map->areas, pva, 0); } } /* * Remove an area from list and reinsert it based on its new size * after a provisional allocation (or reverting one). */ void reinsert_changed_pv_area(struct pv_area *pva) { _remove_area(pva); _insert_area(&pva->map->areas, pva, 1); } uint32_t pv_maps_size(struct dm_list *pvms) { struct pv_map *pvm; uint32_t pe_count = 0; dm_list_iterate_items(pvm, pvms) pe_count += pvm->pe_count; return pe_count; } lvm2-2.02.98/lib/metadata/lv.h0000640000175000017500000000637112037016272014637 0ustar blankblank/* * 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 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_LV_H #define _LVM_LV_H union lvid; struct volume_group; struct dm_list; struct lv_segment; struct replicator_device; struct logical_volume { union lvid lvid; const char *name; struct volume_group *vg; uint64_t status; alloc_policy_t alloc; uint32_t read_ahead; int32_t major; int32_t minor; uint64_t size; /* Sectors */ uint32_t le_count; uint32_t origin_count; struct dm_list snapshot_segs; struct lv_segment *snapshot; struct replicator_device *rdevice;/* For replicator-devs, rimages, slogs - reference to rdevice */ struct dm_list rsites; /* For replicators - all sites */ struct dm_list segments; struct dm_list tags; struct dm_list segs_using_this_lv; uint64_t timestamp; const char *hostname; }; uint64_t lv_size(const struct logical_volume *lv); uint64_t lv_metadata_size(const struct logical_volume *lv); char *lv_attr_dup(struct dm_pool *mem, const struct logical_volume *lv); char *lv_uuid_dup(const struct logical_volume *lv); char *lv_tags_dup(const struct logical_volume *lv); char *lv_path_dup(struct dm_pool *mem, const struct logical_volume *lv); uint64_t lv_origin_size(const struct logical_volume *lv); char *lv_move_pv_dup(struct dm_pool *mem, const struct logical_volume *lv); char *lv_convert_lv_dup(struct dm_pool *mem, const struct logical_volume *lv); int lv_kernel_major(const struct logical_volume *lv); int lv_kernel_minor(const struct logical_volume *lv); char *lv_mirror_log_dup(struct dm_pool *mem, const struct logical_volume *lv); char *lv_data_lv_dup(struct dm_pool *mem, const struct logical_volume *lv); char *lv_metadata_lv_dup(struct dm_pool *mem, const struct logical_volume *lv); char *lv_pool_lv_dup(struct dm_pool *mem, const struct logical_volume *lv); char *lv_modules_dup(struct dm_pool *mem, const struct logical_volume *lv); char *lv_name_dup(struct dm_pool *mem, const struct logical_volume *lv); char *lv_origin_dup(struct dm_pool *mem, const struct logical_volume *lv); uint32_t lv_kernel_read_ahead(const struct logical_volume *lv); uint64_t lvseg_start(const struct lv_segment *seg); uint64_t lvseg_size(const struct lv_segment *seg); uint64_t lvseg_chunksize(const struct lv_segment *seg); char *lvseg_segtype_dup(struct dm_pool *mem, const struct lv_segment *seg); char *lvseg_tags_dup(const struct lv_segment *seg); char *lvseg_devices(struct dm_pool *mem, const struct lv_segment *seg); char *lvseg_seg_pe_ranges(struct dm_pool *mem, const struct lv_segment *seg); char *lv_time_dup(struct dm_pool *mem, const struct logical_volume *lv); char *lv_host_dup(struct dm_pool *mem, const struct logical_volume *lv); int lv_set_creation(struct logical_volume *lv, const char *hostname, uint64_t timestamp); #endif /* _LVM_LV_H */ lvm2-2.02.98/lib/metadata/vg.c0000640000175000017500000003160712037016272014625 0ustar blankblank/* * 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 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 "metadata.h" #include "display.h" #include "activate.h" #include "toolcontext.h" #include "lvmcache.h" struct volume_group *alloc_vg(const char *pool_name, struct cmd_context *cmd, const char *vg_name) { struct dm_pool *vgmem; struct volume_group *vg; if (!(vgmem = dm_pool_create(pool_name, VG_MEMPOOL_CHUNK)) || !(vg = dm_pool_zalloc(vgmem, sizeof(*vg)))) { log_error("Failed to allocate volume group structure"); if (vgmem) dm_pool_destroy(vgmem); return NULL; } if (vg_name && !(vg->name = dm_pool_strdup(vgmem, vg_name))) { log_error("Failed to allocate VG name."); dm_pool_destroy(vgmem); return NULL; } vg->cmd = cmd; vg->vgmem = vgmem; vg->alloc = ALLOC_NORMAL; if (!(vg->hostnames = dm_hash_create(16))) { log_error("Failed to allocate VG hostname hashtable."); dm_pool_destroy(vgmem); return NULL; } dm_list_init(&vg->pvs); dm_list_init(&vg->pvs_to_create); dm_list_init(&vg->lvs); dm_list_init(&vg->tags); dm_list_init(&vg->removed_pvs); log_debug("Allocated VG %s at %p.", vg->name, vg); return vg; } static void _free_vg(struct volume_group *vg) { vg_set_fid(vg, NULL); if (vg->cmd && vg->vgmem == vg->cmd->mem) { log_error(INTERNAL_ERROR "global memory pool used for VG %s", vg->name); return; } log_debug("Freeing VG %s at %p.", vg->name, vg); dm_hash_destroy(vg->hostnames); dm_pool_destroy(vg->vgmem); } void release_vg(struct volume_group *vg) { if (!vg || (vg->fid && vg == vg->fid->fmt->orphan_vg)) return; /* Check if there are any vginfo holders */ if (vg->vginfo && !lvmcache_vginfo_holders_dec_and_test_for_zero(vg->vginfo)) return; _free_vg(vg); } /* * FIXME out of place, but the main (cmd) pool has been already * destroyed and touching the fid (also via release_vg) will crash the * program * * For now quick wrapper to allow destroy of orphan vg */ void free_orphan_vg(struct volume_group *vg) { _free_vg(vg); } char *vg_fmt_dup(const struct volume_group *vg) { if (!vg->fid || !vg->fid->fmt) return NULL; return dm_pool_strdup(vg->vgmem, vg->fid->fmt->name); } char *vg_name_dup(const struct volume_group *vg) { return dm_pool_strdup(vg->vgmem, vg->name); } char *vg_system_id_dup(const struct volume_group *vg) { return dm_pool_strdup(vg->vgmem, vg->system_id); } char *vg_uuid_dup(const struct volume_group *vg) { return id_format_and_copy(vg->vgmem, &vg->id); } char *vg_tags_dup(const struct volume_group *vg) { return tags_format_and_copy(vg->vgmem, &vg->tags); } uint32_t vg_seqno(const struct volume_group *vg) { return vg->seqno; } uint64_t vg_status(const struct volume_group *vg) { return vg->status; } uint64_t vg_size(const struct volume_group *vg) { return (uint64_t) vg->extent_count * vg->extent_size; } uint64_t vg_free(const struct volume_group *vg) { return (uint64_t) vg->free_count * vg->extent_size; } uint64_t vg_extent_size(const struct volume_group *vg) { return (uint64_t) vg->extent_size; } uint64_t vg_extent_count(const struct volume_group *vg) { return (uint64_t) vg->extent_count; } uint64_t vg_free_count(const struct volume_group *vg) { return (uint64_t) vg->free_count; } uint64_t vg_pv_count(const struct volume_group *vg) { return (uint64_t) vg->pv_count; } uint64_t vg_max_pv(const struct volume_group *vg) { return (uint64_t) vg->max_pv; } uint64_t vg_max_lv(const struct volume_group *vg) { return (uint64_t) vg->max_lv; } unsigned snapshot_count(const struct volume_group *vg) { struct lv_list *lvl; unsigned num_snapshots = 0; dm_list_iterate_items(lvl, &vg->lvs) if (lv_is_cow(lvl->lv)) num_snapshots++; return num_snapshots; } unsigned vg_visible_lvs(const struct volume_group *vg) { struct lv_list *lvl; unsigned lv_count = 0; dm_list_iterate_items(lvl, &vg->lvs) { if (lv_is_visible(lvl->lv)) lv_count++; } return lv_count; } uint32_t vg_mda_count(const struct volume_group *vg) { return dm_list_size(&vg->fid->metadata_areas_in_use) + dm_list_size(&vg->fid->metadata_areas_ignored); } uint32_t vg_mda_used_count(const struct volume_group *vg) { uint32_t used_count = 0; struct metadata_area *mda; /* * Ignored mdas could be on either list - the reason being the state * may have changed from ignored to un-ignored and we need to write * the state to disk. */ dm_list_iterate_items(mda, &vg->fid->metadata_areas_in_use) if (!mda_is_ignored(mda)) used_count++; return used_count; } uint32_t vg_mda_copies(const struct volume_group *vg) { return vg->mda_copies; } uint64_t vg_mda_size(const struct volume_group *vg) { return find_min_mda_size(&vg->fid->metadata_areas_in_use); } uint64_t vg_mda_free(const struct volume_group *vg) { uint64_t freespace = UINT64_MAX, mda_free; struct metadata_area *mda; dm_list_iterate_items(mda, &vg->fid->metadata_areas_in_use) { if (!mda->ops->mda_free_sectors) continue; mda_free = mda->ops->mda_free_sectors(mda); if (mda_free < freespace) freespace = mda_free; } if (freespace == UINT64_MAX) freespace = UINT64_C(0); return freespace; } int vg_set_mda_copies(struct volume_group *vg, uint32_t mda_copies) { vg->mda_copies = mda_copies; /* FIXME Use log_verbose when this is due to specific cmdline request. */ log_debug("Setting mda_copies to %"PRIu32" for VG %s", mda_copies, vg->name); return 1; } static int _recalc_extents(uint32_t *extents, const char *desc1, const char *desc2, uint32_t old_size, uint32_t new_size) { uint64_t size = (uint64_t) old_size * (*extents); if (size % new_size) { log_error("New size %" PRIu64 " for %s%s not an exact number " "of new extents.", size, desc1, desc2); return 0; } size /= new_size; if (size > MAX_EXTENT_COUNT) { log_error("New extent count %" PRIu64 " for %s%s exceeds " "32 bits.", size, desc1, desc2); return 0; } *extents = (uint32_t) size; return 1; } int vg_set_extent_size(struct volume_group *vg, uint32_t new_size) { uint32_t old_size = vg->extent_size; struct pv_list *pvl; struct lv_list *lvl; struct physical_volume *pv; struct logical_volume *lv; struct lv_segment *seg; struct pv_segment *pvseg; uint32_t s; if (!vg_is_resizeable(vg)) { log_error("Volume group \"%s\" must be resizeable " "to change PE size", vg->name); return 0; } if (!new_size) { log_error("Physical extent size may not be zero"); return 0; } if (new_size == vg->extent_size) return 1; if (new_size & (new_size - 1)) { log_error("Physical extent size must be a power of 2."); return 0; } if (new_size > vg->extent_size) { if ((uint64_t) vg_size(vg) % new_size) { /* FIXME Adjust used PV sizes instead */ log_error("New extent size is not a perfect fit"); return 0; } } vg->extent_size = new_size; if (vg->fid->fmt->ops->vg_setup && !vg->fid->fmt->ops->vg_setup(vg->fid, vg)) return_0; if (!_recalc_extents(&vg->extent_count, vg->name, "", old_size, new_size)) return_0; if (!_recalc_extents(&vg->free_count, vg->name, " free space", old_size, new_size)) return_0; /* foreach PV */ dm_list_iterate_items(pvl, &vg->pvs) { pv = pvl->pv; pv->pe_size = new_size; if (!_recalc_extents(&pv->pe_count, pv_dev_name(pv), "", old_size, new_size)) return_0; if (!_recalc_extents(&pv->pe_alloc_count, pv_dev_name(pv), " allocated space", old_size, new_size)) return_0; /* foreach free PV Segment */ dm_list_iterate_items(pvseg, &pv->segments) { if (pvseg_is_allocated(pvseg)) continue; if (!_recalc_extents(&pvseg->pe, pv_dev_name(pv), " PV segment start", old_size, new_size)) return_0; if (!_recalc_extents(&pvseg->len, pv_dev_name(pv), " PV segment length", old_size, new_size)) return_0; } } /* foreach LV */ dm_list_iterate_items(lvl, &vg->lvs) { lv = lvl->lv; if (!_recalc_extents(&lv->le_count, lv->name, "", old_size, new_size)) return_0; dm_list_iterate_items(seg, &lv->segments) { if (!_recalc_extents(&seg->le, lv->name, " segment start", old_size, new_size)) return_0; if (!_recalc_extents(&seg->len, lv->name, " segment length", old_size, new_size)) return_0; if (!_recalc_extents(&seg->area_len, lv->name, " area length", old_size, new_size)) return_0; if (!_recalc_extents(&seg->extents_copied, lv->name, " extents moved", old_size, new_size)) return_0; /* foreach area */ for (s = 0; s < seg->area_count; s++) { switch (seg_type(seg, s)) { case AREA_PV: if (!_recalc_extents (&seg_pe(seg, s), lv->name, " pvseg start", old_size, new_size)) return_0; if (!_recalc_extents (&seg_pvseg(seg, s)->len, lv->name, " pvseg length", old_size, new_size)) return_0; break; case AREA_LV: if (!_recalc_extents (&seg_le(seg, s), lv->name, " area start", old_size, new_size)) return_0; break; case AREA_UNASSIGNED: log_error("Unassigned area %u found in " "segment", s); return 0; } } } } return 1; } int vg_set_max_lv(struct volume_group *vg, uint32_t max_lv) { if (!vg_is_resizeable(vg)) { log_error("Volume group \"%s\" must be resizeable " "to change MaxLogicalVolume", vg->name); return 0; } if (!(vg->fid->fmt->features & FMT_UNLIMITED_VOLS)) { if (!max_lv) max_lv = 255; else if (max_lv > 255) { log_error("MaxLogicalVolume limit is 255"); return 0; } } if (max_lv && max_lv < vg_visible_lvs(vg)) { log_error("MaxLogicalVolume is less than the current number " "%d of LVs for %s", vg_visible_lvs(vg), vg->name); return 0; } vg->max_lv = max_lv; return 1; } int vg_set_max_pv(struct volume_group *vg, uint32_t max_pv) { if (!vg_is_resizeable(vg)) { log_error("Volume group \"%s\" must be resizeable " "to change MaxPhysicalVolumes", vg->name); return 0; } if (!(vg->fid->fmt->features & FMT_UNLIMITED_VOLS)) { if (!max_pv) max_pv = 255; else if (max_pv > 255) { log_error("MaxPhysicalVolume limit is 255"); return 0; } } if (max_pv && max_pv < vg->pv_count) { log_error("MaxPhysicalVolumes is less than the current number " "%d of PVs for \"%s\"", vg->pv_count, vg->name); return 0; } vg->max_pv = max_pv; return 1; } int vg_set_alloc_policy(struct volume_group *vg, alloc_policy_t alloc) { if (alloc == ALLOC_INHERIT) { log_error("Volume Group allocation policy cannot inherit " "from anything"); return 0; } if (alloc == vg->alloc) return 1; vg->alloc = alloc; return 1; } int vg_set_clustered(struct volume_group *vg, int clustered) { struct lv_list *lvl; /* * We do not currently support switching the cluster attribute * on active mirrors, snapshots or RAID logical volumes. */ dm_list_iterate_items(lvl, &vg->lvs) { /* * FIXME: * We could allow exclusive activation of RAID LVs, but * for now we disallow them in a cluster VG at all. */ if (lv_is_raid_type(lvl->lv)) { log_error("RAID logical volumes are not allowed " "in a cluster volume group."); return 0; } if (lv_is_active(lvl->lv) && (lv_is_mirrored(lvl->lv) || lv_is_raid_type(lvl->lv))) { log_error("%s logical volumes must be inactive " "when changing the cluster attribute.", lv_is_raid_type(lvl->lv) ? "RAID" : "Mirror"); return 0; } if (clustered) { if (lv_is_origin(lvl->lv) || lv_is_cow(lvl->lv)) { log_error("Volume group %s contains snapshots " "that are not yet supported.", vg->name); return 0; } } if ((lv_is_origin(lvl->lv) || lv_is_cow(lvl->lv)) && lv_is_active(lvl->lv)) { log_error("Snapshot logical volumes must be inactive " "when changing the cluster attribute."); return 0; } } if (clustered) vg->status |= CLUSTERED; else vg->status &= ~CLUSTERED; return 1; } char *vg_attr_dup(struct dm_pool *mem, const struct volume_group *vg) { char *repstr; if (!(repstr = dm_pool_zalloc(mem, 7))) { log_error("dm_pool_alloc failed"); return NULL; } repstr[0] = (vg->status & LVM_WRITE) ? 'w' : 'r'; repstr[1] = (vg_is_resizeable(vg)) ? 'z' : '-'; repstr[2] = (vg_is_exported(vg)) ? 'x' : '-'; repstr[3] = (vg_missing_pv_count(vg)) ? 'p' : '-'; repstr[4] = alloc_policy_char(vg->alloc); repstr[5] = (vg_is_clustered(vg)) ? 'c' : '-'; return repstr; } lvm2-2.02.98/lib/metadata/metadata.h0000640000175000017500000003760112037016272015776 0ustar blankblank/* * 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 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 is the in core representation of a volume group and its * associated physical and logical volumes. */ #ifndef _LVM_METADATA_H #define _LVM_METADATA_H #include "ctype.h" #include "dev-cache.h" #include "lvm-string.h" #include "metadata-exported.h" //#define MAX_STRIPES 128U //#define SECTOR_SHIFT 9L //#define SECTOR_SIZE ( 1L << SECTOR_SHIFT ) //#define STRIPE_SIZE_MIN ( (unsigned) lvm_getpagesize() >> SECTOR_SHIFT) /* PAGESIZE in sectors */ //#define STRIPE_SIZE_MAX ( 512L * 1024L >> SECTOR_SHIFT) /* 512 KB in sectors */ //#define STRIPE_SIZE_LIMIT ((UINT_MAX >> 2) + 1) //#define MAX_RESTRICTED_LVS 255 /* Used by FMT_RESTRICTED_LVIDS */ #define MIRROR_LOG_OFFSET 2 /* sectors */ #define VG_MEMPOOL_CHUNK 10240 /* in bytes, hint only */ #define PV_PE_START_CALC ((uint64_t) -1) /* Calculate pe_start value */ /* * Ceiling(n / sz) */ #define dm_div_up(n, sz) (((n) + (sz) - 1) / (sz)) /* * Ceiling(n / size) * size */ #define dm_round_up(n, sz) (dm_div_up((n), (sz)) * (sz)) /* Various flags */ /* See metadata-exported.h for the complete list. */ /* Note that the bits no longer necessarily correspond to LVM1 disk format */ /* May any free extents on this PV be used or must they be left free? */ #define SPINDOWN_LV UINT64_C(0x00000010) /* LV */ #define BADBLOCK_ON UINT64_C(0x00000020) /* LV */ #define VIRTUAL UINT64_C(0x00010000) /* LV - internal use only */ #define PRECOMMITTED UINT64_C(0x00200000) /* VG - internal use only */ #define POSTORDER_FLAG UINT64_C(0x02000000) /* Not real flags, reserved for */ #define POSTORDER_OPEN_FLAG UINT64_C(0x04000000) /* temporary use inside vg_read_internal. */ #define VIRTUAL_ORIGIN UINT64_C(0x08000000) /* LV - internal use only */ #define SHARED UINT64_C(0x00000800) /* VG */ /* Format features flags */ #define FMT_PRECOMMIT 0x00000040U /* Supports pre-commit? */ struct dm_config_tree; struct metadata_area; struct alloc_handle; struct lvmcache_info; /* Per-format per-metadata area operations */ struct metadata_area_ops { struct dm_list list; struct volume_group *(*vg_read) (struct format_instance * fi, const char *vg_name, struct metadata_area * mda, int single_device); struct volume_group *(*vg_read_precommit) (struct format_instance * fi, const char *vg_name, struct metadata_area * mda); /* * Write out complete VG metadata. You must ensure internal * consistency before calling. eg. PEs can't refer to PVs not * part of the VG. * * It is also the responsibility of the caller to ensure external * consistency, eg by calling pv_write() if removing PVs from * a VG or calling vg_write() a second time if splitting a VG * into two. * * vg_write() should not read or write from any PVs not included * in the volume_group structure it is handed. * (format1 currently breaks this rule.) */ int (*vg_write) (struct format_instance * fid, struct volume_group * vg, struct metadata_area * mda); int (*vg_precommit) (struct format_instance * fid, struct volume_group * vg, struct metadata_area * mda); int (*vg_commit) (struct format_instance * fid, struct volume_group * vg, struct metadata_area * mda); int (*vg_revert) (struct format_instance * fid, struct volume_group * vg, struct metadata_area * mda); int (*vg_remove) (struct format_instance * fi, struct volume_group * vg, struct metadata_area * mda); /* * Per location copy constructor. */ void *(*mda_metadata_locn_copy) (struct dm_pool *mem, void *metadata_locn); /* * Per location description for logging. */ const char *(*mda_metadata_locn_name) (void *metadata_locn); uint64_t (*mda_metadata_locn_offset) (void *metadata_locn); /* * Returns number of free sectors in given metadata area. */ uint64_t (*mda_free_sectors) (struct metadata_area *mda); /* * Returns number of total sectors in given metadata area. */ uint64_t (*mda_total_sectors) (struct metadata_area *mda); /* * Check if metadata area belongs to vg */ int (*mda_in_vg) (struct format_instance * fi, struct volume_group * vg, struct metadata_area *mda); /* * Analyze a metadata area on a PV. */ int (*pv_analyze_mda) (const struct format_type * fmt, struct metadata_area *mda); /* * Do these two metadata_area structures match with respect to * their underlying location? */ unsigned (*mda_locns_match)(struct metadata_area *mda1, struct metadata_area *mda2); struct device *(*mda_get_device)(struct metadata_area *mda); int (*mda_export_text)(struct metadata_area *mda, struct dm_config_tree *cft, struct dm_config_node *parent); int (*mda_import_text)(struct lvmcache_info *info, const struct dm_config_node *cn); }; #define MDA_IGNORED 0x00000001 #define MDA_INCONSISTENT 0x00000002 struct metadata_area { struct dm_list list; struct metadata_area_ops *ops; void *metadata_locn; uint32_t status; }; struct metadata_area *mda_copy(struct dm_pool *mem, struct metadata_area *mda); unsigned mda_is_ignored(struct metadata_area *mda); void mda_set_ignored(struct metadata_area *mda, unsigned ignored); unsigned mda_locns_match(struct metadata_area *mda1, struct metadata_area *mda2); struct device *mda_get_device(struct metadata_area *mda); struct format_instance_ctx { uint32_t type; union { const char *pv_id; struct { const char *vg_name; const char *vg_id; } vg_ref; void *private; } context; }; struct format_instance *alloc_fid(const struct format_type *fmt, const struct format_instance_ctx *fic); /* * Format instance must always be set using pv_set_fid or vg_set_fid * (NULL value as well), never asign it directly! This is essential * for proper reference counting for the format instance. */ void pv_set_fid(struct physical_volume *pv, struct format_instance *fid); void vg_set_fid(struct volume_group *vg, struct format_instance *fid); /* FIXME: Add generic interface for mda counts based on given key. */ int fid_add_mda(struct format_instance *fid, struct metadata_area *mda, const char *key, size_t key_len, const unsigned sub_key); int fid_add_mdas(struct format_instance *fid, struct dm_list *mdas, const char *key, size_t key_len); int fid_remove_mda(struct format_instance *fid, struct metadata_area *mda, const char *key, size_t key_len, const unsigned sub_key); struct metadata_area *fid_get_mda_indexed(struct format_instance *fid, const char *key, size_t key_len, const unsigned sub_key); int mdas_empty_or_ignored(struct dm_list *mdas); #define seg_pvseg(seg, s) (seg)->areas[(s)].u.pv.pvseg #define seg_dev(seg, s) (seg)->areas[(s)].u.pv.pvseg->pv->dev #define seg_pe(seg, s) (seg)->areas[(s)].u.pv.pvseg->pe #define seg_le(seg, s) (seg)->areas[(s)].u.lv.le #define seg_metale(seg, s) (seg)->meta_areas[(s)].u.lv.le struct name_list { struct dm_list list; char *name; }; struct mda_list { struct dm_list list; struct device_area mda; }; struct peg_list { struct dm_list list; struct pv_segment *peg; }; struct seg_list { struct dm_list list; unsigned count; struct lv_segment *seg; }; /* * Ownership of objects passes to caller. */ struct format_handler { /* * Scan any metadata areas that aren't referenced in PV labels */ int (*scan) (const struct format_type * fmt, const char *vgname); /* * Return PV with given path. */ int (*pv_read) (const struct format_type * fmt, const char *pv_name, struct physical_volume * pv, int scan_label_only); /* * Initialise a new PV. */ int (*pv_initialise) (const struct format_type * fmt, int64_t label_sector, uint64_t pe_start, uint32_t extent_count, uint32_t extent_size, unsigned long data_alignment, unsigned long data_alignment_offset, struct physical_volume * pv); /* * Tweak an already filled out a pv ready for importing into a * vg. eg. pe_count is format specific. */ int (*pv_setup) (const struct format_type * fmt, struct physical_volume * pv, struct volume_group * vg); /* * Add metadata area to a PV. Changes will take effect on pv_write. */ int (*pv_add_metadata_area) (const struct format_type * fmt, struct physical_volume * pv, int pe_start_locked, unsigned metadata_index, uint64_t metadata_size, unsigned metadata_ignored); /* * Remove metadata area from a PV. Changes will take effect on pv_write. */ int (*pv_remove_metadata_area) (const struct format_type *fmt, struct physical_volume *pv, unsigned metadata_index); /* * Recalculate the PV size taking into account any existing metadata areas. */ int (*pv_resize) (const struct format_type *fmt, struct physical_volume *pv, struct volume_group *vg, uint64_t size); /* * Write a PV structure to disk. Fails if the PV is in a VG ie * pv->vg_name must be a valid orphan VG name */ int (*pv_write) (const struct format_type * fmt, struct physical_volume * pv); /* * Tweak an already filled out a lv eg, check there * aren't too many extents. */ int (*lv_setup) (struct format_instance * fi, struct logical_volume * lv); /* * Tweak an already filled out vg. eg, max_pv is format * specific. */ int (*vg_setup) (struct format_instance * fi, struct volume_group * vg); /* * Check whether particular segment type is supported. */ int (*segtype_supported) (struct format_instance *fid, const struct segment_type *segtype); /* * Create format instance with a particular metadata area */ struct format_instance *(*create_instance) (const struct format_type *fmt, const struct format_instance_ctx *fic); /* * Destructor for format instance */ void (*destroy_instance) (struct format_instance * fid); /* * Destructor for format type */ void (*destroy) (struct format_type * fmt); }; /* * Utility functions */ unsigned long set_pe_align(struct physical_volume *pv, unsigned long data_alignment); unsigned long set_pe_align_offset(struct physical_volume *pv, unsigned long data_alignment_offset); int vg_validate(struct volume_group *vg); int pv_write_orphan(struct cmd_context *cmd, struct physical_volume *pv); /* Manipulate PV structures */ int pv_add(struct volume_group *vg, struct physical_volume *pv); int pv_remove(struct volume_group *vg, struct physical_volume *pv); struct physical_volume *pv_find(struct volume_group *vg, const char *pv_name); /* Find a PV within a given VG */ int get_pv_from_vg_by_id(const struct format_type *fmt, const char *vg_name, const char *vgid, const char *pvid, struct physical_volume *pv); struct lv_list *find_lv_in_vg_by_lvid(struct volume_group *vg, const union lvid *lvid); struct lv_list *find_lv_in_lv_list(const struct dm_list *ll, const struct logical_volume *lv); /* Return the VG that contains a given LV (based on path given in lv_name) */ /* or environment var */ struct volume_group *find_vg_with_lv(const char *lv_name); /* Find LV with given lvid (used during activation) */ struct logical_volume *lv_from_lvid(struct cmd_context *cmd, const char *lvid_s, unsigned precommitted); /* FIXME Merge these functions with ones above */ struct physical_volume *find_pv(struct volume_group *vg, struct device *dev); struct pv_list *find_pv_in_pv_list(const struct dm_list *pl, const struct physical_volume *pv); /* Find LV segment containing given LE */ struct lv_segment *find_seg_by_le(const struct logical_volume *lv, uint32_t le); /* Find pool LV segment given a thin pool data or metadata segment. */ struct lv_segment *find_pool_seg(const struct lv_segment *seg); /* Find some unused device_id for thin pool LV segment. */ uint32_t get_free_pool_device_id(struct lv_segment *thin_pool_seg); /* * Remove a dev_dir if present. */ const char *strip_dir(const char *vg_name, const char *dir); struct logical_volume *alloc_lv(struct dm_pool *mem); /* * Checks that an lv has no gaps or overlapping segments. * Set complete_vg to perform additional VG level checks. */ int check_lv_segments(struct logical_volume *lv, int complete_vg); /* * Checks that a replicator segment is correct. */ int check_replicator_segment(const struct lv_segment *replicator_seg); /* * Sometimes (eg, after an lvextend), it is possible to merge two * adjacent segments into a single segment. This function trys * to merge as many segments as possible. */ int lv_merge_segments(struct logical_volume *lv); /* * Ensure there's a segment boundary at a given LE, splitting if necessary */ int lv_split_segment(struct logical_volume *lv, uint32_t le); /* * Add/remove upward link from underlying LV to the segment using it * FIXME: ridiculously long name */ int add_seg_to_segs_using_this_lv(struct logical_volume *lv, struct lv_segment *seg); int remove_seg_from_segs_using_this_lv(struct logical_volume *lv, struct lv_segment *seg); struct lv_segment *get_only_segment_using_this_lv(struct logical_volume *lv); int for_each_sub_lv(struct cmd_context *cmd, struct logical_volume *lv, int (*fn)(struct cmd_context *cmd, struct logical_volume *lv, void *data), void *data); int move_lv_segments(struct logical_volume *lv_to, struct logical_volume *lv_from, uint64_t set_status, uint64_t reset_status); /* * Calculate readahead from underlying PV devices */ void lv_calculate_readahead(const struct logical_volume *lv, uint32_t *read_ahead); /* * For internal metadata caching. */ size_t export_vg_to_buffer(struct volume_group *vg, char **buf); int export_vg_to_config_tree(struct volume_group *vg, struct dm_config_tree **cft); struct volume_group *import_vg_from_buffer(const char *buf, struct format_instance *fid); struct volume_group *import_vg_from_config_tree(const struct dm_config_tree *cft, struct format_instance *fid); /* * Mirroring functions */ /* * Given mirror image or mirror log segment, find corresponding mirror segment */ int fixup_imported_mirrors(struct volume_group *vg); /* * From thin_manip.c */ int attach_pool_metadata_lv(struct lv_segment *pool_seg, struct logical_volume *pool_metadata_lv); int attach_pool_data_lv(struct lv_segment *pool_seg, struct logical_volume *pool_data_lv); int attach_pool_lv(struct lv_segment *seg, struct logical_volume *pool_lv, struct logical_volume *origin_lv); int detach_pool_lv(struct lv_segment *seg); int attach_pool_message(struct lv_segment *pool_seg, dm_thin_message_t type, struct logical_volume *lv, uint32_t delete_id, int auto_increment); int pool_has_message(const struct lv_segment *seg, const struct logical_volume *lv, uint32_t device_id); int pool_below_threshold(const struct lv_segment *pool_seg); int extend_pool(struct logical_volume *lv, const struct segment_type *segtype, struct alloc_handle *ah, uint32_t stripes, uint32_t stripe_size); /* * Begin skeleton for external LVM library */ struct id pv_id(const struct physical_volume *pv); const struct format_type *pv_format_type(const struct physical_volume *pv); struct id pv_vgid(const struct physical_volume *pv); struct physical_volume *pv_by_path(struct cmd_context *cmd, const char *pv_name); int add_pv_to_vg(struct volume_group *vg, const char *pv_name, struct physical_volume *pv, struct pvcreate_params *pp); int is_mirror_image_removable(struct logical_volume *mimage_lv, void *baton); uint64_t find_min_mda_size(struct dm_list *mdas); char *tags_format_and_copy(struct dm_pool *mem, const struct dm_list *tags); #endif lvm2-2.02.98/lib/mm/0000750000175000017500000000000012037016272012666 5ustar blankblanklvm2-2.02.98/lib/mm/xlate.h0000640000175000017500000000410212037016272014152 0ustar blankblank/* * 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_XLATE_H #define _LVM_XLATE_H #ifdef linux # include # include #else # include # define bswap_16(x) (((x) & 0x00ffU) << 8 | \ ((x) & 0xff00U) >> 8) # define bswap_32(x) (((x) & 0x000000ffU) << 24 | \ ((x) & 0xff000000U) >> 24 | \ ((x) & 0x0000ff00U) << 8 | \ ((x) & 0x00ff0000U) >> 8) # define bswap_64(x) (((x) & 0x00000000000000ffULL) << 56 | \ ((x) & 0xff00000000000000ULL) >> 56 | \ ((x) & 0x000000000000ff00ULL) << 40 | \ ((x) & 0x00ff000000000000ULL) >> 40 | \ ((x) & 0x0000000000ff0000ULL) << 24 | \ ((x) & 0x0000ff0000000000ULL) >> 24 | \ ((x) & 0x00000000ff000000ULL) << 8 | \ ((x) & 0x000000ff00000000ULL) >> 8) #endif #if BYTE_ORDER == LITTLE_ENDIAN # define xlate16(x) (x) # define xlate32(x) (x) # define xlate64(x) (x) # define xlate16_be(x) bswap_16(x) # define xlate32_be(x) bswap_32(x) # define xlate64_be(x) bswap_64(x) #elif BYTE_ORDER == BIG_ENDIAN # define xlate16(x) bswap_16(x) # define xlate32(x) bswap_32(x) # define xlate64(x) bswap_64(x) # define xlate16_be(x) (x) # define xlate32_be(x) (x) # define xlate64_be(x) (x) #else # include # define xlate16(x) __cpu_to_le16((x)) # define xlate32(x) __cpu_to_le32((x)) # define xlate64(x) __cpu_to_le64((x)) # define xlate16_be(x) __cpu_to_be16((x)) # define xlate32_be(x) __cpu_to_be32((x)) # define xlate64_be(x) __cpu_to_be64((x)) #endif #endif lvm2-2.02.98/lib/mm/memlock.h0000640000175000017500000000273712037016272014500 0ustar blankblank/* * 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 */ #ifndef LVM_MEMLOCK_H #define LVM_MEMLOCK_H struct cmd_context; /* * Inside a critical section, memory is always locked. * * After leaving the critical section, memory stays locked until * memlock_unlock() is called. This happens with * sync_local_dev_names() and sync_dev_names(). * * This allows critical sections to be entered and exited repeatedly without * incurring the expense of locking memory every time. * * memlock_reset() is necessary to clear the state after forking (polldaemon). */ void critical_section_inc(struct cmd_context *cmd, const char *reason); void critical_section_dec(struct cmd_context *cmd, const char *reason); int critical_section(void); void memlock_inc_daemon(struct cmd_context *cmd); void memlock_dec_daemon(struct cmd_context *cmd); void memlock_init(struct cmd_context *cmd); void memlock_reset(void); void memlock_unlock(struct cmd_context *cmd); #endif lvm2-2.02.98/lib/mm/memlock.c0000640000175000017500000002773512037016272014500 0ustar blankblank/* * Copyright (C) 2003-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 "memlock.h" #include "defaults.h" #include "config.h" #include "toolcontext.h" #include #include #include #include #include #include #ifndef DEVMAPPER_SUPPORT void memlock_inc_daemon(struct cmd_context *cmd) { return; } void memlock_dec_daemon(struct cmd_context *cmd) { return; } void critical_section_inc(struct cmd_context *cmd, const char *reason) { return; } void critical_section_dec(struct cmd_context *cmd, const char *reason) { return; } int critical_section(void) { return 0; } void memlock_init(struct cmd_context *cmd) { return; } void memlock_unlock(struct cmd_context *cmd) { return; } void memlock_reset(void) { return; } #else /* DEVMAPPER_SUPPORT */ static size_t _size_stack; static size_t _size_malloc_tmp; static size_t _size_malloc = 2000000; static void *_malloc_mem = NULL; static int _mem_locked = 0; static int _critical_section = 0; static int _memlock_count_daemon = 0; static int _priority; static int _default_priority; /* list of maps, that are unconditionaly ignored */ static const char * const _ignore_maps[] = { "[vdso]", "[vsyscall]", }; /* default blacklist for maps */ static const char * const _blacklist_maps[] = { "locale/locale-archive", "/LC_MESSAGES/", "gconv/gconv-modules.cache", "/libreadline.so.", /* not using readline during mlock */ "/libncurses.so.", /* not using readline during mlock */ "/libtinfo.so.", /* not using readline during mlock */ "/libdl-", /* not using dlopen,dlsym during mlock */ /* "/libdevmapper-event.so" */ }; typedef enum { LVM_MLOCK, LVM_MUNLOCK } lvmlock_t; static unsigned _use_mlockall; static int _maps_fd; static size_t _maps_len = 8192; /* Initial buffer size for reading /proc/self/maps */ static char *_maps_buffer; static char _procselfmaps[PATH_MAX] = ""; #define SELF_MAPS "/self/maps" static size_t _mstats; /* statistic for maps locking */ static void _touch_memory(void *mem, size_t size) { size_t pagesize = lvm_getpagesize(); char *pos = mem; char *end = pos + size - sizeof(long); while (pos < end) { *(long *) pos = 1; pos += pagesize; } } static void _allocate_memory(void) { void *stack_mem, *temp_malloc_mem; struct rlimit limit; /* Check if we could preallocate requested stack */ if ((getrlimit (RLIMIT_STACK, &limit) == 0) && ((_size_stack * 2) < limit.rlim_cur) && ((stack_mem = alloca(_size_stack)))) _touch_memory(stack_mem, _size_stack); /* FIXME else warn user setting got ignored */ if ((temp_malloc_mem = malloc(_size_malloc_tmp))) _touch_memory(temp_malloc_mem, _size_malloc_tmp); if ((_malloc_mem = malloc(_size_malloc))) _touch_memory(_malloc_mem, _size_malloc); free(temp_malloc_mem); } static void _release_memory(void) { free(_malloc_mem); } /* * mlock/munlock memory areas from /proc/self/maps * format described in kernel/Documentation/filesystem/proc.txt */ static int _maps_line(const struct dm_config_node *cn, lvmlock_t lock, const char *line, size_t *mstats) { const struct dm_config_value *cv; long from, to; int pos; unsigned i; char fr, fw, fx, fp; size_t sz; const char *lock_str = (lock == LVM_MLOCK) ? "mlock" : "munlock"; if (sscanf(line, "%lx-%lx %c%c%c%c%n", &from, &to, &fr, &fw, &fx, &fp, &pos) != 6) { log_error("Failed to parse maps line: %s", line); return 0; } /* Select readable maps */ if (fr != 'r') { log_debug("%s area unreadable %s : Skipping.", lock_str, line); return 1; } /* always ignored areas */ for (i = 0; i < sizeof(_ignore_maps) / sizeof(_ignore_maps[0]); ++i) if (strstr(line + pos, _ignore_maps[i])) { log_debug("%s ignore filter '%s' matches '%s': Skipping.", lock_str, _ignore_maps[i], line); return 1; } sz = to - from; if (!cn) { /* If no blacklist configured, use an internal set */ for (i = 0; i < sizeof(_blacklist_maps) / sizeof(_blacklist_maps[0]); ++i) if (strstr(line + pos, _blacklist_maps[i])) { log_debug("%s default filter '%s' matches '%s': Skipping.", lock_str, _blacklist_maps[i], line); return 1; } } else { for (cv = cn->v; cv; cv = cv->next) { if ((cv->type != DM_CFG_STRING) || !cv->v.str[0]) continue; if (strstr(line + pos, cv->v.str)) { log_debug("%s_filter '%s' matches '%s': Skipping.", lock_str, cv->v.str, line); return 1; } } } #ifdef VALGRIND_POOL /* * Valgrind is continually eating memory while executing code * so we need to deactivate check of locked memory size */ sz -= sz; /* = 0, but avoids getting warning about dead assigment */ #endif *mstats += sz; log_debug("%s %10ldKiB %12lx - %12lx %c%c%c%c%s", lock_str, ((long)sz + 1023) / 1024, from, to, fr, fw, fx, fp, line + pos); if (lock == LVM_MLOCK) { if (mlock((const void*)from, sz) < 0) { log_sys_error("mlock", line); return 0; } } else { if (munlock((const void*)from, sz) < 0) { log_sys_error("munlock", line); return 0; } } return 1; } static int _memlock_maps(struct cmd_context *cmd, lvmlock_t lock, size_t *mstats) { const struct dm_config_node *cn; char *line, *line_end; size_t len; ssize_t n; int ret = 1; if (_use_mlockall) { #ifdef MCL_CURRENT if (lock == LVM_MLOCK) { if (mlockall(MCL_CURRENT | MCL_FUTURE)) { log_sys_error("mlockall", ""); return 0; } } else { if (munlockall()) { log_sys_error("munlockall", ""); return 0; } } return 1; #else return 0; #endif } /* Force libc.mo load */ if (lock == LVM_MLOCK) (void)strerror(0); /* Reset statistic counters */ *mstats = 0; /* read mapping into a single memory chunk without reallocation * in the middle of reading maps file */ for (len = 0;;) { if (!_maps_buffer || len >= _maps_len) { if (_maps_buffer) _maps_len *= 2; if (!(_maps_buffer = dm_realloc(_maps_buffer, _maps_len))) { log_error("Allocation of maps buffer failed"); return 0; } } if (lseek(_maps_fd, 0, SEEK_SET)) log_sys_error("lseek", _procselfmaps); for (len = 0 ; len < _maps_len; len += n) { if (!(n = read(_maps_fd, _maps_buffer + len, _maps_len - len))) { _maps_buffer[len] = '\0'; break; /* EOF */ } if (n == -1) return_0; } if (len < _maps_len) /* fits in buffer */ break; } line = _maps_buffer; cn = find_config_tree_node(cmd, "activation/mlock_filter"); while ((line_end = strchr(line, '\n'))) { *line_end = '\0'; /* remove \n */ if (!_maps_line(cn, lock, line, mstats)) ret = 0; line = line_end + 1; } log_debug("%socked %ld bytes", (lock == LVM_MLOCK) ? "L" : "Unl", (long)*mstats); return ret; } /* Stop memory getting swapped out */ static void _lock_mem(struct cmd_context *cmd) { _allocate_memory(); /* * For daemon we need to use mlockall() * so even future adition of thread which may not even use lvm lib * will not block memory locked thread * Note: assuming _memlock_count_daemon is updated before _memlock_count */ _use_mlockall = _memlock_count_daemon ? 1 : find_config_tree_bool(cmd, "activation/use_mlockall", DEFAULT_USE_MLOCKALL); if (!_use_mlockall) { if (!*_procselfmaps && dm_snprintf(_procselfmaps, sizeof(_procselfmaps), "%s" SELF_MAPS, cmd->proc_dir) < 0) { log_error("proc_dir too long"); return; } if (!(_maps_fd = open(_procselfmaps, O_RDONLY))) { log_sys_error("open", _procselfmaps); return; } } log_very_verbose("Locking memory"); if (!_memlock_maps(cmd, LVM_MLOCK, &_mstats)) stack; errno = 0; if (((_priority = getpriority(PRIO_PROCESS, 0)) == -1) && errno) log_sys_error("getpriority", ""); else if (setpriority(PRIO_PROCESS, 0, _default_priority)) log_error("setpriority %d failed: %s", _default_priority, strerror(errno)); } static void _unlock_mem(struct cmd_context *cmd) { size_t unlock_mstats; log_very_verbose("Unlocking memory"); if (!_memlock_maps(cmd, LVM_MUNLOCK, &unlock_mstats)) stack; if (!_use_mlockall) { if (close(_maps_fd)) log_sys_error("close", _procselfmaps); dm_free(_maps_buffer); _maps_buffer = NULL; if (_mstats < unlock_mstats) { if ((_mstats + lvm_getpagesize()) < unlock_mstats) log_error(INTERNAL_ERROR "Reserved memory (%ld) not enough: used %ld. Increase activation/reserved_memory?", (long)_mstats, (long)unlock_mstats); else /* FIXME Believed due to incorrect use of yes_no_prompt while locks held */ log_debug("Suppressed internal error: Maps lock %ld < unlock %ld, a one-page difference.", (long)_mstats, (long)unlock_mstats); } } if (setpriority(PRIO_PROCESS, 0, _priority)) log_error("setpriority %u failed: %s", _priority, strerror(errno)); _release_memory(); } static void _lock_mem_if_needed(struct cmd_context *cmd) { log_debug("Lock: Memlock counters: locked:%d critical:%d daemon:%d suspended:%d", _mem_locked, _critical_section, _memlock_count_daemon, dm_get_suspended_counter()); if (!_mem_locked && ((_critical_section + _memlock_count_daemon) == 1)) { _mem_locked = 1; _lock_mem(cmd); } } static void _unlock_mem_if_possible(struct cmd_context *cmd) { log_debug("Unlock: Memlock counters: locked:%d critical:%d daemon:%d suspended:%d", _mem_locked, _critical_section, _memlock_count_daemon, dm_get_suspended_counter()); if (_mem_locked && !_critical_section && !_memlock_count_daemon) { _unlock_mem(cmd); _mem_locked = 0; } } void critical_section_inc(struct cmd_context *cmd, const char *reason) { if (!_critical_section) { _critical_section = 1; log_debug("Entering critical section (%s).", reason); } _lock_mem_if_needed(cmd); } void critical_section_dec(struct cmd_context *cmd, const char *reason) { if (_critical_section && !dm_get_suspended_counter()) { _critical_section = 0; log_debug("Leaving critical section (%s).", reason); } } int critical_section(void) { return _critical_section; } /* * The memlock_*_daemon functions will force the mlockall() call that we need * to stay in memory, but they will have no effect on device scans (unlike * normal critical_section_inc/dec). Memory is kept locked as long as either * of critical_section or memlock_daemon is in effect. */ void memlock_inc_daemon(struct cmd_context *cmd) { ++_memlock_count_daemon; if (_memlock_count_daemon == 1 && _critical_section > 0) log_error(INTERNAL_ERROR "_memlock_inc_daemon used in critical section."); log_debug("memlock_count_daemon inc to %d", _memlock_count_daemon); _lock_mem_if_needed(cmd); } void memlock_dec_daemon(struct cmd_context *cmd) { if (!_memlock_count_daemon) log_error(INTERNAL_ERROR "_memlock_count_daemon has dropped below 0."); --_memlock_count_daemon; log_debug("memlock_count_daemon dec to %d", _memlock_count_daemon); _unlock_mem_if_possible(cmd); } void memlock_init(struct cmd_context *cmd) { /* When threaded, caller already limited stack size so just use the default. */ _size_stack = 1024ULL * (cmd->threaded ? DEFAULT_RESERVED_STACK : find_config_tree_int(cmd, "activation/reserved_stack", DEFAULT_RESERVED_STACK)); _size_malloc_tmp = find_config_tree_int(cmd, "activation/reserved_memory", DEFAULT_RESERVED_MEMORY) * 1024ULL; _default_priority = find_config_tree_int(cmd, "activation/process_priority", DEFAULT_PROCESS_PRIORITY); } void memlock_reset(void) { log_debug("memlock reset."); _mem_locked = 0; _critical_section = 0; _memlock_count_daemon = 0; } void memlock_unlock(struct cmd_context *cmd) { _unlock_mem_if_possible(cmd); } #endif lvm2-2.02.98/lib/misc/0000750000175000017500000000000012037016273013211 5ustar blankblanklvm2-2.02.98/lib/misc/timestamp.h0000640000175000017500000000164012037016272015366 0ustar blankblank/* * Copyright (C) 2006 Rackable Systems 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_TIMESTAMP_H #define _LVM_TIMESTAMP_H struct timestamp; struct timestamp *get_timestamp(void); /* cmp_timestamp: Compare two timestamps * * Return: -1 if t1 is less than t2 * 0 if t1 is equal to t2 * 1 if t1 is greater than t2 */ int cmp_timestamp(struct timestamp *t1, struct timestamp *t2); void destroy_timestamp(struct timestamp *t); #endif /* _LVM_TIMESTAMP_H */ lvm2-2.02.98/lib/misc/crc_gen.c0000640000175000017500000000203212037016272014752 0ustar blankblank/* * 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 */ /* * Helper program to generate table included in crc.c. */ #include "lib.h" int main(int argc, char **argv) { uint32_t crc, i, j; printf("\t/* CRC-32 byte lookup table generated by crc_gen.c */\n"); printf("\tstatic const uint32_t crctab[] = {"); for (i = 0; i < 256; i++) { crc = i; for (j = 0; j < 8; j++) { if (crc & 1) crc = 0xedb88320L ^ (crc >> 1); else crc = crc >> 1; } if (i % 8) printf(" "); else printf("\n\t\t"); printf("0x%08.8x,", crc); } printf("\n\t};\n"); return 0; } lvm2-2.02.98/lib/misc/crc.c0000640000175000017500000001273212037016272014131 0ustar blankblank/* * Copyright (C) 2001-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 */ #include "lib.h" #include "crc.h" #include "xlate.h" /* Calculate an endian-independent CRC of supplied buffer */ #ifndef DEBUG_CRC32 uint32_t calc_crc(uint32_t initial, const uint8_t *buf, uint32_t size) #else static uint32_t _calc_crc_new(uint32_t initial, const uint8_t *buf, uint32_t size) #endif { /* CRC-32 byte lookup table generated by crc_gen.c */ static const uint32_t crctab[] = { 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, }; const uint32_t *start = (const uint32_t *) buf; const uint32_t *end = (const uint32_t *) (buf + (size & 0xfffffffc)); uint32_t crc = initial; /* Process 4 bytes per iteration */ while (start < end) { crc = crc ^ xlate32(*start++); crc = crctab[crc & 0xff] ^ crc >> 8; crc = crctab[crc & 0xff] ^ crc >> 8; crc = crctab[crc & 0xff] ^ crc >> 8; crc = crctab[crc & 0xff] ^ crc >> 8; } /* Process any bytes left over */ buf = (const uint8_t *) start; size = size & 0x3; while (size--) { crc = crc ^ *buf++; crc = crctab[crc & 0xff] ^ crc >> 8; } return crc; } #ifdef DEBUG_CRC32 static uint32_t _calc_crc_old(uint32_t initial, const uint8_t *buf, uint32_t size) { static const uint32_t crctab[] = { 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c }; uint32_t i, crc = initial; for (i = 0; i < size; i++) { crc ^= *buf++; crc = (crc >> 4) ^ crctab[crc & 0xf]; crc = (crc >> 4) ^ crctab[crc & 0xf]; } return crc; } uint32_t calc_crc(uint32_t initial, const uint8_t *buf, uint32_t size) { uint32_t new_crc = _calc_crc_new(initial, buf, size); uint32_t old_crc = _calc_crc_old(initial, buf, size); if (new_crc != old_crc) log_error(INTERNAL_ERROR "Old and new crc32 algorithms mismatch: 0x%08x != 0x%08x", old_crc, new_crc); return old_crc; } #endif /* DEBUG_CRC32 */ lvm2-2.02.98/lib/misc/lvm-string.h0000640000175000017500000000212412037016272015463 0ustar blankblank/* * 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_STRING_H #define _LVM_STRING_H #include #include #define NAME_LEN 128 #define UUID_PREFIX "LVM-" struct pool; int emit_to_buffer(char **buffer, size_t *size, const char *fmt, ...) __attribute__ ((format(printf, 3, 4))); char *build_dm_uuid(struct dm_pool *mem, const char *lvid, const char *layer); int validate_name(const char *n); int validate_tag(const char *n); int apply_lvname_restrictions(const char *name); int is_reserved_lvname(const char *name); #endif lvm2-2.02.98/lib/misc/lvm-file.c0000640000175000017500000001322012037016272015066 0ustar blankblank/* * 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 "lvm-file.h" #include #include #include #include #include /* * Creates a temporary filename, and opens a descriptor to the * file. Both the filename and descriptor are needed so we can * rename the file after successfully writing it. Grab * NFS-supported exclusive fcntl discretionary lock. */ int create_temp_name(const char *dir, char *buffer, size_t len, int *fd, unsigned *seed) { int i, num; pid_t pid; char hostname[255]; char *p; struct flock lock = { .l_type = F_WRLCK, .l_whence = 0, .l_start = 0, .l_len = 0 }; num = rand_r(seed); pid = getpid(); if (gethostname(hostname, sizeof(hostname)) < 0) { log_sys_error("gethostname", ""); strcpy(hostname, "nohostname"); } else { /* Replace any '/' with '?' found in the hostname. */ p = hostname; while ((p = strchr(p, '/'))) *p = '?'; } for (i = 0; i < 20; i++, num++) { if (dm_snprintf(buffer, len, "%s/.lvm_%s_%d_%d", dir, hostname, pid, num) == -1) { log_error("Not enough space to build temporary file " "string."); return 0; } *fd = open(buffer, O_CREAT | O_EXCL | O_WRONLY | O_APPEND, S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH); if (*fd < 0) continue; if (!fcntl(*fd, F_SETLK, &lock)) return 1; if (close(*fd)) log_sys_error("close", buffer); } return 0; } /* * NFS-safe rename of a temporary file to a common name, designed * to avoid race conditions and not overwrite the destination if * it exists. * * Try to create the new filename as a hard link to the original. * Check the link count of the original file to see if it worked. * (Assumes nothing else touches our temporary file!) If it * worked, unlink the old filename. */ int lvm_rename(const char *old, const char *new) { struct stat buf; if (link(old, new)) { log_error("%s: rename to %s failed: %s", old, new, strerror(errno)); return 0; } if (stat(old, &buf)) { log_sys_error("stat", old); return 0; } if (buf.st_nlink != 2) { log_error("%s: rename to %s failed", old, new); return 0; } if (unlink(old)) { log_sys_error("unlink", old); return 0; } return 1; } int path_exists(const char *path) { struct stat info; if (!*path) return 0; if (stat(path, &info) < 0) return 0; return 1; } int dir_exists(const char *path) { struct stat info; if (!*path) return 0; if (stat(path, &info) < 0) return 0; if (!S_ISDIR(info.st_mode)) return 0; return 1; } int is_empty_dir(const char *dir) { struct dirent *dirent; DIR *d; if (!(d = opendir(dir))) { log_sys_error("opendir", dir); return 0; } while ((dirent = readdir(d))) if (strcmp(dirent->d_name, ".") && strcmp(dirent->d_name, "..")) break; if (closedir(d)) { log_sys_error("closedir", dir); } return dirent ? 0 : 1; } void sync_dir(const char *file) { int fd; char *dir, *c; if (!(dir = dm_strdup(file))) { log_error("sync_dir failed in strdup"); return; } if (!dir_exists(dir)) { c = dir + strlen(dir); while (*c != '/' && c > dir) c--; if (c == dir) *c++ = '.'; *c = '\0'; } if ((fd = open(dir, O_RDONLY)) == -1) { log_sys_error("open", dir); goto out; } if (fsync(fd) && (errno != EROFS) && (errno != EINVAL)) log_sys_error("fsync", dir); if (close(fd)) log_sys_error("close", dir); out: dm_free(dir); } /* * Attempt to obtain fcntl lock on a file, if necessary creating file first * or waiting. * Returns file descriptor on success, else -1. * mode is F_WRLCK or F_RDLCK */ int fcntl_lock_file(const char *file, short lock_type, int warn_if_read_only) { int lockfd; char *dir; char *c; struct flock lock = { .l_type = lock_type, .l_whence = 0, .l_start = 0, .l_len = 0 }; if (!(dir = dm_strdup(file))) { log_error("fcntl_lock_file failed in strdup."); return -1; } if ((c = strrchr(dir, '/'))) *c = '\0'; if (!dm_create_dir(dir)) { dm_free(dir); return -1; } dm_free(dir); log_very_verbose("Locking %s (%s, %hd)", file, (lock_type == F_WRLCK) ? "F_WRLCK" : "F_RDLCK", lock_type); if ((lockfd = open(file, O_RDWR | O_CREAT, 0777)) < 0) { /* EACCES has been reported on NFS */ if (warn_if_read_only || (errno != EROFS && errno != EACCES)) log_sys_error("open", file); else stack; return -1; } if (fcntl(lockfd, F_SETLKW, &lock)) { log_sys_error("fcntl", file); if (close(lockfd)) log_sys_error("close", file); return -1; } return lockfd; } void fcntl_unlock_file(int lockfd) { struct flock lock = { .l_type = F_UNLCK, .l_whence = 0, .l_start = 0, .l_len = 0 }; log_very_verbose("Unlocking fd %d", lockfd); if (fcntl(lockfd, F_SETLK, &lock) == -1) log_error("fcntl unlock failed on fd %d: %s", lockfd, strerror(errno)); if (close(lockfd)) log_error("lock file close failed on fd %d: %s", lockfd, strerror(errno)); } int lvm_fclose(FILE *fp, const char *filename) { if (!dm_fclose(fp)) return 0; if (errno == 0) log_error("%s: write error", filename); else log_sys_error("write error", filename); return EOF; } lvm2-2.02.98/lib/misc/lvm-globals.h0000640000175000017500000000510012037016272015575 0ustar blankblank/* * 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 */ #ifndef _LVM_GLOBALS_H #define _LVM_GLOBALS_H #define VERBOSE_BASE_LEVEL _LOG_WARN #define SECURITY_LEVEL 0 #define PV_MIN_SIZE_KB 512 void init_verbose(int level); void init_silent(int silent); void init_test(int level); void init_md_filtering(int level); void init_pvmove(int level); void init_full_scan_done(int level); void init_obtain_device_list_from_udev(int device_list_from_udev); void init_trust_cache(int trustcache); void init_debug(int level); void init_cmd_name(int status); void init_ignorelockingfailure(int level); void init_lockingfailed(int level); void init_security_level(int level); void init_mirror_in_sync(int in_sync); void init_dmeventd_monitor(int reg); void init_background_polling(int polling); void init_ignore_suspended_devices(int ignore); void init_error_message_produced(int produced); void init_is_static(unsigned value); void init_udev_checking(int checking); void init_dev_disable_after_error_count(int value); void init_pv_min_size(uint64_t sectors); void init_activation_checks(int checks); void init_detect_internal_vg_cache_corruption(int detect); void init_retry_deactivation(int retry); void set_cmd_name(const char *cmd_name); void set_sysfs_dir_path(const char *path); int test_mode(void); int md_filtering(void); int pvmove_mode(void); int full_scan_done(void); int obtain_device_list_from_udev(void); int trust_cache(void); int verbose_level(void); int silent_mode(void); int debug_level(void); int ignorelockingfailure(void); int lockingfailed(void); int security_level(void); int mirror_in_sync(void); int background_polling(void); int ignore_suspended_devices(void); const char *log_command_name(void); unsigned is_static(void); int udev_checking(void); const char *sysfs_dir_path(void); uint64_t pv_min_size(void); int activation_checks(void); int detect_internal_vg_cache_corruption(void); int retry_deactivation(void); #define DMEVENTD_MONITOR_IGNORE -1 int dmeventd_monitor_mode(void); #define NO_DEV_ERROR_COUNT_LIMIT 0 int dev_disable_after_error_count(void); #endif lvm2-2.02.98/lib/misc/lvm-exec.h0000640000175000017500000000216212037016272015103 0ustar blankblank/* * 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 */ #ifndef _LVM_EXEC_H #define _LVM_EXEC_H #include "lib.h" struct cmd_context; /** * Execute command with paramaters and return status * * \param rstatus * Returns command's exit status code. * * \param sync_needed * Bool specifying whether local devices needs to be synchronized * before executing command. * Note: You cannot synchronize devices within activation context. * * \return * 0 (success) or -1 (failure). */ int exec_cmd(struct cmd_context *cmd, const char *const argv[], int *rstatus, int sync_needed); #endif lvm2-2.02.98/lib/misc/lvm-percent.c0000640000175000017500000000212612037016272015612 0ustar blankblank/* * 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 "lvm-percent.h" float percent_to_float(percent_t v) { return (float)v / PERCENT_1; } percent_t make_percent(uint64_t numerator, uint64_t denominator) { percent_t percent; if (!denominator) return PERCENT_100; /* FIXME? */ if (!numerator) return PERCENT_0; if (numerator == denominator) return PERCENT_100; switch (percent = PERCENT_100 * ((double) numerator / (double) denominator)) { case PERCENT_100: return PERCENT_100 - 1; case PERCENT_0: return PERCENT_0 + 1; default: return percent; } } lvm2-2.02.98/lib/misc/lvm-wrappers.h0000640000175000017500000000244112037016272016022 0ustar blankblank/* * Copyright (C) 2001-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_WRAPPERS_H #define _LVM_WRAPPERS_H #ifdef UDEV_SYNC_SUPPORT #include struct udev *udev_get_library_context(void); #endif int udev_init_library_context(void); void udev_fin_library_context(void); int udev_is_running(void); int lvm_getpagesize(void); /* * Read 'len' bytes of entropy from /dev/urandom and store in 'buf'. */ int read_urandom(void *buf, size_t len); # ifndef HAVE_SIGINTERRUPT # define siginterrupt(sig, flag) \ do { \ int ret; \ struct sigaction act; \ (void) sigaction(sig, NULL, &act); \ if (flag) \ act.sa_flags &= SA_RESTART; \ else \ act.sa_flags |= SA_RESTART; \ ret = sigaction(sig, &act, NULL); \ return ret; \ while (0) # endif #endif lvm2-2.02.98/lib/misc/last-path-component.h0000640000175000017500000000144712037016272017265 0ustar blankblank/* * 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 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 */ /* * Return the address of the last file name component of NAME. * If NAME ends in a slash, return the empty string. */ #include static inline const char *last_path_component(char const *name) { char const *slash = strrchr(name, '/'); return (slash) ? slash + 1 : name; } lvm2-2.02.98/lib/misc/sharedlib.c0000640000175000017500000000361612037016272015320 0ustar blankblank/* * 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 */ #include "lib.h" #include "config.h" #include "sharedlib.h" #include #include #include void get_shared_library_path(struct cmd_context *cmd, const char *libname, char *path, size_t path_len) { struct stat info; const char *lib_dir; /* If libname doesn't begin with '/' then use lib_dir/libname, * if present */ if (libname[0] == '/' || !(lib_dir = find_config_tree_str(cmd, "global/library_dir", 0)) || (dm_snprintf(path, path_len, "%s/%s", lib_dir, libname) == -1) || stat(path, &info) == -1) { strncpy(path, libname, path_len - 1); path[path_len - 1] = '\0'; } } void *load_shared_library(struct cmd_context *cmd, const char *libname, const char *desc, int silent) { char path[PATH_MAX]; void *library; if (is_static()) { log_error("Not loading shared %s library %s in static mode.", desc, libname); return NULL; } get_shared_library_path(cmd, libname, path, sizeof(path)); log_very_verbose("Opening shared %s library %s", desc, path); if (!(library = dlopen(path, RTLD_LAZY | RTLD_GLOBAL))) { if (silent && ignorelockingfailure()) log_verbose("Unable to open external %s library %s: %s", desc, path, dlerror()); else log_error("Unable to open external %s library %s: %s", desc, path, dlerror()); } return library; } lvm2-2.02.98/lib/misc/lvm-string.c0000640000175000017500000000625612037016272015470 0ustar blankblank/* * 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 "lvm-string.h" #include int emit_to_buffer(char **buffer, size_t *size, const char *fmt, ...) { int n; va_list ap; va_start(ap, fmt); n = vsnprintf(*buffer, *size, fmt, ap); va_end(ap); /* * Revert to old glibc behaviour (version <= 2.0.6) where snprintf * returned -1 if buffer was too small. From glibc 2.1 it returns number * of chars that would have been written had there been room. */ if (n < 0 || ((unsigned) n + 1 > *size)) n = -1; if (n < 0 || ((size_t)n == *size)) return 0; *buffer += n; *size -= n; return 1; } /* * A-Za-z0-9._-+/=!:&# */ int validate_tag(const char *n) { register char c; /* int len = 0; */ if (!n || !*n) return 0; /* FIXME: Is unlimited tag size support needed ? */ while ((/* len++, */ c = *n++)) if (!isalnum(c) && c != '.' && c != '_' && c != '-' && c != '+' && c != '/' && c != '=' && c != '!' && c != ':' && c != '&' && c != '#') return 0; return 1; } /* * Device layer names are all of the form --, any * other hyphens that appear in these names are quoted with yet * another hyphen. The top layer of any device has no layer * name. eg, vg0-lvol0. */ int validate_name(const char *n) { register char c; register int len = 0; if (!n || !*n) return 0; /* Hyphen used as VG-LV separator - ambiguity if LV starts with it */ if (*n == '-') return 0; if (!strcmp(n, ".") || !strcmp(n, "..")) return 0; while ((len++, c = *n++)) if (!isalnum(c) && c != '.' && c != '_' && c != '-' && c != '+') return 0; if (len > NAME_LEN) return 0; return 1; } int apply_lvname_restrictions(const char *name) { const char *reserved_prefixes[] = { "snapshot", "pvmove", NULL }; const char *reserved_strings[] = { "_mlog", "_mimage", "_rimage", "_rmeta", "_vorigin", "_tdata", "_tmeta", NULL }; unsigned i; const char *s; for (i = 0; (s = reserved_prefixes[i]); i++) { if (!strncmp(name, s, strlen(s))) { log_error("Names starting \"%s\" are reserved. " "Please choose a different LV name.", s); return 0; } } for (i = 0; (s = reserved_strings[i]); i++) { if (strstr(name, s)) { log_error("Names including \"%s\" are reserved. " "Please choose a different LV name.", s); return 0; } } return 1; } int is_reserved_lvname(const char *name) { int rc, old_suppress; old_suppress = log_suppress(2); rc = !apply_lvname_restrictions(name); log_suppress(old_suppress); return rc; } char *build_dm_uuid(struct dm_pool *mem, const char *lvid, const char *layer) { return dm_build_dm_uuid(mem, UUID_PREFIX, lvid, layer); } lvm2-2.02.98/lib/misc/lvm-percent.h0000640000175000017500000000273012037016272015620 0ustar blankblank/* * 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 */ #ifndef _LVM_PERCENT_H #define _LVM_PERCENT_H #include /* * A fixed-point representation of percent values. One percent equals to * PERCENT_1 as defined below. Values that are not multiples of PERCENT_1 * represent fractions, with precision of 1/1000000 of a percent. See * percent_to_float for a conversion to a floating-point representation. * * You should always use make_percent when building percent_t values. The * implementation of make_percent is biased towards the middle: it ensures that * the result is PERCENT_0 or PERCENT_100 if and only if this is the actual * value -- it never rounds any intermediate value (> 0 or < 100) to either 0 * or 100. */ typedef int32_t percent_t; typedef enum { PERCENT_0 = 0, PERCENT_1 = 1000000, PERCENT_100 = 100 * PERCENT_1, PERCENT_INVALID = -1, PERCENT_MERGE_FAILED = -2 } percent_range_t; float percent_to_float(percent_t v); percent_t make_percent(uint64_t numerator, uint64_t denominator); #endif lvm2-2.02.98/lib/misc/lvm-file.h0000640000175000017500000000375412037016272015106 0ustar blankblank/* * 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_FILE_H #define _LVM_FILE_H /* * Create a temporary filename, and opens a descriptor to the file. */ int create_temp_name(const char *dir, char *buffer, size_t len, int *fd, unsigned *seed); /* * NFS-safe rename of a temporary file to a common name, designed * to avoid race conditions and not overwrite the destination if * it exists. */ int lvm_rename(const char *old, const char *new); /* * Return 1 if path exists else return 0 */ int path_exists(const char *path); int dir_exists(const char *path); /* * Return 1 if dir is empty */ int is_empty_dir(const char *dir); /* Sync directory changes */ void sync_dir(const char *file); /* fcntl locking wrappers */ int fcntl_lock_file(const char *file, short lock_type, int warn_if_read_only); void fcntl_unlock_file(int lockfd); #define is_same_inode(buf1, buf2) \ ((buf1).st_ino == (buf2).st_ino && \ (buf1).st_dev == (buf2).st_dev) #define is_valid_fd(fd) (!(fcntl(fd, F_GETFD) == -1 && errno == EBADF)) /* * Close the specified stream, taking care to detect and diagnose any write * error. If there is an error, use the supplied file name in a diagnostic * that is reported via log_error or log_sys_error, as appropriate. * Use this function to close a stream when you've written data to it via * unchecked fprintf, fputc, etc. calls. Return 0 on success, EOF on failure. */ int lvm_fclose(FILE *fp, const char *filename); #endif lvm2-2.02.98/lib/misc/sharedlib.h0000640000175000017500000000162212037016272015320 0ustar blankblank/* * 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_SHAREDLIB_H #define _LVM_SHAREDLIB_H #include "config.h" #include void get_shared_library_path(struct cmd_context *cmd, const char *libname, char *path, size_t path_len); void *load_shared_library(struct cmd_context *cmd, const char *libname, const char *what, int silent); #endif lvm2-2.02.98/lib/misc/util.h0000640000175000017500000000210012037016272014330 0ustar blankblank/* * 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 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_UTIL_H #define _LVM_UTIL_H #define min(a, b) ({ typeof(a) _a = (a); \ typeof(b) _b = (b); \ (void) (&_a == &_b); \ _a < _b ? _a : _b; }) #define max(a, b) ({ typeof(a) _a = (a); \ typeof(b) _b = (b); \ (void) (&_a == &_b); \ _a > _b ? _a : _b; }) #if defined(__clang__) || (defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 6) #define uninitialized_var(x) x #else #define uninitialized_var(x) x = x #endif #define KERNEL_VERSION(major, minor, release) (((major) << 16) + ((minor) << 8) + (release)) #endif lvm2-2.02.98/lib/misc/lvm-version.h.in0000640000175000017500000000171212037016272016251 0ustar blankblank/* * 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_VERSION_H /** * The LVM version number * * LVM_MAJOR.LVM_MINOR.LVM_PATCHLEVEL(LVM_LIBAPI)[-LVM_RELEASE] */ #define LVM_VERSION @LVM_VERSION@ #define LVM_MAJOR @LVM_MAJOR@ #define LVM_MINOR @LVM_MINOR@ #define LVM_PATCHLEVEL @LVM_PATCHLEVEL@ #define LVM_LIBAPI @LVM_LIBAPI@ #define LVM_RELEASE @LVM_RELEASE@ #define LVM_RELEASE_DATE @LVM_RELEASE_DATE@ #endif lvm2-2.02.98/lib/misc/lvm-exec.c0000640000175000017500000000456312037016272015105 0ustar blankblank/* * 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 "device.h" #include "locking.h" #include "lvm-exec.h" #include "toolcontext.h" #include "activate.h" #include #include /* * Create verbose string with list of parameters */ static char *_verbose_args(const char *const argv[], char *buf, size_t sz) { int pos = 0; int len; unsigned i; buf[0] = '\0'; for (i = 0; argv[i]; i++) { if ((len = dm_snprintf(buf + pos, sz - pos, " %s", argv[i])) < 0) /* Truncated */ break; pos += len; } return buf; } /* * Execute and wait for external command */ int exec_cmd(struct cmd_context *cmd, const char *const argv[], int *rstatus, int sync_needed) { pid_t pid; int status; char buf[PATH_MAX * 2]; if (rstatus) *rstatus = -1; if (sync_needed) if (!sync_local_dev_names(cmd)) /* Flush ops and reset dm cookie */ return_0; log_verbose("Executing:%s", _verbose_args(argv, buf, sizeof(buf))); if ((pid = fork()) == -1) { log_error("fork failed: %s", strerror(errno)); return 0; } if (!pid) { /* Child */ reset_locking(); dev_close_all(); /* FIXME Fix effect of reset_locking on cache then include this */ /* destroy_toolcontext(cmd); */ /* FIXME Use execve directly */ execvp(argv[0], (char **) argv); log_sys_error("execvp", argv[0]); _exit(errno); } /* Parent */ if (wait4(pid, &status, 0, NULL) != pid) { log_error("wait4 child process %u failed: %s", pid, strerror(errno)); return 0; } if (!WIFEXITED(status)) { log_error("Child %u exited abnormally", pid); return 0; } if (WEXITSTATUS(status)) { if (rstatus) { *rstatus = WEXITSTATUS(status); log_verbose("%s failed: %u", argv[0], *rstatus); } else log_error("%s failed: %u", argv[0], WEXITSTATUS(status)); return 0; } if (rstatus) *rstatus = 0; return 1; } lvm2-2.02.98/lib/misc/crc.h0000640000175000017500000000135112037016272014131 0ustar blankblank/* * Copyright (C) 2001-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_CRC_H #define _LVM_CRC_H #define INITIAL_CRC 0xf597a6cf uint32_t calc_crc(uint32_t initial, const uint8_t *buf, uint32_t size); #endif lvm2-2.02.98/lib/misc/configure.h.in0000640000175000017500000004330412037016272015754 0ustar blankblank/* lib/misc/configure.h.in. Generated from configure.in by autoheader. */ /* Define to 1 if the `closedir' function returns void instead of `int'. */ #undef CLOSEDIR_VOID /* Define to 1 to include built-in support for clustered LVM locking. */ #undef CLUSTER_LOCKING_INTERNAL /* Path to clvmd binary. */ #undef CLVMD_PATH /* Path to clvmd pidfile. */ #undef CLVMD_PIDFILE /* Path to cmirrord pidfile. */ #undef CMIRRORD_PIDFILE /* Define to 0 to exclude libSaCkpt. */ #undef CMIRROR_HAS_CHECKPOINT /* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP systems. This function is required for `alloca.c' support on those systems. */ #undef CRAY_STACKSEG_END /* Define to 1 if using `alloca.c'. */ #undef C_ALLOCA /* Name of default metadata archive subdirectory. */ #undef DEFAULT_ARCHIVE_SUBDIR /* Name of default metadata backup subdirectory. */ #undef DEFAULT_BACKUP_SUBDIR /* Name of default metadata cache subdirectory. */ #undef DEFAULT_CACHE_SUBDIR /* Default data alignment. */ #undef DEFAULT_DATA_ALIGNMENT /* Define default node creation behavior with dmsetup create */ #undef DEFAULT_DM_ADD_NODE /* Define default name mangling behaviour */ #undef DEFAULT_DM_NAME_MANGLING /* Default DM run directory. */ #undef DEFAULT_DM_RUN_DIR /* Name of default locking directory. */ #undef DEFAULT_LOCK_DIR /* Default directory to keep PID files in. */ #undef DEFAULT_PID_DIR /* Default LVM run directory. */ #undef DEFAULT_RUN_DIR /* Define to 0 to reinstate the pre-2.02.54 handling of unit suffixes. */ #undef DEFAULT_SI_UNIT_CONSISTENCY /* Path to LVM system directory. */ #undef DEFAULT_SYS_DIR /* Define to 1 to enable LVM2 device-mapper interaction. */ #undef DEVMAPPER_SUPPORT /* Define to 1 to enable the device-mapper event daemon. */ #undef DMEVENTD /* Path to dmeventd binary. */ #undef DMEVENTD_PATH /* Path to dmeventd pidfile. */ #undef DMEVENTD_PIDFILE /* Library version */ #undef DM_LIB_VERSION /* Define to 1 if you have `alloca', as a function or macro. */ #undef HAVE_ALLOCA /* Define to 1 if you have and it should be used (not on Ultrix). */ #undef HAVE_ALLOCA_H /* Define to 1 if you have the header file. */ #undef HAVE_ARPA_INET_H /* Define to 1 if you have the header file. */ #undef HAVE_ASM_BYTEORDER_H /* Define to 1 if you have the header file. */ #undef HAVE_ASSERT_H /* Define to 1 if canonicalize_file_name is available. */ #undef HAVE_CANONICALIZE_FILE_NAME /* Define to 1 if your system has a working `chown' function. */ #undef HAVE_CHOWN /* Define to 1 if you have the header file. */ #undef HAVE_COROSYNC_CMAP_H /* Define to 1 if you have the header file. */ #undef HAVE_COROSYNC_CONFDB_H /* Define to 1 if you have the header file. */ #undef HAVE_CTYPE_H /* Define to 1 if you have the header file. */ #undef HAVE_DIRENT_H /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H /* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ #undef HAVE_DOPRNT /* Define to 1 if you have the `dup2' function. */ #undef HAVE_DUP2 /* Define to 1 if you have the header file. */ #undef HAVE_ERRNO_H /* Define to 1 if you have the header file. */ #undef HAVE_FCNTL_H /* Define to 1 if you have the `fork' function. */ #undef HAVE_FORK /* Define to 1 if you have the `ftruncate' function. */ #undef HAVE_FTRUNCATE /* Define to 1 if you have the `gethostname' function. */ #undef HAVE_GETHOSTNAME /* Define to 1 if getline is available. */ #undef HAVE_GETLINE /* Define to 1 if you have the `getmntent' function. */ #undef HAVE_GETMNTENT /* Define to 1 if getopt_long is available. */ #undef HAVE_GETOPTLONG /* Define to 1 if you have the header file. */ #undef HAVE_GETOPT_H /* Define to 1 if you have the `getpagesize' function. */ #undef HAVE_GETPAGESIZE /* Define to 1 if you have the `gettimeofday' function. */ #undef HAVE_GETTIMEOFDAY /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_LANGINFO_H /* Define to 1 if you have the header file. */ #undef HAVE_LIBCMAN_H /* Define to 1 if dynamic libraries are available. */ #undef HAVE_LIBDL /* Define to 1 if you have the header file. */ #undef HAVE_LIBDLM_H /* Define to 1 if you have the header file. */ #undef HAVE_LIBGEN_H /* Define to 1 if you have the header file. */ #undef HAVE_LIBINTL_H /* Define to 1 if you have the header file. */ #undef HAVE_LIMITS_H /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_FS_H /* Define to 1 if you have the header file. */ #undef HAVE_LOCALE_H /* Define to 1 if `lstat' has the bug that it succeeds when given the zero-length file name argument. */ #undef HAVE_LSTAT_EMPTY_STRING_BUG /* Define to 1 if you have the header file. */ #undef HAVE_MACHINE_ENDIAN_H /* Define to 1 if your system has a GNU libc compatible `malloc' function, and to 0 otherwise. */ #undef HAVE_MALLOC /* Define to 1 if you have the header file. */ #undef HAVE_MALLOC_H /* Define to 1 if you have the `memmove' function. */ #undef HAVE_MEMMOVE /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the `memset' function. */ #undef HAVE_MEMSET /* Define to 1 if you have the `mkdir' function. */ #undef HAVE_MKDIR /* Define to 1 if you have the `mkfifo' function. */ #undef HAVE_MKFIFO /* Define to 1 if you have a working `mmap' system call. */ #undef HAVE_MMAP /* Define to 1 if you have the header file. */ #undef HAVE_MNTENT_H /* Define to 1 if you have the `munmap' function. */ #undef HAVE_MUNMAP /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_NDIR_H /* Define to 1 if you have the header file. */ #undef HAVE_NETDB_H /* Define to 1 if you have the header file. */ #undef HAVE_NETINET_IN_H /* Define to 1 if you have the `nl_langinfo' function. */ #undef HAVE_NL_LANGINFO /* Define to 1 if you have the header file. */ #undef HAVE_PTHREAD_H /* Define to 1 if you have the header file. */ #undef HAVE_READLINE_HISTORY_H /* Define to 1 if you have the header file. */ #undef HAVE_READLINE_READLINE_H /* Define to 1 if your system has a GNU libc compatible `realloc' function, and to 0 otherwise. */ #undef HAVE_REALLOC /* Define to 1 to include support for realtime clock. */ #undef HAVE_REALTIME /* Define to 1 if you have the `rl_completion_matches' function. */ #undef HAVE_RL_COMPLETION_MATCHES /* Define to 1 if you have the `rmdir' function. */ #undef HAVE_RMDIR /* Define to 1 if you have the header file. */ #undef HAVE_SEARCH_H /* Define to 1 if you have the `select' function. */ #undef HAVE_SELECT /* Define to 1 to include support for selinux. */ #undef HAVE_SELINUX /* Define to 1 if you have the header file. */ #undef HAVE_SELINUX_LABEL_H /* Define to 1 if you have the header file. */ #undef HAVE_SELINUX_SELINUX_H /* Define to 1 if sepol_check_context is available. */ #undef HAVE_SEPOL /* Define to 1 if you have the `setenv' function. */ #undef HAVE_SETENV /* Define to 1 if you have the `setlocale' function. */ #undef HAVE_SETLOCALE /* Define to 1 if you have the `siginterrupt' function. */ #undef HAVE_SIGINTERRUPT /* Define to 1 if you have the header file. */ #undef HAVE_SIGNAL_H /* Define to 1 if you have the `socket' function. */ #undef HAVE_SOCKET /* Define to 1 if `stat' has the bug that it succeeds when given the zero-length file name argument. */ #undef HAVE_STAT_EMPTY_STRING_BUG /* Define to 1 if you have the header file. */ #undef HAVE_STDARG_H /* Define to 1 if you have the header file. */ #undef HAVE_STDDEF_H /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDIO_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the `strcasecmp' function. */ #undef HAVE_STRCASECMP /* Define to 1 if you have the `strchr' function. */ #undef HAVE_STRCHR /* Define to 1 if you have the `strcspn' function. */ #undef HAVE_STRCSPN /* Define to 1 if you have the `strdup' function. */ #undef HAVE_STRDUP /* Define to 1 if you have the `strerror' function. */ #undef HAVE_STRERROR /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the `strncasecmp' function. */ #undef HAVE_STRNCASECMP /* Define to 1 if you have the `strrchr' function. */ #undef HAVE_STRRCHR /* Define to 1 if you have the `strspn' function. */ #undef HAVE_STRSPN /* Define to 1 if you have the `strstr' function. */ #undef HAVE_STRSTR /* Define to 1 if you have the `strtol' function. */ #undef HAVE_STRTOL /* Define to 1 if you have the `strtoul' function. */ #undef HAVE_STRTOUL /* Define to 1 if `st_rdev' is a member of `struct stat'. */ #undef HAVE_STRUCT_STAT_ST_RDEV /* Define to 1 if you have the header file. */ #undef HAVE_SYSLOG_H /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_SYS_DIR_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_DISK_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_FILE_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_IOCTL_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_IPC_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_MMAN_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_MOUNT_H /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_SYS_NDIR_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_PARAM_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_RESOURCE_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SELECT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SEM_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SOCKET_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STATVFS_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TIME_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_UIO_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_UN_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_UTSNAME_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_WAIT_H /* Define to 1 if you have the header file. */ #undef HAVE_TERMIOS_H /* Define to 1 if you have the header file. */ #undef HAVE_TIME_H /* Define to 1 if you have the `uname' function. */ #undef HAVE_UNAME /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to 1 if you have the header file. */ #undef HAVE_UTMPX_H /* Define to 1 if you have the `vfork' function. */ #undef HAVE_VFORK /* Define to 1 if you have the header file. */ #undef HAVE_VFORK_H /* Define to 1 if you have the `vprintf' function. */ #undef HAVE_VPRINTF /* Define to 1 if `fork' works. */ #undef HAVE_WORKING_FORK /* Define to 1 if `vfork' works. */ #undef HAVE_WORKING_VFORK /* Define to 1 if `lstat' dereferences a symlink specified with a trailing slash. */ #undef LSTAT_FOLLOWS_SLASHED_SYMLINK /* Define to 1 if 'lvm' should fall back to using LVM1 binaries if device-mapper is missing from the kernel */ #undef LVM1_FALLBACK /* Define to 1 to include built-in support for LVM1 metadata. */ #undef LVM1_INTERNAL /* Path to lvmetad pidfile. */ #undef LVMETAD_PIDFILE /* Define to 1 to include code that uses lvmetad. */ #undef LVMETAD_SUPPORT /* Path to lvm binary. */ #undef LVM_PATH /* Define to 1 if `major', `minor', and `makedev' are declared in . */ #undef MAJOR_IN_MKDEV /* Define to 1 if `major', `minor', and `makedev' are declared in . */ #undef MAJOR_IN_SYSMACROS /* Define to 1 to include built-in support for mirrors. */ #undef MIRRORED_INTERNAL /* The path to 'modprobe', if available. */ #undef MODPROBE_CMD /* Define to 1 to enable O_DIRECT support. */ #undef O_DIRECT_SUPPORT /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Define to 1 to include built-in support for GFS pool metadata. */ #undef POOL_INTERNAL /* Define to 1 to include built-in support for raid. */ #undef RAID_INTERNAL /* Define to 1 to include the LVM readline shell. */ #undef READLINE_SUPPORT /* Define to 1 to include built-in support for replicators. */ #undef REPLICATOR_INTERNAL /* Define as the return type of signal handlers (`int' or `void'). */ #undef RETSIGTYPE /* Define to the type of arg 1 for `select'. */ #undef SELECT_TYPE_ARG1 /* Define to the type of args 2, 3 and 4 for `select'. */ #undef SELECT_TYPE_ARG234 /* Define to the type of arg 5 for `select'. */ #undef SELECT_TYPE_ARG5 /* Define to 1 to include built-in support for snapshots. */ #undef SNAPSHOT_INTERNAL /* If using the C implementation of alloca, define if you know the direction of stack growth for your system; otherwise it will be automatically deduced at runtime. STACK_DIRECTION > 0 => grows toward higher addresses STACK_DIRECTION < 0 => grows toward lower addresses STACK_DIRECTION = 0 => direction of growth unknown */ #undef STACK_DIRECTION /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* The path to 'thin_check', if available. */ #undef THIN_CHECK_CMD /* Define to 1 to include built-in support for thin provisioning. */ #undef THIN_INTERNAL /* Define to 1 if you can safely include both and . */ #undef TIME_WITH_SYS_TIME /* Define to 1 if your declares `struct tm'. */ #undef TM_IN_SYS_TIME /* Define to 1 to enable synchronisation with udev processing. */ #undef UDEV_SYNC_SUPPORT /* Enable a valgrind aware build of pool */ #undef VALGRIND_POOL /* Define for Solaris 2.5.1 so the uint32_t typedef from , , or is not used. If the typedef were allowed, the #define below would cause a syntax error. */ #undef _UINT32_T /* Define for Solaris 2.5.1 so the uint64_t typedef from , , or is not used. If the typedef were allowed, the #define below would cause a syntax error. */ #undef _UINT64_T /* Define for Solaris 2.5.1 so the uint8_t typedef from , , or is not used. If the typedef were allowed, the #define below would cause a syntax error. */ #undef _UINT8_T /* Define to empty if `const' does not conform to ANSI C. */ #undef const /* Define to `int' if doesn't define. */ #undef gid_t /* Define to `__inline__' or `__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ #ifndef __cplusplus #undef inline #endif /* Define to the type of a signed integer type of width exactly 16 bits if such a type exists and the standard includes do not define it. */ #undef int16_t /* Define to the type of a signed integer type of width exactly 32 bits if such a type exists and the standard includes do not define it. */ #undef int32_t /* Define to the type of a signed integer type of width exactly 64 bits if such a type exists and the standard includes do not define it. */ #undef int64_t /* Define to the type of a signed integer type of width exactly 8 bits if such a type exists and the standard includes do not define it. */ #undef int8_t /* Define to rpl_malloc if the replacement function should be used. */ #undef malloc /* Define to `int' if does not define. */ #undef mode_t /* Define to `long int' if does not define. */ #undef off_t /* Define to `int' if does not define. */ #undef pid_t /* Define to rpl_realloc if the replacement function should be used. */ #undef realloc /* Define to `unsigned int' if does not define. */ #undef size_t /* Define to `int' if does not define. */ #undef ssize_t /* Define to `int' if doesn't define. */ #undef uid_t /* Define to the type of an unsigned integer type of width exactly 16 bits if such a type exists and the standard includes do not define it. */ #undef uint16_t /* Define to the type of an unsigned integer type of width exactly 32 bits if such a type exists and the standard includes do not define it. */ #undef uint32_t /* Define to the type of an unsigned integer type of width exactly 64 bits if such a type exists and the standard includes do not define it. */ #undef uint64_t /* Define to the type of an unsigned integer type of width exactly 8 bits if such a type exists and the standard includes do not define it. */ #undef uint8_t /* Define as `fork' if `vfork' does not work. */ #undef vfork lvm2-2.02.98/lib/misc/timestamp.c0000640000175000017500000000513412037016272015363 0ustar blankblank/* * Copyright (C) 2006 Rackable Systems 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 */ /* * Abstract out the time methods used so they can be adjusted later - * the results of these routines should stay in-core. This implementation * requires librt. */ #include "lib.h" #include #include "timestamp.h" /* * The realtime section uses clock_gettime with the CLOCK_MONOTONIC * parameter to prevent issues with time warps */ #ifdef HAVE_REALTIME #include #include struct timestamp { struct timespec t; }; struct timestamp *get_timestamp(void) { struct timestamp *ts = NULL; if (!(ts = dm_malloc(sizeof(*ts)))) return_NULL; if (clock_gettime(CLOCK_MONOTONIC, &ts->t)) { log_sys_error("clock_gettime", "get_timestamp"); return NULL; } return ts; } /* cmp_timestamp: Compare two timestamps * * Return: -1 if t1 is less than t2 * 0 if t1 is equal to t2 * 1 if t1 is greater than t2 */ int cmp_timestamp(struct timestamp *t1, struct timestamp *t2) { if(t1->t.tv_sec < t2->t.tv_sec) return -1; if(t1->t.tv_sec > t2->t.tv_sec) return 1; if(t1->t.tv_nsec < t2->t.tv_nsec) return -1; if(t1->t.tv_nsec > t2->t.tv_nsec) return 1; return 0; } #else /* ! HAVE_REALTIME */ /* * The !realtime section just uses gettimeofday and is therefore subject * to ntp-type time warps - not sure if should allow that. */ #include struct timestamp { struct timeval t; }; struct timestamp *get_timestamp(void) { struct timestamp *ts = NULL; if (!(ts = dm_malloc(sizeof(*ts)))) return_NULL; if (gettimeofday(&ts->t, NULL)) { log_sys_error("gettimeofday", "get_timestamp"); return NULL; } return ts; } /* cmp_timestamp: Compare two timestamps * * Return: -1 if t1 is less than t2 * 0 if t1 is equal to t2 * 1 if t1 is greater than t2 */ int cmp_timestamp(struct timestamp *t1, struct timestamp *t2) { if(t1->t.tv_sec < t2->t.tv_sec) return -1; if(t1->t.tv_sec > t2->t.tv_sec) return 1; if(t1->t.tv_usec < t2->t.tv_usec) return -1; if(t1->t.tv_usec > t2->t.tv_usec) return 1; return 0; } #endif /* HAVE_REALTIME */ void destroy_timestamp(struct timestamp *t) { dm_free(t); } lvm2-2.02.98/lib/misc/intl.h0000640000175000017500000000140312037016272014326 0ustar blankblank/* * Copyright (C) 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_INTL_H #define _LVM_INTL_H #ifdef INTL_PACKAGE # include # define _(String) dgettext(INTL_PACKAGE, (String)) #else # define _(String) (String) #endif #endif lvm2-2.02.98/lib/misc/lib.h0000640000175000017500000000216512037016272014134 0ustar blankblank/* * 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 */ /* * This file must be included first by every library source file. */ #ifndef _LVM_LIB_H #define _LVM_LIB_H #include "configure.h" #define _REENTRANT #define _GNU_SOURCE #define _FILE_OFFSET_BITS 64 #include "intl.h" #include "libdevmapper.h" #include "lvm-globals.h" #include "lvm-wrappers.h" #include "lvm-types.h" #include "util.h" #ifdef DM # include "dm-logging.h" #else # include "lvm-logging.h" #endif #include #include #include #include #include #include #endif lvm2-2.02.98/lib/misc/lvm-globals.c0000640000175000017500000001341512037016272015600 0ustar blankblank/* * 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 "device.h" #include "memlock.h" #include "lvm-string.h" #include "defaults.h" #include "metadata-exported.h" #include static int _verbose_level = VERBOSE_BASE_LEVEL; static int _silent = 0; static int _test = 0; static int _md_filtering = 0; static int _pvmove = 0; static int _full_scan_done = 0; /* Restrict to one full scan during each cmd */ static int _obtain_device_list_from_udev = DEFAULT_OBTAIN_DEVICE_LIST_FROM_UDEV; static int _trust_cache = 0; /* Don't scan when incomplete VGs encountered */ static int _debug_level = 0; static int _log_cmd_name = 0; static int _ignorelockingfailure = 0; static int _security_level = SECURITY_LEVEL; static char _cmd_name[30] = ""; static int _mirror_in_sync = 0; static int _dmeventd_monitor = DEFAULT_DMEVENTD_MONITOR; static int _background_polling = DEFAULT_BACKGROUND_POLLING; static int _ignore_suspended_devices = 0; static int _error_message_produced = 0; static unsigned _is_static = 0; static int _udev_checking = 1; static int _retry_deactivation = DEFAULT_RETRY_DEACTIVATION; static int _activation_checks = 0; static char _sysfs_dir_path[PATH_MAX] = ""; static int _dev_disable_after_error_count = DEFAULT_DISABLE_AFTER_ERROR_COUNT; static uint64_t _pv_min_size = (DEFAULT_PV_MIN_SIZE_KB * 1024L >> SECTOR_SHIFT); static int _detect_internal_vg_cache_corruption = DEFAULT_DETECT_INTERNAL_VG_CACHE_CORRUPTION; void init_verbose(int level) { _verbose_level = level; } void init_silent(int silent) { _silent = silent; } void init_test(int level) { if (!_test && level) log_warn("TEST MODE: Metadata will NOT be updated and volumes will not be (de)activated."); _test = level; } void init_md_filtering(int level) { _md_filtering = level; } void init_pvmove(int level) { _pvmove = level; } void init_full_scan_done(int level) { _full_scan_done = level; } void init_obtain_device_list_from_udev(int device_list_from_udev) { _obtain_device_list_from_udev = device_list_from_udev; } void init_trust_cache(int trustcache) { _trust_cache = trustcache; } void init_ignorelockingfailure(int level) { _ignorelockingfailure = level; } void init_security_level(int level) { _security_level = level; } void init_mirror_in_sync(int in_sync) { _mirror_in_sync = in_sync; } void init_dmeventd_monitor(int reg) { _dmeventd_monitor = reg; } void init_background_polling(int polling) { _background_polling = polling; } void init_ignore_suspended_devices(int ignore) { _ignore_suspended_devices = ignore; } void init_cmd_name(int status) { _log_cmd_name = status; } void init_is_static(unsigned value) { _is_static = value; } void init_udev_checking(int checking) { if ((_udev_checking = checking)) log_debug("LVM udev checking enabled"); else log_debug("LVM udev checking disabled"); } void init_retry_deactivation(int retry) { _retry_deactivation = retry; } void init_activation_checks(int checks) { if ((_activation_checks = checks)) log_debug("LVM activation checks enabled"); else log_debug("LVM activation checks disabled"); } void init_dev_disable_after_error_count(int value) { _dev_disable_after_error_count = value; } void init_pv_min_size(uint64_t sectors) { _pv_min_size = sectors; } void init_detect_internal_vg_cache_corruption(int detect) { _detect_internal_vg_cache_corruption = detect; } void set_cmd_name(const char *cmd) { strncpy(_cmd_name, cmd, sizeof(_cmd_name) - 1); _cmd_name[sizeof(_cmd_name) - 1] = '\0'; } void set_sysfs_dir_path(const char *path) { strncpy(_sysfs_dir_path, path, sizeof(_sysfs_dir_path) - 1); _sysfs_dir_path[sizeof(_sysfs_dir_path) - 1] = '\0'; } const char *log_command_name(void) { if (!_log_cmd_name) return ""; return _cmd_name; } void init_error_message_produced(int value) { _error_message_produced = value; } int error_message_produced(void) { return _error_message_produced; } int test_mode(void) { return _test; } int md_filtering(void) { return _md_filtering; } int pvmove_mode(void) { return _pvmove; } int full_scan_done(void) { return _full_scan_done; } int obtain_device_list_from_udev(void) { return _obtain_device_list_from_udev; } int trust_cache(void) { return _trust_cache; } int background_polling(void) { return _background_polling; } int ignorelockingfailure(void) { return _ignorelockingfailure; } int security_level(void) { return _security_level; } int mirror_in_sync(void) { return _mirror_in_sync; } int dmeventd_monitor_mode(void) { return _dmeventd_monitor; } int ignore_suspended_devices(void) { return _ignore_suspended_devices; } void init_debug(int level) { _debug_level = level; } int verbose_level(void) { return _verbose_level; } int debug_level(void) { return _debug_level; } int silent_mode(void) { return _silent; } unsigned is_static(void) { return _is_static; } int udev_checking(void) { return _udev_checking; } int retry_deactivation(void) { return _retry_deactivation; } int activation_checks(void) { return _activation_checks; } const char *sysfs_dir_path(void) { return _sysfs_dir_path; } int dev_disable_after_error_count(void) { return _dev_disable_after_error_count; } uint64_t pv_min_size(void) { return _pv_min_size; } int detect_internal_vg_cache_corruption(void) { return _detect_internal_vg_cache_corruption; } lvm2-2.02.98/lib/misc/lvm-wrappers.c0000640000175000017500000000407212037016272016017 0ustar blankblank/* * Copyright (C) 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 */ #include "lib.h" #include #include #ifdef UDEV_SYNC_SUPPORT static const char _no_context_msg[] = "Udev library context not set."; struct udev *_udev; int udev_init_library_context(void) { if (_udev) udev_unref(_udev); if (!(_udev = udev_new())) { log_error("Failed to create udev library context."); return 0; } return 1; } void udev_fin_library_context(void) { udev_unref(_udev); _udev = NULL; } int udev_is_running(void) { struct udev_queue *udev_queue; int r; if (!_udev) { log_debug(_no_context_msg); goto bad; } if (!(udev_queue = udev_queue_new(_udev))) { log_debug("Could not get udev state."); goto bad; } r = udev_queue_get_udev_is_active(udev_queue); udev_queue_unref(udev_queue); return r; bad: log_debug("Assuming udev is not running."); return 0; } struct udev* udev_get_library_context(void) { return _udev; } #else /* UDEV_SYNC_SUPPORT */ int udev_init_library_context(void) { return 1; } void udev_fin_library_context(void) { } int udev_is_running(void) { return 0; } #endif int lvm_getpagesize(void) { return getpagesize(); } int read_urandom(void *buf, size_t len) { int fd; /* FIXME: we should stat here, and handle other cases */ /* FIXME: use common _io() routine's open/read/close */ if ((fd = open("/dev/urandom", O_RDONLY)) < 0) { log_sys_error("open", "read_urandom: /dev/urandom"); return 0; } if (read(fd, buf, len) != (ssize_t) len) { log_sys_error("read", "read_urandom: /dev/urandom"); if (close(fd)) stack; return 0; } if (close(fd)) stack; return 1; } lvm2-2.02.98/lib/activate/0000750000175000017500000000000012037016272014055 5ustar blankblanklvm2-2.02.98/lib/activate/fs.c0000640000175000017500000003204312037016272014634 0ustar blankblank/* * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU 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 #include #include #include #include /* * 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 _fs_create = 0; static int _mk_dir(const char *dev_dir, const char *vg_name) { static 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) { static 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; static 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) { static char lv_path[PATH_MAX], link_path[PATH_MAX], lvm1_group_path[PATH_MAX]; static 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; static 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)) { if (errno == ENOENT) return 1; log_sys_error("lstat", lv_path); return 0; } 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, NUM_FS_OPS } 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; default: ; /* NOTREACHED */ } return 1; } static DM_LIST_INIT(_fs_ops); /* * Count number of stacked fs_op_t operations to allow to skip dm_list search. * FIXME: handling of FS_RENAME */ static int _count_fs_ops[NUM_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 void _del_fs_op(struct fs_op_parms *fsp) { _count_fs_ops[fsp->type]--; dm_list_del(&fsp->list); dm_free(fsp); } /* Check if there is other the type of fs operation stacked */ static int _other_fs_ops(fs_op_t type) { unsigned i; for (i = 0; i < NUM_FS_OPS; i++) if (type != i && _count_fs_ops[i]) return 1; return 0; } /* Check if udev is supposed to create nodes */ static int _check_udev(int check_udev) { return check_udev && dm_udev_get_sync_support() && dm_udev_get_checking(); } /* FIXME: duplication of the code from libdm-common.c */ 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 dm_list *fsph, *fspht; 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 ((type == FS_DEL) && _other_fs_ops(type)) /* * Ignore any outstanding operations on the fs_op if deleting it. */ dm_list_iterate_safe(fsph, fspht, &_fs_ops) { fsp = dm_list_item(fsph, struct fs_op_parms); if (!strcmp(lv_name, fsp->lv_name) && !strcmp(vg_name, fsp->vg_name)) { _del_fs_op(fsp); if (!_other_fs_ops(type)) break; /* no other non DEL ops */ } } else if ((type == FS_ADD) && _count_fs_ops[FS_DEL] && _check_udev(check_udev)) /* * If udev is running ignore previous DEL operation on added fs_op. * (No other operations for this device then DEL could be stacked here). */ dm_list_iterate_safe(fsph, fspht, &_fs_ops) { fsp = dm_list_item(fsph, struct fs_op_parms); if ((fsp->type == FS_DEL) && !strcmp(lv_name, fsp->lv_name) && !strcmp(vg_name, fsp->vg_name)) { _del_fs_op(fsp); break; /* no other DEL ops */ } } else if ((type == FS_RENAME) && _check_udev(check_udev)) /* * If udev is running ignore any outstanding operations if renaming it. * * Currently RENAME operation happens through 'suspend -> resume'. * On 'resume' device is added with read_ahead settings, so it * safe to remove any stacked ADD, RENAME, READ_AHEAD operation * There cannot be any DEL operation on the renamed device. */ dm_list_iterate_safe(fsph, fspht, &_fs_ops) { fsp = dm_list_item(fsph, struct fs_op_parms); if (!strcmp(old_lv_name, fsp->lv_name) && !strcmp(vg_name, fsp->vg_name)) _del_fs_op(fsp); } 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); _count_fs_ops[type]++; 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); _del_fs_op(fsp); } _fs_create = 0; } 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 (critical_section()) { 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 (!critical_section()) { 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; } void fs_set_create(void) { _fs_create = 1; } int fs_has_non_delete_ops(void) { return _fs_create || _other_fs_ops(FS_DEL); } lvm2-2.02.98/lib/activate/fs.h0000640000175000017500000000244212037016272014641 0ustar blankblank/* * 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); void fs_set_create(void); int fs_has_non_delete_ops(void); #endif lvm2-2.02.98/lib/activate/activate.c0000640000175000017500000013150412037016272016026 0ustar blankblank/* * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU 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 "metadata.h" #include "activate.h" #include "memlock.h" #include "display.h" #include "fs.h" #include "lvm-exec.h" #include "lvm-file.h" #include "lvm-string.h" #include "toolcontext.h" #include "dev_manager.h" #include "str_list.h" #include "config.h" #include "filter.h" #include "segtype.h" #include "sharedlib.h" #include #include #include #define _skip(fmt, args...) log_very_verbose("Skipping: " fmt , ## args) int lvm1_present(struct cmd_context *cmd) { static char path[PATH_MAX]; if (dm_snprintf(path, sizeof(path), "%s/lvm/global", cmd->proc_dir) < 0) { log_error("LVM1 proc global snprintf failed"); return 0; } if (path_exists(path)) return 1; else return 0; } int list_segment_modules(struct dm_pool *mem, const struct lv_segment *seg, struct dm_list *modules) { unsigned int s; struct lv_segment *seg2, *snap_seg; struct dm_list *snh; if (seg->segtype->ops->modules_needed && !seg->segtype->ops->modules_needed(mem, seg, modules)) { log_error("module string allocation failed"); return 0; } if (lv_is_origin(seg->lv)) dm_list_iterate(snh, &seg->lv->snapshot_segs) if (!list_lv_modules(mem, dm_list_struct_base(snh, struct lv_segment, origin_list)->cow, modules)) return_0; if (lv_is_cow(seg->lv)) { snap_seg = find_cow(seg->lv); if (snap_seg->segtype->ops->modules_needed && !snap_seg->segtype->ops->modules_needed(mem, snap_seg, modules)) { log_error("snap_seg module string allocation failed"); return 0; } } for (s = 0; s < seg->area_count; s++) { switch (seg_type(seg, s)) { case AREA_LV: seg2 = find_seg_by_le(seg_lv(seg, s), seg_le(seg, s)); if (seg2 && !list_segment_modules(mem, seg2, modules)) return_0; break; case AREA_PV: case AREA_UNASSIGNED: ; } } return 1; } int list_lv_modules(struct dm_pool *mem, const struct logical_volume *lv, struct dm_list *modules) { struct lv_segment *seg; dm_list_iterate_items(seg, &lv->segments) if (!list_segment_modules(mem, seg, modules)) return_0; return 1; } #ifndef DEVMAPPER_SUPPORT void set_activation(int act) { static int warned = 0; if (warned || !act) return; log_error("Compiled without libdevmapper support. " "Can't enable activation."); warned = 1; } int activation(void) { return 0; } int library_version(char *version, size_t size) { return 0; } int driver_version(char *version, size_t size) { return 0; } int target_version(const char *target_name, uint32_t *maj, uint32_t *min, uint32_t *patchlevel) { return 0; } int target_present(struct cmd_context *cmd, const char *target_name, int use_modprobe) { return 0; } int lvm_dm_prefix_check(int major, int minor, const char *prefix) { return 0; } int lv_info(struct cmd_context *cmd, const struct logical_volume *lv, int use_layer, struct lvinfo *info, int with_open_count, int with_read_ahead) { return 0; } int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s, int use_layer, struct lvinfo *info, int with_open_count, int with_read_ahead) { return 0; } int lv_check_not_in_use(struct cmd_context *cmd __attribute__((unused)), struct logical_volume *lv, struct lvinfo *info) { return 0; } int lv_snapshot_percent(const struct logical_volume *lv, percent_t *percent) { return 0; } int lv_mirror_percent(struct cmd_context *cmd, const struct logical_volume *lv, int wait, percent_t *percent, uint32_t *event_nr) { return 0; } int lv_raid_percent(const struct logical_volume *lv, percent_t *percent) { return 0; } int lv_thin_pool_percent(const struct logical_volume *lv, int metadata, percent_t *percent) { return 0; } int lv_thin_percent(const struct logical_volume *lv, int mapped, percent_t *percent) { return 0; } int lv_thin_pool_transaction_id(const struct logical_volume *lv, uint64_t *transaction_id) { return 0; } int lvs_in_vg_activated(const struct volume_group *vg) { return 0; } int lvs_in_vg_opened(const struct volume_group *vg) { return 0; } /****** int lv_suspend(struct cmd_context *cmd, const char *lvid_s) { return 1; } *******/ int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s, unsigned origin_only, unsigned exclusive) { return 1; } int lv_resume(struct cmd_context *cmd, const char *lvid_s, unsigned origin_only) { return 1; } int lv_resume_if_active(struct cmd_context *cmd, const char *lvid_s, unsigned origin_only, unsigned exclusive, unsigned revert) { return 1; } int lv_deactivate(struct cmd_context *cmd, const char *lvid_s) { return 1; } int lv_activation_filter(struct cmd_context *cmd, const char *lvid_s, int *activate_lv) { return 1; } int lv_activate(struct cmd_context *cmd, const char *lvid_s, int exclusive) { return 1; } int lv_activate_with_filter(struct cmd_context *cmd, const char *lvid_s, int exclusive) { return 1; } int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv) { return 1; } int pv_uses_vg(struct physical_volume *pv, struct volume_group *vg) { return 0; } void activation_release(void) { } void activation_exit(void) { } int lv_is_active(const struct logical_volume *lv) { return 0; } int lv_is_active_but_not_locally(const struct logical_volume *lv) { return 0; } int lv_is_active_exclusive(const struct logical_volume *lv) { return 0; } int lv_is_active_exclusive_locally(const struct logical_volume *lv) { return 0; } int lv_is_active_exclusive_remotely(const struct logical_volume *lv) { return 0; } int lv_check_transient(struct logical_volume *lv) { return 1; } int monitor_dev_for_events(struct cmd_context *cmd, struct logical_volume *lv, const struct lv_activate_opts *laopts, int monitor) { return 1; } /* fs.c */ void fs_unlock(void) { } /* dev_manager.c */ #include "targets.h" int add_areas_line(struct dev_manager *dm, struct lv_segment *seg, struct dm_tree_node *node, uint32_t start_area, uint32_t areas) { return 0; } int device_is_usable(struct device *dev) { return 0; } int lv_has_target_type(struct dm_pool *mem, struct logical_volume *lv, const char *layer, const char *target_type) { return 0; } #else /* DEVMAPPER_SUPPORT */ static int _activation = 1; void set_activation(int act) { if (act == _activation) return; _activation = act; if (_activation) log_verbose("Activation enabled. Device-mapper kernel " "driver will be used."); else log_warn("WARNING: Activation disabled. No device-mapper " "interaction will be attempted."); } int activation(void) { return _activation; } static int _lv_passes_volumes_filter(struct cmd_context *cmd, struct logical_volume *lv, const struct dm_config_node *cn, const char *config_path) { const struct dm_config_value *cv; const char *str; static char path[PATH_MAX]; log_verbose("%s configuration setting defined: " "Checking the list to match %s/%s", config_path, lv->vg->name, lv->name); for (cv = cn->v; cv; cv = cv->next) { if (cv->type != DM_CFG_STRING) { log_error("Ignoring invalid string in config file %s", config_path); continue; } str = cv->v.str; if (!*str) { log_error("Ignoring empty string in config file %s", config_path); continue; } /* Tag? */ if (*str == '@') { str++; if (!*str) { log_error("Ignoring empty tag in config file " "%s", config_path); continue; } /* If any host tag matches any LV or VG tag, activate */ if (!strcmp(str, "*")) { if (str_list_match_list(&cmd->tags, &lv->tags, NULL) || str_list_match_list(&cmd->tags, &lv->vg->tags, NULL)) return 1; else continue; } /* If supplied tag matches LV or VG tag, activate */ if (str_list_match_item(&lv->tags, str) || str_list_match_item(&lv->vg->tags, str)) return 1; else continue; } if (!strchr(str, '/')) { /* vgname supplied */ if (!strcmp(str, lv->vg->name)) return 1; else continue; } /* vgname/lvname */ if (dm_snprintf(path, sizeof(path), "%s/%s", lv->vg->name, lv->name) < 0) { log_error("dm_snprintf error from %s/%s", lv->vg->name, lv->name); continue; } if (!strcmp(path, str)) return 1; } log_verbose("No item supplied in %s configuration setting " "matches %s/%s", config_path, lv->vg->name, lv->name); return 0; } static int _passes_activation_filter(struct cmd_context *cmd, struct logical_volume *lv) { const struct dm_config_node *cn; if (!(cn = find_config_tree_node(cmd, "activation/volume_list"))) { log_verbose("activation/volume_list configuration setting " "not defined: Checking only host tags for %s/%s", lv->vg->name, lv->name); /* If no host tags defined, activate */ if (dm_list_empty(&cmd->tags)) return 1; /* If any host tag matches any LV or VG tag, activate */ if (str_list_match_list(&cmd->tags, &lv->tags, NULL) || str_list_match_list(&cmd->tags, &lv->vg->tags, NULL)) return 1; log_verbose("No host tag matches %s/%s", lv->vg->name, lv->name); /* Don't activate */ return 0; } return _lv_passes_volumes_filter(cmd, lv, cn, "activation/volume_list"); } static int _passes_readonly_filter(struct cmd_context *cmd, struct logical_volume *lv) { const struct dm_config_node *cn; if (!(cn = find_config_tree_node(cmd, "activation/read_only_volume_list"))) return 0; return _lv_passes_volumes_filter(cmd, lv, cn, "activation/read_only_volume_list"); } int lv_passes_auto_activation_filter(struct cmd_context *cmd, struct logical_volume *lv) { const struct dm_config_node *cn; if (!(cn = find_config_tree_node(cmd, "activation/auto_activation_volume_list"))) { log_verbose("activation/auto_activation_volume_list configuration setting " "not defined: All logical volumes will be auto-activated."); return 1; } return _lv_passes_volumes_filter(cmd, lv, cn, "activation/auto_activation_volume_list"); } int library_version(char *version, size_t size) { if (!activation()) return 0; return dm_get_library_version(version, size); } int driver_version(char *version, size_t size) { if (!activation()) return 0; log_very_verbose("Getting driver version"); return dm_driver_version(version, size); } int target_version(const char *target_name, uint32_t *maj, uint32_t *min, uint32_t *patchlevel) { int r = 0; struct dm_task *dmt; struct dm_versions *target, *last_target; log_very_verbose("Getting target version for %s", target_name); if (!(dmt = dm_task_create(DM_DEVICE_LIST_VERSIONS))) return_0; if (activation_checks() && !dm_task_enable_checks(dmt)) goto_out; if (!dm_task_run(dmt)) { log_debug("Failed to get %s target version", target_name); /* Assume this was because LIST_VERSIONS isn't supported */ *maj = 0; *min = 0; *patchlevel = 0; r = 1; goto out; } target = dm_task_get_versions(dmt); do { last_target = target; if (!strcmp(target_name, target->name)) { r = 1; *maj = target->version[0]; *min = target->version[1]; *patchlevel = target->version[2]; goto out; } target = (struct dm_versions *)((char *) target + target->next); } while (last_target != target); out: if (r) log_very_verbose("Found %s target " "v%" PRIu32 ".%" PRIu32 ".%" PRIu32 ".", target_name, *maj, *min, *patchlevel); dm_task_destroy(dmt); return r; } int lvm_dm_prefix_check(int major, int minor, const char *prefix) { struct dm_task *dmt; const char *uuid; int r; if (!(dmt = dm_task_create(DM_DEVICE_STATUS))) return_0; if (!dm_task_set_minor(dmt, minor) || !dm_task_set_major(dmt, major) || !dm_task_run(dmt) || !(uuid = dm_task_get_uuid(dmt))) { dm_task_destroy(dmt); return 0; } r = strncasecmp(uuid, prefix, strlen(prefix)); dm_task_destroy(dmt); return r ? 0 : 1; } int module_present(struct cmd_context *cmd, const char *target_name) { int ret = 0; #ifdef MODPROBE_CMD char module[128]; const char *argv[3]; if (dm_snprintf(module, sizeof(module), "dm-%s", target_name) < 0) { log_error("module_present module name too long: %s", target_name); return 0; } argv[0] = MODPROBE_CMD; argv[1] = module; argv[2] = NULL; ret = exec_cmd(cmd, argv, NULL, 0); #endif return ret; } int target_present(struct cmd_context *cmd, const char *target_name, int use_modprobe) { uint32_t maj, min, patchlevel; if (!activation()) return 0; #ifdef MODPROBE_CMD if (use_modprobe) { if (target_version(target_name, &maj, &min, &patchlevel)) return 1; if (!module_present(cmd, target_name)) return_0; } #endif return target_version(target_name, &maj, &min, &patchlevel); } /* * Returns 1 if info structure populated, else 0 on failure. */ int lv_info(struct cmd_context *cmd, const struct logical_volume *lv, int use_layer, struct lvinfo *info, int with_open_count, int with_read_ahead) { struct dm_info dminfo; const char *layer; if (!activation()) return 0; /* * If open_count info is requested and we have to be sure our own udev * transactions are finished * For non-clustered locking type we are only interested for non-delete operation * in progress - as only those could lead to opened files */ if (with_open_count) { if (locking_is_clustered()) sync_local_dev_names(cmd); /* Wait to have udev in sync */ else if (fs_has_non_delete_ops()) fs_unlock(); /* For non clustered - wait if there are non-delete ops */ } if (use_layer && lv_is_thin_pool(lv)) layer = "tpool"; else if (use_layer && lv_is_origin(lv)) layer = "real"; else layer = NULL; if (!dev_manager_info(lv->vg->cmd->mem, lv, layer, with_open_count, with_read_ahead, &dminfo, &info->read_ahead)) return_0; info->exists = dminfo.exists; info->suspended = dminfo.suspended; info->open_count = dminfo.open_count; info->major = dminfo.major; info->minor = dminfo.minor; info->read_only = dminfo.read_only; info->live_table = dminfo.live_table; info->inactive_table = dminfo.inactive_table; return 1; } int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s, int use_layer, struct lvinfo *info, int with_open_count, int with_read_ahead) { int r; struct logical_volume *lv; if (!(lv = lv_from_lvid(cmd, lvid_s, 0))) return 0; r = lv_info(cmd, lv, use_layer, info, with_open_count, with_read_ahead); release_vg(lv->vg); return r; } int lv_check_not_in_use(struct cmd_context *cmd __attribute__((unused)), struct logical_volume *lv, struct lvinfo *info) { if (!info->exists) return 1; /* If sysfs is not used, use open_count information only. */ if (!*dm_sysfs_dir()) { if (info->open_count) { log_error("Logical volume %s/%s in use.", lv->vg->name, lv->name); return 0; } return 1; } if (dm_device_has_holders(info->major, info->minor)) { log_error("Logical volume %s/%s is used by another device.", lv->vg->name, lv->name); return 0; } if (dm_device_has_mounted_fs(info->major, info->minor)) { log_error("Logical volume %s/%s contains a filesystem in use.", lv->vg->name, lv->name); return 0; } return 1; } /* * Returns 1 if percent set, else 0 on failure. */ int lv_check_transient(struct logical_volume *lv) { int r; struct dev_manager *dm; if (!activation()) return 0; log_debug("Checking transient status for LV %s/%s", lv->vg->name, lv->name); if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name, 1))) return_0; if (!(r = dev_manager_transient(dm, lv))) stack; dev_manager_destroy(dm); return r; } /* * Returns 1 if percent set, else 0 on failure. */ int lv_snapshot_percent(const struct logical_volume *lv, percent_t *percent) { int r; struct dev_manager *dm; if (!activation()) return 0; log_debug("Checking snapshot percent for LV %s/%s", lv->vg->name, lv->name); if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name, 1))) return_0; if (!(r = dev_manager_snapshot_percent(dm, lv, percent))) stack; dev_manager_destroy(dm); return r; } /* FIXME Merge with snapshot_percent */ int lv_mirror_percent(struct cmd_context *cmd, const struct logical_volume *lv, int wait, percent_t *percent, uint32_t *event_nr) { int r; struct dev_manager *dm; struct lvinfo info; /* If mirrored LV is temporarily shrinked to 1 area (= linear), * it should be considered in-sync. */ if (dm_list_size(&lv->segments) == 1 && first_seg(lv)->area_count == 1) { *percent = PERCENT_100; return 1; } if (!activation()) return 0; log_debug("Checking mirror percent for LV %s/%s", lv->vg->name, lv->name); if (!lv_info(cmd, lv, 0, &info, 0, 0)) return_0; if (!info.exists) return 0; if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name, 1))) return_0; if (!(r = dev_manager_mirror_percent(dm, lv, wait, percent, event_nr))) stack; dev_manager_destroy(dm); return r; } int lv_raid_percent(const struct logical_volume *lv, percent_t *percent) { return lv_mirror_percent(lv->vg->cmd, lv, 0, percent, NULL); } /* * Returns data or metadata percent usage, depends on metadata 0/1. * Returns 1 if percent set, else 0 on failure. */ int lv_thin_pool_percent(const struct logical_volume *lv, int metadata, percent_t *percent) { int r; struct dev_manager *dm; if (!activation()) return 0; log_debug("Checking thin %sdata percent for LV %s/%s", (metadata) ? "meta" : "", lv->vg->name, lv->name); if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name, 1))) return_0; if (!(r = dev_manager_thin_pool_percent(dm, lv, metadata, percent))) stack; dev_manager_destroy(dm); return r; } /* * Returns 1 if percent set, else 0 on failure. */ int lv_thin_percent(const struct logical_volume *lv, int mapped, percent_t *percent) { int r; struct dev_manager *dm; if (!activation()) return 0; log_debug("Checking thin percent for LV %s/%s", lv->vg->name, lv->name); if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name, 1))) return_0; if (!(r = dev_manager_thin_percent(dm, lv, mapped, percent))) stack; dev_manager_destroy(dm); return r; } /* * Returns 1 if transaction_id set, else 0 on failure. */ int lv_thin_pool_transaction_id(const struct logical_volume *lv, uint64_t *transaction_id) { int r; struct dev_manager *dm; struct dm_status_thin_pool *status; if (!activation()) return 0; log_debug("Checking thin percent for LV %s/%s", lv->vg->name, lv->name); if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name, 1))) return_0; if (!(r = dev_manager_thin_pool_status(dm, lv, &status))) stack; else *transaction_id = status->transaction_id; dev_manager_destroy(dm); return r; } static int _lv_active(struct cmd_context *cmd, const struct logical_volume *lv) { struct lvinfo info; if (!lv_info(cmd, lv, 0, &info, 0, 0)) { stack; return -1; } return info.exists; } static int _lv_open_count(struct cmd_context *cmd, struct logical_volume *lv) { struct lvinfo info; if (!lv_info(cmd, lv, 0, &info, 1, 0)) { stack; return -1; } return info.open_count; } static int _lv_activate_lv(struct logical_volume *lv, struct lv_activate_opts *laopts) { int r; struct dev_manager *dm; if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name, (lv->status & PVMOVE) ? 0 : 1))) return_0; if (!(r = dev_manager_activate(dm, lv, laopts))) stack; dev_manager_destroy(dm); return r; } static int _lv_preload(struct logical_volume *lv, struct lv_activate_opts *laopts, int *flush_required) { int r = 0; struct dev_manager *dm; int old_readonly = laopts->read_only; laopts->read_only = _passes_readonly_filter(lv->vg->cmd, lv); if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name, (lv->status & PVMOVE) ? 0 : 1))) goto_out; if (!(r = dev_manager_preload(dm, lv, laopts, flush_required))) stack; dev_manager_destroy(dm); laopts->read_only = old_readonly; out: return r; } static int _lv_deactivate(struct logical_volume *lv) { int r; struct dev_manager *dm; if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name, 1))) return_0; if (!(r = dev_manager_deactivate(dm, lv))) stack; dev_manager_destroy(dm); return r; } static int _lv_suspend_lv(struct logical_volume *lv, struct lv_activate_opts *laopts, int lockfs, int flush_required) { int r; struct dev_manager *dm; laopts->read_only = _passes_readonly_filter(lv->vg->cmd, lv); /* * When we are asked to manipulate (normally suspend/resume) the PVMOVE * device directly, we don't want to touch the devices that use it. */ if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name, (lv->status & PVMOVE) ? 0 : 1))) return_0; if (!(r = dev_manager_suspend(dm, lv, laopts, lockfs, flush_required))) stack; dev_manager_destroy(dm); return r; } /* * These two functions return the number of visible LVs in the state, * or -1 on error. FIXME Check this. */ int lvs_in_vg_activated(const struct volume_group *vg) { struct lv_list *lvl; int count = 0; if (!activation()) return 0; dm_list_iterate_items(lvl, &vg->lvs) if (lv_is_visible(lvl->lv)) count += (_lv_active(vg->cmd, lvl->lv) == 1); log_debug("Counted %d active LVs in VG %s", count, vg->name); return count; } int lvs_in_vg_opened(const struct volume_group *vg) { const struct lv_list *lvl; int count = 0; if (!activation()) return 0; dm_list_iterate_items(lvl, &vg->lvs) if (lv_is_visible(lvl->lv)) count += (_lv_open_count(vg->cmd, lvl->lv) > 0); log_debug("Counted %d open LVs in VG %s", count, vg->name); return count; } /* * _lv_is_active * @lv: logical volume being queried * @locally: set if active locally (when provided) * @exclusive: set if active exclusively (when provided) * * Determine whether an LV is active locally or in a cluster. * In addition to the return code which indicates whether or * not the LV is active somewhere, two other values are set * to yield more information about the status of the activation: * return locally exclusively status * ====== ======= =========== ====== * 0 0 0 not active * 1 0 0 active remotely * 1 0 1 exclusive remotely * 1 1 0 active locally and possibly remotely * 1 1 1 exclusive locally (or local && !cluster) * The VG lock must be held to call this function. * * Returns: 0 or 1 */ static int _lv_is_active(const struct logical_volume *lv, int *locally, int *exclusive) { int r, l, e; /* remote, local, and exclusive */ r = l = e = 0; if (_lv_active(lv->vg->cmd, lv)) l = 1; if (!vg_is_clustered(lv->vg)) { if (l) e = 1; /* exclusive by definition */ goto out; } /* Active locally, and the caller doesn't care about exclusive */ if (l && !exclusive) goto out; if ((r = remote_lock_held(lv->lvid.s, &e)) >= 0) goto out; /* * If lock query is not supported (due to interfacing with old * code), then we cannot evaluate exclusivity properly. * * Old users of this function will never be affected by this, * since they are only concerned about active vs. not active. * New users of this function who specifically ask for 'exclusive' * will be given an error message. */ log_error("Unable to determine exclusivity of %s", lv->name); e = 0; /* * We used to attempt activate_lv_excl_local(lv->vg->cmd, lv) here, * but it's unreliable. */ out: if (locally) *locally = l; if (exclusive) *exclusive = e; log_very_verbose("%s/%s is %sactive%s%s", lv->vg->name, lv->name, (r || l) ? "" : "not ", (exclusive && e) ? " exclusive" : "", e ? (l ? " locally" : " remotely") : ""); return r || l; } int lv_is_active(const struct logical_volume *lv) { return _lv_is_active(lv, NULL, NULL); } int lv_is_active_but_not_locally(const struct logical_volume *lv) { int l; return _lv_is_active(lv, &l, NULL) && !l; } int lv_is_active_exclusive(const struct logical_volume *lv) { int e; return _lv_is_active(lv, NULL, &e) && e; } int lv_is_active_exclusive_locally(const struct logical_volume *lv) { int l, e; return _lv_is_active(lv, &l, &e) && l && e; } int lv_is_active_exclusive_remotely(const struct logical_volume *lv) { int l, e; return _lv_is_active(lv, &l, &e) && !l && e; } #ifdef DMEVENTD static struct dm_event_handler *_create_dm_event_handler(struct cmd_context *cmd, const char *dmuuid, const char *dso, const int timeout, enum dm_event_mask mask) { struct dm_event_handler *dmevh; if (!(dmevh = dm_event_handler_create())) return_NULL; if (dm_event_handler_set_dmeventd_path(dmevh, find_config_tree_str(cmd, "dmeventd/executable", NULL))) goto_bad; if (dm_event_handler_set_dso(dmevh, dso)) goto_bad; if (dm_event_handler_set_uuid(dmevh, dmuuid)) goto_bad; dm_event_handler_set_timeout(dmevh, timeout); dm_event_handler_set_event_mask(dmevh, mask); return dmevh; bad: dm_event_handler_destroy(dmevh); return NULL; } char *get_monitor_dso_path(struct cmd_context *cmd, const char *libpath) { char *path; if (!(path = dm_pool_alloc(cmd->mem, PATH_MAX))) { log_error("Failed to allocate dmeventd library path."); return NULL; } get_shared_library_path(cmd, libpath, path, PATH_MAX); return path; } static char *_build_target_uuid(struct cmd_context *cmd, struct logical_volume *lv) { const char *layer; if (lv_is_thin_pool(lv)) layer = "tpool"; /* Monitor "tpool" for the "thin pool". */ else if (lv_is_origin(lv)) layer = "real"; /* Monitor "real" for "snapshot-origin". */ else layer = NULL; return build_dm_uuid(cmd->mem, lv->lvid.s, layer); } int target_registered_with_dmeventd(struct cmd_context *cmd, const char *dso, struct logical_volume *lv, int *pending) { char *uuid; enum dm_event_mask evmask = 0; struct dm_event_handler *dmevh; *pending = 0; if (!dso) return_0; if (!(uuid = _build_target_uuid(cmd, lv))) return_0; if (!(dmevh = _create_dm_event_handler(cmd, uuid, dso, 0, DM_EVENT_ALL_ERRORS))) return_0; if (dm_event_get_registered_device(dmevh, 0)) { dm_event_handler_destroy(dmevh); return 0; } evmask = dm_event_handler_get_event_mask(dmevh); if (evmask & DM_EVENT_REGISTRATION_PENDING) { *pending = 1; evmask &= ~DM_EVENT_REGISTRATION_PENDING; } dm_event_handler_destroy(dmevh); return evmask; } int target_register_events(struct cmd_context *cmd, const char *dso, struct logical_volume *lv, int evmask __attribute__((unused)), int set, int timeout) { char *uuid; struct dm_event_handler *dmevh; int r; if (!dso) return_0; /* We always monitor the "real" device, never the "snapshot-origin" itself. */ if (!(uuid = _build_target_uuid(cmd, lv))) return_0; if (!(dmevh = _create_dm_event_handler(cmd, uuid, dso, timeout, DM_EVENT_ALL_ERRORS | (timeout ? DM_EVENT_TIMEOUT : 0)))) return_0; r = set ? dm_event_register_handler(dmevh) : dm_event_unregister_handler(dmevh); dm_event_handler_destroy(dmevh); if (!r) return_0; log_info("%s %s for events", set ? "Monitored" : "Unmonitored", uuid); return 1; } #endif /* * Returns 0 if an attempt to (un)monitor the device failed. * Returns 1 otherwise. */ int monitor_dev_for_events(struct cmd_context *cmd, struct logical_volume *lv, const struct lv_activate_opts *laopts, int monitor) { #ifdef DMEVENTD int i, pending = 0, monitored; int r = 1; struct dm_list *tmp, *snh, *snht; struct lv_segment *seg; struct lv_segment *log_seg; int (*monitor_fn) (struct lv_segment *s, int e); uint32_t s; static const struct lv_activate_opts zlaopts = { 0 }; static const struct lv_activate_opts thinopts = { .skip_in_use = 1 }; struct lvinfo info; if (!laopts) laopts = &zlaopts; /* skip dmeventd code altogether */ if (dmeventd_monitor_mode() == DMEVENTD_MONITOR_IGNORE) return 1; /* * Nothing to do if dmeventd configured not to be used. */ if (monitor && !dmeventd_monitor_mode()) return 1; /* * Allow to unmonitor thin pool via explicit pool unmonitor * or unmonitor before the last thin pool user deactivation * Skip unmonitor, if invoked via unmonitor of thin volume * and there is another thin pool user (open_count > 1) */ if (laopts->skip_in_use && lv_info(lv->vg->cmd, lv, 1, &info, 1, 0) && (info.open_count != 1)) { log_debug("Skipping unmonitor of opened %s (open:%d)", lv->name, info.open_count); return 1; } /* * In case of a snapshot device, we monitor lv->snapshot->lv, * not the actual LV itself. */ if (lv_is_cow(lv) && (laopts->no_merging || !lv_is_merging_cow(lv))) return monitor_dev_for_events(cmd, lv->snapshot->lv, NULL, monitor); /* * In case this LV is a snapshot origin, we instead monitor * each of its respective snapshots. The origin itself may * also need to be monitored if it is a mirror, for example. */ if (!laopts->origin_only && lv_is_origin(lv)) dm_list_iterate_safe(snh, snht, &lv->snapshot_segs) if (!monitor_dev_for_events(cmd, dm_list_struct_base(snh, struct lv_segment, origin_list)->cow, NULL, monitor)) r = 0; /* * If the volume is mirrored and its log is also mirrored, monitor * the log volume as well. */ if ((seg = first_seg(lv)) != NULL && seg->log_lv != NULL && (log_seg = first_seg(seg->log_lv)) != NULL && seg_is_mirrored(log_seg)) if (!monitor_dev_for_events(cmd, seg->log_lv, NULL, monitor)) r = 0; dm_list_iterate(tmp, &lv->segments) { seg = dm_list_item(tmp, struct lv_segment); /* Recurse for AREA_LV */ for (s = 0; s < seg->area_count; s++) { if (seg_type(seg, s) != AREA_LV) continue; if (!monitor_dev_for_events(cmd, seg_lv(seg, s), NULL, monitor)) { log_error("Failed to %smonitor %s", monitor ? "" : "un", seg_lv(seg, s)->name); r = 0; } } /* * If requested unmonitoring of thin volume, request test * if there is no other thin pool user * * FIXME: code here looks like _lv_postorder() */ if (seg->pool_lv && !monitor_dev_for_events(cmd, seg->pool_lv, (!monitor) ? &thinopts : NULL, monitor)) r = 0; if (seg->metadata_lv && !monitor_dev_for_events(cmd, seg->metadata_lv, NULL, monitor)) r = 0; if (!seg_monitored(seg) || (seg->status & PVMOVE)) continue; monitor_fn = NULL; /* Check monitoring status */ if (seg->segtype->ops->target_monitored) monitored = seg->segtype->ops->target_monitored(seg, &pending); else continue; /* segtype doesn't support registration */ /* * FIXME: We should really try again if pending */ monitored = (pending) ? 0 : monitored; if (monitor) { if (monitored) log_verbose("%s/%s already monitored.", lv->vg->name, lv->name); else if (seg->segtype->ops->target_monitor_events) monitor_fn = seg->segtype->ops->target_monitor_events; } else { if (!monitored) log_verbose("%s/%s already not monitored.", lv->vg->name, lv->name); else if (seg->segtype->ops->target_unmonitor_events) monitor_fn = seg->segtype->ops->target_unmonitor_events; } /* Do [un]monitor */ if (!monitor_fn) continue; log_verbose("%sonitoring %s/%s%s", monitor ? "M" : "Not m", lv->vg->name, lv->name, test_mode() ? " [Test mode: skipping this]" : ""); /* FIXME Test mode should really continue a bit further. */ if (test_mode()) continue; /* FIXME specify events */ if (!monitor_fn(seg, 0)) { log_error("%s/%s: %s segment monitoring function failed.", lv->vg->name, lv->name, seg->segtype->name); return 0; } /* Check [un]monitor results */ /* Try a couple times if pending, but not forever... */ for (i = 0; i < 10; i++) { pending = 0; monitored = seg->segtype->ops->target_monitored(seg, &pending); if (pending || (!monitored && monitor) || (monitored && !monitor)) log_very_verbose("%s/%s %smonitoring still pending: waiting...", lv->vg->name, lv->name, monitor ? "" : "un"); else break; sleep(1); } if (r) r = (monitored && monitor) || (!monitored && !monitor); } if (!r && !error_message_produced()) log_error("%sonitoring %s/%s failed.", monitor ? "M" : "Not m", lv->vg->name, lv->name); return r; #else return 1; #endif } struct detached_lv_data { struct logical_volume *lv_pre; struct lv_activate_opts *laopts; int *flush_required; }; static int _preload_detached_lv(struct cmd_context *cmd, struct logical_volume *lv, void *data) { struct detached_lv_data *detached = data; struct lv_list *lvl_pre; if ((lvl_pre = find_lv_in_vg(detached->lv_pre->vg, lv->name))) { if (lv_is_visible(lvl_pre->lv) && lv_is_active(lv) && (!lv_is_cow(lv) || !lv_is_cow(lvl_pre->lv)) && !_lv_preload(lvl_pre->lv, detached->laopts, detached->flush_required)) return_0; } return 1; } static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s, struct lv_activate_opts *laopts, int error_if_not_suspended) { struct logical_volume *lv = NULL, *lv_pre = NULL, *pvmove_lv = NULL; struct lv_list *lvl_pre; struct seg_list *sl; struct lv_segment *snap_seg; struct lvinfo info; int r = 0, lockfs = 0, flush_required = 0; struct detached_lv_data detached; if (!activation()) return 1; if (!(lv = lv_from_lvid(cmd, lvid_s, 0))) goto_out; /* Use precommitted metadata if present */ if (!(lv_pre = lv_from_lvid(cmd, lvid_s, 1))) goto_out; /* Ignore origin_only unless LV is origin in both old and new metadata */ if (!lv_is_thin_volume(lv) && !(lv_is_origin(lv) && lv_is_origin(lv_pre))) laopts->origin_only = 0; if (test_mode()) { _skip("Suspending %s%s.", lv->name, laopts->origin_only ? " origin without snapshots" : ""); r = 1; goto out; } if (!lv_info(cmd, lv, laopts->origin_only, &info, 0, 0)) goto_out; if (!info.exists || info.suspended) { if (!error_if_not_suspended) { r = 1; if (info.suspended) critical_section_inc(cmd, "already suspended"); } goto out; } if (!lv_read_replicator_vgs(lv)) goto_out; lv_calculate_readahead(lv, NULL); /* * Preload devices for the LV. * If the PVMOVE LV is being removed, it's only present in the old * metadata and not the new, so we must explicitly add the new * tables for all the changed LVs here, as the relationships * are not found by walking the new metadata. */ if (!(lv_pre->status & LOCKED) && (lv->status & LOCKED) && (pvmove_lv = find_pvmove_lv_in_lv(lv))) { /* Preload all the LVs above the PVMOVE LV */ dm_list_iterate_items(sl, &pvmove_lv->segs_using_this_lv) { if (!(lvl_pre = find_lv_in_vg(lv_pre->vg, sl->seg->lv->name))) { log_error(INTERNAL_ERROR "LV %s missing from preload metadata", sl->seg->lv->name); goto out; } if (!_lv_preload(lvl_pre->lv, laopts, &flush_required)) goto_out; } /* Now preload the PVMOVE LV itself */ if (!(lvl_pre = find_lv_in_vg(lv_pre->vg, pvmove_lv->name))) { log_error(INTERNAL_ERROR "LV %s missing from preload metadata", pvmove_lv->name); goto out; } if (!_lv_preload(lvl_pre->lv, laopts, &flush_required)) goto_out; } else { if (!_lv_preload(lv_pre, laopts, &flush_required)) /* FIXME Revert preloading */ goto_out; /* * Search for existing LVs that have become detached and preload them. */ detached.lv_pre = lv_pre; detached.laopts = laopts; detached.flush_required = &flush_required; if (!for_each_sub_lv(cmd, lv, &_preload_detached_lv, &detached)) goto_out; /* * Preload any snapshots that are being removed. */ if (!laopts->origin_only && lv_is_origin(lv)) { dm_list_iterate_items_gen(snap_seg, &lv->snapshot_segs, origin_list) { if (!(lvl_pre = find_lv_in_vg_by_lvid(lv_pre->vg, &snap_seg->cow->lvid))) { log_error(INTERNAL_ERROR "LV %s (%s) missing from preload metadata", snap_seg->cow->name, snap_seg->cow->lvid.id[1].uuid); goto out; } if (!lv_is_cow(lvl_pre->lv) && !_lv_preload(lvl_pre->lv, laopts, &flush_required)) goto_out; } } } if (!monitor_dev_for_events(cmd, lv, laopts, 0)) /* FIXME Consider aborting here */ stack; critical_section_inc(cmd, "suspending"); if (pvmove_lv) critical_section_inc(cmd, "suspending pvmove LV"); if (!laopts->origin_only && (lv_is_origin(lv_pre) || lv_is_cow(lv_pre))) lockfs = 1; if (laopts->origin_only && lv_is_thin_volume(lv) && lv_is_thin_volume(lv_pre)) lockfs = 1; /* * Suspending an LV directly above a PVMOVE LV also * suspends other LVs using that same PVMOVE LV. * FIXME Remove this and delay the 'clear node' until * after the code knows whether there's a different * inactive table to load or not instead so lv_suspend * can be called separately for each LV safely. */ if ((lv_pre->vg->status & PRECOMMITTED) && (lv_pre->status & LOCKED) && find_pvmove_lv_in_lv(lv_pre)) { if (!_lv_suspend_lv(lv_pre, laopts, lockfs, flush_required)) { critical_section_dec(cmd, "failed precommitted suspend"); if (pvmove_lv) critical_section_dec(cmd, "failed precommitted suspend (pvmove)"); goto_out; } } else { /* Normal suspend */ if (!_lv_suspend_lv(lv, laopts, lockfs, flush_required)) { critical_section_dec(cmd, "failed suspend"); if (pvmove_lv) critical_section_dec(cmd, "failed suspend (pvmove)"); goto_out; } } r = 1; out: if (lv_pre) release_vg(lv_pre->vg); if (lv) { lv_release_replicator_vgs(lv); release_vg(lv->vg); } return r; } /* * In a cluster, set exclusive to indicate that only one node is using the * device. Any preloaded tables may then use non-clustered targets. * * Returns success if the device is not active */ int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s, unsigned origin_only, unsigned exclusive) { struct lv_activate_opts laopts = { .origin_only = origin_only, .exclusive = exclusive }; return _lv_suspend(cmd, lvid_s, &laopts, 0); } /* No longer used */ /*********** int lv_suspend(struct cmd_context *cmd, const char *lvid_s) { return _lv_suspend(cmd, lvid_s, 1); } ***********/ static int _lv_resume(struct cmd_context *cmd, const char *lvid_s, struct lv_activate_opts *laopts, int error_if_not_active) { struct logical_volume *lv; struct lvinfo info; int r = 0; int messages_only = 0; if (!activation()) return 1; if (!(lv = lv_from_lvid(cmd, lvid_s, 0))) goto_out; if (lv_is_thin_pool(lv) && laopts->origin_only) messages_only = 1; if (!lv_is_origin(lv) && !lv_is_thin_volume(lv)) laopts->origin_only = 0; if (test_mode()) { _skip("Resuming %s%s%s.", lv->name, laopts->origin_only ? " without snapshots" : "", laopts->revert ? " (reverting)" : ""); r = 1; goto out; } log_debug("Resuming LV %s/%s%s%s%s.", lv->vg->name, lv->name, error_if_not_active ? "" : " if active", laopts->origin_only ? " without snapshots" : "", laopts->revert ? " (reverting)" : ""); if (!lv_info(cmd, lv, laopts->origin_only, &info, 0, 0)) goto_out; if (!info.exists || !(info.suspended || messages_only)) { if (error_if_not_active) goto_out; r = 1; if (!info.suspended) critical_section_dec(cmd, "already resumed"); goto out; } laopts->read_only = _passes_readonly_filter(cmd, lv); if (!_lv_activate_lv(lv, laopts)) goto_out; critical_section_dec(cmd, "resumed"); if (!monitor_dev_for_events(cmd, lv, laopts, 1)) stack; r = 1; out: if (lv) release_vg(lv->vg); return r; } /* * In a cluster, set exclusive to indicate that only one node is using the * device. Any tables loaded may then use non-clustered targets. * * @origin_only * @exclusive This parameter only has an affect in cluster-context. * It forces local target type to be used (instead of * cluster-aware type). * Returns success if the device is not active */ int lv_resume_if_active(struct cmd_context *cmd, const char *lvid_s, unsigned origin_only, unsigned exclusive, unsigned revert) { struct lv_activate_opts laopts = { .origin_only = origin_only, .exclusive = exclusive, .revert = revert }; return _lv_resume(cmd, lvid_s, &laopts, 0); } int lv_resume(struct cmd_context *cmd, const char *lvid_s, unsigned origin_only) { struct lv_activate_opts laopts = { .origin_only = origin_only, }; return _lv_resume(cmd, lvid_s, &laopts, 1); } static int _lv_has_open_snapshots(struct logical_volume *lv) { struct lv_segment *snap_seg; struct lvinfo info; int r = 0; dm_list_iterate_items_gen(snap_seg, &lv->snapshot_segs, origin_list) { if (!lv_info(lv->vg->cmd, snap_seg->cow, 0, &info, 1, 0)) { r = 1; continue; } if (info.exists && info.open_count) { log_error("LV %s/%s has open snapshot %s: " "not deactivating", lv->vg->name, lv->name, snap_seg->cow->name); r = 1; } } return r; } int lv_deactivate(struct cmd_context *cmd, const char *lvid_s) { struct logical_volume *lv; struct lvinfo info; int r = 0; if (!activation()) return 1; if (!(lv = lv_from_lvid(cmd, lvid_s, 0))) goto out; if (test_mode()) { _skip("Deactivating '%s'.", lv->name); r = 1; goto out; } log_debug("Deactivating %s/%s.", lv->vg->name, lv->name); if (!lv_info(cmd, lv, 0, &info, 1, 0)) goto_out; if (!info.exists) { r = 1; goto out; } if (lv_is_visible(lv)) { if (!lv_check_not_in_use(cmd, lv, &info)) goto_out; if (lv_is_origin(lv) && _lv_has_open_snapshots(lv)) goto_out; } if (!lv_read_replicator_vgs(lv)) goto_out; lv_calculate_readahead(lv, NULL); if (!monitor_dev_for_events(cmd, lv, NULL, 0)) stack; critical_section_inc(cmd, "deactivating"); r = _lv_deactivate(lv); critical_section_dec(cmd, "deactivated"); if (!lv_info(cmd, lv, 0, &info, 0, 0) || info.exists) r = 0; out: if (lv) { lv_release_replicator_vgs(lv); release_vg(lv->vg); } return r; } /* Test if LV passes filter */ int lv_activation_filter(struct cmd_context *cmd, const char *lvid_s, int *activate_lv) { struct logical_volume *lv; int r = 0; if (!activation()) { *activate_lv = 1; return 1; } if (!(lv = lv_from_lvid(cmd, lvid_s, 0))) goto out; if (!_passes_activation_filter(cmd, lv)) { log_verbose("Not activating %s/%s since it does not pass " "activation filter.", lv->vg->name, lv->name); *activate_lv = 0; } else *activate_lv = 1; r = 1; out: if (lv) release_vg(lv->vg); return r; } static int _lv_activate(struct cmd_context *cmd, const char *lvid_s, struct lv_activate_opts *laopts, int filter) { struct logical_volume *lv; struct lvinfo info; int r = 0; if (!activation()) return 1; if (!(lv = lv_from_lvid(cmd, lvid_s, 0))) goto out; if (filter && !_passes_activation_filter(cmd, lv)) { log_error("Not activating %s/%s since it does not pass " "activation filter.", lv->vg->name, lv->name); goto out; } if ((!lv->vg->cmd->partial_activation) && (lv->status & PARTIAL_LV)) { log_error("Refusing activation of partial LV %s. Use --partial to override.", lv->name); goto_out; } if (lv_has_unknown_segments(lv)) { log_error("Refusing activation of LV %s containing " "an unrecognised segment.", lv->name); goto_out; } if (test_mode()) { _skip("Activating '%s'.", lv->name); r = 1; goto out; } if (filter) laopts->read_only = _passes_readonly_filter(cmd, lv); log_debug("Activating %s/%s%s%s.", lv->vg->name, lv->name, laopts->exclusive ? " exclusively" : "", laopts->read_only ? " read-only" : ""); if (!lv_info(cmd, lv, 0, &info, 0, 0)) goto_out; /* * Nothing to do? */ if (info.exists && !info.suspended && info.live_table && (info.read_only == read_only_lv(lv, laopts))) { r = 1; goto out; } if (!lv_read_replicator_vgs(lv)) goto_out; lv_calculate_readahead(lv, NULL); critical_section_inc(cmd, "activating"); if (!(r = _lv_activate_lv(lv, laopts))) stack; critical_section_dec(cmd, "activated"); if (r && !monitor_dev_for_events(cmd, lv, laopts, 1)) stack; out: if (lv) { lv_release_replicator_vgs(lv); release_vg(lv->vg); } return r; } /* Activate LV */ int lv_activate(struct cmd_context *cmd, const char *lvid_s, int exclusive) { struct lv_activate_opts laopts = { .exclusive = exclusive }; if (!_lv_activate(cmd, lvid_s, &laopts, 0)) return_0; return 1; } /* Activate LV only if it passes filter */ int lv_activate_with_filter(struct cmd_context *cmd, const char *lvid_s, int exclusive) { struct lv_activate_opts laopts = { .exclusive = exclusive }; if (!_lv_activate(cmd, lvid_s, &laopts, 1)) return_0; return 1; } int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv) { int r = 1; if (!lv) { r = dm_mknodes(NULL); fs_unlock(); return r; } if (!activation()) return 1; r = dev_manager_mknodes(lv); fs_unlock(); return r; } /* * Does PV use VG somewhere in its construction? * Returns 1 on failure. */ int pv_uses_vg(struct physical_volume *pv, struct volume_group *vg) { if (!activation() || !pv->dev) return 0; if (!dm_is_dm_major(MAJOR(pv->dev->dev))) return 0; return dev_manager_device_uses_vg(pv->dev, vg); } void activation_release(void) { dev_manager_release(); } void activation_exit(void) { dev_manager_exit(); } #endif lvm2-2.02.98/lib/activate/activate.h0000640000175000017500000001370612037016272016036 0ustar blankblank/* * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU 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; }; struct lv_activate_opts { int exclusive; int origin_only; int no_merging; int real_pool; int is_activate; int skip_in_use; unsigned revert; unsigned read_only; }; /* target attribute flags */ #define MIRROR_LOG_CLUSTERED 0x00000001U /* thin target attribute flags */ enum { /* bitfields - new features from 1.1 version */ THIN_FEATURE_DISCARDS = (1 << 0), THIN_FEATURE_EXTERNAL_ORIGIN = (1 << 1), THIN_FEATURE_HELD_ROOT = (1 << 2), THIN_FEATURE_BLOCK_SIZE = (1 << 3), }; 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 lvm_dm_prefix_check(int major, int minor, const char *prefix); 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, unsigned exclusive); 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, unsigned exclusive, unsigned revert); 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, int use_layer, struct lvinfo *info, int with_open_count, int with_read_ahead); int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s, int use_layer, struct lvinfo *info, int with_open_count, int with_read_ahead); int lv_check_not_in_use(struct cmd_context *cmd, struct logical_volume *lv, struct lvinfo *info); /* * 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); /* * Checks against the auto_activation_volume_list and * returns 1 if the LV should be activated, 0 otherwise. */ int lv_passes_auto_activation_filter(struct cmd_context *cmd, struct logical_volume *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, const struct logical_volume *lv, int wait, percent_t *percent, uint32_t *event_nr); int lv_raid_percent(const struct logical_volume *lv, percent_t *percent); int lv_thin_pool_percent(const struct logical_volume *lv, int metadata, percent_t *percent); int lv_thin_percent(const struct logical_volume *lv, int mapped, percent_t *percent); int lv_thin_pool_transaction_id(const struct logical_volume *lv, uint64_t *transaction_id); /* * Return number of LVs in the VG that are active. */ int lvs_in_vg_activated(const struct volume_group *vg); int lvs_in_vg_opened(const struct volume_group *vg); int lv_is_active(const struct logical_volume *lv); int lv_is_active_but_not_locally(const struct logical_volume *lv); int lv_is_active_exclusive(const struct logical_volume *lv); int lv_is_active_exclusive_locally(const struct logical_volume *lv); int lv_is_active_exclusive_remotely(const 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, const struct lv_activate_opts *laopts, 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 int add_linear_area_to_dtree(struct dm_tree_node *node, uint64_t size, uint32_t extent_size, int use_linear_target, const char *vgname, const char *lvname); /* * 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 lvm2-2.02.98/lib/activate/dev_manager.h0000640000175000017500000000613112037016272016500 0ustar blankblank/* * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved. * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU 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 lv_activate_opts; struct volume_group; struct cmd_context; struct dev_manager; struct dm_info; struct device; int read_only_lv(struct logical_volume *lv, struct lv_activate_opts *laopts); /* * Constructor and destructor. */ struct dev_manager *dev_manager_create(struct cmd_context *cmd, const char *vg_name, unsigned track_pvmove_deps); 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_thin_pool_status(struct dev_manager *dm, const struct logical_volume *lv, struct dm_status_thin_pool **status); int dev_manager_thin_pool_percent(struct dev_manager *dm, const struct logical_volume *lv, int metadata, percent_t *percent); int dev_manager_thin_percent(struct dev_manager *dm, const struct logical_volume *lv, int mapped, percent_t *percent); int dev_manager_suspend(struct dev_manager *dm, struct logical_volume *lv, struct lv_activate_opts *laopts, int lockfs, int flush_required); int dev_manager_activate(struct dev_manager *dm, struct logical_volume *lv, struct lv_activate_opts *laopts); int dev_manager_preload(struct dev_manager *dm, struct logical_volume *lv, struct lv_activate_opts *laopts, 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 lvm2-2.02.98/lib/activate/dev_manager.c0000640000175000017500000017143112037016272016501 0ustar blankblank/* * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved. * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU 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 "dev_manager.h" #include "lvm-string.h" #include "fs.h" #include "defaults.h" #include "segtype.h" #include "display.h" #include "toolcontext.h" #include "targets.h" #include "config.h" #include "filter.h" #include "activate.h" #include "lvm-exec.h" #include #include #define MAX_TARGET_PARAMSIZE 50000 typedef enum { PRELOAD, ACTIVATE, DEACTIVATE, SUSPEND, SUSPEND_WITH_LOCKFS, CLEAN } action_t; struct dev_manager { struct dm_pool *mem; struct cmd_context *cmd; void *target_state; uint32_t pvmove_mirror_count; int flush_required; unsigned track_pvmove_deps; char *vg_name; }; struct lv_layer { struct logical_volume *lv; const char *old_name; }; static const char _thin_layer[] = "tpool"; int read_only_lv(struct logical_volume *lv, struct lv_activate_opts *laopts) { return (laopts->read_only || !(lv->vg->status & LVM_WRITE) || !(lv->status & LVM_WRITE)); } /* * Low level device-layer operations. */ static struct dm_task *_setup_task(const char *name, const char *uuid, uint32_t *event_nr, int task, uint32_t major, uint32_t minor) { struct dm_task *dmt; if (!(dmt = dm_task_create(task))) return_NULL; if (name && !dm_task_set_name(dmt, name)) goto_out; if (uuid && *uuid && !dm_task_set_uuid(dmt, uuid)) goto_out; if (event_nr && !dm_task_set_event_nr(dmt, *event_nr)) goto_out; if (major && !dm_task_set_major_minor(dmt, major, minor, 1)) goto_out; if (activation_checks() && !dm_task_enable_checks(dmt)) goto_out; return dmt; out: dm_task_destroy(dmt); return NULL; } static int _info_run(const char *name, const char *dlid, struct dm_info *info, uint32_t *read_ahead, int mknodes, int with_open_count, int with_read_ahead, uint32_t major, uint32_t minor) { int r = 0; struct dm_task *dmt; int dmtask; dmtask = mknodes ? DM_DEVICE_MKNODES : DM_DEVICE_INFO; if (!(dmt = _setup_task(mknodes ? name : NULL, dlid, 0, dmtask, major, minor))) return_0; if (!with_open_count) if (!dm_task_no_open_count(dmt)) log_error("Failed to disable open_count"); if (!dm_task_run(dmt)) goto_out; if (!dm_task_get_info(dmt, info)) goto_out; if (with_read_ahead && info->exists) { if (!dm_task_get_read_ahead(dmt, read_ahead)) goto_out; } else if (read_ahead) *read_ahead = DM_READ_AHEAD_NONE; r = 1; out: dm_task_destroy(dmt); return r; } int device_is_usable(struct device *dev) { struct dm_task *dmt; struct dm_info info; const char *name, *uuid; uint64_t start, length; char *target_type = NULL; char *params, *vgname = NULL, *lvname, *layer; void *next = NULL; int only_error_target = 1; int r = 0; if (!(dmt = dm_task_create(DM_DEVICE_STATUS))) return_0; if (!dm_task_set_major_minor(dmt, MAJOR(dev->dev), MINOR(dev->dev), 1)) goto_out; if (activation_checks() && !dm_task_enable_checks(dmt)) goto_out; if (!dm_task_run(dmt)) { log_error("Failed to get state of mapped device"); goto out; } if (!dm_task_get_info(dmt, &info)) goto_out; if (!info.exists) goto out; name = dm_task_get_name(dmt); uuid = dm_task_get_uuid(dmt); if (!info.target_count) { log_debug("%s: Empty device %s not usable.", dev_name(dev), name); goto out; } if (info.suspended && ignore_suspended_devices()) { log_debug("%s: Suspended device %s not usable.", dev_name(dev), name); goto out; } /* FIXME Also check for mirror block_on_error and mpath no paths */ /* For now, we exclude all mirrors */ do { next = dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms); /* Skip if target type doesn't match */ if (target_type && !strcmp(target_type, "mirror") && ignore_suspended_devices()) { log_debug("%s: Mirror device %s not usable.", dev_name(dev), name); goto out; } /* * Snapshot origin could be sitting on top of a mirror which * could be blocking I/O. Skip snapshot origins entirely for * now. * * FIXME: rather than skipping origin, check if mirror is * underneath and if the mirror is blocking I/O. */ if (target_type && !strcmp(target_type, "snapshot-origin") && ignore_suspended_devices()) { log_debug("%s: Snapshot-origin device %s not usable.", dev_name(dev), name); goto out; } if (target_type && strcmp(target_type, "error")) only_error_target = 0; } while (next); /* Skip devices consisting entirely of error targets. */ /* FIXME Deal with device stacked above error targets? */ if (only_error_target) { log_debug("%s: Error device %s not usable.", dev_name(dev), name); goto out; } /* FIXME Also check dependencies? */ /* Check internal lvm devices */ if (uuid && !strncmp(uuid, UUID_PREFIX, sizeof(UUID_PREFIX) - 1)) { if (!(vgname = dm_strdup(name)) || !dm_split_lvm_name(NULL, NULL, &vgname, &lvname, &layer)) goto_out; if (lvname && (is_reserved_lvname(lvname) || *layer)) { log_debug("%s: Reserved internal LV device %s/%s%s%s not usable.", dev_name(dev), vgname, lvname, *layer ? "-" : "", layer); goto out; } } r = 1; out: dm_free(vgname); dm_task_destroy(dmt); return r; } static int _info(const char *dlid, int with_open_count, int with_read_ahead, struct dm_info *info, uint32_t *read_ahead) { int r = 0; if ((r = _info_run(NULL, dlid, info, read_ahead, 0, with_open_count, with_read_ahead, 0, 0)) && info->exists) return 1; else if ((r = _info_run(NULL, dlid + sizeof(UUID_PREFIX) - 1, info, read_ahead, 0, with_open_count, with_read_ahead, 0, 0)) && info->exists) return 1; return r; } static int _info_by_dev(uint32_t major, uint32_t minor, struct dm_info *info) { return _info_run(NULL, NULL, info, NULL, 0, 0, 0, major, minor); } 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) { char *dlid, *name; int r; if (!(name = dm_build_dm_name(mem, lv->vg->name, lv->name, layer))) { log_error("name build failed for %s", lv->name); return 0; } if (!(dlid = build_dm_uuid(mem, lv->lvid.s, layer))) { log_error("dlid build failed for %s", name); return 0; } log_debug("Getting device info for %s [%s]", name, dlid); r = _info(dlid, with_open_count, with_read_ahead, info, read_ahead); dm_pool_free(mem, name); return r; } static const struct dm_info *_cached_info(struct dm_pool *mem, const struct logical_volume *lv, struct dm_tree *dtree) { const char *dlid; struct dm_tree_node *dnode; const struct dm_info *dinfo; if (!(dlid = build_dm_uuid(mem, lv->lvid.s, NULL))) { log_error("dlid build failed for %s", lv->name); return NULL; } /* An activating merging origin won't have a node in the tree yet */ if (!(dnode = dm_tree_find_node_by_uuid(dtree, dlid))) return NULL; if (!(dinfo = dm_tree_node_get_info(dnode))) { log_error("failed to get info from tree node for %s", lv->name); return NULL; } if (!dinfo->exists) return NULL; return dinfo; } #if 0 /* FIXME Interface must cope with multiple targets */ static int _status_run(const char *name, const char *uuid, unsigned long long *s, unsigned long long *l, char **t, uint32_t t_size, char **p, uint32_t p_size) { int r = 0; struct dm_task *dmt; struct dm_info info; void *next = NULL; uint64_t start, length; char *type = NULL; char *params = NULL; if (!(dmt = _setup_task(name, uuid, 0, DM_DEVICE_STATUS, 0, 0))) return_0; if (!dm_task_no_open_count(dmt)) log_error("Failed to disable open_count"); if (!dm_task_run(dmt)) goto_out; if (!dm_task_get_info(dmt, &info) || !info.exists) goto_out; do { next = dm_get_next_target(dmt, next, &start, &length, &type, ¶ms); if (type) { *s = start; *l = length; /* Make sure things are null terminated */ strncpy(*t, type, t_size); (*t)[t_size - 1] = '\0'; strncpy(*p, params, p_size); (*p)[p_size - 1] = '\0'; r = 1; /* FIXME Cope with multiple targets! */ break; } } while (next); out: dm_task_destroy(dmt); return r; } static int _status(const char *name, const char *uuid, unsigned long long *start, unsigned long long *length, char **type, uint32_t type_size, char **params, uint32_t param_size) __attribute__ ((unused)); static int _status(const char *name, const char *uuid, unsigned long long *start, unsigned long long *length, char **type, uint32_t type_size, char **params, uint32_t param_size) { if (uuid && *uuid) { if (_status_run(NULL, uuid, start, length, type, type_size, params, param_size) && *params) return 1; else if (_status_run(NULL, uuid + sizeof(UUID_PREFIX) - 1, start, length, type, type_size, params, param_size) && *params) return 1; } if (name && _status_run(name, NULL, start, length, type, type_size, params, param_size)) return 1; return 0; } #endif int lv_has_target_type(struct dm_pool *mem, struct logical_volume *lv, const char *layer, const char *target_type) { int r = 0; char *dlid; struct dm_task *dmt; struct dm_info info; void *next = NULL; uint64_t start, length; char *type = NULL; char *params = NULL; if (!(dlid = build_dm_uuid(mem, lv->lvid.s, layer))) return_0; if (!(dmt = _setup_task(NULL, dlid, 0, DM_DEVICE_STATUS, 0, 0))) goto_bad; if (!dm_task_no_open_count(dmt)) log_error("Failed to disable open_count"); if (!dm_task_run(dmt)) goto_out; if (!dm_task_get_info(dmt, &info) || !info.exists) goto_out; do { next = dm_get_next_target(dmt, next, &start, &length, &type, ¶ms); if (type && strncmp(type, target_type, strlen(target_type)) == 0) { if (info.live_table) r = 1; break; } } while (next); out: dm_task_destroy(dmt); bad: dm_pool_free(mem, dlid); return r; } int add_linear_area_to_dtree(struct dm_tree_node *node, uint64_t size, uint32_t extent_size, int use_linear_target, const char *vgname, const char *lvname) { uint32_t page_size; /* * Use striped or linear target? */ if (!use_linear_target) { page_size = lvm_getpagesize() >> SECTOR_SHIFT; /* * We'll use the extent size as the stripe size. * Extent size and page size are always powers of 2. * The striped target requires that the stripe size is * divisible by the page size. */ if (extent_size >= page_size) { /* Use striped target */ if (!dm_tree_node_add_striped_target(node, size, extent_size)) return_0; return 1; } else /* Some exotic cases are unsupported by striped. */ log_warn("WARNING: Using linear target for %s/%s: Striped requires extent size (%" PRIu32 " sectors) >= page size (%" PRIu32 ").", vgname, lvname, extent_size, page_size); } /* * Use linear target. */ if (!dm_tree_node_add_linear_target(node, size)) return_0; return 1; } static percent_range_t _combine_percent(percent_t a, percent_t b, uint32_t numerator, uint32_t denominator) { if (a == PERCENT_MERGE_FAILED || b == PERCENT_MERGE_FAILED) return PERCENT_MERGE_FAILED; if (a == PERCENT_INVALID || b == PERCENT_INVALID) return PERCENT_INVALID; if (a == PERCENT_100 && b == PERCENT_100) return PERCENT_100; if (a == PERCENT_0 && b == PERCENT_0) return PERCENT_0; return (percent_range_t) make_percent(numerator, denominator); } static int _percent_run(struct dev_manager *dm, const char *name, const char *dlid, const char *target_type, int wait, const struct logical_volume *lv, percent_t *overall_percent, uint32_t *event_nr, int fail_if_percent_unsupported) { int r = 0; struct dm_task *dmt; struct dm_info info; void *next = NULL; uint64_t start, length; char *type = NULL; char *params = NULL; const struct dm_list *segh = lv ? &lv->segments : NULL; struct lv_segment *seg = NULL; struct segment_type *segtype; int first_time = 1; percent_t percent = PERCENT_INVALID; uint64_t total_numerator = 0, total_denominator = 0; *overall_percent = percent; if (!(dmt = _setup_task(name, dlid, event_nr, wait ? DM_DEVICE_WAITEVENT : DM_DEVICE_STATUS, 0, 0))) return_0; if (!dm_task_no_open_count(dmt)) log_error("Failed to disable open_count"); if (!dm_task_run(dmt)) goto_out; if (!dm_task_get_info(dmt, &info) || !info.exists) goto_out; if (event_nr) *event_nr = info.event_nr; do { next = dm_get_next_target(dmt, next, &start, &length, &type, ¶ms); if (lv) { if (!(segh = dm_list_next(&lv->segments, segh))) { log_error("Number of segments in active LV %s " "does not match metadata", lv->name); goto out; } seg = dm_list_item(segh, struct lv_segment); } if (!type || !params) continue; if (!(segtype = get_segtype_from_string(dm->cmd, target_type))) continue; if (strcmp(type, target_type)) { /* If kernel's type isn't an exact match is it compatible? */ if (!segtype->ops->target_status_compatible || !segtype->ops->target_status_compatible(type)) continue; } if (!segtype->ops->target_percent) continue; if (!segtype->ops->target_percent(&dm->target_state, &percent, dm->mem, dm->cmd, seg, params, &total_numerator, &total_denominator)) goto_out; if (first_time) { *overall_percent = percent; first_time = 0; } else *overall_percent = _combine_percent(*overall_percent, percent, total_numerator, total_denominator); } while (next); if (lv && dm_list_next(&lv->segments, segh)) { log_error("Number of segments in active LV %s does not " "match metadata", lv->name); goto out; } if (first_time) { /* above ->target_percent() was not executed! */ /* FIXME why return PERCENT_100 et. al. in this case? */ *overall_percent = PERCENT_100; if (fail_if_percent_unsupported) goto_out; } log_debug("LV percent: %f", percent_to_float(*overall_percent)); r = 1; out: dm_task_destroy(dmt); return r; } static int _percent(struct dev_manager *dm, const char *name, const char *dlid, const char *target_type, int wait, const struct logical_volume *lv, percent_t *percent, uint32_t *event_nr, int fail_if_percent_unsupported) { if (dlid && *dlid) { if (_percent_run(dm, NULL, dlid, target_type, wait, lv, percent, event_nr, fail_if_percent_unsupported)) return 1; else if (_percent_run(dm, NULL, dlid + sizeof(UUID_PREFIX) - 1, target_type, wait, lv, percent, event_nr, fail_if_percent_unsupported)) return 1; } if (name && _percent_run(dm, name, NULL, target_type, wait, lv, percent, event_nr, fail_if_percent_unsupported)) return 1; return 0; } /* FIXME Merge with the percent function */ int dev_manager_transient(struct dev_manager *dm, struct logical_volume *lv) { int r = 0; struct dm_task *dmt; struct dm_info info; void *next = NULL; uint64_t start, length; char *type = NULL; char *params = NULL; char *dlid = NULL; const char *layer = lv_is_origin(lv) ? "real" : NULL; const struct dm_list *segh = &lv->segments; struct lv_segment *seg = NULL; if (!(dlid = build_dm_uuid(dm->mem, lv->lvid.s, layer))) return_0; if (!(dmt = _setup_task(0, dlid, NULL, DM_DEVICE_STATUS, 0, 0))) return_0; if (!dm_task_no_open_count(dmt)) log_error("Failed to disable open_count"); if (!dm_task_run(dmt)) goto_out; if (!dm_task_get_info(dmt, &info) || !info.exists) goto_out; do { next = dm_get_next_target(dmt, next, &start, &length, &type, ¶ms); if (!(segh = dm_list_next(&lv->segments, segh))) { log_error("Number of segments in active LV %s " "does not match metadata", lv->name); goto out; } seg = dm_list_item(segh, struct lv_segment); if (!type || !params) continue; if (!seg) { log_error(INTERNAL_ERROR "Segment is not selected."); goto out; } if (seg->segtype->ops->check_transient_status && !seg->segtype->ops->check_transient_status(seg, params)) goto_out; } while (next); if (dm_list_next(&lv->segments, segh)) { log_error("Number of segments in active LV %s does not " "match metadata", lv->name); goto out; } r = 1; out: dm_task_destroy(dmt); return r; } /* * dev_manager implementation. */ struct dev_manager *dev_manager_create(struct cmd_context *cmd, const char *vg_name, unsigned track_pvmove_deps) { struct dm_pool *mem; struct dev_manager *dm; if (!(mem = dm_pool_create("dev_manager", 16 * 1024))) return_NULL; if (!(dm = dm_pool_zalloc(mem, sizeof(*dm)))) goto_bad; dm->cmd = cmd; dm->mem = mem; if (!(dm->vg_name = dm_pool_strdup(dm->mem, vg_name))) goto_bad; /* * When we manipulate (normally suspend/resume) the PVMOVE * device directly, there's no need to touch the LVs above. */ dm->track_pvmove_deps = track_pvmove_deps; dm->target_state = NULL; dm_udev_set_sync_support(cmd->current_settings.udev_sync); return dm; bad: dm_pool_destroy(mem); return NULL; } void dev_manager_destroy(struct dev_manager *dm) { dm_pool_destroy(dm->mem); } void dev_manager_release(void) { dm_lib_release(); } void dev_manager_exit(void) { dm_lib_exit(); } int dev_manager_snapshot_percent(struct dev_manager *dm, const struct logical_volume *lv, percent_t *percent) { const struct logical_volume *snap_lv; char *name; const char *dlid; int fail_if_percent_unsupported = 0; if (lv_is_merging_origin(lv)) { /* * Set 'fail_if_percent_unsupported', otherwise passing * unsupported LV types to _percent will lead to a default * successful return with percent_range as PERCENT_100. * - For a merging origin, this will result in a polldaemon * that runs infinitely (because completion is PERCENT_0) * - We unfortunately don't yet _know_ if a snapshot-merge * target is active (activation is deferred if dev is open); * so we can't short-circuit origin devices based purely on * existing LVM LV attributes. */ fail_if_percent_unsupported = 1; } if (lv_is_merging_cow(lv)) { /* must check percent of origin for a merging snapshot */ snap_lv = origin_from_cow(lv); } else snap_lv = lv; /* * Build a name for the top layer. */ if (!(name = dm_build_dm_name(dm->mem, snap_lv->vg->name, snap_lv->name, NULL))) return_0; if (!(dlid = build_dm_uuid(dm->mem, snap_lv->lvid.s, NULL))) return_0; /* * Try and get some info on this device. */ log_debug("Getting device status percentage for %s", name); if (!(_percent(dm, name, dlid, "snapshot", 0, NULL, percent, NULL, fail_if_percent_unsupported))) return_0; /* If the snapshot isn't available, percent will be -1 */ return 1; } /* FIXME Merge with snapshot_percent, auto-detecting target type */ /* FIXME Cope with more than one target */ int dev_manager_mirror_percent(struct dev_manager *dm, const struct logical_volume *lv, int wait, percent_t *percent, uint32_t *event_nr) { char *name; const char *dlid; const char *target_type = first_seg(lv)->segtype->name; const char *layer = (lv_is_origin(lv)) ? "real" : NULL; /* * Build a name for the top layer. */ if (!(name = dm_build_dm_name(dm->mem, lv->vg->name, lv->name, layer))) return_0; if (!(dlid = build_dm_uuid(dm->mem, lv->lvid.s, layer))) { log_error("dlid build failed for %s", lv->name); return 0; } log_debug("Getting device %s status percentage for %s", target_type, name); if (!(_percent(dm, name, dlid, target_type, wait, lv, percent, event_nr, 0))) return_0; return 1; } #if 0 log_very_verbose("%s %s", sus ? "Suspending" : "Resuming", name); log_verbose("Loading %s", dl->name); log_very_verbose("Activating %s read-only", dl->name); log_very_verbose("Activated %s %s %03u:%03u", dl->name, dl->dlid, dl->info.major, dl->info.minor); if (_get_flag(dl, VISIBLE)) log_verbose("Removing %s", dl->name); else log_very_verbose("Removing %s", dl->name); log_debug("Adding target: %" PRIu64 " %" PRIu64 " %s %s", extent_size * seg->le, extent_size * seg->len, target, params); log_debug("Adding target: 0 %" PRIu64 " snapshot-origin %s", dl->lv->size, params); log_debug("Adding target: 0 %" PRIu64 " snapshot %s", size, params); log_debug("Getting device info for %s", dl->name); /* Rename? */ if ((suffix = strrchr(dl->dlid + sizeof(UUID_PREFIX) - 1, '-'))) suffix++; new_name = dm_build_dm_name(dm->mem, dm->vg_name, dl->lv->name, suffix); static int _belong_to_vg(const char *vgname, const char *name) { const char *v = vgname, *n = name; while (*v) { if ((*v != *n) || (*v == '-' && *(++n) != '-')) return 0; v++, n++; } if (*n == '-' && *(n + 1) != '-') return 1; else return 0; } if (!(snap_seg = find_cow(lv))) return 1; old_origin = snap_seg->origin; /* Was this the last active snapshot with this origin? */ dm_list_iterate_items(lvl, active_head) { active = lvl->lv; if ((snap_seg = find_cow(active)) && snap_seg->origin == old_origin) { return 1; } } #endif int dev_manager_thin_pool_status(struct dev_manager *dm, const struct logical_volume *lv, struct dm_status_thin_pool **status) { const char *dlid; struct dm_task *dmt; struct dm_info info; uint64_t start, length; char *type = NULL; char *params = NULL; int r = 0; /* Build dlid for the thin pool layer */ if (!(dlid = build_dm_uuid(dm->mem, lv->lvid.s, _thin_layer))) return_0; log_debug("Getting thin pool device status for %s.", lv->name); if (!(dmt = _setup_task(NULL, dlid, 0, DM_DEVICE_STATUS, 0, 0))) return_0; if (!dm_task_no_open_count(dmt)) log_error("Failed to disable open_count."); if (!dm_task_run(dmt)) goto_out; if (!dm_task_get_info(dmt, &info) || !info.exists) goto_out; dm_get_next_target(dmt, NULL, &start, &length, &type, ¶ms); if (!dm_get_status_thin_pool(dm->mem, params, status)) goto_out; r = 1; out: dm_task_destroy(dmt); return r; } int dev_manager_thin_pool_percent(struct dev_manager *dm, const struct logical_volume *lv, int metadata, percent_t *percent) { char *name; const char *dlid; /* Build a name for the top layer */ if (!(name = dm_build_dm_name(dm->mem, lv->vg->name, lv->name, _thin_layer))) return_0; if (!(dlid = build_dm_uuid(dm->mem, lv->lvid.s, _thin_layer))) return_0; log_debug("Getting device status percentage for %s", name); if (!(_percent(dm, name, dlid, "thin-pool", 0, (metadata) ? lv : NULL, percent, NULL, 1))) return_0; return 1; } int dev_manager_thin_percent(struct dev_manager *dm, const struct logical_volume *lv, int mapped, percent_t *percent) { char *name; const char *dlid; const char *layer = lv_is_origin(lv) ? "real" : NULL; /* Build a name for the top layer */ if (!(name = dm_build_dm_name(dm->mem, lv->vg->name, lv->name, layer))) return_0; if (!(dlid = build_dm_uuid(dm->mem, lv->lvid.s, layer))) return_0; log_debug("Getting device status percentage for %s", name); if (!(_percent(dm, name, dlid, "thin", 0, (mapped) ? NULL : lv, percent, NULL, 1))) return_0; return 1; } /*************************/ /* NEW CODE STARTS HERE */ /*************************/ static int _dev_manager_lv_mknodes(const struct logical_volume *lv) { char *name; if (!(name = dm_build_dm_name(lv->vg->cmd->mem, lv->vg->name, lv->name, NULL))) return_0; return fs_add_lv(lv, name); } static int _dev_manager_lv_rmnodes(const struct logical_volume *lv) { return fs_del_lv(lv); } int dev_manager_mknodes(const struct logical_volume *lv) { struct dm_info dminfo; char *name; int r = 0; if (!(name = dm_build_dm_name(lv->vg->cmd->mem, lv->vg->name, lv->name, NULL))) return_0; if ((r = _info_run(name, NULL, &dminfo, NULL, 1, 0, 0, 0, 0))) { if (dminfo.exists) { if (lv_is_visible(lv)) r = _dev_manager_lv_mknodes(lv); } else r = _dev_manager_lv_rmnodes(lv); } dm_pool_free(lv->vg->cmd->mem, name); return r; } static uint16_t _get_udev_flags(struct dev_manager *dm, struct logical_volume *lv, const char *layer) { uint16_t udev_flags = 0; /* * Instruct also libdevmapper to disable udev * fallback in accordance to LVM2 settings. */ if (!dm->cmd->current_settings.udev_fallback) udev_flags |= DM_UDEV_DISABLE_LIBRARY_FALLBACK; /* * Is this top-level and visible device? * If not, create just the /dev/mapper content. */ /* FIXME: add target's method for this */ if (layer || !lv_is_visible(lv) || lv_is_thin_pool(lv)) udev_flags |= DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG | DM_UDEV_DISABLE_DISK_RULES_FLAG | DM_UDEV_DISABLE_OTHER_RULES_FLAG; /* * There's no need for other udev rules to touch special LVs with * reserved names. We don't need to populate /dev/disk here either. * Even if they happen to be visible and top-level. */ else if (is_reserved_lvname(lv->name)) udev_flags |= DM_UDEV_DISABLE_DISK_RULES_FLAG | DM_UDEV_DISABLE_OTHER_RULES_FLAG; /* * Snapshots and origins could have the same rule applied that will * give symlinks exactly the same name (e.g. a name based on * filesystem UUID). We give preference to origins to make such * naming deterministic (e.g. symlinks in /dev/disk/by-uuid). */ if (lv_is_cow(lv)) udev_flags |= DM_UDEV_LOW_PRIORITY_FLAG; /* * Finally, add flags to disable /dev/mapper and /dev/ content * to be created by udev if it is requested by user's configuration. * This is basically an explicit fallback to old node/symlink creation * without udev. */ if (!dm->cmd->current_settings.udev_rules) udev_flags |= DM_UDEV_DISABLE_DM_RULES_FLAG | DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG; return udev_flags; } static int _add_dev_to_dtree(struct dev_manager *dm, struct dm_tree *dtree, struct logical_volume *lv, const char *layer) { char *dlid, *name; struct dm_info info, info2; if (!(name = dm_build_dm_name(dm->mem, lv->vg->name, lv->name, layer))) return_0; if (!(dlid = build_dm_uuid(dm->mem, lv->lvid.s, layer))) return_0; log_debug("Getting device info for %s [%s]", name, dlid); if (!_info(dlid, 1, 0, &info, NULL)) { log_error("Failed to get info for %s [%s].", name, dlid); return 0; } /* * For top level volumes verify that existing device match * requested major/minor and that major/minor pair is available for use */ if (!layer && lv->major != -1 && lv->minor != -1) { /* * FIXME compare info.major with lv->major if multiple major support */ if (info.exists && (info.minor != lv->minor)) { log_error("Volume %s (%" PRIu32 ":%" PRIu32")" " differs from already active device " "(%" PRIu32 ":%" PRIu32")", lv->name, lv->major, lv->minor, info.major, info.minor); return 0; } if (!info.exists && _info_by_dev(lv->major, lv->minor, &info2) && info2.exists) { log_error("The requested major:minor pair " "(%" PRIu32 ":%" PRIu32") is already used", lv->major, lv->minor); return 0; } } if (info.exists && !dm_tree_add_dev_with_udev_flags(dtree, info.major, info.minor, _get_udev_flags(dm, lv, layer))) { log_error("Failed to add device (%" PRIu32 ":%" PRIu32") to dtree", info.major, info.minor); return 0; } return 1; } /* * Add replicator devices * * Using _add_dev_to_dtree() directly instead of _add_lv_to_dtree() * to avoid extra checks with extensions. */ static int _add_partial_replicator_to_dtree(struct dev_manager *dm, struct dm_tree *dtree, struct logical_volume *lv) { struct logical_volume *rlv = first_seg(lv)->replicator; struct replicator_device *rdev; struct replicator_site *rsite; struct dm_tree_node *rep_node, *rdev_node; const char *uuid; if (!lv_is_active_replicator_dev(lv)) { if (!_add_dev_to_dtree(dm, dtree, lv->rdevice->lv, NULL)) return_0; return 1; } /* Add _rlog and replicator device */ if (!_add_dev_to_dtree(dm, dtree, first_seg(rlv)->rlog_lv, NULL)) return_0; if (!_add_dev_to_dtree(dm, dtree, rlv, NULL)) return_0; if (!(uuid = build_dm_uuid(dm->mem, rlv->lvid.s, NULL))) return_0; rep_node = dm_tree_find_node_by_uuid(dtree, uuid); /* Add all related devices for replicator */ dm_list_iterate_items(rsite, &rlv->rsites) dm_list_iterate_items(rdev, &rsite->rdevices) { if (rsite->state == REPLICATOR_STATE_ACTIVE) { /* Add _rimage LV */ if (!_add_dev_to_dtree(dm, dtree, rdev->lv, NULL)) return_0; /* Add replicator-dev LV, except of the already added one */ if ((lv != rdev->replicator_dev->lv) && !_add_dev_to_dtree(dm, dtree, rdev->replicator_dev->lv, NULL)) return_0; /* If replicator exists - try connect existing heads */ if (rep_node) { uuid = build_dm_uuid(dm->mem, rdev->replicator_dev->lv->lvid.s, NULL); if (!uuid) return_0; rdev_node = dm_tree_find_node_by_uuid(dtree, uuid); if (rdev_node) dm_tree_node_set_presuspend_node(rdev_node, rep_node); } } if (!rdev->rsite->vg_name) continue; if (!_add_dev_to_dtree(dm, dtree, rdev->lv, NULL)) return_0; if (rdev->slog && !_add_dev_to_dtree(dm, dtree, rdev->slog, NULL)) return_0; } return 1; } struct thin_cb_data { const struct logical_volume *pool_lv; struct dev_manager *dm; }; static int _thin_pool_callback(struct dm_tree_node *node, dm_node_callback_t type, void *cb_data) { int ret, status; const struct thin_cb_data *data = cb_data; const char *dmdir = dm_dir(); const struct dm_config_node *cn; const struct dm_config_value *cv; const char *thin_check = find_config_tree_str_allow_empty(data->pool_lv->vg->cmd, "global/thin_check_executable", THIN_CHECK_CMD); const struct logical_volume *mlv = first_seg(data->pool_lv)->metadata_lv; size_t len = strlen(dmdir) + 2 * (strlen(mlv->vg->name) + strlen(mlv->name)) + 3; char meta_path[len]; int args = 0; const char *argv[19]; /* Max supported 15 args */ char *split, *dm_name; if (!thin_check[0]) return 1; /* Checking disabled */ if (!(dm_name = dm_build_dm_name(data->dm->mem, mlv->vg->name, mlv->name, NULL)) || (dm_snprintf(meta_path, len, "%s/%s", dmdir, dm_name) < 0)) { log_error("Failed to build thin metadata path."); return 0; } if ((cn = find_config_tree_node(mlv->vg->cmd, "global/thin_check_options"))) { for (cv = cn->v; cv && args < 16; cv = cv->next) { if (cv->type != DM_CFG_STRING) { log_error("Invalid string in config file: " "global/thin_check_options"); return 0; } argv[++args] = cv->v.str; } } else { /* Use default options (no support for options with spaces) */ if (!(split = dm_pool_strdup(data->dm->mem, DEFAULT_THIN_CHECK_OPTIONS))) { log_error("Failed to duplicate thin check string."); return 0; } args = dm_split_words(split, 16, 0, (char**) argv + 1); } if (args == 16) { log_error("Too many options for thin check command."); return 0; } argv[0] = thin_check; argv[++args] = meta_path; argv[++args] = NULL; if (!(ret = exec_cmd(data->pool_lv->vg->cmd, (const char * const *)argv, &status, 0))) { switch (type) { case DM_NODE_CALLBACK_PRELOADED: log_err_once("Check of thin pool %s/%s failed (status:%d). " "Manual repair required (thin_dump --repair %s)!", data->pool_lv->vg->name, data->pool_lv->name, status, meta_path); break; default: log_warn("WARNING: Integrity check of metadata for thin pool " "%s/%s failed.", data->pool_lv->vg->name, data->pool_lv->name); } /* * FIXME: What should we do here?? * * Maybe mark the node, so it's not activating * as thin_pool but as error/linear and let the * dm tree resolve the issue. */ } dm_pool_free(data->dm->mem, dm_name); return ret; } static int _thin_pool_register_callback(struct dev_manager *dm, struct dm_tree_node *node, const struct logical_volume *lv) { struct thin_cb_data *data; /* Skip metadata testing for unused pool. */ if (!first_seg(lv)->transaction_id) return 1; if (!(data = dm_pool_alloc(dm->mem, sizeof(*data)))) { log_error("Failed to allocated path for callback."); return 0; } data->dm = dm; data->pool_lv = lv; dm_tree_node_set_callback(node, _thin_pool_callback, data); return 1; } /* * Add LV and any known dependencies */ static int _add_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree, struct logical_volume *lv, int origin_only) { uint32_t s; struct seg_list *sl; struct lv_segment *seg = first_seg(lv); struct dm_tree_node *thin_node; const char *uuid; if ((!origin_only || lv_is_thin_volume(lv)) && !_add_dev_to_dtree(dm, dtree, lv, NULL)) return_0; /* FIXME Can we avoid doing this every time? */ if (!_add_dev_to_dtree(dm, dtree, lv, "real")) return_0; if (!origin_only && !_add_dev_to_dtree(dm, dtree, lv, "cow")) return_0; if ((lv->status & MIRRORED) && seg->log_lv && !_add_dev_to_dtree(dm, dtree, seg->log_lv, NULL)) return_0; if (lv->status & RAID) for (s = 0; s < seg->area_count; s++) if (!_add_dev_to_dtree(dm, dtree, seg_metalv(seg, s), NULL)) return_0; /* Add any LVs referencing a PVMOVE LV unless told not to. */ if (dm->track_pvmove_deps && lv->status & PVMOVE) dm_list_iterate_items(sl, &lv->segs_using_this_lv) if (!_add_lv_to_dtree(dm, dtree, sl->seg->lv, origin_only)) return_0; /* Adding LV head of replicator adds all other related devs */ if (lv_is_replicator_dev(lv) && !_add_partial_replicator_to_dtree(dm, dtree, lv)) return_0; if (lv_is_thin_volume(lv)) { #if 0 /* FIXME Implement dm_tree_node_skip_children optimisation */ if (origin_only) { if (!(uuid = build_dm_uuid(dm->mem, lv->lvid.s, NULL))) return_0; if ((thin_node = dm_tree_find_node_by_uuid(dtree, uuid))) dm_tree_node_skip_children(thin_node, 1); } #endif /* Add thin pool LV layer */ lv = seg->pool_lv; seg = first_seg(lv); } if (!origin_only && lv_is_thin_pool(lv)) { if (!_add_lv_to_dtree(dm, dtree, seg->metadata_lv, 0)) return_0; /* FIXME code from _create_partial_dtree() should be moved here */ if (!_add_lv_to_dtree(dm, dtree, seg_lv(seg, 0), 0)) return_0; if (!_add_dev_to_dtree(dm, dtree, lv, _thin_layer)) return_0; /* If the partial tree is used for deactivation, setup callback */ if (!(uuid = build_dm_uuid(dm->mem, lv->lvid.s, _thin_layer))) return_0; if ((thin_node = dm_tree_find_node_by_uuid(dtree, uuid)) && !_thin_pool_register_callback(dm, thin_node, lv)) return_0; } return 1; } static struct dm_tree *_create_partial_dtree(struct dev_manager *dm, struct logical_volume *lv, int origin_only) { struct dm_tree *dtree; struct dm_list *snh; struct lv_segment *seg; uint32_t s; if (!(dtree = dm_tree_create())) { log_debug("Partial dtree creation failed for %s.", lv->name); return NULL; } if (!_add_lv_to_dtree(dm, dtree, lv, (lv_is_origin(lv) || lv_is_thin_volume(lv)) ? origin_only : 0)) goto_bad; /* Add any snapshots of this LV */ if (!origin_only && lv_is_origin(lv)) dm_list_iterate(snh, &lv->snapshot_segs) if (!_add_lv_to_dtree(dm, dtree, dm_list_struct_base(snh, struct lv_segment, origin_list)->cow, 0)) goto_bad; /* Add any LVs used by segments in this LV */ dm_list_iterate_items(seg, &lv->segments) for (s = 0; s < seg->area_count; s++) if (seg_type(seg, s) == AREA_LV && seg_lv(seg, s)) { if (!_add_lv_to_dtree(dm, dtree, seg_lv(seg, s), 0)) goto_bad; } return dtree; bad: dm_tree_free(dtree); return NULL; } static char *_add_error_device(struct dev_manager *dm, struct dm_tree *dtree, struct lv_segment *seg, int s) { char *dlid, *name; char errid[32]; struct dm_tree_node *node; struct lv_segment *seg_i; struct dm_info info; int segno = -1, i = 0; uint64_t size = (uint64_t) seg->len * seg->lv->vg->extent_size; dm_list_iterate_items(seg_i, &seg->lv->segments) { if (seg == seg_i) segno = i; ++i; } if (segno < 0) { log_error("_add_error_device called with bad segment"); return NULL; } sprintf(errid, "missing_%d_%d", segno, s); if (!(dlid = build_dm_uuid(dm->mem, seg->lv->lvid.s, errid))) return_NULL; if (!(name = dm_build_dm_name(dm->mem, seg->lv->vg->name, seg->lv->name, errid))) return_NULL; log_debug("Getting device info for %s [%s]", name, dlid); if (!_info(dlid, 1, 0, &info, NULL)) { log_error("Failed to get info for %s [%s].", name, dlid); return 0; } if (!info.exists) { /* Create new node */ if (!(node = dm_tree_add_new_dev(dtree, name, dlid, 0, 0, 0, 0, 0))) return_NULL; if (!dm_tree_node_add_error_target(node, size)) return_NULL; } else { /* Already exists */ if (!dm_tree_add_dev(dtree, info.major, info.minor)) { log_error("Failed to add device (%" PRIu32 ":%" PRIu32") to dtree", info.major, info.minor); return_NULL; } } return dlid; } static int _add_error_area(struct dev_manager *dm, struct dm_tree_node *node, struct lv_segment *seg, int s) { char *dlid; uint64_t extent_size = seg->lv->vg->extent_size; if (!strcmp(dm->cmd->stripe_filler, "error")) { /* * FIXME, the tree pointer is first field of dm_tree_node, but * we don't have the struct definition available. */ struct dm_tree **tree = (struct dm_tree **) node; if (!(dlid = _add_error_device(dm, *tree, seg, s))) return_0; if (!dm_tree_node_add_target_area(node, NULL, dlid, extent_size * seg_le(seg, s))) return_0; } else if (!dm_tree_node_add_target_area(node, dm->cmd->stripe_filler, NULL, UINT64_C(0))) return_0; return 1; } int add_areas_line(struct dev_manager *dm, struct lv_segment *seg, struct dm_tree_node *node, uint32_t start_area, uint32_t areas) { uint64_t extent_size = seg->lv->vg->extent_size; uint32_t s; char *dlid; struct stat info; const char *name; unsigned num_error_areas = 0; unsigned num_existing_areas = 0; /* FIXME Avoid repeating identical stat in dm_tree_node_add_target_area */ for (s = start_area; s < areas; s++) { if ((seg_type(seg, s) == AREA_PV && (!seg_pvseg(seg, s) || !seg_pv(seg, s) || !seg_dev(seg, s) || !(name = dev_name(seg_dev(seg, s))) || !*name || stat(name, &info) < 0 || !S_ISBLK(info.st_mode))) || (seg_type(seg, s) == AREA_LV && !seg_lv(seg, s))) { if (!seg->lv->vg->cmd->partial_activation) { log_error("Aborting. LV %s is now incomplete " "and --partial was not specified.", seg->lv->name); return 0; } if (!_add_error_area(dm, node, seg, s)) return_0; num_error_areas++; } else if (seg_type(seg, s) == AREA_PV) { if (!dm_tree_node_add_target_area(node, dev_name(seg_dev(seg, s)), NULL, (seg_pv(seg, s)->pe_start + (extent_size * seg_pe(seg, s))))) return_0; num_existing_areas++; } else if (seg_is_raid(seg)) { /* * RAID can handle unassigned areas. It simple puts * '- -' in for the metadata/data device pair. This * is a valid way to indicate to the RAID target that * the device is missing. * * If an image is marked as VISIBLE_LV and !LVM_WRITE, * it means the device has temporarily been extracted * from the array. It may come back at a future date, * so the bitmap must track differences. Again, '- -' * is used in the CTR table. */ if ((seg_type(seg, s) == AREA_UNASSIGNED) || ((seg_lv(seg, s)->status & VISIBLE_LV) && !(seg_lv(seg, s)->status & LVM_WRITE))) { /* One each for metadata area and data area */ if (!dm_tree_node_add_null_area(node, 0) || !dm_tree_node_add_null_area(node, 0)) return_0; continue; } if (!(dlid = build_dm_uuid(dm->mem, seg_metalv(seg, s)->lvid.s, NULL))) return_0; if (!dm_tree_node_add_target_area(node, NULL, dlid, extent_size * seg_metale(seg, s))) return_0; if (!(dlid = build_dm_uuid(dm->mem, seg_lv(seg, s)->lvid.s, NULL))) return_0; if (!dm_tree_node_add_target_area(node, NULL, dlid, extent_size * seg_le(seg, s))) return_0; } else if (seg_type(seg, s) == AREA_LV) { if (!(dlid = build_dm_uuid(dm->mem, seg_lv(seg, s)->lvid.s, NULL))) return_0; if (!dm_tree_node_add_target_area(node, NULL, dlid, extent_size * seg_le(seg, s))) return_0; } else { log_error(INTERNAL_ERROR "Unassigned area found in LV %s.", seg->lv->name); return 0; } } if (num_error_areas) { /* Thins currently do not support partial activation */ if (lv_is_thin_type(seg->lv)) { log_error("Cannot activate %s%s: pool incomplete.", seg->lv->vg->name, seg->lv->name); return 0; } } return 1; } static int _add_origin_target_to_dtree(struct dev_manager *dm, struct dm_tree_node *dnode, struct logical_volume *lv) { const char *real_dlid; if (!(real_dlid = build_dm_uuid(dm->mem, lv->lvid.s, "real"))) return_0; if (!dm_tree_node_add_snapshot_origin_target(dnode, lv->size, real_dlid)) return_0; return 1; } static int _add_snapshot_merge_target_to_dtree(struct dev_manager *dm, struct dm_tree_node *dnode, struct logical_volume *lv) { const char *origin_dlid, *cow_dlid, *merge_dlid; struct lv_segment *merging_cow_seg = find_merging_cow(lv); if (!(origin_dlid = build_dm_uuid(dm->mem, lv->lvid.s, "real"))) return_0; if (!(cow_dlid = build_dm_uuid(dm->mem, merging_cow_seg->cow->lvid.s, "cow"))) return_0; if (!(merge_dlid = build_dm_uuid(dm->mem, merging_cow_seg->cow->lvid.s, NULL))) return_0; if (!dm_tree_node_add_snapshot_merge_target(dnode, lv->size, origin_dlid, cow_dlid, merge_dlid, merging_cow_seg->chunk_size)) return_0; return 1; } static int _add_snapshot_target_to_dtree(struct dev_manager *dm, struct dm_tree_node *dnode, struct logical_volume *lv, struct lv_activate_opts *laopts) { const char *origin_dlid; const char *cow_dlid; struct lv_segment *snap_seg; uint64_t size; if (!(snap_seg = find_cow(lv))) { log_error("Couldn't find snapshot for '%s'.", lv->name); return 0; } if (!(origin_dlid = build_dm_uuid(dm->mem, snap_seg->origin->lvid.s, "real"))) return_0; if (!(cow_dlid = build_dm_uuid(dm->mem, snap_seg->cow->lvid.s, "cow"))) return_0; size = (uint64_t) snap_seg->len * snap_seg->origin->vg->extent_size; if (!laopts->no_merging && lv_is_merging_cow(lv)) { /* cow is to be merged so load the error target */ if (!dm_tree_node_add_error_target(dnode, size)) return_0; } else if (!dm_tree_node_add_snapshot_target(dnode, size, origin_dlid, cow_dlid, 1, snap_seg->chunk_size)) return_0; return 1; } static int _add_target_to_dtree(struct dev_manager *dm, struct dm_tree_node *dnode, struct lv_segment *seg, struct lv_activate_opts *laopts) { uint64_t extent_size = seg->lv->vg->extent_size; if (!seg->segtype->ops->add_target_line) { log_error(INTERNAL_ERROR "_emit_target cannot handle " "segment type %s", seg->segtype->name); return 0; } return seg->segtype->ops->add_target_line(dm, dm->mem, dm->cmd, &dm->target_state, seg, laopts, dnode, extent_size * seg->len, &dm-> pvmove_mirror_count); } static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree, struct logical_volume *lv, struct lv_activate_opts *laopts, const char *layer); /* Add all replicators' LVs */ static int _add_replicator_dev_target_to_dtree(struct dev_manager *dm, struct dm_tree *dtree, struct lv_segment *seg, struct lv_activate_opts *laopts) { struct replicator_device *rdev; struct replicator_site *rsite; /* For inactive replicator add linear mapping */ if (!lv_is_active_replicator_dev(seg->lv)) { if (!_add_new_lv_to_dtree(dm, dtree, seg->lv->rdevice->lv, laopts, NULL)) return_0; return 1; } /* Add rlog and replicator nodes */ if (!seg->replicator || !first_seg(seg->replicator)->rlog_lv || !_add_new_lv_to_dtree(dm, dtree, first_seg(seg->replicator)->rlog_lv, laopts, NULL) || !_add_new_lv_to_dtree(dm, dtree, seg->replicator, laopts, NULL)) return_0; /* Activation of one replicator_dev node activates all other nodes */ dm_list_iterate_items(rsite, &seg->replicator->rsites) { dm_list_iterate_items(rdev, &rsite->rdevices) { if (rdev->lv && !_add_new_lv_to_dtree(dm, dtree, rdev->lv, laopts, NULL)) return_0; if (rdev->slog && !_add_new_lv_to_dtree(dm, dtree, rdev->slog, laopts, NULL)) return_0; } } /* Add remaining replicator-dev nodes in the second loop * to avoid multiple retries for inserting all elements */ dm_list_iterate_items(rsite, &seg->replicator->rsites) { if (rsite->state != REPLICATOR_STATE_ACTIVE) continue; dm_list_iterate_items(rdev, &rsite->rdevices) { if (rdev->replicator_dev->lv == seg->lv) continue; if (!rdev->replicator_dev->lv || !_add_new_lv_to_dtree(dm, dtree, rdev->replicator_dev->lv, laopts, NULL)) return_0; } } return 1; } static int _add_segment_to_dtree(struct dev_manager *dm, struct dm_tree *dtree, struct dm_tree_node *dnode, struct lv_segment *seg, struct lv_activate_opts *laopts, const char *layer) { uint32_t s; struct dm_list *snh; struct lv_segment *seg_present; const char *target_name; struct lv_activate_opts lva; /* Ensure required device-mapper targets are loaded */ seg_present = find_cow(seg->lv) ? : seg; target_name = (seg_present->segtype->ops->target_name ? seg_present->segtype->ops->target_name(seg_present, laopts) : seg_present->segtype->name); log_debug("Checking kernel supports %s segment type for %s%s%s", target_name, seg->lv->name, layer ? "-" : "", layer ? : ""); if (seg_present->segtype->ops->target_present && !seg_present->segtype->ops->target_present(seg_present->lv->vg->cmd, seg_present, NULL)) { log_error("Can't process LV %s: %s target support missing " "from kernel?", seg->lv->name, target_name); return 0; } /* Add mirror log */ if (seg->log_lv && !_add_new_lv_to_dtree(dm, dtree, seg->log_lv, laopts, NULL)) return_0; if (seg_is_replicator_dev(seg)) { if (!_add_replicator_dev_target_to_dtree(dm, dtree, seg, laopts)) return_0; /* If this is a snapshot origin, add real LV */ /* If this is a snapshot origin + merging snapshot, add cow + real LV */ } else if (lv_is_origin(seg->lv) && !layer) { if (!laopts->no_merging && lv_is_merging_origin(seg->lv)) { if (!_add_new_lv_to_dtree(dm, dtree, find_merging_cow(seg->lv)->cow, laopts, "cow")) return_0; /* * Must also add "real" LV for use when * snapshot-merge target is added */ } if (!_add_new_lv_to_dtree(dm, dtree, seg->lv, laopts, "real")) return_0; } else if (lv_is_cow(seg->lv) && !layer) { if (!_add_new_lv_to_dtree(dm, dtree, seg->lv, laopts, "cow")) return_0; } else if ((layer != _thin_layer) && seg_is_thin(seg)) { lva = *laopts; lva.real_pool = 1; if (!_add_new_lv_to_dtree(dm, dtree, seg_is_thin_pool(seg) ? seg->lv : seg->pool_lv, &lva, _thin_layer)) return_0; } else { if (seg_is_thin_pool(seg) && !_add_new_lv_to_dtree(dm, dtree, seg->metadata_lv, laopts, NULL)) return_0; /* Add any LVs used by this segment */ for (s = 0; s < seg->area_count; s++) { if ((seg_type(seg, s) == AREA_LV) && (!_add_new_lv_to_dtree(dm, dtree, seg_lv(seg, s), laopts, NULL))) return_0; if (seg_is_raid(seg) && !_add_new_lv_to_dtree(dm, dtree, seg_metalv(seg, s), laopts, NULL)) return_0; } } /* Now we've added its dependencies, we can add the target itself */ if (lv_is_origin(seg->lv) && !layer) { if (laopts->no_merging || !lv_is_merging_origin(seg->lv)) { if (!_add_origin_target_to_dtree(dm, dnode, seg->lv)) return_0; } else { if (!_add_snapshot_merge_target_to_dtree(dm, dnode, seg->lv)) return_0; } } else if (lv_is_cow(seg->lv) && !layer) { if (!_add_snapshot_target_to_dtree(dm, dnode, seg->lv, laopts)) return_0; } else if (!_add_target_to_dtree(dm, dnode, seg, laopts)) return_0; if (lv_is_origin(seg->lv) && !layer) /* Add any snapshots of this LV */ dm_list_iterate(snh, &seg->lv->snapshot_segs) if (!_add_new_lv_to_dtree(dm, dtree, dm_list_struct_base(snh, struct lv_segment, origin_list)->cow, laopts, NULL)) return_0; return 1; } static int _set_udev_flags_for_children(struct dev_manager *dm, struct volume_group *vg, struct dm_tree_node *dnode) { char *p; const char *uuid; void *handle = NULL; struct dm_tree_node *child; const struct dm_info *info; struct lv_list *lvl; while ((child = dm_tree_next_child(&handle, dnode, 0))) { /* Ignore root node */ if (!(info = dm_tree_node_get_info(child)) || !info->exists) continue; if (!(uuid = dm_tree_node_get_uuid(child))) { log_error(INTERNAL_ERROR "Failed to get uuid for %" PRIu32 ":%" PRIu32, info->major, info->minor); continue; } /* Ignore non-LVM devices */ if (!(p = strstr(uuid, UUID_PREFIX))) continue; p += strlen(UUID_PREFIX); /* Ignore LVs that belong to different VGs (due to stacking) */ if (strncmp(p, (char *)vg->id.uuid, ID_LEN)) continue; /* Ignore LVM devices with 'layer' suffixes */ if (strrchr(p, '-')) continue; if (!(lvl = find_lv_in_vg_by_lvid(vg, (const union lvid *)p))) { log_error(INTERNAL_ERROR "%s (%" PRIu32 ":%" PRIu32 ") not found in VG", dm_tree_node_get_name(child), info->major, info->minor); return 0; } dm_tree_node_set_udev_flags(child, _get_udev_flags(dm, lvl->lv, NULL)); } return 1; } static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree, struct logical_volume *lv, struct lv_activate_opts *laopts, const char *layer) { struct lv_segment *seg; struct lv_layer *lvlayer; struct seg_list *sl; struct dm_tree_node *dnode; const struct dm_info *dinfo; char *name, *dlid; uint32_t max_stripe_size = UINT32_C(0); uint32_t read_ahead = lv->read_ahead; uint32_t read_ahead_flags = UINT32_C(0); /* FIXME Seek a simpler way to lay out the snapshot-merge tree. */ if (lv_is_origin(lv) && lv_is_merging_origin(lv) && !layer) { /* * Clear merge attributes if merge isn't currently possible: * either origin or merging snapshot are open * - but use "snapshot-merge" if it is already in use * - open_count is always retrieved (as of dm-ioctl 4.7.0) * so just use the tree's existing nodes' info */ if (((dinfo = _cached_info(dm->mem, lv, dtree)) && dinfo->open_count) || ((dinfo = _cached_info(dm->mem, find_merging_cow(lv)->cow, dtree)) && dinfo->open_count)) { /* FIXME Is there anything simpler to check for instead? */ if (!lv_has_target_type(dm->mem, lv, NULL, "snapshot-merge")) laopts->no_merging = 1; } } if (!(name = dm_build_dm_name(dm->mem, lv->vg->name, lv->name, layer))) return_0; if (!(dlid = build_dm_uuid(dm->mem, lv->lvid.s, layer))) return_0; /* We've already processed this node if it already has a context ptr */ if ((dnode = dm_tree_find_node_by_uuid(dtree, dlid)) && dm_tree_node_get_context(dnode)) return 1; if (!(lvlayer = dm_pool_alloc(dm->mem, sizeof(*lvlayer)))) { log_error("_add_new_lv_to_dtree: pool alloc failed for %s %s.", lv->name, layer); return 0; } lvlayer->lv = lv; /* * Add LV to dtree. * If we're working with precommitted metadata, clear any * existing inactive table left behind. * Major/minor settings only apply to the visible layer. */ /* FIXME Move the clear from here until later, so we can leave * identical inactive tables untouched. (For pvmove.) */ if (!(dnode = dm_tree_add_new_dev_with_udev_flags(dtree, name, dlid, layer ? UINT32_C(0) : (uint32_t) lv->major, layer ? UINT32_C(0) : (uint32_t) lv->minor, read_only_lv(lv, laopts), ((lv->vg->status & PRECOMMITTED) | laopts->revert) ? 1 : 0, lvlayer, _get_udev_flags(dm, lv, layer)))) return_0; /* Store existing name so we can do rename later */ lvlayer->old_name = dm_tree_node_get_name(dnode); /* Create table */ dm->pvmove_mirror_count = 0u; dm_list_iterate_items(seg, &lv->segments) { if (!_add_segment_to_dtree(dm, dtree, dnode, seg, laopts, layer)) return_0; /* These aren't real segments in the LVM2 metadata */ if (lv_is_origin(lv) && !layer) break; if (!laopts->no_merging && lv_is_cow(lv) && !layer) break; if (max_stripe_size < seg->stripe_size * seg->area_count) max_stripe_size = seg->stripe_size * seg->area_count; } if (read_ahead == DM_READ_AHEAD_AUTO) { /* we need RA at least twice a whole stripe - see the comment in md/raid0.c */ read_ahead = max_stripe_size * 2; if (!read_ahead) lv_calculate_readahead(lv, &read_ahead); read_ahead_flags = DM_READ_AHEAD_MINIMUM_FLAG; } dm_tree_node_set_read_ahead(dnode, read_ahead, read_ahead_flags); /* Setup thin pool callback */ if (layer && lv_is_thin_pool(lv) && !_thin_pool_register_callback(dm, dnode, lv)) return_0; /* Add any LVs referencing a PVMOVE LV unless told not to */ if (dm->track_pvmove_deps && (lv->status & PVMOVE)) dm_list_iterate_items(sl, &lv->segs_using_this_lv) if (!_add_new_lv_to_dtree(dm, dtree, sl->seg->lv, laopts, NULL)) return_0; if (!_set_udev_flags_for_children(dm, lv->vg, dnode)) return_0; return 1; } /* FIXME: symlinks should be created/destroyed at the same time * as the kernel devices but we can't do that from within libdevmapper * at present so we must walk the tree twice instead. */ /* * Create LV symlinks for children of supplied root node. */ static int _create_lv_symlinks(struct dev_manager *dm, struct dm_tree_node *root) { void *handle = NULL; struct dm_tree_node *child; struct lv_layer *lvlayer; char *old_vgname, *old_lvname, *old_layer; char *new_vgname, *new_lvname, *new_layer; const char *name; int r = 1; /* Nothing to do if udev fallback is disabled. */ if (!dm->cmd->current_settings.udev_fallback) { fs_set_create(); return 1; } while ((child = dm_tree_next_child(&handle, root, 0))) { if (!(lvlayer = dm_tree_node_get_context(child))) continue; /* Detect rename */ name = dm_tree_node_get_name(child); if (name && lvlayer->old_name && *lvlayer->old_name && strcmp(name, lvlayer->old_name)) { if (!dm_split_lvm_name(dm->mem, lvlayer->old_name, &old_vgname, &old_lvname, &old_layer)) { log_error("_create_lv_symlinks: Couldn't split up old device name %s", lvlayer->old_name); return 0; } if (!dm_split_lvm_name(dm->mem, name, &new_vgname, &new_lvname, &new_layer)) { log_error("_create_lv_symlinks: Couldn't split up new device name %s", name); return 0; } if (!fs_rename_lv(lvlayer->lv, name, old_vgname, old_lvname)) r = 0; continue; } if (lv_is_visible(lvlayer->lv)) { if (!_dev_manager_lv_mknodes(lvlayer->lv)) r = 0; continue; } if (!_dev_manager_lv_rmnodes(lvlayer->lv)) r = 0; } return r; } /* * Remove LV symlinks for children of supplied root node. */ static int _remove_lv_symlinks(struct dev_manager *dm, struct dm_tree_node *root) { void *handle = NULL; struct dm_tree_node *child; char *vgname, *lvname, *layer; int r = 1; /* Nothing to do if udev fallback is disabled. */ if (!dm->cmd->current_settings.udev_fallback) return 1; while ((child = dm_tree_next_child(&handle, root, 0))) { if (!dm_split_lvm_name(dm->mem, dm_tree_node_get_name(child), &vgname, &lvname, &layer)) { r = 0; continue; } if (!*vgname) continue; /* only top level layer has symlinks */ if (*layer) continue; fs_del_lv_byname(dm->cmd->dev_dir, vgname, lvname, dm->cmd->current_settings.udev_rules); } return r; } static int _clean_tree(struct dev_manager *dm, struct dm_tree_node *root, char *non_toplevel_tree_dlid) { void *handle = NULL; struct dm_tree_node *child; char *vgname, *lvname, *layer; const char *name, *uuid; while ((child = dm_tree_next_child(&handle, root, 0))) { if (!(name = dm_tree_node_get_name(child))) continue; if (!(uuid = dm_tree_node_get_uuid(child))) continue; if (!dm_split_lvm_name(dm->mem, name, &vgname, &lvname, &layer)) { log_error("_clean_tree: Couldn't split up device name %s.", name); return 0; } /* Not meant to be top level? */ if (!*layer) continue; /* If operation was performed on a partial tree, don't remove it */ if (non_toplevel_tree_dlid && !strcmp(non_toplevel_tree_dlid, uuid)) continue; if (!dm_tree_deactivate_children(root, uuid, strlen(uuid))) return_0; } return 1; } static int _tree_action(struct dev_manager *dm, struct logical_volume *lv, struct lv_activate_opts *laopts, action_t action) { const size_t DLID_SIZE = ID_LEN + sizeof(UUID_PREFIX) - 1; struct dm_tree *dtree; struct dm_tree_node *root; char *dlid; int r = 0; laopts->is_activate = (action == ACTIVATE); if (!(dtree = _create_partial_dtree(dm, lv, laopts->origin_only))) return_0; if (!(root = dm_tree_find_node(dtree, 0, 0))) { log_error("Lost dependency tree root node"); goto out_no_root; } /* Restore fs cookie */ dm_tree_set_cookie(root, fs_get_cookie()); if (!(dlid = build_dm_uuid(dm->mem, lv->lvid.s, (lv_is_origin(lv) && laopts->origin_only) ? "real" : NULL))) goto_out; /* Only process nodes with uuid of "LVM-" plus VG id. */ switch(action) { case CLEAN: /* Deactivate any unused non-toplevel nodes */ if (!_clean_tree(dm, root, laopts->origin_only ? dlid : NULL)) goto_out; break; case DEACTIVATE: if (retry_deactivation()) dm_tree_retry_remove(root); /* Deactivate LV and all devices it references that nothing else has open. */ if (!dm_tree_deactivate_children(root, dlid, DLID_SIZE)) goto_out; if (!_remove_lv_symlinks(dm, root)) log_warn("Failed to remove all device symlinks associated with %s.", lv->name); break; case SUSPEND: dm_tree_skip_lockfs(root); if (!dm->flush_required && !seg_is_raid(first_seg(lv)) && (lv->status & MIRRORED) && !(lv->status & PVMOVE)) dm_tree_use_no_flush_suspend(root); /* Fall through */ case SUSPEND_WITH_LOCKFS: if (!dm_tree_suspend_children(root, dlid, DLID_SIZE)) goto_out; break; case PRELOAD: case ACTIVATE: /* Add all required new devices to tree */ if (!_add_new_lv_to_dtree(dm, dtree, lv, laopts, (lv_is_origin(lv) && laopts->origin_only) ? "real" : NULL)) goto_out; /* Preload any devices required before any suspensions */ if (!dm_tree_preload_children(root, dlid, DLID_SIZE)) goto_out; if (dm_tree_node_size_changed(root)) dm->flush_required = 1; if (action == ACTIVATE) { if (!dm_tree_activate_children(root, dlid, DLID_SIZE)) goto_out; if (!_create_lv_symlinks(dm, root)) log_warn("Failed to create symlinks for %s.", lv->name); } break; default: log_error("_tree_action: Action %u not supported.", action); goto out; } r = 1; out: /* Save fs cookie for udev settle, do not wait here */ fs_set_cookie(dm_tree_get_cookie(root)); out_no_root: dm_tree_free(dtree); return r; } /* origin_only may only be set if we are resuming (not activating) an origin LV */ int dev_manager_activate(struct dev_manager *dm, struct logical_volume *lv, struct lv_activate_opts *laopts) { if (!_tree_action(dm, lv, laopts, ACTIVATE)) return_0; if (!_tree_action(dm, lv, laopts, CLEAN)) return_0; return 1; } /* origin_only may only be set if we are resuming (not activating) an origin LV */ int dev_manager_preload(struct dev_manager *dm, struct logical_volume *lv, struct lv_activate_opts *laopts, int *flush_required) { if (!_tree_action(dm, lv, laopts, PRELOAD)) return_0; *flush_required = dm->flush_required; return 1; } int dev_manager_deactivate(struct dev_manager *dm, struct logical_volume *lv) { struct lv_activate_opts laopts = { 0 }; if (!_tree_action(dm, lv, &laopts, DEACTIVATE)) return_0; return 1; } int dev_manager_suspend(struct dev_manager *dm, struct logical_volume *lv, struct lv_activate_opts *laopts, int lockfs, int flush_required) { dm->flush_required = flush_required; if (!_tree_action(dm, lv, laopts, lockfs ? SUSPEND_WITH_LOCKFS : SUSPEND)) return_0; return 1; } /* * Does device use VG somewhere in its construction? * Returns 1 if uncertain. */ int dev_manager_device_uses_vg(struct device *dev, struct volume_group *vg) { struct dm_tree *dtree; struct dm_tree_node *root; char dlid[sizeof(UUID_PREFIX) + sizeof(struct id) - 1] __attribute__((aligned(8))); int r = 1; if (!(dtree = dm_tree_create())) { log_error("partial dtree creation failed"); return r; } if (!dm_tree_add_dev(dtree, (uint32_t) MAJOR(dev->dev), (uint32_t) MINOR(dev->dev))) { log_error("Failed to add device %s (%" PRIu32 ":%" PRIu32") to dtree", dev_name(dev), (uint32_t) MAJOR(dev->dev), (uint32_t) MINOR(dev->dev)); goto out; } memcpy(dlid, UUID_PREFIX, sizeof(UUID_PREFIX) - 1); memcpy(dlid + sizeof(UUID_PREFIX) - 1, &vg->id.uuid[0], sizeof(vg->id)); if (!(root = dm_tree_find_node(dtree, 0, 0))) { log_error("Lost dependency tree root node"); goto out; } if (dm_tree_children_use_uuid(root, dlid, sizeof(UUID_PREFIX) + sizeof(vg->id) - 1)) goto_out; r = 0; out: dm_tree_free(dtree); return r; } lvm2-2.02.98/lib/activate/targets.h0000640000175000017500000000213212037016272015676 0ustar blankblank/* * 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 lvm2-2.02.98/lib/display/0000750000175000017500000000000012037016272013722 5ustar blankblanklvm2-2.02.98/lib/display/display.c0000640000175000017500000006135212037016272015543 0ustar blankblank/* * 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 "metadata.h" #include "display.h" #include "activate.h" #include "toolcontext.h" #include "segtype.h" #include "defaults.h" #define SIZE_BUF 128 typedef enum { SIZE_LONG = 0, SIZE_SHORT = 1, SIZE_UNIT = 2 } size_len_t; static const struct { alloc_policy_t alloc; const char str[14]; /* must be changed when size extends 13 chars */ const char repchar; } _policies[] = { { ALLOC_CONTIGUOUS, "contiguous", 'c'}, { ALLOC_CLING, "cling", 'l'}, { ALLOC_CLING_BY_TAGS, "cling_by_tags", 't'}, { /* Only used in log mesgs */ ALLOC_NORMAL, "normal", 'n'}, { ALLOC_ANYWHERE, "anywhere", 'a'}, { ALLOC_INHERIT, "inherit", 'i'} }; static const int _num_policies = sizeof(_policies) / sizeof(*_policies); uint64_t units_to_bytes(const char *units, char *unit_type) { char *ptr = NULL; uint64_t v; double custom_value = 0; uint64_t multiplier; if (isdigit(*units)) { custom_value = strtod(units, &ptr); if (ptr == units) return 0; v = (uint64_t) strtoull(units, NULL, 10); if ((double) v == custom_value) custom_value = 0; /* Use integer arithmetic */ units = ptr; } else v = 1; /* Only one units char permitted. */ if (units[0] && units[1]) return 0; if (v == 1) *unit_type = *units; else *unit_type = 'U'; switch (*units) { case 'h': case 'H': multiplier = v = UINT64_C(1); *unit_type = *units; break; case 'b': case 'B': multiplier = UINT64_C(1); break; #define KILO UINT64_C(1024) case 's': case 'S': multiplier = (KILO/2); break; case 'k': multiplier = KILO; break; case 'm': multiplier = KILO * KILO; break; case 'g': multiplier = KILO * KILO * KILO; break; case 't': multiplier = KILO * KILO * KILO * KILO; break; case 'p': multiplier = KILO * KILO * KILO * KILO * KILO; break; case 'e': multiplier = KILO * KILO * KILO * KILO * KILO * KILO; break; #undef KILO #define KILO UINT64_C(1000) case 'K': multiplier = KILO; break; case 'M': multiplier = KILO * KILO; break; case 'G': multiplier = KILO * KILO * KILO; break; case 'T': multiplier = KILO * KILO * KILO * KILO; break; case 'P': multiplier = KILO * KILO * KILO * KILO * KILO; break; case 'E': multiplier = KILO * KILO * KILO * KILO * KILO * KILO; break; #undef KILO default: return 0; } if (custom_value) return (uint64_t) (custom_value * multiplier); else return v * multiplier; } char alloc_policy_char(alloc_policy_t alloc) { int i; for (i = 0; i < _num_policies; i++) if (_policies[i].alloc == alloc) return _policies[i].repchar; return '-'; } const char *get_alloc_string(alloc_policy_t alloc) { int i; for (i = 0; i < _num_policies; i++) if (_policies[i].alloc == alloc) return _policies[i].str; return NULL; } alloc_policy_t get_alloc_from_string(const char *str) { int i; /* cling_by_tags is part of cling */ if (!strcmp("cling_by_tags", str)) return ALLOC_CLING; for (i = 0; i < _num_policies; i++) if (!strcmp(_policies[i].str, str)) return _policies[i].alloc; /* Special case for old metadata */ if (!strcmp("next free", str)) return ALLOC_NORMAL; log_error("Unrecognised allocation policy %s", str); return ALLOC_INVALID; } #define BASE_UNKNOWN 0 #define BASE_SHARED 1 #define BASE_1024 7 #define BASE_1000 13 #define BASE_SPECIAL 19 #define NUM_UNIT_PREFIXES 6 #define NUM_SPECIAL 3 /* Size supplied in sectors */ static const char *_display_size(const struct cmd_context *cmd, uint64_t size, size_len_t sl) { unsigned base = BASE_UNKNOWN; unsigned s; int suffix = 1, precision; uint64_t byte = UINT64_C(0); uint64_t units = UINT64_C(1024); char *size_buf = NULL; const char * const size_str[][3] = { /* BASE_UNKNOWN */ {" ", " ", " "}, /* [0] */ /* BASE_SHARED - Used if cmd->si_unit_consistency = 0 */ {" Exabyte", " EB", "E"}, /* [1] */ {" Petabyte", " PB", "P"}, /* [2] */ {" Terabyte", " TB", "T"}, /* [3] */ {" Gigabyte", " GB", "G"}, /* [4] */ {" Megabyte", " MB", "M"}, /* [5] */ {" Kilobyte", " KB", "K"}, /* [6] */ /* BASE_1024 - Used if cmd->si_unit_consistency = 1 */ {" Exbibyte", " EiB", "e"}, /* [7] */ {" Pebibyte", " PiB", "p"}, /* [8] */ {" Tebibyte", " TiB", "t"}, /* [9] */ {" Gibibyte", " GiB", "g"}, /* [10] */ {" Mebibyte", " MiB", "m"}, /* [11] */ {" Kibibyte", " KiB", "k"}, /* [12] */ /* BASE_1000 - Used if cmd->si_unit_consistency = 1 */ {" Exabyte", " EB", "E"}, /* [13] */ {" Petabyte", " PB", "P"}, /* [14] */ {" Terabyte", " TB", "T"}, /* [15] */ {" Gigabyte", " GB", "G"}, /* [16] */ {" Megabyte", " MB", "M"}, /* [17] */ {" Kilobyte", " kB", "K"}, /* [18] */ /* BASE_SPECIAL */ {" Byte ", " B ", "B"}, /* [19] */ {" Units ", " Un", "U"}, /* [20] */ {" Sectors ", " Se", "S"}, /* [21] */ }; if (!(size_buf = dm_pool_alloc(cmd->mem, SIZE_BUF))) { log_error("no memory for size display buffer"); return ""; } suffix = cmd->current_settings.suffix; if (!cmd->si_unit_consistency) { /* Case-independent match */ for (s = 0; s < NUM_UNIT_PREFIXES; s++) if (toupper((int) cmd->current_settings.unit_type) == *size_str[BASE_SHARED + s][2]) { base = BASE_SHARED; break; } } else { /* Case-dependent match for powers of 1000 */ for (s = 0; s < NUM_UNIT_PREFIXES; s++) if (cmd->current_settings.unit_type == *size_str[BASE_1000 + s][2]) { base = BASE_1000; break; } /* Case-dependent match for powers of 1024 */ if (base == BASE_UNKNOWN) for (s = 0; s < NUM_UNIT_PREFIXES; s++) if (cmd->current_settings.unit_type == *size_str[BASE_1024 + s][2]) { base = BASE_1024; break; } } if (base == BASE_UNKNOWN) /* Check for special units - s, b or u */ for (s = 0; s < NUM_SPECIAL; s++) if (toupper((int) cmd->current_settings.unit_type) == *size_str[BASE_SPECIAL + s][2]) { base = BASE_SPECIAL; break; } if (size == UINT64_C(0)) { if (base == BASE_UNKNOWN) s = 0; sprintf(size_buf, "0%s", suffix ? size_str[base + s][sl] : ""); return size_buf; } size *= UINT64_C(512); if (base != BASE_UNKNOWN) byte = cmd->current_settings.unit_factor; else { /* Human-readable style */ if (cmd->current_settings.unit_type == 'H') { units = UINT64_C(1000); base = BASE_1000; } else { units = UINT64_C(1024); base = BASE_1024; } if (!cmd->si_unit_consistency) base = BASE_SHARED; byte = units * units * units * units * units * units; for (s = 0; s < NUM_UNIT_PREFIXES && size < byte; s++) byte /= units; suffix = 1; } /* FIXME Make precision configurable */ switch(toupper((int) cmd->current_settings.unit_type)) { case 'B': case 'S': precision = 0; break; default: precision = 2; } snprintf(size_buf, SIZE_BUF - 1, "%.*f%s", precision, (double) size / byte, suffix ? size_str[base + s][sl] : ""); return size_buf; } const char *display_size_long(const struct cmd_context *cmd, uint64_t size) { return _display_size(cmd, size, SIZE_LONG); } const char *display_size_units(const struct cmd_context *cmd, uint64_t size) { return _display_size(cmd, size, SIZE_UNIT); } const char *display_size(const struct cmd_context *cmd, uint64_t size) { return _display_size(cmd, size, SIZE_SHORT); } void pvdisplay_colons(const struct physical_volume *pv) { char uuid[64] __attribute__((aligned(8))); if (!pv) return; if (!id_write_format(&pv->id, uuid, sizeof(uuid))) { stack; return; } log_print("%s:%s:%" PRIu64 ":-1:%" PRIu64 ":%" PRIu64 ":-1:%" PRIu32 ":%u:%u:%u:%s", pv_dev_name(pv), pv->vg_name, pv->size, /* FIXME pv->pv_number, Derive or remove? */ pv->status, /* FIXME Support old or new format here? */ pv->status & ALLOCATABLE_PV, /* FIXME remove? */ /* FIXME pv->lv_cur, Remove? */ pv->pe_size / 2, pv->pe_count, pv->pe_count - pv->pe_alloc_count, pv->pe_alloc_count, *uuid ? uuid : "none"); } void pvdisplay_segments(const struct physical_volume *pv) { const struct pv_segment *pvseg; if (pv->pe_size) log_print("--- Physical Segments ---"); dm_list_iterate_items(pvseg, &pv->segments) { log_print("Physical extent %u to %u:", pvseg->pe, pvseg->pe + pvseg->len - 1); if (pvseg_is_allocated(pvseg)) { log_print(" Logical volume\t%s%s/%s", pvseg->lvseg->lv->vg->cmd->dev_dir, pvseg->lvseg->lv->vg->name, pvseg->lvseg->lv->name); log_print(" Logical extents\t%d to %d", pvseg->lvseg->le, pvseg->lvseg->le + pvseg->lvseg->len - 1); } else log_print(" FREE"); } log_print(" "); } /* FIXME Include label fields */ void pvdisplay_full(const struct cmd_context *cmd, const struct physical_volume *pv, void *handle __attribute__((unused))) { char uuid[64] __attribute__((aligned(8))); const char *size; uint32_t pe_free; uint64_t data_size, pvsize, unusable; if (!pv) return; if (!id_write_format(&pv->id, uuid, sizeof(uuid))) { stack; return; } log_print("--- %sPhysical volume ---", pv->pe_size ? "" : "NEW "); log_print("PV Name %s", pv_dev_name(pv)); log_print("VG Name %s%s", is_orphan(pv) ? "" : pv->vg_name, pv->status & EXPORTED_VG ? " (exported)" : ""); data_size = (uint64_t) pv->pe_count * pv->pe_size; if (pv->size > data_size + pv->pe_start) { pvsize = pv->size; unusable = pvsize - data_size; } else { pvsize = data_size + pv->pe_start; unusable = pvsize - pv->size; } size = display_size(cmd, pvsize); if (data_size) log_print("PV Size %s / not usable %s", /* [LVM: %s]", */ size, display_size(cmd, unusable)); else log_print("PV Size %s", size); /* PV number not part of LVM2 design log_print("PV# %u", pv->pv_number); */ pe_free = pv->pe_count - pv->pe_alloc_count; if (pv->pe_count && (pv->status & ALLOCATABLE_PV)) log_print("Allocatable yes %s", (!pe_free && pv->pe_count) ? "(but full)" : ""); else log_print("Allocatable NO"); /* LV count is no longer available when displaying PV log_print("Cur LV %u", vg->lv_count); */ if (cmd->si_unit_consistency) log_print("PE Size %s", display_size(cmd, (uint64_t) pv->pe_size)); else log_print("PE Size (KByte) %" PRIu32, pv->pe_size / 2); log_print("Total PE %u", pv->pe_count); log_print("Free PE %" PRIu32, pe_free); log_print("Allocated PE %u", pv->pe_alloc_count); log_print("PV UUID %s", *uuid ? uuid : "none"); log_print(" "); } int pvdisplay_short(const struct cmd_context *cmd __attribute__((unused)), const struct volume_group *vg __attribute__((unused)), const struct physical_volume *pv, void *handle __attribute__((unused))) { char uuid[64] __attribute__((aligned(8))); if (!pv) return 0; if (!id_write_format(&pv->id, uuid, sizeof(uuid))) return_0; log_print("PV Name %s ", pv_dev_name(pv)); /* FIXME pv->pv_number); */ log_print("PV UUID %s", *uuid ? uuid : "none"); log_print("PV Status %sallocatable", (pv->status & ALLOCATABLE_PV) ? "" : "NOT "); log_print("Total PE / Free PE %u / %u", pv->pe_count, pv->pe_count - pv->pe_alloc_count); log_print(" "); return 0; } void lvdisplay_colons(const struct logical_volume *lv) { int inkernel; struct lvinfo info; inkernel = lv_info(lv->vg->cmd, lv, 0, &info, 1, 0) && info.exists; log_print("%s%s/%s:%s:%" PRIu64 ":%d:-1:%d:%" PRIu64 ":%d:-1:%d:%d:%d:%d", lv->vg->cmd->dev_dir, lv->vg->name, lv->name, lv->vg->name, ((lv->status & (LVM_READ | LVM_WRITE)) >> 8) | ((inkernel && info.read_only) ? 4 : 0), inkernel ? 1 : 0, /* FIXME lv->lv_number, */ inkernel ? info.open_count : 0, lv->size, lv->le_count, /* FIXME Add num allocated to struct! lv->lv_allocated_le, */ (lv->alloc == ALLOC_CONTIGUOUS ? 2 : 0), lv->read_ahead, inkernel ? info.major : -1, inkernel ? info.minor : -1); } int lvdisplay_full(struct cmd_context *cmd, const struct logical_volume *lv, void *handle __attribute__((unused))) { struct lvinfo info; int inkernel, snap_active = 0; char uuid[64] __attribute__((aligned(8))); const char *access_str; struct lv_segment *snap_seg = NULL, *mirror_seg = NULL; struct lv_segment *seg = NULL; int lvm1compat; percent_t snap_percent; int thin_data_active = 0, thin_metadata_active = 0; percent_t thin_data_percent, thin_metadata_percent; int thin_active = 0; percent_t thin_percent; if (!id_write_format(&lv->lvid.id[1], uuid, sizeof(uuid))) return_0; inkernel = lv_info(cmd, lv, 0, &info, 1, 1) && info.exists; if ((lv->status & LVM_WRITE) && inkernel && info.read_only) access_str = "read/write (activated read only)"; else if (lv->status & LVM_WRITE) access_str = "read/write"; else access_str = "read only"; log_print("--- Logical volume ---"); lvm1compat = find_config_tree_int(cmd, "global/lvdisplay_shows_full_device_path", DEFAULT_LVDISPLAY_SHOWS_FULL_DEVICE_PATH); if (lvm1compat) /* /dev/vgname/lvname doen't actually exist for internal devices */ log_print("LV Name %s%s/%s", lv->vg->cmd->dev_dir, lv->vg->name, lv->name); else if (lv_is_visible(lv)) { /* Thin pool does not have /dev/vg/name link */ if (!lv_is_thin_pool(lv)) log_print("LV Path %s%s/%s", lv->vg->cmd->dev_dir, lv->vg->name, lv->name); log_print("LV Name %s", lv->name); } else log_print("Internal LV Name %s", lv->name); log_print("VG Name %s", lv->vg->name); log_print("LV UUID %s", uuid); log_print("LV Write Access %s", access_str); log_print("LV Creation host, time %s, %s", lv_host_dup(cmd->mem, lv), lv_time_dup(cmd->mem, lv)); if (lv_is_origin(lv)) { log_print("LV snapshot status source of"); dm_list_iterate_items_gen(snap_seg, &lv->snapshot_segs, origin_list) { if (inkernel && (snap_active = lv_snapshot_percent(snap_seg->cow, &snap_percent))) if (snap_percent == PERCENT_INVALID) snap_active = 0; if (lvm1compat) log_print(" %s%s/%s [%s]", lv->vg->cmd->dev_dir, lv->vg->name, snap_seg->cow->name, snap_active ? "active" : "INACTIVE"); else log_print(" %s [%s]", snap_seg->cow->name, snap_active ? "active" : "INACTIVE"); } snap_seg = NULL; } else if ((snap_seg = find_cow(lv))) { if (inkernel && (snap_active = lv_snapshot_percent(snap_seg->cow, &snap_percent))) if (snap_percent == PERCENT_INVALID) snap_active = 0; if (lvm1compat) log_print("LV snapshot status %s destination for %s%s/%s", snap_active ? "active" : "INACTIVE", lv->vg->cmd->dev_dir, lv->vg->name, snap_seg->origin->name); else log_print("LV snapshot status %s destination for %s", snap_active ? "active" : "INACTIVE", snap_seg->origin->name); } if (lv_is_thin_volume(lv)) { seg = first_seg(lv); log_print("LV Pool name %s", seg->pool_lv->name); if (seg->origin) log_print("LV Thin origin name %s", seg->origin->name); if (inkernel) thin_active = lv_thin_percent(lv, 0, &thin_percent); } else if (lv_is_thin_pool(lv)) { if (inkernel) { thin_data_active = lv_thin_pool_percent(lv, 0, &thin_data_percent); thin_metadata_active = lv_thin_pool_percent(lv, 1, &thin_metadata_percent); } /* FIXME: display thin_pool targets transid for activated LV as well */ seg = first_seg(lv); log_print("LV Pool transaction ID %" PRIu64, seg->transaction_id); log_print("LV Pool metadata %s", seg->metadata_lv->name); log_print("LV Pool data %s", seg_lv(seg, 0)->name); log_print("LV Pool chunk size %s", display_size(cmd, seg->chunk_size)); log_print("LV Zero new blocks %s", seg->zero_new_blocks ? "yes" : "no"); } if (inkernel && info.suspended) log_print("LV Status suspended"); else log_print("LV Status %savailable", inkernel ? "" : "NOT "); /********* FIXME lv_number log_print("LV # %u", lv->lv_number + 1); ************/ if (inkernel) log_print("# open %u", info.open_count); log_print("LV Size %s", display_size(cmd, snap_seg ? snap_seg->origin->size : lv->size)); if (thin_data_active) log_print("Allocated pool data %.2f%%", percent_to_float(thin_data_percent)); if (thin_metadata_active) log_print("Allocated metadata %.2f%%", percent_to_float(thin_metadata_percent)); if (thin_active) log_print("Mapped size %.2f%%", percent_to_float(thin_percent)); log_print("Current LE %u", snap_seg ? snap_seg->origin->le_count : lv->le_count); if (snap_seg) { log_print("COW-table size %s", display_size(cmd, (uint64_t) lv->size)); log_print("COW-table LE %u", lv->le_count); if (snap_active) log_print("Allocated to snapshot %.2f%%", percent_to_float(snap_percent)); log_print("Snapshot chunk size %s", display_size(cmd, (uint64_t) snap_seg->chunk_size)); } if (lv->status & MIRRORED) { mirror_seg = first_seg(lv); log_print("Mirrored volumes %" PRIu32, mirror_seg->area_count); if (lv->status & CONVERTING) log_print("LV type Mirror undergoing conversion"); } log_print("Segments %u", dm_list_size(&lv->segments)); /********* FIXME Stripes & stripesize for each segment log_print("Stripe size %s", display_size(cmd, (uint64_t) lv->stripesize)); ***********/ log_print("Allocation %s", get_alloc_string(lv->alloc)); if (lv->read_ahead == DM_READ_AHEAD_AUTO) log_print("Read ahead sectors auto"); else if (lv->read_ahead == DM_READ_AHEAD_NONE) log_print("Read ahead sectors 0"); else log_print("Read ahead sectors %u", lv->read_ahead); if (inkernel && lv->read_ahead != info.read_ahead) log_print("- currently set to %u", info.read_ahead); if (lv->status & FIXED_MINOR) { if (lv->major >= 0) log_print("Persistent major %d", lv->major); log_print("Persistent minor %d", lv->minor); } if (inkernel) log_print("Block device %d:%d", info.major, info.minor); log_print(" "); return 0; } void display_stripe(const struct lv_segment *seg, uint32_t s, const char *pre) { switch (seg_type(seg, s)) { case AREA_PV: /* FIXME Re-check the conditions for 'Missing' */ log_print("%sPhysical volume\t%s", pre, seg_pv(seg, s) ? pv_dev_name(seg_pv(seg, s)) : "Missing"); if (seg_pv(seg, s)) log_print("%sPhysical extents\t%d to %d", pre, seg_pe(seg, s), seg_pe(seg, s) + seg->area_len - 1); break; case AREA_LV: log_print("%sLogical volume\t%s", pre, seg_lv(seg, s) ? seg_lv(seg, s)->name : "Missing"); if (seg_lv(seg, s)) log_print("%sLogical extents\t%d to %d", pre, seg_le(seg, s), seg_le(seg, s) + seg->area_len - 1); break; case AREA_UNASSIGNED: log_print("%sUnassigned area", pre); } } int lvdisplay_segments(const struct logical_volume *lv) { const struct lv_segment *seg; log_print("--- Segments ---"); dm_list_iterate_items(seg, &lv->segments) { log_print("Logical extent %u to %u:", seg->le, seg->le + seg->len - 1); log_print(" Type\t\t%s", seg->segtype->ops->name(seg)); if (seg->segtype->ops->display) seg->segtype->ops->display(seg); } log_print(" "); return 1; } void vgdisplay_extents(const struct volume_group *vg __attribute__((unused))) { } void vgdisplay_full(const struct volume_group *vg) { uint32_t access_str; uint32_t active_pvs; char uuid[64] __attribute__((aligned(8))); active_pvs = vg->pv_count - vg_missing_pv_count(vg); log_print("--- Volume group ---"); log_print("VG Name %s", vg->name); log_print("System ID %s", vg->system_id); log_print("Format %s", vg->fid->fmt->name); if (vg->fid->fmt->features & FMT_MDAS) { log_print("Metadata Areas %d", vg_mda_count(vg)); log_print("Metadata Sequence No %d", vg->seqno); } access_str = vg->status & (LVM_READ | LVM_WRITE); log_print("VG Access %s%s%s%s", access_str == (LVM_READ | LVM_WRITE) ? "read/write" : "", access_str == LVM_READ ? "read" : "", access_str == LVM_WRITE ? "write" : "", access_str == 0 ? "error" : ""); log_print("VG Status %s%sresizable", vg_is_exported(vg) ? "exported/" : "", vg_is_resizeable(vg) ? "" : "NOT "); /* vg number not part of LVM2 design log_print ("VG # %u\n", vg->vg_number); */ if (vg_is_clustered(vg)) { log_print("Clustered yes"); log_print("Shared %s", vg->status & SHARED ? "yes" : "no"); } log_print("MAX LV %u", vg->max_lv); log_print("Cur LV %u", vg_visible_lvs(vg)); log_print("Open LV %u", lvs_in_vg_opened(vg)); /****** FIXME Max LV Size log_print ( "MAX LV Size %s", ( s1 = display_size ( LVM_LV_SIZE_MAX(vg)))); free ( s1); *********/ log_print("Max PV %u", vg->max_pv); log_print("Cur PV %u", vg->pv_count); log_print("Act PV %u", active_pvs); log_print("VG Size %s", display_size(vg->cmd, (uint64_t) vg->extent_count * vg->extent_size)); log_print("PE Size %s", display_size(vg->cmd, (uint64_t) vg->extent_size)); log_print("Total PE %u", vg->extent_count); log_print("Alloc PE / Size %u / %s", vg->extent_count - vg->free_count, display_size(vg->cmd, ((uint64_t) vg->extent_count - vg->free_count) * vg->extent_size)); log_print("Free PE / Size %u / %s", vg->free_count, display_size(vg->cmd, vg_free(vg))); if (!id_write_format(&vg->id, uuid, sizeof(uuid))) { stack; return; } log_print("VG UUID %s", uuid); log_print(" "); } void vgdisplay_colons(const struct volume_group *vg) { uint32_t active_pvs; const char *access_str; char uuid[64] __attribute__((aligned(8))); active_pvs = vg->pv_count - vg_missing_pv_count(vg); switch (vg->status & (LVM_READ | LVM_WRITE)) { case LVM_READ | LVM_WRITE: access_str = "r/w"; break; case LVM_READ: access_str = "r"; break; case LVM_WRITE: access_str = "w"; break; default: access_str = ""; } if (!id_write_format(&vg->id, uuid, sizeof(uuid))) { stack; return; } log_print("%s:%s:%" PRIu64 ":-1:%u:%u:%u:-1:%u:%u:%u:%" PRIu64 ":%" PRIu32 ":%u:%u:%u:%s", vg->name, access_str, vg->status, /* internal volume group number; obsolete */ vg->max_lv, vg_visible_lvs(vg), lvs_in_vg_opened(vg), /* FIXME: maximum logical volume size */ vg->max_pv, vg->pv_count, active_pvs, (uint64_t) vg->extent_count * (vg->extent_size / 2), vg->extent_size / 2, vg->extent_count, vg->extent_count - vg->free_count, vg->free_count, uuid[0] ? uuid : "none"); } void vgdisplay_short(const struct volume_group *vg) { log_print("\"%s\" %-9s [%-9s used / %s free]", vg->name, /********* FIXME if "open" print "/used" else print "/idle"??? ******/ display_size(vg->cmd, (uint64_t) vg->extent_count * vg->extent_size), display_size(vg->cmd, ((uint64_t) vg->extent_count - vg->free_count) * vg->extent_size), display_size(vg->cmd, vg_free(vg))); } void display_formats(const struct cmd_context *cmd) { const struct format_type *fmt; dm_list_iterate_items(fmt, &cmd->formats) { log_print("%s", fmt->name); } } void display_segtypes(const struct cmd_context *cmd) { const struct segment_type *segtype; dm_list_iterate_items(segtype, &cmd->segtypes) { log_print("%s", segtype->name); } } /* * Prompt for y or n from stdin. * Defaults to 'no' in silent mode. * All callers should support --yes and/or --force to override this. */ char yes_no_prompt(const char *prompt, ...) { int c = 0, ret = 0; va_list ap; if (silent_mode()) return 'n'; sigint_allow(); do { if (c == '\n' || !c) { va_start(ap, prompt); vfprintf(stderr, prompt, ap); va_end(ap); fflush(stderr); ret = 0; } if ((c = getchar()) == EOF) { ret = 'n'; break; } c = tolower(c); if ((c == 'y') || (c == 'n')) { /* If both 'y' and 'n' given, begin again. */ if (ret && c != ret) ret = -1; else ret = c; } } while (ret < 1 || c != '\n'); sigint_restore(); if (c != '\n') fprintf(stderr, "\n"); return ret; } lvm2-2.02.98/lib/display/display.h0000640000175000017500000000446112037016272015546 0ustar blankblank/* * 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_DISPLAY_H #define _LVM_DISPLAY_H #include "metadata-exported.h" #include "locking.h" #include uint64_t units_to_bytes(const char *units, char *unit_type); /* Specify size in KB */ const char *display_size(const struct cmd_context *cmd, uint64_t size); const char *display_size_long(const struct cmd_context *cmd, uint64_t size); const char *display_size_units(const struct cmd_context *cmd, uint64_t size); char *display_uuid(char *uuidstr); void display_stripe(const struct lv_segment *seg, uint32_t s, const char *pre); void pvdisplay_colons(const struct physical_volume *pv); void pvdisplay_segments(const struct physical_volume *pv); void pvdisplay_full(const struct cmd_context *cmd, const struct physical_volume *pv, void *handle); int pvdisplay_short(const struct cmd_context *cmd, const struct volume_group *vg, const struct physical_volume *pv, void *handle); void lvdisplay_colons(const struct logical_volume *lv); int lvdisplay_segments(const struct logical_volume *lv); int lvdisplay_full(struct cmd_context *cmd, const struct logical_volume *lv, void *handle); void vgdisplay_extents(const struct volume_group *vg); void vgdisplay_full(const struct volume_group *vg); void vgdisplay_colons(const struct volume_group *vg); void vgdisplay_short(const struct volume_group *vg); void display_formats(const struct cmd_context *cmd); void display_segtypes(const struct cmd_context *cmd); /* * Allocation policy display conversion routines. */ const char *get_alloc_string(alloc_policy_t alloc); char alloc_policy_char(alloc_policy_t alloc); alloc_policy_t get_alloc_from_string(const char *str); char yes_no_prompt(const char *prompt, ...) __attribute__ ((format(printf, 1, 2))); #endif lvm2-2.02.98/lib/format1/0000750000175000017500000000000012037016272013626 5ustar blankblanklvm2-2.02.98/lib/format1/.exported_symbols0000640000175000017500000000001412037016272017225 0ustar blankblankinit_format lvm2-2.02.98/lib/format1/vg_number.c0000640000175000017500000000303412037016272015757 0ustar blankblank/* * Copyright (C) 2001-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 */ #include "lib.h" #include "disk-rep.h" /* * FIXME: Quick hack. We can use caching to * prevent a total re-read, even so vg_number * causes the tools to check *every* pv. Yuck. * Put in separate file so it wouldn't contaminate * other code. */ int get_free_vg_number(struct format_instance *fid, struct dev_filter *filter, const char *candidate_vg, int *result) { struct dm_list all_pvs; struct disk_list *dl; struct dm_pool *mem = dm_pool_create("lvm1 vg_number", 10 * 1024); int i, r = 0, numbers[MAX_VG] = { 0 }; dm_list_init(&all_pvs); if (!mem) return_0; if (!read_pvs_in_vg(fid->fmt, NULL, filter, mem, &all_pvs)) goto_out; dm_list_iterate_items(dl, &all_pvs) { if (!*dl->pvd.vg_name || !strcmp((char *)dl->pvd.vg_name, candidate_vg)) continue; numbers[dl->vgd.vg_number] = 1; } for (i = 0; i < MAX_VG; i++) { if (!numbers[i]) { r = 1; *result = i; break; } } out: dm_pool_destroy(mem); return r; } lvm2-2.02.98/lib/format1/lvm1-label.c0000640000175000017500000000604012037016272015727 0ustar blankblank/* * 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 */ #include "lib.h" #include "lvm1-label.h" #include "disk-rep.h" #include "label.h" #include "metadata.h" #include "xlate.h" #include "format1.h" #include #include static void _not_supported(const char *op) { log_error("The '%s' operation is not supported for the lvm1 labeller.", op); } static int _lvm1_can_handle(struct labeller *l __attribute__((unused)), void *buf, uint64_t sector) { struct pv_disk *pvd = (struct pv_disk *) buf; uint32_t version; /* LVM1 label must always be in first sector */ if (sector) return 0; version = xlate16(pvd->version); if (pvd->id[0] == 'H' && pvd->id[1] == 'M' && (version == 1 || version == 2)) return 1; return 0; } static int _lvm1_write(struct label *label __attribute__((unused)), void *buf __attribute__((unused))) { _not_supported("write"); return 0; } static int _lvm1_read(struct labeller *l, struct device *dev, void *buf, struct label **label) { struct pv_disk *pvd = (struct pv_disk *) buf; struct vg_disk vgd; struct lvmcache_info *info; const char *vgid = FMT_LVM1_ORPHAN_VG_NAME; const char *vgname = FMT_LVM1_ORPHAN_VG_NAME; unsigned exported = 0; munge_pvd(dev, pvd); if (*pvd->vg_name) { if (!read_vgd(dev, &vgd, pvd)) return_0; vgid = (char *) vgd.vg_uuid; vgname = (char *) pvd->vg_name; exported = pvd->pv_status & VG_EXPORTED; } if (!(info = lvmcache_add(l, (char *)pvd->pv_uuid, dev, vgname, vgid, exported))) return_0; *label = lvmcache_get_label(info); lvmcache_set_device_size(info, ((uint64_t)xlate32(pvd->pv_size)) << SECTOR_SHIFT); lvmcache_del_mdas(info); lvmcache_make_valid(info); return 1; } static int _lvm1_initialise_label(struct labeller *l __attribute__((unused)), struct label *label) { strcpy(label->type, "LVM1"); return 1; } static void _lvm1_destroy_label(struct labeller *l __attribute__((unused)), struct label *label __attribute__((unused))) { } static void _lvm1_destroy(struct labeller *l) { dm_free(l); } struct label_ops _lvm1_ops = { .can_handle = _lvm1_can_handle, .write = _lvm1_write, .read = _lvm1_read, .verify = _lvm1_can_handle, .initialise_label = _lvm1_initialise_label, .destroy_label = _lvm1_destroy_label, .destroy = _lvm1_destroy, }; struct labeller *lvm1_labeller_create(struct format_type *fmt) { struct labeller *l; if (!(l = dm_malloc(sizeof(*l)))) { log_error("Couldn't allocate labeller object."); return NULL; } l->ops = &_lvm1_ops; l->private = (const void *) fmt; return l; } lvm2-2.02.98/lib/format1/import-extents.c0000640000175000017500000002104612037016272017000 0ustar blankblank/* * 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 "metadata.h" #include "disk-rep.h" #include "lv_alloc.h" #include "display.h" #include "segtype.h" /* * After much thought I have decided it is easier, * and probably no less efficient, to convert the * pe->le map to a full le->pe map, and then * process this to get the segments form that * we're after. Any code which goes directly from * the pe->le map to segments would be gladly * accepted, if it is less complicated than this * file. */ struct pe_specifier { struct physical_volume *pv; uint32_t pe; }; struct lv_map { struct logical_volume *lv; uint32_t stripes; uint32_t stripe_size; struct pe_specifier *map; }; static struct dm_hash_table *_create_lv_maps(struct dm_pool *mem, struct volume_group *vg) { struct dm_hash_table *maps = dm_hash_create(32); struct lv_list *ll; struct lv_map *lvm; if (!maps) { log_error("Unable to create hash table for holding " "extent maps."); return NULL; } dm_list_iterate_items(ll, &vg->lvs) { if (ll->lv->status & SNAPSHOT) continue; if (!(lvm = dm_pool_alloc(mem, sizeof(*lvm)))) goto_bad; lvm->lv = ll->lv; /* * Alloc 1 extra element, so the loop in _area_length() and * _check_stripe() finds the last map member as noncontinuous. */ if (!(lvm->map = dm_pool_zalloc(mem, sizeof(*lvm->map) * (ll->lv->le_count + 1)))) goto_bad; if (!dm_hash_insert(maps, ll->lv->name, lvm)) goto_bad; } return maps; bad: dm_hash_destroy(maps); return NULL; } static int _fill_lv_array(struct lv_map **lvs, struct dm_hash_table *maps, struct disk_list *dl) { struct lvd_list *ll; struct lv_map *lvm; memset(lvs, 0, sizeof(*lvs) * MAX_LV); dm_list_iterate_items(ll, &dl->lvds) { if (!(lvm = dm_hash_lookup(maps, strrchr((char *)ll->lvd.lv_name, '/') + 1))) { log_error("Physical volume (%s) contains an " "unknown logical volume (%s).", dev_name(dl->dev), ll->lvd.lv_name); return 0; } lvm->stripes = ll->lvd.lv_stripes; lvm->stripe_size = ll->lvd.lv_stripesize; lvs[ll->lvd.lv_number] = lvm; } return 1; } static int _fill_maps(struct dm_hash_table *maps, struct volume_group *vg, struct dm_list *pvds) { struct disk_list *dl; struct physical_volume *pv; struct lv_map *lvms[MAX_LV], *lvm; struct pe_disk *e; uint32_t i, lv_num, le; dm_list_iterate_items(dl, pvds) { if (!(pv = find_pv(vg, dl->dev))) { log_error("PV %s not found.", dl->dev->pvid); return 0; } e = dl->extents; /* build an array of lv's for this pv */ if (!_fill_lv_array(lvms, maps, dl)) return_0; for (i = 0; i < dl->pvd.pe_total; i++) { lv_num = e[i].lv_num; if (lv_num == UNMAPPED_EXTENT) continue; else { lv_num--; lvm = lvms[lv_num]; if (!lvm) { log_error("Invalid LV in extent map " "(PV %s, PE %" PRIu32 ", LV %" PRIu32 ", LE %" PRIu32 ")", dev_name(pv->dev), i, lv_num, e[i].le_num); return 0; } le = e[i].le_num; if (le >= lvm->lv->le_count) { log_error("logical extent number " "out of bounds"); return 0; } if (lvm->map[le].pv) { log_error("logical extent (%u) " "already mapped.", le); return 0; } lvm->map[le].pv = pv; lvm->map[le].pe = i; } } } return 1; } static int _check_single_map(struct lv_map *lvm) { uint32_t i; for (i = 0; i < lvm->lv->le_count; i++) { if (!lvm->map[i].pv) { log_error("Logical volume (%s) contains an incomplete " "mapping table.", lvm->lv->name); return 0; } } return 1; } static int _check_maps_are_complete(struct dm_hash_table *maps) { struct dm_hash_node *n; struct lv_map *lvm; for (n = dm_hash_get_first(maps); n; n = dm_hash_get_next(maps, n)) { lvm = (struct lv_map *) dm_hash_get_data(maps, n); if (!_check_single_map(lvm)) return_0; } return 1; } static uint32_t _area_length(struct lv_map *lvm, uint32_t le) { uint32_t len = 0; do len++; while ((lvm->map[le + len].pv == lvm->map[le].pv) && (lvm->map[le].pv && lvm->map[le + len].pe == lvm->map[le].pe + len)); return len; } static int _read_linear(struct cmd_context *cmd, struct lv_map *lvm) { uint32_t le = 0, len; struct lv_segment *seg; struct segment_type *segtype; if (!(segtype = get_segtype_from_string(cmd, "striped"))) return_0; while (le < lvm->lv->le_count) { len = _area_length(lvm, le); if (!(seg = alloc_lv_segment(segtype, lvm->lv, le, len, 0, 0, NULL, NULL, 1, len, 0, 0, 0, NULL))) { log_error("Failed to allocate linear segment."); return 0; } if (!set_lv_segment_area_pv(seg, 0, lvm->map[le].pv, lvm->map[le].pe)) return_0; dm_list_add(&lvm->lv->segments, &seg->list); le += seg->len; } return 1; } static int _check_stripe(struct lv_map *lvm, uint32_t area_count, uint32_t area_len, uint32_t base_le, uint32_t total_area_len) { uint32_t st; /* * Is the next physical extent in every stripe adjacent to the last? */ for (st = 0; st < area_count; st++) if ((lvm->map[base_le + st * total_area_len + area_len].pv != lvm->map[base_le + st * total_area_len].pv) || (lvm->map[base_le + st * total_area_len].pv && lvm->map[base_le + st * total_area_len + area_len].pe != lvm->map[base_le + st * total_area_len].pe + area_len)) return 0; return 1; } static int _read_stripes(struct cmd_context *cmd, struct lv_map *lvm) { uint32_t st, first_area_le = 0, total_area_len; uint32_t area_len; struct lv_segment *seg; struct segment_type *segtype; /* * Work out overall striped length */ if (lvm->lv->le_count % lvm->stripes) { log_error("Number of stripes (%u) incompatible " "with logical extent count (%u) for %s", lvm->stripes, lvm->lv->le_count, lvm->lv->name); } total_area_len = lvm->lv->le_count / lvm->stripes; if (!(segtype = get_segtype_from_string(cmd, "striped"))) return_0; while (first_area_le < total_area_len) { area_len = 1; /* * Find how many extents are contiguous in all stripes * and so can form part of this segment */ while (_check_stripe(lvm, lvm->stripes, area_len, first_area_le, total_area_len)) area_len++; if (!(seg = alloc_lv_segment(segtype, lvm->lv, lvm->stripes * first_area_le, lvm->stripes * area_len, 0, lvm->stripe_size, NULL, NULL, lvm->stripes, area_len, 0, 0, 0, NULL))) { log_error("Failed to allocate striped segment."); return 0; } /* * Set up start positions of each stripe in this segment */ for (st = 0; st < seg->area_count; st++) if (!set_lv_segment_area_pv(seg, st, lvm->map[first_area_le + st * total_area_len].pv, lvm->map[first_area_le + st * total_area_len].pe)) return_0; dm_list_add(&lvm->lv->segments, &seg->list); first_area_le += area_len; } return 1; } static int _build_segments(struct cmd_context *cmd, struct lv_map *lvm) { return (lvm->stripes > 1 ? _read_stripes(cmd, lvm) : _read_linear(cmd, lvm)); } static int _build_all_segments(struct cmd_context *cmd, struct dm_hash_table *maps) { struct dm_hash_node *n; struct lv_map *lvm; for (n = dm_hash_get_first(maps); n; n = dm_hash_get_next(maps, n)) { lvm = (struct lv_map *) dm_hash_get_data(maps, n); if (!_build_segments(cmd, lvm)) return_0; } return 1; } int import_extents(struct cmd_context *cmd, struct volume_group *vg, struct dm_list *pvds) { int r = 0; struct dm_pool *scratch = dm_pool_create("lvm1 import_extents", 10 * 1024); struct dm_hash_table *maps; if (!scratch) return_0; if (!(maps = _create_lv_maps(scratch, vg))) { log_error("Couldn't allocate logical volume maps."); goto out; } if (!_fill_maps(maps, vg, pvds)) { log_error("Couldn't fill logical volume maps."); goto out; } if (!_check_maps_are_complete(maps) && !(vg->status & PARTIAL_VG)) goto_out; if (!_build_all_segments(cmd, maps)) { log_error("Couldn't build extent segments."); goto out; } r = 1; out: if (maps) dm_hash_destroy(maps); dm_pool_destroy(scratch); return r; } lvm2-2.02.98/lib/format1/disk-rep.h0000640000175000017500000001744512037016272015531 0ustar blankblank/* * Copyright (C) 2001-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 DISK_REP_FORMAT1_H #define DISK_REP_FORMAT1_H #include "lvm-types.h" #include "metadata.h" #include "toolcontext.h" #define MAX_PV 256 #define MAX_LV 256 #define MAX_VG 99 #define LVM_BLK_MAJOR 58 #define MAX_PV_SIZE ((uint32_t) -1) /* 2TB in sectors - 1 */ #define MIN_PE_SIZE (8192L >> SECTOR_SHIFT) /* 8 KB in sectors */ #define MAX_PE_SIZE (16L * 1024L * (1024L >> SECTOR_SHIFT) * 1024L) #define PE_SIZE_PV_SIZE_REL 5 /* PV size must be at least 5 times PE size */ #define MAX_LE_TOTAL 65534 /* 2^16 - 2 */ #define MAX_PE_TOTAL ((uint32_t) -2) #define UNMAPPED_EXTENT 0 /* volume group */ #define VG_ACTIVE 0x01 /* vg_status */ #define VG_EXPORTED 0x02 /* " */ #define VG_EXTENDABLE 0x04 /* " */ #define VG_READ 0x01 /* vg_access */ #define VG_WRITE 0x02 /* " */ #define VG_CLUSTERED 0x04 /* " */ #define VG_SHARED 0x08 /* " */ /* logical volume */ #define LV_ACTIVE 0x01 /* lv_status */ #define LV_SPINDOWN 0x02 /* " */ #define LV_PERSISTENT_MINOR 0x04 /* " */ #define LV_READ 0x01 /* lv_access */ #define LV_WRITE 0x02 /* " */ #define LV_SNAPSHOT 0x04 /* " */ #define LV_SNAPSHOT_ORG 0x08 /* " */ #define LV_BADBLOCK_ON 0x01 /* lv_badblock */ #define LV_STRICT 0x01 /* lv_allocation */ #define LV_CONTIGUOUS 0x02 /* " */ /* physical volume */ #define PV_ACTIVE 0x01 /* pv_status */ #define PV_ALLOCATABLE 0x02 /* pv_allocatable */ #define EXPORTED_TAG "PV_EXP" /* Identifier for exported PV */ #define IMPORTED_TAG "PV_IMP" /* Identifier for imported PV */ struct data_area { uint32_t base; uint32_t size; } __attribute__ ((packed)); struct pv_disk { int8_t id[2]; uint16_t version; /* lvm version */ struct data_area pv_on_disk; struct data_area vg_on_disk; struct data_area pv_uuidlist_on_disk; struct data_area lv_on_disk; struct data_area pe_on_disk; int8_t pv_uuid[NAME_LEN]; int8_t vg_name[NAME_LEN]; int8_t system_id[NAME_LEN]; /* for vgexport/vgimport */ uint32_t pv_major; uint32_t pv_number; uint32_t pv_status; uint32_t pv_allocatable; uint32_t pv_size; uint32_t lv_cur; uint32_t pe_size; uint32_t pe_total; uint32_t pe_allocated; /* only present on version == 2 pv's */ uint32_t pe_start; } __attribute__ ((packed)); struct lv_disk { int8_t lv_name[NAME_LEN]; int8_t vg_name[NAME_LEN]; uint32_t lv_access; uint32_t lv_status; uint32_t lv_open; uint32_t lv_dev; uint32_t lv_number; uint32_t lv_mirror_copies; /* for future use */ uint32_t lv_recovery; /* " */ uint32_t lv_schedule; /* " */ uint32_t lv_size; uint32_t lv_snapshot_minor; /* minor number of original */ uint16_t lv_chunk_size; /* chunk size of snapshot */ uint16_t dummy; uint32_t lv_allocated_le; uint32_t lv_stripes; uint32_t lv_stripesize; uint32_t lv_badblock; /* for future use */ uint32_t lv_allocation; uint32_t lv_io_timeout; /* for future use */ uint32_t lv_read_ahead; } __attribute__ ((packed)); struct vg_disk { int8_t vg_uuid[ID_LEN]; /* volume group UUID */ int8_t vg_name_dummy[NAME_LEN - ID_LEN]; /* rest of v1 VG name */ uint32_t vg_number; /* volume group number */ uint32_t vg_access; /* read/write */ uint32_t vg_status; /* active or not */ uint32_t lv_max; /* maximum logical volumes */ uint32_t lv_cur; /* current logical volumes */ uint32_t lv_open; /* open logical volumes */ uint32_t pv_max; /* maximum physical volumes */ uint32_t pv_cur; /* current physical volumes FU */ uint32_t pv_act; /* active physical volumes */ uint32_t dummy; uint32_t vgda; /* volume group descriptor arrays FU */ uint32_t pe_size; /* physical extent size in sectors */ uint32_t pe_total; /* total of physical extents */ uint32_t pe_allocated; /* allocated physical extents */ uint32_t pvg_total; /* physical volume groups FU */ } __attribute__ ((packed)); struct pe_disk { uint16_t lv_num; uint16_t le_num; } __attribute__ ((packed)); struct uuid_list { struct dm_list list; char uuid[NAME_LEN] __attribute__((aligned(8))); }; struct lvd_list { struct dm_list list; struct lv_disk lvd; }; struct disk_list { struct dm_list list; struct dm_pool *mem; struct device *dev; struct pv_disk pvd __attribute__((aligned(8))); struct vg_disk vgd __attribute__((aligned(8))); struct dm_list uuids __attribute__((aligned(8))); struct dm_list lvds __attribute__((aligned(8))); struct pe_disk *extents __attribute__((aligned(8))); }; /* * Layout constants. */ #define METADATA_ALIGN 4096UL #define LVM1_PE_ALIGN (65536UL >> SECTOR_SHIFT) /* PE alignment */ #define METADATA_BASE 0UL #define PV_SIZE 1024UL #define VG_SIZE 4096UL /* * Functions to calculate layout info. */ int calculate_layout(struct disk_list *dl); int calculate_extent_count(struct physical_volume *pv, uint32_t extent_size, uint32_t max_extent_count, uint64_t pe_start); /* * Low level io routines which read/write * disk_lists. */ struct disk_list *read_disk(const struct format_type *fmt, struct device *dev, struct dm_pool *mem, const char *vg_name); int read_pvs_in_vg(const struct format_type *fmt, const char *vg_name, struct dev_filter *filter, struct dm_pool *mem, struct dm_list *results); int write_disks(const struct format_type *fmt, struct dm_list *pvds); /* * Functions to translate to between disk and in * core structures. */ int import_pv(const struct format_type *fmt, struct dm_pool *mem, struct device *dev, struct volume_group *vg, struct physical_volume *pv, struct pv_disk *pvd, struct vg_disk *vgd); int export_pv(struct cmd_context *cmd, struct dm_pool *mem, struct volume_group *vg, struct pv_disk *pvd, struct physical_volume *pv); int import_vg(struct dm_pool *mem, struct volume_group *vg, struct disk_list *dl); int export_vg(struct vg_disk *vgd, struct volume_group *vg); int import_lv(struct cmd_context *cmd, struct dm_pool *mem, struct logical_volume *lv, struct lv_disk *lvd); int import_extents(struct cmd_context *cmd, struct volume_group *vg, struct dm_list *pvds); int export_extents(struct disk_list *dl, uint32_t lv_num, struct logical_volume *lv, struct physical_volume *pv); int import_pvs(const struct format_type *fmt, struct dm_pool *mem, struct volume_group *vg, struct dm_list *pvds); int import_lvs(struct dm_pool *mem, struct volume_group *vg, struct dm_list *pvds); int export_lvs(struct disk_list *dl, struct volume_group *vg, struct physical_volume *pv, const char *dev_dir); int import_snapshots(struct dm_pool *mem, struct volume_group *vg, struct dm_list *pvds); int export_uuids(struct disk_list *dl, struct volume_group *vg); void export_numbers(struct dm_list *pvds, struct volume_group *vg); void export_pv_act(struct dm_list *pvds); int munge_pvd(struct device *dev, struct pv_disk *pvd); int read_vgd(struct device *dev, struct vg_disk *vgd, struct pv_disk *pvd); /* blech */ int get_free_vg_number(struct format_instance *fid, struct dev_filter *filter, const char *candidate_vg, int *result); int export_vg_number(struct format_instance *fid, struct dm_list *pvds, const char *vg_name, struct dev_filter *filter); #endif lvm2-2.02.98/lib/format1/disk-rep.c0000640000175000017500000004077212037016272015523 0ustar blankblank/* * 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 "disk-rep.h" #include "xlate.h" #include "filter.h" #include "lvmcache.h" #include #define xx16(v) disk->v = xlate16(disk->v) #define xx32(v) disk->v = xlate32(disk->v) #define xx64(v) disk->v = xlate64(disk->v) /* * Functions to perform the endian conversion * between disk and core. The same code works * both ways of course. */ static void _xlate_pvd(struct pv_disk *disk) { xx16(version); xx32(pv_on_disk.base); xx32(pv_on_disk.size); xx32(vg_on_disk.base); xx32(vg_on_disk.size); xx32(pv_uuidlist_on_disk.base); xx32(pv_uuidlist_on_disk.size); xx32(lv_on_disk.base); xx32(lv_on_disk.size); xx32(pe_on_disk.base); xx32(pe_on_disk.size); xx32(pv_major); xx32(pv_number); xx32(pv_status); xx32(pv_allocatable); xx32(pv_size); xx32(lv_cur); xx32(pe_size); xx32(pe_total); xx32(pe_allocated); xx32(pe_start); } static void _xlate_lvd(struct lv_disk *disk) { xx32(lv_access); xx32(lv_status); xx32(lv_open); xx32(lv_dev); xx32(lv_number); xx32(lv_mirror_copies); xx32(lv_recovery); xx32(lv_schedule); xx32(lv_size); xx32(lv_snapshot_minor); xx16(lv_chunk_size); xx16(dummy); xx32(lv_allocated_le); xx32(lv_stripes); xx32(lv_stripesize); xx32(lv_badblock); xx32(lv_allocation); xx32(lv_io_timeout); xx32(lv_read_ahead); } static void _xlate_vgd(struct vg_disk *disk) { xx32(vg_number); xx32(vg_access); xx32(vg_status); xx32(lv_max); xx32(lv_cur); xx32(lv_open); xx32(pv_max); xx32(pv_cur); xx32(pv_act); xx32(dummy); xx32(vgda); xx32(pe_size); xx32(pe_total); xx32(pe_allocated); xx32(pvg_total); } static void _xlate_extents(struct pe_disk *extents, uint32_t count) { unsigned i; for (i = 0; i < count; i++) { extents[i].lv_num = xlate16(extents[i].lv_num); extents[i].le_num = xlate16(extents[i].le_num); } } /* * Handle both minor metadata formats. */ static int _munge_formats(struct pv_disk *pvd) { uint32_t pe_start; unsigned b, e; switch (pvd->version) { case 1: pvd->pe_start = ((pvd->pe_on_disk.base + pvd->pe_on_disk.size) >> SECTOR_SHIFT); break; case 2: pvd->version = 1; pe_start = pvd->pe_start << SECTOR_SHIFT; pvd->pe_on_disk.size = pe_start - pvd->pe_on_disk.base; break; default: return 0; } /* UUID too long? */ if (pvd->pv_uuid[ID_LEN]) { /* Retain ID_LEN chars from end */ for (e = ID_LEN; e < sizeof(pvd->pv_uuid); e++) { if (!pvd->pv_uuid[e]) { e--; break; } } for (b = 0; b < ID_LEN; b++) { pvd->pv_uuid[b] = pvd->pv_uuid[++e - ID_LEN]; /* FIXME Remove all invalid chars */ if (pvd->pv_uuid[b] == '/') pvd->pv_uuid[b] = '#'; } memset(&pvd->pv_uuid[ID_LEN], 0, sizeof(pvd->pv_uuid) - ID_LEN); } /* If UUID is missing, create one */ if (pvd->pv_uuid[0] == '\0') { uuid_from_num((char *)pvd->pv_uuid, pvd->pv_number); pvd->pv_uuid[ID_LEN] = '\0'; } return 1; } /* * If exported, remove "PV_EXP" from end of VG name */ static void _munge_exported_vg(struct pv_disk *pvd) { int l; size_t s; /* Return if PV not in a VG */ if ((!*pvd->vg_name)) return; /* FIXME also check vgd->status & VG_EXPORTED? */ l = strlen((char *)pvd->vg_name); s = sizeof(EXPORTED_TAG); if (!strncmp((char *)pvd->vg_name + l - s + 1, EXPORTED_TAG, s)) { pvd->vg_name[l - s + 1] = '\0'; pvd->pv_status |= VG_EXPORTED; } } int munge_pvd(struct device *dev, struct pv_disk *pvd) { _xlate_pvd(pvd); if (pvd->id[0] != 'H' || pvd->id[1] != 'M') { log_very_verbose("%s does not have a valid LVM1 PV identifier", dev_name(dev)); return 0; } if (!_munge_formats(pvd)) { log_very_verbose("format1: Unknown metadata version %d " "found on %s", pvd->version, dev_name(dev)); return 0; } /* If VG is exported, set VG name back to the real name */ _munge_exported_vg(pvd); return 1; } static int _read_pvd(struct device *dev, struct pv_disk *pvd) { if (!dev_read(dev, UINT64_C(0), sizeof(*pvd), pvd)) { log_very_verbose("Failed to read PV data from %s", dev_name(dev)); return 0; } return munge_pvd(dev, pvd); } static int _read_lvd(struct device *dev, uint64_t pos, struct lv_disk *disk) { if (!dev_read(dev, pos, sizeof(*disk), disk)) return_0; _xlate_lvd(disk); return 1; } int read_vgd(struct device *dev, struct vg_disk *vgd, struct pv_disk *pvd) { uint64_t pos = pvd->vg_on_disk.base; if (!dev_read(dev, pos, sizeof(*vgd), vgd)) return_0; _xlate_vgd(vgd); if ((vgd->lv_max > MAX_LV) || (vgd->pv_max > MAX_PV)) return_0; /* If UUID is missing, create one */ if (vgd->vg_uuid[0] == '\0') uuid_from_num((char *)vgd->vg_uuid, vgd->vg_number); return 1; } static int _read_uuids(struct disk_list *data) { unsigned num_read = 0; struct uuid_list *ul; char buffer[NAME_LEN] __attribute__((aligned(8))); uint64_t pos = data->pvd.pv_uuidlist_on_disk.base; uint64_t end = pos + data->pvd.pv_uuidlist_on_disk.size; while (pos < end && num_read < data->vgd.pv_cur) { if (!dev_read(data->dev, pos, sizeof(buffer), buffer)) return_0; if (!(ul = dm_pool_alloc(data->mem, sizeof(*ul)))) return_0; memcpy(ul->uuid, buffer, NAME_LEN); ul->uuid[NAME_LEN - 1] = '\0'; dm_list_add(&data->uuids, &ul->list); pos += NAME_LEN; num_read++; } return 1; } static int _check_lvd(struct lv_disk *lvd) { return !(lvd->lv_name[0] == '\0'); } static int _read_lvs(struct disk_list *data) { unsigned int i, lvs_read = 0; uint64_t pos; struct lvd_list *ll; struct vg_disk *vgd = &data->vgd; for (i = 0; (i < vgd->lv_max) && (lvs_read < vgd->lv_cur); i++) { pos = data->pvd.lv_on_disk.base + (i * sizeof(struct lv_disk)); ll = dm_pool_alloc(data->mem, sizeof(*ll)); if (!ll) return_0; if (!_read_lvd(data->dev, pos, &ll->lvd)) return_0; if (!_check_lvd(&ll->lvd)) continue; lvs_read++; dm_list_add(&data->lvds, &ll->list); } return 1; } static int _read_extents(struct disk_list *data) { size_t len = sizeof(struct pe_disk) * data->pvd.pe_total; struct pe_disk *extents = dm_pool_alloc(data->mem, len); uint64_t pos = data->pvd.pe_on_disk.base; if (!extents) return_0; if (!dev_read(data->dev, pos, len, extents)) return_0; _xlate_extents(extents, data->pvd.pe_total); data->extents = extents; return 1; } static void __update_lvmcache(const struct format_type *fmt, struct disk_list *dl, struct device *dev, const char *vgid, unsigned exported) { struct lvmcache_info *info; const char *vgname = *((char *)dl->pvd.vg_name) ? (char *)dl->pvd.vg_name : fmt->orphan_vg_name; if (!(info = lvmcache_add(fmt->labeller, (char *)dl->pvd.pv_uuid, dev, vgname, vgid, exported ? EXPORTED_VG : 0))) { stack; return; } lvmcache_set_device_size(info, ((uint64_t)xlate32(dl->pvd.pv_size)) << SECTOR_SHIFT); lvmcache_del_mdas(info); lvmcache_make_valid(info); } static struct disk_list *__read_disk(const struct format_type *fmt, struct device *dev, struct dm_pool *mem, const char *vg_name) { struct disk_list *dl = dm_pool_zalloc(mem, sizeof(*dl)); const char *name = dev_name(dev); if (!dl) return_NULL; dl->dev = dev; dl->mem = mem; dm_list_init(&dl->uuids); dm_list_init(&dl->lvds); if (!_read_pvd(dev, &dl->pvd)) goto_bad; /* * is it an orphan ? */ if (!*dl->pvd.vg_name) { log_very_verbose("%s is not a member of any format1 VG", name); __update_lvmcache(fmt, dl, dev, fmt->orphan_vg_name, 0); return (vg_name) ? NULL : dl; } if (!read_vgd(dl->dev, &dl->vgd, &dl->pvd)) { log_error("Failed to read VG data from PV (%s)", name); __update_lvmcache(fmt, dl, dev, fmt->orphan_vg_name, 0); goto bad; } if (vg_name && strcmp(vg_name, (char *)dl->pvd.vg_name)) { log_very_verbose("%s is not a member of the VG %s", name, vg_name); __update_lvmcache(fmt, dl, dev, fmt->orphan_vg_name, 0); goto bad; } __update_lvmcache(fmt, dl, dev, (char *)dl->vgd.vg_uuid, dl->vgd.vg_status & VG_EXPORTED); if (!_read_uuids(dl)) { log_error("Failed to read PV uuid list from %s", name); goto bad; } if (!_read_lvs(dl)) { log_error("Failed to read LV's from %s", name); goto bad; } if (!_read_extents(dl)) { log_error("Failed to read extents from %s", name); goto bad; } log_very_verbose("Found %s in %sVG %s", name, (dl->vgd.vg_status & VG_EXPORTED) ? "exported " : "", dl->pvd.vg_name); return dl; bad: dm_pool_free(dl->mem, dl); return NULL; } struct disk_list *read_disk(const struct format_type *fmt, struct device *dev, struct dm_pool *mem, const char *vg_name) { struct disk_list *dl; if (!dev_open_readonly(dev)) return_NULL; dl = __read_disk(fmt, dev, mem, vg_name); if (!dev_close(dev)) stack; return dl; } static void _add_pv_to_list(struct dm_list *head, struct disk_list *data) { struct pv_disk *pvd; struct disk_list *diskl; dm_list_iterate_items(diskl, head) { pvd = &diskl->pvd; if (!strncmp((char *)data->pvd.pv_uuid, (char *)pvd->pv_uuid, sizeof(pvd->pv_uuid))) { if (!dev_subsystem_part_major(data->dev)) { log_very_verbose("Ignoring duplicate PV %s on " "%s", pvd->pv_uuid, dev_name(data->dev)); return; } log_very_verbose("Duplicate PV %s - using %s %s", pvd->pv_uuid, dev_subsystem_name(data->dev), dev_name(data->dev)); dm_list_del(&diskl->list); break; } } dm_list_add(head, &data->list); } struct _read_pvs_in_vg_baton { const char *vg_name; struct dm_list *head; struct disk_list *data; struct dm_pool *mem; int empty; }; static int _read_pv_in_vg(struct lvmcache_info *info, void *baton) { struct _read_pvs_in_vg_baton *b = baton; b->empty = 0; if (!lvmcache_device(info) || !(b->data = read_disk(lvmcache_fmt(info), lvmcache_device(info), b->mem, b->vg_name))) return 0; /* stop here */ _add_pv_to_list(b->head, b->data); return 1; } /* * Build a list of pv_d's structures, allocated from mem. * We keep track of the first object allocated from the pool * so we can free off all the memory if something goes wrong. */ int read_pvs_in_vg(const struct format_type *fmt, const char *vg_name, struct dev_filter *filter, struct dm_pool *mem, struct dm_list *head) { struct dev_iter *iter; struct device *dev; struct lvmcache_vginfo *vginfo; struct _read_pvs_in_vg_baton baton; baton.head = head; baton.empty = 1; baton.data = NULL; baton.mem = mem; baton.vg_name = vg_name; /* Fast path if we already saw this VG and cached the list of PVs */ if (vg_name && (vginfo = lvmcache_vginfo_from_vgname(vg_name, NULL))) { lvmcache_foreach_pv(vginfo, _read_pv_in_vg, &baton); if (!baton.empty) { /* Did we find the whole VG? */ if (!vg_name || is_orphan_vg(vg_name) || (baton.data && *baton.data->pvd.vg_name && dm_list_size(head) == baton.data->vgd.pv_cur)) return 1; /* Failed */ dm_list_init(head); /* vgcache_del(vg_name); */ } } if (!(iter = dev_iter_create(filter, 1))) { log_error("read_pvs_in_vg: dev_iter_create failed"); return 0; } /* Otherwise do a complete scan */ for (dev = dev_iter_get(iter); dev; dev = dev_iter_get(iter)) { if ((baton.data = read_disk(fmt, dev, mem, vg_name))) { _add_pv_to_list(head, baton.data); } } dev_iter_destroy(iter); if (dm_list_empty(head)) return 0; return 1; } static int _write_vgd(struct disk_list *data) { struct vg_disk *vgd = &data->vgd; uint64_t pos = data->pvd.vg_on_disk.base; log_debug("Writing %s VG metadata to %s at %" PRIu64 " len %" PRIsize_t, data->pvd.vg_name, dev_name(data->dev), pos, sizeof(*vgd)); _xlate_vgd(vgd); if (!dev_write(data->dev, pos, sizeof(*vgd), vgd)) return_0; _xlate_vgd(vgd); return 1; } static int _write_uuids(struct disk_list *data) { struct uuid_list *ul; uint64_t pos = data->pvd.pv_uuidlist_on_disk.base; uint64_t end = pos + data->pvd.pv_uuidlist_on_disk.size; dm_list_iterate_items(ul, &data->uuids) { if (pos >= end) { log_error("Too many uuids to fit on %s", dev_name(data->dev)); return 0; } log_debug("Writing %s uuidlist to %s at %" PRIu64 " len %d", data->pvd.vg_name, dev_name(data->dev), pos, NAME_LEN); if (!dev_write(data->dev, pos, NAME_LEN, ul->uuid)) return_0; pos += NAME_LEN; } return 1; } static int _write_lvd(struct device *dev, uint64_t pos, struct lv_disk *disk) { log_debug("Writing %s LV %s metadata to %s at %" PRIu64 " len %" PRIsize_t, disk->vg_name, disk->lv_name, dev_name(dev), pos, sizeof(*disk)); _xlate_lvd(disk); if (!dev_write(dev, pos, sizeof(*disk), disk)) return_0; _xlate_lvd(disk); return 1; } static int _write_lvs(struct disk_list *data) { struct lvd_list *ll; uint64_t pos, offset; pos = data->pvd.lv_on_disk.base; if (!dev_set(data->dev, pos, data->pvd.lv_on_disk.size, 0)) { log_error("Couldn't zero lv area on device '%s'", dev_name(data->dev)); return 0; } dm_list_iterate_items(ll, &data->lvds) { offset = sizeof(struct lv_disk) * ll->lvd.lv_number; if (offset + sizeof(struct lv_disk) > data->pvd.lv_on_disk.size) { log_error("lv_number %d too large", ll->lvd.lv_number); return 0; } if (!_write_lvd(data->dev, pos + offset, &ll->lvd)) return_0; } return 1; } static int _write_extents(struct disk_list *data) { size_t len = sizeof(struct pe_disk) * data->pvd.pe_total; struct pe_disk *extents = data->extents; uint64_t pos = data->pvd.pe_on_disk.base; log_debug("Writing %s extents metadata to %s at %" PRIu64 " len %" PRIsize_t, data->pvd.vg_name, dev_name(data->dev), pos, len); _xlate_extents(extents, data->pvd.pe_total); if (!dev_write(data->dev, pos, len, extents)) return_0; _xlate_extents(extents, data->pvd.pe_total); return 1; } static int _write_pvd(struct disk_list *data) { char *buf; uint64_t pos = data->pvd.pv_on_disk.base; size_t size = data->pvd.pv_on_disk.size; if (size < sizeof(struct pv_disk)) { log_error("Invalid PV structure size."); return 0; } /* Make sure that the gap between the PV structure and the next one is zeroed in order to make non LVM tools happy (idea from AED) */ buf = dm_zalloc(size); if (!buf) { log_error("Couldn't allocate temporary PV buffer."); return 0; } memcpy(buf, &data->pvd, sizeof(struct pv_disk)); log_debug("Writing %s PV metadata to %s at %" PRIu64 " len %" PRIsize_t, data->pvd.vg_name, dev_name(data->dev), pos, size); _xlate_pvd((struct pv_disk *) buf); if (!dev_write(data->dev, pos, size, buf)) { dm_free(buf); return_0; } dm_free(buf); return 1; } /* * assumes the device has been opened. */ static int __write_all_pvd(const struct format_type *fmt __attribute__((unused)), struct disk_list *data) { const char *pv_name = dev_name(data->dev); if (!_write_pvd(data)) { log_error("Failed to write PV structure onto %s", pv_name); return 0; } /* vgcache_add(data->pvd.vg_name, data->vgd.vg_uuid, data->dev, fmt); */ /* * Stop here for orphan pv's. */ if (data->pvd.vg_name[0] == '\0') { /* if (!test_mode()) vgcache_add(data->pvd.vg_name, NULL, data->dev, fmt); */ return 1; } /* if (!test_mode()) vgcache_add(data->pvd.vg_name, data->vgd.vg_uuid, data->dev, fmt); */ if (!_write_vgd(data)) { log_error("Failed to write VG data to %s", pv_name); return 0; } if (!_write_uuids(data)) { log_error("Failed to write PV uuid list to %s", pv_name); return 0; } if (!_write_lvs(data)) { log_error("Failed to write LV's to %s", pv_name); return 0; } if (!_write_extents(data)) { log_error("Failed to write extents to %s", pv_name); return 0; } return 1; } /* * opens the device and hands to the above fn. */ static int _write_all_pvd(const struct format_type *fmt, struct disk_list *data) { int r; if (!dev_open(data->dev)) return_0; r = __write_all_pvd(fmt, data); if (!dev_close(data->dev)) stack; return r; } /* * Writes all the given pv's to disk. Does very * little sanity checking, so make sure correct * data is passed to here. */ int write_disks(const struct format_type *fmt, struct dm_list *pvs) { struct disk_list *dl; dm_list_iterate_items(dl, pvs) { if (!(_write_all_pvd(fmt, dl))) return_0; log_very_verbose("Successfully wrote data to %s", dev_name(dl->dev)); } return 1; } lvm2-2.02.98/lib/format1/layout.c0000640000175000017500000001013312037016272015306 0ustar blankblank/* * Copyright (C) 2001-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 */ #include "lib.h" #include "disk-rep.h" /* * Only works with powers of 2. */ static uint32_t _round_up(uint32_t n, uint32_t size) { size--; return (n + size) & ~size; } /* Unused. static uint32_t _div_up(uint32_t n, uint32_t size) { return _round_up(n, size) / size; } */ /* * Each chunk of metadata should be aligned to * METADATA_ALIGN. */ static uint32_t _next_base(struct data_area *area) { return _round_up(area->base + area->size, METADATA_ALIGN); } /* * Quick calculation based on pe_start. */ static int _adjust_pe_on_disk(struct pv_disk *pvd) { uint32_t pe_start = pvd->pe_start << SECTOR_SHIFT; if (pe_start < pvd->pe_on_disk.base + pvd->pe_on_disk.size) return 0; pvd->pe_on_disk.size = pe_start - pvd->pe_on_disk.base; return 1; } static void _calc_simple_layout(struct pv_disk *pvd) { pvd->pv_on_disk.base = METADATA_BASE; pvd->pv_on_disk.size = PV_SIZE; pvd->vg_on_disk.base = _next_base(&pvd->pv_on_disk); pvd->vg_on_disk.size = VG_SIZE; pvd->pv_uuidlist_on_disk.base = _next_base(&pvd->vg_on_disk); pvd->pv_uuidlist_on_disk.size = MAX_PV * NAME_LEN; pvd->lv_on_disk.base = _next_base(&pvd->pv_uuidlist_on_disk); pvd->lv_on_disk.size = MAX_LV * sizeof(struct lv_disk); pvd->pe_on_disk.base = _next_base(&pvd->lv_on_disk); pvd->pe_on_disk.size = pvd->pe_total * sizeof(struct pe_disk); } static int _check_vg_limits(struct disk_list *dl) { if (dl->vgd.lv_max > MAX_LV) { log_error("MaxLogicalVolumes of %d exceeds format limit of %d " "for VG '%s'", dl->vgd.lv_max, MAX_LV - 1, dl->pvd.vg_name); return 0; } if (dl->vgd.pv_max > MAX_PV) { log_error("MaxPhysicalVolumes of %d exceeds format limit of %d " "for VG '%s'", dl->vgd.pv_max, MAX_PV - 1, dl->pvd.vg_name); return 0; } return 1; } /* * This assumes pe_count and pe_start have already * been calculated correctly. */ int calculate_layout(struct disk_list *dl) { struct pv_disk *pvd = &dl->pvd; _calc_simple_layout(pvd); if (!_adjust_pe_on_disk(pvd)) { log_error("Insufficient space for metadata and PE's."); return 0; } if (!_check_vg_limits(dl)) return 0; return 1; } /* * The number of extents that can fit on a disk is metadata format dependant. * pe_start is any existing value for pe_start */ int calculate_extent_count(struct physical_volume *pv, uint32_t extent_size, uint32_t max_extent_count, uint64_t pe_start) { struct pv_disk *pvd = dm_malloc(sizeof(*pvd)); uint32_t end; if (!pvd) return_0; /* * Guess how many extents will fit, bearing in mind that * one is going to be knocked off at the start of the * next loop. */ if (max_extent_count) pvd->pe_total = max_extent_count + 1; else pvd->pe_total = (pv->size / extent_size); if (pvd->pe_total < PE_SIZE_PV_SIZE_REL) { log_error("Too few extents on %s. Try smaller extent size.", pv_dev_name(pv)); dm_free(pvd); return 0; } do { pvd->pe_total--; _calc_simple_layout(pvd); end = ((pvd->pe_on_disk.base + pvd->pe_on_disk.size + SECTOR_SIZE - 1) >> SECTOR_SHIFT); if (pe_start && end < pe_start) end = pe_start; pvd->pe_start = _round_up(end, LVM1_PE_ALIGN); } while ((pvd->pe_start + ((uint64_t)pvd->pe_total * extent_size)) > pv->size); if (pvd->pe_total > MAX_PE_TOTAL) { log_error("Metadata extent limit (%u) exceeded for %s - " "%u required", MAX_PE_TOTAL, pv_dev_name(pv), pvd->pe_total); dm_free(pvd); return 0; } pv->pe_count = pvd->pe_total; pv->pe_start = pvd->pe_start; /* We can't set pe_size here without breaking LVM1 compatibility */ dm_free(pvd); return 1; } lvm2-2.02.98/lib/format1/format1.h0000640000175000017500000000155012037016272015352 0ustar blankblank/* * 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_FORMAT1_H #define _LVM_FORMAT1_H #include "metadata.h" #include "lvmcache.h" #define FMT_LVM1_NAME "lvm1" #define FMT_LVM1_ORPHAN_VG_NAME ORPHAN_VG_NAME(FMT_LVM1_NAME) #ifdef LVM1_INTERNAL struct format_type *init_lvm1_format(struct cmd_context *cmd); #endif #endif lvm2-2.02.98/lib/format1/Makefile.in0000640000175000017500000000157512037016272015704 0ustar blankblank# # 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 srcdir = @srcdir@ top_srcdir = @top_srcdir@ top_builddir = @top_builddir@ SOURCES =\ disk-rep.c \ format1.c \ import-export.c \ import-extents.c \ layout.c \ lvm1-label.c \ vg_number.c LIB_SHARED = liblvm2format1.$(LIB_SUFFIX) LIB_VERSION = $(LIB_VERSION_LVM) include $(top_builddir)/make.tmpl install: install_lvm2_plugin lvm2-2.02.98/lib/format1/import-export.c0000640000175000017500000003717712037016272016643 0ustar blankblank/* * Copyright (C) 2001-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 */ /* * Translates between disk and in-core formats. */ #include "lib.h" #include "disk-rep.h" #include "lvm-string.h" #include "filter.h" #include "toolcontext.h" #include "segtype.h" #include "pv_alloc.h" #include "display.h" #include "metadata.h" #include static int _check_vg_name(const char *name) { return strlen(name) < NAME_LEN; } /* * Extracts the last part of a path. */ static char *_create_lv_name(struct dm_pool *mem, const char *full_name) { const char *ptr = strrchr(full_name, '/'); if (!ptr) ptr = full_name; else ptr++; return dm_pool_strdup(mem, ptr); } int import_pv(const struct format_type *fmt, struct dm_pool *mem, struct device *dev, struct volume_group *vg, struct physical_volume *pv, struct pv_disk *pvd, struct vg_disk *vgd) { uint64_t size; memset(pv, 0, sizeof(*pv)); memcpy(&pv->id, pvd->pv_uuid, ID_LEN); pv->dev = dev; if (!*pvd->vg_name) pv->vg_name = fmt->orphan_vg_name; else if (!(pv->vg_name = dm_pool_strdup(mem, (char *)pvd->vg_name))) { log_error("Volume Group name allocation failed."); return 0; } memcpy(&pv->vgid, vgd->vg_uuid, sizeof(vg->id)); /* Store system_id from first PV if PV belongs to a VG */ if (vg && !*vg->system_id) strncpy(vg->system_id, (char *)pvd->system_id, NAME_LEN); if (vg && strncmp(vg->system_id, (char *)pvd->system_id, sizeof(pvd->system_id))) log_very_verbose("System ID %s on %s differs from %s for " "volume group", pvd->system_id, pv_dev_name(pv), vg->system_id); /* * If exported, we still need to flag in pv->status too because * we don't always have a struct volume_group when we need this. */ if (pvd->pv_status & VG_EXPORTED) pv->status |= EXPORTED_VG; if (pvd->pv_allocatable) pv->status |= ALLOCATABLE_PV; pv->size = pvd->pv_size; pv->pe_size = pvd->pe_size; pv->pe_start = pvd->pe_start; pv->pe_count = pvd->pe_total; pv->pe_alloc_count = 0; pv->pe_align = 0; pv->is_labelled = 0; /* format1 PVs have no label */ pv->label_sector = 0; /* Fix up pv size if missing or impossibly large */ if (!pv->size || pv->size > (1ULL << 62)) { if (!dev_get_size(dev, &pv->size)) { log_error("%s: Couldn't get size.", pv_dev_name(pv)); return 0; } log_verbose("Fixing up missing format1 size (%s) " "for PV %s", display_size(fmt->cmd, pv->size), pv_dev_name(pv)); if (vg) { size = pv->pe_count * (uint64_t) vg->extent_size + pv->pe_start; if (size > pv->size) log_warn("WARNING: Physical Volume %s is too " "large for underlying device", pv_dev_name(pv)); } } dm_list_init(&pv->tags); dm_list_init(&pv->segments); if (!alloc_pv_segment_whole_pv(mem, pv)) return_0; return 1; } static int _system_id(struct cmd_context *cmd, char *s, const char *prefix) { if (dm_snprintf(s, NAME_LEN, "%s%s%lu", prefix, cmd->hostname, time(NULL)) < 0) { log_error("Generated system_id too long"); return 0; } return 1; } int export_pv(struct cmd_context *cmd, struct dm_pool *mem __attribute__((unused)), struct volume_group *vg, struct pv_disk *pvd, struct physical_volume *pv) { memset(pvd, 0, sizeof(*pvd)); pvd->id[0] = 'H'; pvd->id[1] = 'M'; pvd->version = 1; memcpy(pvd->pv_uuid, pv->id.uuid, ID_LEN); if (pv->vg_name && !is_orphan(pv) && !(pv->status & UNLABELLED_PV)) { if (!_check_vg_name(pv->vg_name)) return_0; strncpy((char *)pvd->vg_name, pv->vg_name, sizeof(pvd->vg_name)); } /* Preserve existing system_id if it exists */ if (vg && *vg->system_id) strncpy((char *)pvd->system_id, vg->system_id, sizeof(pvd->system_id)); /* Is VG already exported or being exported? */ if (vg && vg_is_exported(vg)) { /* Does system_id need setting? */ if (!*vg->system_id || strncmp(vg->system_id, EXPORTED_TAG, sizeof(EXPORTED_TAG) - 1)) { if (!_system_id(cmd, (char *)pvd->system_id, EXPORTED_TAG)) return_0; } if (strlen((char *)pvd->vg_name) + sizeof(EXPORTED_TAG) > sizeof(pvd->vg_name)) { log_error("Volume group name %s too long to export", pvd->vg_name); return 0; } strcat((char *)pvd->vg_name, EXPORTED_TAG); } /* Is VG being imported? */ if (vg && !vg_is_exported(vg) && *vg->system_id && !strncmp(vg->system_id, EXPORTED_TAG, sizeof(EXPORTED_TAG) - 1)) { if (!_system_id(cmd, (char *)pvd->system_id, IMPORTED_TAG)) return_0; } /* Generate system_id if PV is in VG */ if (!pvd->system_id[0]) if (!_system_id(cmd, (char *)pvd->system_id, "")) return_0; /* Update internal system_id if we changed it */ if (vg && (!*vg->system_id || strncmp(vg->system_id, (char *)pvd->system_id, sizeof(pvd->system_id)))) strncpy(vg->system_id, (char *)pvd->system_id, NAME_LEN); //pvd->pv_major = MAJOR(pv->dev); if (pv->status & ALLOCATABLE_PV) pvd->pv_allocatable = PV_ALLOCATABLE; pvd->pv_size = pv->size; pvd->lv_cur = 0; /* this is set when exporting the lv list */ if (vg) pvd->pe_size = vg->extent_size; else pvd->pe_size = pv->pe_size; pvd->pe_total = pv->pe_count; pvd->pe_allocated = pv->pe_alloc_count; pvd->pe_start = pv->pe_start; return 1; } int import_vg(struct dm_pool *mem, struct volume_group *vg, struct disk_list *dl) { struct vg_disk *vgd = &dl->vgd; memcpy(vg->id.uuid, vgd->vg_uuid, ID_LEN); if (!_check_vg_name((char *)dl->pvd.vg_name)) return_0; if (!(vg->name = dm_pool_strdup(mem, (char *)dl->pvd.vg_name))) return_0; if (!(vg->system_id = dm_pool_zalloc(mem, NAME_LEN + 1))) return_0; *vg->system_id = '\0'; if (vgd->vg_status & VG_EXPORTED) vg->status |= EXPORTED_VG; if (vgd->vg_status & VG_EXTENDABLE) vg->status |= RESIZEABLE_VG; if (vgd->vg_access & VG_READ) vg->status |= LVM_READ; if (vgd->vg_access & VG_WRITE) vg->status |= LVM_WRITE; if (vgd->vg_access & VG_CLUSTERED) vg->status |= CLUSTERED; if (vgd->vg_access & VG_SHARED) vg->status |= SHARED; vg->extent_size = vgd->pe_size; vg->extent_count = vgd->pe_total; vg->free_count = vgd->pe_total; vg->max_lv = vgd->lv_max; vg->max_pv = vgd->pv_max; vg->alloc = ALLOC_NORMAL; return 1; } int export_vg(struct vg_disk *vgd, struct volume_group *vg) { memset(vgd, 0, sizeof(*vgd)); memcpy(vgd->vg_uuid, vg->id.uuid, ID_LEN); if (vg->status & LVM_READ) vgd->vg_access |= VG_READ; if (vg->status & LVM_WRITE) vgd->vg_access |= VG_WRITE; if (vg_is_clustered(vg)) vgd->vg_access |= VG_CLUSTERED; if (vg->status & SHARED) vgd->vg_access |= VG_SHARED; if (vg_is_exported(vg)) vgd->vg_status |= VG_EXPORTED; if (vg_is_resizeable(vg)) vgd->vg_status |= VG_EXTENDABLE; vgd->lv_max = vg->max_lv; vgd->lv_cur = vg_visible_lvs(vg) + snapshot_count(vg); vgd->pv_max = vg->max_pv; vgd->pv_cur = vg->pv_count; vgd->pe_size = vg->extent_size; vgd->pe_total = vg->extent_count; vgd->pe_allocated = vg->extent_count - vg->free_count; return 1; } int import_lv(struct cmd_context *cmd, struct dm_pool *mem, struct logical_volume *lv, struct lv_disk *lvd) { if (!(lv->name = _create_lv_name(mem, (char *)lvd->lv_name))) return_0; lv->status |= VISIBLE_LV; if (lvd->lv_status & LV_SPINDOWN) lv->status |= SPINDOWN_LV; if (lvd->lv_status & LV_PERSISTENT_MINOR) { lv->status |= FIXED_MINOR; lv->minor = MINOR(lvd->lv_dev); lv->major = MAJOR(lvd->lv_dev); } else { lv->major = -1; lv->minor = -1; } if (lvd->lv_access & LV_READ) lv->status |= LVM_READ; if (lvd->lv_access & LV_WRITE) lv->status |= LVM_WRITE; if (lvd->lv_badblock) lv->status |= BADBLOCK_ON; /* Drop the unused LV_STRICT here */ if (lvd->lv_allocation & LV_CONTIGUOUS) lv->alloc = ALLOC_CONTIGUOUS; else lv->alloc = ALLOC_NORMAL; if (!lvd->lv_read_ahead) lv->read_ahead = cmd->default_settings.read_ahead; else lv->read_ahead = lvd->lv_read_ahead; lv->size = lvd->lv_size; lv->le_count = lvd->lv_allocated_le; return 1; } static void _export_lv(struct lv_disk *lvd, struct volume_group *vg, struct logical_volume *lv, const char *dev_dir) { memset(lvd, 0, sizeof(*lvd)); snprintf((char *)lvd->lv_name, sizeof(lvd->lv_name), "%s%s/%s", dev_dir, vg->name, lv->name); strcpy((char *)lvd->vg_name, vg->name); if (lv->status & LVM_READ) lvd->lv_access |= LV_READ; if (lv->status & LVM_WRITE) lvd->lv_access |= LV_WRITE; if (lv->status & SPINDOWN_LV) lvd->lv_status |= LV_SPINDOWN; if (lv->status & FIXED_MINOR) { lvd->lv_status |= LV_PERSISTENT_MINOR; lvd->lv_dev = MKDEV(lv->major, lv->minor); } else { lvd->lv_dev = MKDEV(LVM_BLK_MAJOR, lvnum_from_lvid(&lv->lvid)); } if (lv->read_ahead == DM_READ_AHEAD_AUTO || lv->read_ahead == DM_READ_AHEAD_NONE) lvd->lv_read_ahead = 0; else lvd->lv_read_ahead = lv->read_ahead; lvd->lv_stripes = dm_list_item(lv->segments.n, struct lv_segment)->area_count; lvd->lv_stripesize = dm_list_item(lv->segments.n, struct lv_segment)->stripe_size; lvd->lv_size = lv->size; lvd->lv_allocated_le = lv->le_count; if (lv->status & BADBLOCK_ON) lvd->lv_badblock = LV_BADBLOCK_ON; if (lv->alloc == ALLOC_CONTIGUOUS) lvd->lv_allocation |= LV_CONTIGUOUS; } int export_extents(struct disk_list *dl, uint32_t lv_num, struct logical_volume *lv, struct physical_volume *pv) { struct pe_disk *ped; struct lv_segment *seg; uint32_t pe, s; dm_list_iterate_items(seg, &lv->segments) { for (s = 0; s < seg->area_count; s++) { if (!(seg->segtype->flags & SEG_FORMAT1_SUPPORT)) { log_error("Segment type %s in LV %s: " "unsupported by format1", seg->segtype->name, lv->name); return 0; } if (seg_type(seg, s) != AREA_PV) { log_error("Non-PV stripe found in LV %s: " "unsupported by format1", lv->name); return 0; } if (seg_pv(seg, s) != pv) continue; /* not our pv */ for (pe = 0; pe < (seg->len / seg->area_count); pe++) { ped = &dl->extents[pe + seg_pe(seg, s)]; ped->lv_num = lv_num; ped->le_num = (seg->le / seg->area_count) + pe + s * (lv->le_count / seg->area_count); } } } return 1; } int import_pvs(const struct format_type *fmt, struct dm_pool *mem, struct volume_group *vg, struct dm_list *pvds) { struct disk_list *dl; struct pv_list *pvl; vg->pv_count = 0; dm_list_iterate_items(dl, pvds) { if (!(pvl = dm_pool_zalloc(mem, sizeof(*pvl))) || !(pvl->pv = dm_pool_alloc(mem, sizeof(*pvl->pv)))) return_0; if (!import_pv(fmt, mem, dl->dev, vg, pvl->pv, &dl->pvd, &dl->vgd)) return_0; pvl->pv->fmt = fmt; add_pvl_to_vgs(vg, pvl); } return 1; } static struct logical_volume *_add_lv(struct dm_pool *mem, struct volume_group *vg, struct lv_disk *lvd) { struct logical_volume *lv; if (!(lv = alloc_lv(mem))) return_NULL; lvid_from_lvnum(&lv->lvid, &vg->id, lvd->lv_number); if (!import_lv(vg->cmd, mem, lv, lvd)) goto_bad; if (!link_lv_to_vg(vg, lv)) goto_bad; return lv; bad: dm_pool_free(mem, lv); return NULL; } int import_lvs(struct dm_pool *mem, struct volume_group *vg, struct dm_list *pvds) { struct disk_list *dl; struct lvd_list *ll; struct lv_disk *lvd; dm_list_iterate_items(dl, pvds) { dm_list_iterate_items(ll, &dl->lvds) { lvd = &ll->lvd; if (!find_lv(vg, (char *)lvd->lv_name) && !_add_lv(mem, vg, lvd)) return_0; } } return 1; } /* FIXME: tidy */ int export_lvs(struct disk_list *dl, struct volume_group *vg, struct physical_volume *pv, const char *dev_dir) { int r = 0; struct lv_list *ll; struct lvd_list *lvdl; size_t len; uint32_t lv_num; struct dm_hash_table *lvd_hash; if (!_check_vg_name(vg->name)) return_0; if (!(lvd_hash = dm_hash_create(32))) return_0; /* * setup the pv's extents array */ len = sizeof(struct pe_disk) * dl->pvd.pe_total; if (!(dl->extents = dm_pool_zalloc(dl->mem, len))) goto_out; dm_list_iterate_items(ll, &vg->lvs) { if (ll->lv->status & SNAPSHOT) continue; if (!(lvdl = dm_pool_alloc(dl->mem, sizeof(*lvdl)))) goto_out; _export_lv(&lvdl->lvd, vg, ll->lv, dev_dir); lv_num = lvnum_from_lvid(&ll->lv->lvid); lvdl->lvd.lv_number = lv_num; if (!dm_hash_insert(lvd_hash, ll->lv->name, &lvdl->lvd)) goto_out; if (!export_extents(dl, lv_num + 1, ll->lv, pv)) goto_out; if (lv_is_origin(ll->lv)) lvdl->lvd.lv_access |= LV_SNAPSHOT_ORG; if (lv_is_cow(ll->lv)) { lvdl->lvd.lv_access |= LV_SNAPSHOT; lvdl->lvd.lv_chunk_size = ll->lv->snapshot->chunk_size; lvdl->lvd.lv_snapshot_minor = lvnum_from_lvid(&ll->lv->snapshot->origin->lvid); } dm_list_add(&dl->lvds, &lvdl->list); dl->pvd.lv_cur++; } r = 1; out: dm_hash_destroy(lvd_hash); return r; } /* * FIXME: More inefficient code. */ int import_snapshots(struct dm_pool *mem __attribute__((unused)), struct volume_group *vg, struct dm_list *pvds) { struct logical_volume *lvs[MAX_LV] = { 0 }; struct disk_list *dl; struct lvd_list *ll; struct lv_disk *lvd; int lvnum; struct logical_volume *org, *cow; /* build an index of lv numbers */ dm_list_iterate_items(dl, pvds) { dm_list_iterate_items(ll, &dl->lvds) { lvd = &ll->lvd; lvnum = lvd->lv_number; if (lvnum >= MAX_LV) { log_error("Logical volume number " "out of bounds."); return 0; } if (!lvs[lvnum] && !(lvs[lvnum] = find_lv(vg, (char *)lvd->lv_name))) { log_error("Couldn't find logical volume '%s'.", lvd->lv_name); return 0; } } } /* * Now iterate through yet again adding the snapshots. */ dm_list_iterate_items(dl, pvds) { dm_list_iterate_items(ll, &dl->lvds) { lvd = &ll->lvd; if (!(lvd->lv_access & LV_SNAPSHOT)) continue; lvnum = lvd->lv_number; cow = lvs[lvnum]; if (!(org = lvs[lvd->lv_snapshot_minor])) { log_error("Couldn't find origin logical volume " "for snapshot '%s'.", lvd->lv_name); return 0; } /* we may have already added this snapshot */ if (lv_is_cow(cow)) continue; /* insert the snapshot */ if (!vg_add_snapshot(org, cow, NULL, org->le_count, lvd->lv_chunk_size)) { log_error("Couldn't add snapshot."); return 0; } } } return 1; } int export_uuids(struct disk_list *dl, struct volume_group *vg) { struct uuid_list *ul; struct pv_list *pvl; dm_list_iterate_items(pvl, &vg->pvs) { if (!(ul = dm_pool_alloc(dl->mem, sizeof(*ul)))) return_0; memset(ul->uuid, 0, sizeof(ul->uuid)); memcpy(ul->uuid, pvl->pv->id.uuid, ID_LEN); dm_list_add(&dl->uuids, &ul->list); } return 1; } /* * This calculates the nasty pv_number field * used by LVM1. */ void export_numbers(struct dm_list *pvds, struct volume_group *vg __attribute__((unused))) { struct disk_list *dl; int pv_num = 1; dm_list_iterate_items(dl, pvds) dl->pvd.pv_number = pv_num++; } /* * Calculate vg_disk->pv_act. */ void export_pv_act(struct dm_list *pvds) { struct disk_list *dl; int act = 0; dm_list_iterate_items(dl, pvds) if (dl->pvd.pv_status & PV_ACTIVE) act++; dm_list_iterate_items(dl, pvds) dl->vgd.pv_act = act; } int export_vg_number(struct format_instance *fid, struct dm_list *pvds, const char *vg_name, struct dev_filter *filter) { struct disk_list *dl; int vg_num; if (!get_free_vg_number(fid, filter, vg_name, &vg_num)) return_0; dm_list_iterate_items(dl, pvds) dl->vgd.vg_number = vg_num; return 1; } lvm2-2.02.98/lib/format1/lvm1-label.h0000640000175000017500000000134112037016272015733 0ustar blankblank/* * 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 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_LVM1_LABEL_H #define _LVM_LVM1_LABEL_H #include "metadata.h" struct labeller *lvm1_labeller_create(struct format_type *fmt); #endif lvm2-2.02.98/lib/format1/format1.c0000640000175000017500000003735312037016272015357 0ustar blankblank/* * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU 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 "disk-rep.h" #include "limits.h" #include "display.h" #include "toolcontext.h" #include "lvm1-label.h" #include "format1.h" #include "segtype.h" #include "pv_alloc.h" /* VG consistency checks */ static int _check_vgs(struct dm_list *pvs, struct volume_group *vg) { struct dm_list *pvh, *t; struct disk_list *dl = NULL; struct disk_list *first = NULL; uint32_t pv_count = 0; uint32_t exported = 0; int first_time = 1; /* * If there are exported and unexported PVs, ignore exported ones. * This means an active VG won't be affected if disks are inserted * bearing an exported VG with the same name. */ dm_list_iterate_items(dl, pvs) { if (first_time) { exported = dl->pvd.pv_status & VG_EXPORTED; first_time = 0; continue; } if (exported != (dl->pvd.pv_status & VG_EXPORTED)) { /* Remove exported PVs */ dm_list_iterate_safe(pvh, t, pvs) { dl = dm_list_item(pvh, struct disk_list); if (dl->pvd.pv_status & VG_EXPORTED) dm_list_del(pvh); } break; } } /* Remove any PVs with VG structs that differ from the first */ dm_list_iterate_safe(pvh, t, pvs) { dl = dm_list_item(pvh, struct disk_list); if (!first) first = dl; else if (memcmp(&first->vgd, &dl->vgd, sizeof(first->vgd))) { log_error("VG data differs between PVs %s and %s", dev_name(first->dev), dev_name(dl->dev)); log_debug("VG data on %s: %s %s %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32, dev_name(first->dev), first->vgd.vg_uuid, first->vgd.vg_name_dummy, first->vgd.vg_number, first->vgd.vg_access, first->vgd.vg_status, first->vgd.lv_max, first->vgd.lv_cur, first->vgd.lv_open, first->vgd.pv_max, first->vgd.pv_cur, first->vgd.pv_act, first->vgd.dummy, first->vgd.vgda, first->vgd.pe_size, first->vgd.pe_total, first->vgd.pe_allocated, first->vgd.pvg_total); log_debug("VG data on %s: %s %s %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32, dev_name(dl->dev), dl->vgd.vg_uuid, dl->vgd.vg_name_dummy, dl->vgd.vg_number, dl->vgd.vg_access, dl->vgd.vg_status, dl->vgd.lv_max, dl->vgd.lv_cur, dl->vgd.lv_open, dl->vgd.pv_max, dl->vgd.pv_cur, dl->vgd.pv_act, dl->vgd.dummy, dl->vgd.vgda, dl->vgd.pe_size, dl->vgd.pe_total, dl->vgd.pe_allocated, dl->vgd.pvg_total); dm_list_del(pvh); return 0; } pv_count++; } /* On entry to fn, list known to be non-empty */ if (pv_count != first->vgd.pv_cur) { log_error("%d PV(s) found for VG %s: expected %d", pv_count, first->pvd.vg_name, first->vgd.pv_cur); vg->status |= PARTIAL_VG; } return 1; } static int _fix_partial_vg(struct volume_group *vg, struct dm_list *pvs) { uint32_t extent_count = 0; struct disk_list *dl; struct dm_list *pvh; struct pv_list *pvl; struct lv_list *ll; struct lv_segment *seg; /* * FIXME: code should remap missing segments to error segment. * Also current mapping code allocates 1 segment per missing extent. * For now bail out completely - allocated structures are not complete */ dm_list_iterate_items(ll, &vg->lvs) dm_list_iterate_items(seg, &ll->lv->segments) { /* area_count is always 1 here, s == 0 */ if (seg_type(seg, 0) != AREA_PV) continue; if (seg_pv(seg, 0)) continue; log_error("Partial mode support for missing lvm1 PVs and " "partially available LVs is currently not implemented."); return 0; } dm_list_iterate(pvh, pvs) { dl = dm_list_item(pvh, struct disk_list); extent_count += dl->pvd.pe_total; } /* FIXME: move this to one place to pv_manip */ if (!(pvl = dm_pool_zalloc(vg->vgmem, sizeof(*pvl))) || !(pvl->pv = dm_pool_zalloc(vg->vgmem, sizeof(*pvl->pv)))) return_0; /* Use vg uuid with replaced first chars to "missing" as missing PV UUID */ memcpy(&pvl->pv->id.uuid, vg->id.uuid, sizeof(pvl->pv->id.uuid)); memcpy(&pvl->pv->id.uuid, "missing", 7); if (!(pvl->pv->vg_name = dm_pool_strdup(vg->vgmem, vg->name))) goto_out; memcpy(&pvl->pv->vgid, &vg->id, sizeof(vg->id)); pvl->pv->status |= MISSING_PV; dm_list_init(&pvl->pv->tags); dm_list_init(&pvl->pv->segments); pvl->pv->pe_size = vg->extent_size; pvl->pv->pe_count = vg->extent_count - extent_count; if (!alloc_pv_segment_whole_pv(vg->vgmem, pvl->pv)) goto_out; add_pvl_to_vgs(vg, pvl); log_debug("%s: partial VG, allocated missing PV using %d extents.", vg->name, pvl->pv->pe_count); return 1; out: dm_pool_free(vg->vgmem, pvl); return 0; } static struct volume_group *_format1_vg_read(struct format_instance *fid, const char *vg_name, struct metadata_area *mda __attribute__((unused)), int single_device __attribute__((unused))) { struct volume_group *vg; struct disk_list *dl; DM_LIST_INIT(pvs); /* Strip dev_dir if present */ if (vg_name) vg_name = strip_dir(vg_name, fid->fmt->cmd->dev_dir); if (!(vg = alloc_vg("format1_vg_read", fid->fmt->cmd, NULL))) return_NULL; if (!read_pvs_in_vg(fid->fmt, vg_name, fid->fmt->cmd->filter, vg->vgmem, &pvs)) goto_bad; if (dm_list_empty(&pvs)) goto_bad; vg_set_fid(vg, fid); if (!_check_vgs(&pvs, vg)) goto_bad; dl = dm_list_item(pvs.n, struct disk_list); if (!import_vg(vg->vgmem, vg, dl)) goto_bad; if (!import_pvs(fid->fmt, vg->vgmem, vg, &pvs)) goto_bad; if (!import_lvs(vg->vgmem, vg, &pvs)) goto_bad; if (!import_extents(fid->fmt->cmd, vg, &pvs)) goto_bad; if (!import_snapshots(vg->vgmem, vg, &pvs)) goto_bad; /* Fix extents counts by adding missing PV if partial VG */ if ((vg->status & PARTIAL_VG) && !_fix_partial_vg(vg, &pvs)) goto_bad; return vg; bad: release_vg(vg); return NULL; } static struct disk_list *_flatten_pv(struct format_instance *fid, struct dm_pool *mem, struct volume_group *vg, struct physical_volume *pv, const char *dev_dir) { struct disk_list *dl = dm_pool_alloc(mem, sizeof(*dl)); if (!dl) return_NULL; dl->mem = mem; dl->dev = pv->dev; dm_list_init(&dl->uuids); dm_list_init(&dl->lvds); if (!export_pv(fid->fmt->cmd, mem, vg, &dl->pvd, pv) || !export_vg(&dl->vgd, vg) || !export_uuids(dl, vg) || !export_lvs(dl, vg, pv, dev_dir) || !calculate_layout(dl)) { dm_pool_free(mem, dl); return_NULL; } return dl; } static int _flatten_vg(struct format_instance *fid, struct dm_pool *mem, struct volume_group *vg, struct dm_list *pvds, const char *dev_dir, struct dev_filter *filter) { struct pv_list *pvl; struct disk_list *data; dm_list_iterate_items(pvl, &vg->pvs) { if (!(data = _flatten_pv(fid, mem, vg, pvl->pv, dev_dir))) return_0; dm_list_add(pvds, &data->list); } export_numbers(pvds, vg); export_pv_act(pvds); if (!export_vg_number(fid, pvds, vg->name, filter)) return_0; return 1; } static int _format1_vg_write(struct format_instance *fid, struct volume_group *vg, struct metadata_area *mda __attribute__((unused))) { struct dm_pool *mem = dm_pool_create("lvm1 vg_write", VG_MEMPOOL_CHUNK); struct dm_list pvds; int r = 0; if (!mem) return_0; dm_list_init(&pvds); r = (_flatten_vg(fid, mem, vg, &pvds, fid->fmt->cmd->dev_dir, fid->fmt->cmd->filter) && write_disks(fid->fmt, &pvds)); lvmcache_update_vg(vg, 0); dm_pool_destroy(mem); return r; } static int _format1_pv_read(const struct format_type *fmt, const char *pv_name, struct physical_volume *pv, int scan_label_only __attribute__((unused))) { struct dm_pool *mem = dm_pool_create("lvm1 pv_read", 1024); struct disk_list *dl; struct device *dev; int r = 0; log_very_verbose("Reading physical volume data %s from disk", pv_name); if (!mem) return_0; if (!(dev = dev_cache_get(pv_name, fmt->cmd->filter))) goto_out; if (!(dl = read_disk(fmt, dev, mem, NULL))) goto_out; if (!import_pv(fmt, fmt->cmd->mem, dl->dev, NULL, pv, &dl->pvd, &dl->vgd)) goto_out; pv->fmt = fmt; r = 1; out: dm_pool_destroy(mem); return r; } static int _format1_pv_initialise(const struct format_type * fmt, int64_t label_sector __attribute__((unused)), uint64_t pe_start, uint32_t extent_count, uint32_t extent_size, unsigned long data_alignment __attribute__((unused)), unsigned long data_alignment_offset __attribute__((unused)), struct physical_volume * pv) { if (pv->size > MAX_PV_SIZE) pv->size--; if (pv->size > MAX_PV_SIZE) { log_error("Physical volumes cannot be bigger than %s", display_size(fmt->cmd, (uint64_t) MAX_PV_SIZE)); return 0; } /* Nothing more to do if extent size isn't provided */ if (!extent_size) return 1; /* * This works out pe_start and pe_count. */ if (!calculate_extent_count(pv, extent_size, extent_count, pe_start)) return_0; /* Retain existing extent locations exactly */ if (((pe_start || extent_count) && (pe_start != pv->pe_start)) || (extent_count && (extent_count != pv->pe_count))) { log_error("Metadata would overwrite physical extents"); return 0; } return 1; } static int _format1_pv_setup(const struct format_type *fmt, struct physical_volume *pv, struct volume_group *vg) { return _format1_pv_initialise(fmt, -1, 0, 0, vg->extent_size, 0, 0, pv); } static int _format1_lv_setup(struct format_instance *fid, struct logical_volume *lv) { uint64_t max_size = UINT_MAX; if (!*lv->lvid.s) lvid_from_lvnum(&lv->lvid, &lv->vg->id, find_free_lvnum(lv)); if (lv->le_count > MAX_LE_TOTAL) { log_error("logical volumes cannot contain more than " "%d extents.", MAX_LE_TOTAL); return 0; } if (lv->size > max_size) { log_error("logical volumes cannot be larger than %s", display_size(fid->fmt->cmd, max_size)); return 0; } return 1; } static int _format1_pv_write(const struct format_type *fmt, struct physical_volume *pv) { struct dm_pool *mem; struct disk_list *dl; struct dm_list pvs; struct lvmcache_info *info; int pe_count, pe_size, pe_start; int r = 1; if (!(info = lvmcache_add(fmt->labeller, (char *) &pv->id, pv->dev, pv->vg_name, NULL, 0))) return_0; lvmcache_update_pv(info, pv, fmt); lvmcache_del_mdas(info); lvmcache_del_das(info); dm_list_init(&pvs); pe_count = pv->pe_count; pe_size = pv->pe_size; pe_start = pv->pe_start; /* Ensure any residual PE structure is gone */ pv->pe_size = pv->pe_count = 0; pv->pe_start = LVM1_PE_ALIGN; if (!(mem = dm_pool_create("lvm1 pv_write", 1024))) return_0; if (!(dl = dm_pool_alloc(mem, sizeof(*dl)))) goto_bad; dl->mem = mem; dl->dev = pv->dev; dm_list_init(&dl->uuids); dm_list_init(&dl->lvds); if (!export_pv(fmt->cmd, mem, NULL, &dl->pvd, pv)) goto_bad; /* must be set to be able to zero gap after PV structure in dev_write in order to make other disk tools happy */ dl->pvd.pv_on_disk.base = METADATA_BASE; dl->pvd.pv_on_disk.size = PV_SIZE; dl->pvd.pe_on_disk.base = LVM1_PE_ALIGN << SECTOR_SHIFT; dm_list_add(&pvs, &dl->list); if (!write_disks(fmt, &pvs)) goto_bad; goto out; bad: r = 0; out: pv->pe_size = pe_size; pv->pe_count = pe_count; pv->pe_start = pe_start; dm_pool_destroy(mem); return r; } static int _format1_vg_setup(struct format_instance *fid, struct volume_group *vg) { /* just check max_pv and max_lv */ if (!vg->max_lv || vg->max_lv >= MAX_LV) vg->max_lv = MAX_LV - 1; if (!vg->max_pv || vg->max_pv >= MAX_PV) vg->max_pv = MAX_PV - 1; if (vg->extent_size > MAX_PE_SIZE || vg->extent_size < MIN_PE_SIZE) { log_error("Extent size must be between %s and %s", display_size(fid->fmt->cmd, (uint64_t) MIN_PE_SIZE), display_size(fid->fmt->cmd, (uint64_t) MAX_PE_SIZE)); return 0; } if (vg->extent_size % MIN_PE_SIZE) { log_error("Extent size must be multiple of %s", display_size(fid->fmt->cmd, (uint64_t) MIN_PE_SIZE)); return 0; } /* Redundant? */ if (vg->extent_size & (vg->extent_size - 1)) { log_error("Extent size must be power of 2"); return 0; } return 1; } static int _format1_segtype_supported(struct format_instance *fid __attribute__((unused)), const struct segment_type *segtype) { if (!(segtype->flags & SEG_FORMAT1_SUPPORT)) return_0; return 1; } static struct metadata_area_ops _metadata_format1_ops = { .vg_read = _format1_vg_read, .vg_write = _format1_vg_write, }; static struct format_instance *_format1_create_instance(const struct format_type *fmt, const struct format_instance_ctx *fic) { struct format_instance *fid; struct metadata_area *mda; if (!(fid = alloc_fid(fmt, fic))) return_NULL; /* Define a NULL metadata area */ if (!(mda = dm_pool_zalloc(fid->mem, sizeof(*mda)))) { log_error("Unable to allocate metadata area structure " "for lvm1 format"); goto bad; } mda->ops = &_metadata_format1_ops; mda->metadata_locn = NULL; mda->status = 0; dm_list_add(&fid->metadata_areas_in_use, &mda->list); return fid; bad: dm_pool_destroy(fid->mem); return NULL; } static void _format1_destroy_instance(struct format_instance *fid) { if (--fid->ref_count <= 1) dm_pool_destroy(fid->mem); } static void _format1_destroy(struct format_type *fmt) { if (fmt->orphan_vg) free_orphan_vg(fmt->orphan_vg); dm_free(fmt); } static struct format_handler _format1_ops = { .pv_read = _format1_pv_read, .pv_initialise = _format1_pv_initialise, .pv_setup = _format1_pv_setup, .pv_write = _format1_pv_write, .lv_setup = _format1_lv_setup, .vg_setup = _format1_vg_setup, .segtype_supported = _format1_segtype_supported, .create_instance = _format1_create_instance, .destroy_instance = _format1_destroy_instance, .destroy = _format1_destroy, }; #ifdef LVM1_INTERNAL struct format_type *init_lvm1_format(struct cmd_context *cmd) #else /* Shared */ struct format_type *init_format(struct cmd_context *cmd); struct format_type *init_format(struct cmd_context *cmd) #endif { struct format_type *fmt = dm_malloc(sizeof(*fmt)); struct format_instance_ctx fic; struct format_instance *fid; if (!fmt) { log_error("Failed to allocate format1 format type structure."); return NULL; } fmt->cmd = cmd; fmt->ops = &_format1_ops; fmt->name = FMT_LVM1_NAME; fmt->alias = NULL; fmt->orphan_vg_name = FMT_LVM1_ORPHAN_VG_NAME; fmt->features = FMT_RESTRICTED_LVIDS | FMT_ORPHAN_ALLOCATABLE | FMT_RESTRICTED_READAHEAD; fmt->private = NULL; dm_list_init(&fmt->mda_ops); if (!(fmt->labeller = lvm1_labeller_create(fmt))) { log_error("Couldn't create lvm1 label handler."); dm_free(fmt); return NULL; } if (!(label_register_handler(FMT_LVM1_NAME, fmt->labeller))) { log_error("Couldn't register lvm1 label handler."); fmt->labeller->ops->destroy(fmt->labeller); dm_free(fmt); return NULL; } if (!(fmt->orphan_vg = alloc_vg("format1_orphan", cmd, fmt->orphan_vg_name))) { log_error("Couldn't create lvm1 orphan VG."); dm_free(fmt); return NULL; } fic.type = FMT_INSTANCE_AUX_MDAS; fic.context.vg_ref.vg_name = fmt->orphan_vg_name; fic.context.vg_ref.vg_id = NULL; if (!(fid = _format1_create_instance(fmt, &fic))) { _format1_destroy(fmt); return_NULL; } vg_set_fid(fmt->orphan_vg, fid); log_very_verbose("Initialised format: %s", fmt->name); return fmt; } lvm2-2.02.98/lib/raid/0000750000175000017500000000000012037016272013174 5ustar blankblanklvm2-2.02.98/lib/raid/.exported_symbols0000640000175000017500000000002712037016272016577 0ustar blankblankinit_multiple_segtypes lvm2-2.02.98/lib/raid/raid.c0000640000175000017500000003000012037016272014251 0ustar blankblank/* * Copyright (C) 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 "toolcontext.h" #include "segtype.h" #include "display.h" #include "text_export.h" #include "text_import.h" #include "config.h" #include "str_list.h" #include "targets.h" #include "lvm-string.h" #include "activate.h" #include "metadata.h" #include "lv_alloc.h" #include "defaults.h" static const char *_raid_name(const struct lv_segment *seg) { return seg->segtype->name; } static int _raid_text_import_area_count(const struct dm_config_node *sn, uint32_t *area_count) { if (!dm_config_get_uint32(sn, "device_count", area_count)) { log_error("Couldn't read 'device_count' for " "segment '%s'.", dm_config_parent_name(sn)); return 0; } return 1; } static int _raid_text_import_areas(struct lv_segment *seg, const struct dm_config_node *sn, const struct dm_config_value *cv) { unsigned int s; struct logical_volume *lv1; const char *seg_name = dm_config_parent_name(sn); if (!seg->area_count) { log_error("No areas found for segment %s", seg_name); return 0; } for (s = 0; cv && s < seg->area_count; s++, cv = cv->next) { if (cv->type != DM_CFG_STRING) { log_error("Bad volume name in areas array for segment %s.", seg_name); return 0; } if (!cv->next) { log_error("Missing data device in areas array for segment %s.", seg_name); return 0; } /* Metadata device comes first */ if (!(lv1 = find_lv(seg->lv->vg, cv->v.str))) { log_error("Couldn't find volume '%s' for segment '%s'.", cv->v.str ? : "NULL", seg_name); return 0; } if (!set_lv_segment_area_lv(seg, s, lv1, 0, RAID_META)) return_0; /* Data device comes second */ cv = cv->next; if (!(lv1 = find_lv(seg->lv->vg, cv->v.str))) { log_error("Couldn't find volume '%s' for segment '%s'.", cv->v.str ? : "NULL", seg_name); return 0; } if (!set_lv_segment_area_lv(seg, s, lv1, 0, RAID_IMAGE)) return_0; } /* * Check we read the correct number of RAID data/meta pairs. */ if (cv || (s < seg->area_count)) { log_error("Incorrect number of areas in area array " "for segment '%s'.", seg_name); return 0; } return 1; } static int _raid_text_import(struct lv_segment *seg, const struct dm_config_node *sn, struct dm_hash_table *pv_hash) { const struct dm_config_value *cv; if (dm_config_has_node(sn, "region_size")) { if (!dm_config_get_uint32(sn, "region_size", &seg->region_size)) { log_error("Couldn't read 'region_size' for " "segment %s of logical volume %s.", dm_config_parent_name(sn), seg->lv->name); return 0; } } if (dm_config_has_node(sn, "stripe_size")) { if (!dm_config_get_uint32(sn, "stripe_size", &seg->stripe_size)) { log_error("Couldn't read 'stripe_size' for " "segment %s of logical volume %s.", dm_config_parent_name(sn), seg->lv->name); return 0; } } if (!dm_config_get_list(sn, "raids", &cv)) { log_error("Couldn't find RAID array for " "segment %s of logical volume %s.", dm_config_parent_name(sn), seg->lv->name); return 0; } if (!_raid_text_import_areas(seg, sn, cv)) { log_error("Failed to import RAID images"); return 0; } seg->status |= RAID; return 1; } static int _raid_text_export(const struct lv_segment *seg, struct formatter *f) { outf(f, "device_count = %u", seg->area_count); if (seg->region_size) outf(f, "region_size = %" PRIu32, seg->region_size); if (seg->stripe_size) outf(f, "stripe_size = %" PRIu32, seg->stripe_size); return out_areas(f, seg, "raid"); } static int _raid_add_target_line(struct dev_manager *dm __attribute__((unused)), struct dm_pool *mem __attribute__((unused)), struct cmd_context *cmd __attribute__((unused)), void **target_state __attribute__((unused)), struct lv_segment *seg, const struct lv_activate_opts *laopts __attribute__((unused)), struct dm_tree_node *node, uint64_t len, uint32_t *pvmove_mirror_count __attribute__((unused))) { uint32_t s; uint64_t flags = 0; uint64_t rebuilds = 0; if (!seg->area_count) { log_error(INTERNAL_ERROR "_raid_add_target_line called " "with no areas for %s.", seg->lv->name); return 0; } /* * 64 device restriction imposed by kernel as well. It is * not strictly a userspace limitation. */ if (seg->area_count > 64) { log_error("Unable to handle more than 64 devices in a " "single RAID array"); return 0; } if (!seg->region_size) { log_error("Missing region size for mirror segment."); return 0; } for (s = 0; s < seg->area_count; s++) if (seg_lv(seg, s)->status & LV_REBUILD) rebuilds |= 1 << s; if (mirror_in_sync()) flags = DM_NOSYNC; if (!dm_tree_node_add_raid_target(node, len, _raid_name(seg), seg->region_size, seg->stripe_size, rebuilds, flags)) return_0; return add_areas_line(dm, seg, node, 0u, seg->area_count); } static int _raid_target_status_compatible(const char *type) { return (strstr(type, "raid") != NULL); } static int _raid_target_percent(void **target_state, percent_t *percent, struct dm_pool *mem, struct cmd_context *cmd, struct lv_segment *seg, char *params, uint64_t *total_numerator, uint64_t *total_denominator) { int i; uint64_t numerator, denominator; char *pos = params; /* * Status line: * <#devs> / * Example: * raid1 2 AA 1024000/1024000 */ for (i = 0; i < 3; i++) { pos = strstr(pos, " "); if (pos) pos++; else break; } if (!pos || (sscanf(pos, "%" PRIu64 "/%" PRIu64 "%n", &numerator, &denominator, &i) != 2)) { log_error("Failed to parse %s status fraction: %s", (seg) ? seg->segtype->name : "segment", params); return 0; } *total_numerator += numerator; *total_denominator += denominator; if (seg) seg->extents_copied = seg->area_len * numerator / denominator; *percent = make_percent(numerator, denominator); return 1; } static int _raid_target_present(struct cmd_context *cmd, const struct lv_segment *seg __attribute__((unused)), unsigned *attributes __attribute__((unused))) { static int _raid_checked = 0; static int _raid_present = 0; if (!_raid_checked) _raid_present = target_present(cmd, "raid", 1); _raid_checked = 1; return _raid_present; } static int _raid_modules_needed(struct dm_pool *mem, const struct lv_segment *seg __attribute__((unused)), struct dm_list *modules) { if (!str_list_add(mem, modules, "raid")) { log_error("raid module string list allocation failed"); return 0; } return 1; } static void _raid_destroy(struct segment_type *segtype) { dm_free((void *) segtype); } #ifdef DEVMAPPER_SUPPORT #ifdef DMEVENTD static const char *_get_raid_dso_path(struct cmd_context *cmd) { const char *config_str = find_config_tree_str(cmd, "dmeventd/raid_library", DEFAULT_DMEVENTD_RAID_LIB); return get_monitor_dso_path(cmd, config_str); } static int _raid_target_monitored(struct lv_segment *seg, int *pending) { struct cmd_context *cmd = seg->lv->vg->cmd; const char *dso_path = _get_raid_dso_path(cmd); return target_registered_with_dmeventd(cmd, dso_path, seg->lv, pending); } static int _raid_set_events(struct lv_segment *seg, int evmask, int set) { struct cmd_context *cmd = seg->lv->vg->cmd; const char *dso_path = _get_raid_dso_path(cmd); return target_register_events(cmd, dso_path, seg->lv, evmask, set, 0); } static int _raid_target_monitor_events(struct lv_segment *seg, int events) { return _raid_set_events(seg, events, 1); } static int _raid_target_unmonitor_events(struct lv_segment *seg, int events) { return _raid_set_events(seg, events, 0); } #endif /* DEVMAPPER_SUPPORT */ #endif /* DMEVENTD */ static struct segtype_handler _raid_ops = { .name = _raid_name, .text_import_area_count = _raid_text_import_area_count, .text_import = _raid_text_import, .text_export = _raid_text_export, .add_target_line = _raid_add_target_line, .target_status_compatible = _raid_target_status_compatible, #ifdef DEVMAPPER_SUPPORT .target_percent = _raid_target_percent, .target_present = _raid_target_present, # ifdef DMEVENTD .target_monitored = _raid_target_monitored, .target_monitor_events = _raid_target_monitor_events, .target_unmonitor_events = _raid_target_unmonitor_events, # endif /* DMEVENTD */ #endif .modules_needed = _raid_modules_needed, .destroy = _raid_destroy, }; static struct segment_type *_init_raid_segtype(struct cmd_context *cmd, const char *raid_type) { struct segment_type *segtype = dm_zalloc(sizeof(*segtype)); if (!segtype) { log_error("Failed to allocate memory for %s segtype", raid_type); return NULL; } segtype->cmd = cmd; segtype->flags = SEG_RAID; #ifdef DEVMAPPER_SUPPORT #ifdef DMEVENTD if (_get_raid_dso_path(cmd)) segtype->flags |= SEG_MONITORED; #endif #endif segtype->parity_devs = strstr(raid_type, "raid6") ? 2 : 1; segtype->ops = &_raid_ops; segtype->name = raid_type; segtype->private = NULL; log_very_verbose("Initialised segtype: %s", segtype->name); return segtype; } static struct segment_type *_init_raid1_segtype(struct cmd_context *cmd) { struct segment_type *segtype; segtype = _init_raid_segtype(cmd, "raid1"); if (!segtype) return NULL; segtype->flags |= SEG_AREAS_MIRRORED; segtype->parity_devs = 0; return segtype; } static struct segment_type *_init_raid10_segtype(struct cmd_context *cmd) { struct segment_type *segtype; segtype = _init_raid_segtype(cmd, "raid10"); if (!segtype) return NULL; segtype->flags |= SEG_AREAS_MIRRORED; segtype->parity_devs = 0; return segtype; } static struct segment_type *_init_raid4_segtype(struct cmd_context *cmd) { return _init_raid_segtype(cmd, "raid4"); } static struct segment_type *_init_raid5_segtype(struct cmd_context *cmd) { return _init_raid_segtype(cmd, "raid5"); } static struct segment_type *_init_raid5_la_segtype(struct cmd_context *cmd) { return _init_raid_segtype(cmd, "raid5_la"); } static struct segment_type *_init_raid5_ra_segtype(struct cmd_context *cmd) { return _init_raid_segtype(cmd, "raid5_ra"); } static struct segment_type *_init_raid5_ls_segtype(struct cmd_context *cmd) { return _init_raid_segtype(cmd, "raid5_ls"); } static struct segment_type *_init_raid5_rs_segtype(struct cmd_context *cmd) { return _init_raid_segtype(cmd, "raid5_rs"); } static struct segment_type *_init_raid6_segtype(struct cmd_context *cmd) { return _init_raid_segtype(cmd, "raid6"); } static struct segment_type *_init_raid6_zr_segtype(struct cmd_context *cmd) { return _init_raid_segtype(cmd, "raid6_zr"); } static struct segment_type *_init_raid6_nr_segtype(struct cmd_context *cmd) { return _init_raid_segtype(cmd, "raid6_nr"); } static struct segment_type *_init_raid6_nc_segtype(struct cmd_context *cmd) { return _init_raid_segtype(cmd, "raid6_nc"); } #ifdef RAID_INTERNAL /* Shared */ int init_raid_segtypes(struct cmd_context *cmd, struct segtype_library *seglib) #else int init_multiple_segtypes(struct cmd_context *cmd, struct segtype_library *seglib); int init_multiple_segtypes(struct cmd_context *cmd, struct segtype_library *seglib) #endif { struct segment_type *segtype; unsigned i = 0; struct segment_type *(*raid_segtype_fn[])(struct cmd_context *) = { _init_raid1_segtype, _init_raid10_segtype, _init_raid4_segtype, _init_raid5_segtype, _init_raid5_la_segtype, _init_raid5_ra_segtype, _init_raid5_ls_segtype, _init_raid5_rs_segtype, _init_raid6_segtype, _init_raid6_zr_segtype, _init_raid6_nr_segtype, _init_raid6_nc_segtype, NULL, }; do { if ((segtype = raid_segtype_fn[i](cmd)) && !lvm_register_segtype(seglib, segtype)) /* segtype is already destroyed */ return_0; } while (raid_segtype_fn[++i]); return 1; } lvm2-2.02.98/lib/raid/Makefile.in0000640000175000017500000000142512037016272015244 0ustar blankblank# # Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved. # Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved. # # This file is part of LVM2. # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions # of the GNU General Public License v.2. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation, # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA srcdir = @srcdir@ top_srcdir = @top_srcdir@ top_builddir = @top_builddir@ SOURCES = raid.c LIB_SHARED = liblvm2raid.$(LIB_SUFFIX) LIB_VERSION = $(LIB_VERSION_LVM) include $(top_builddir)/make.tmpl install: install_lvm2_plugin lvm2-2.02.98/lib/uuid/0000750000175000017500000000000012037016272013223 5ustar blankblanklvm2-2.02.98/lib/uuid/uuid.c0000640000175000017500000001030512037016272014335 0ustar blankblank/* * Copyright (C) 2001-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 */ #include "lib.h" #include "uuid.h" #include "lvm-wrappers.h" #include #include #include #include #include static const char _c[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!#"; static int _built_inverse; static char _inverse_c[256]; int lvid_create(union lvid *lvid, struct id *vgid) { memcpy(lvid->id, vgid, sizeof(*lvid->id)); return id_create(&lvid->id[1]); } void uuid_from_num(char *uuid, uint32_t num) { unsigned i; for (i = ID_LEN; i; i--) { uuid[i - 1] = _c[num % (sizeof(_c) - 1)]; num /= sizeof(_c) - 1; } } int lvid_from_lvnum(union lvid *lvid, struct id *vgid, uint32_t lv_num) { int i; memcpy(lvid->id, vgid, sizeof(*lvid->id)); for (i = ID_LEN; i; i--) { lvid->id[1].uuid[i - 1] = _c[lv_num % (sizeof(_c) - 1)]; lv_num /= sizeof(_c) - 1; } lvid->s[sizeof(lvid->s) - 1] = '\0'; return 1; } int lvnum_from_lvid(union lvid *lvid) { int i, lv_num = 0; char *c; for (i = 0; i < ID_LEN; i++) { lv_num *= sizeof(_c) - 1; if ((c = strchr(_c, lvid->id[1].uuid[i]))) lv_num += (int) (c - _c); if (lv_num < 0) lv_num = 0; } return lv_num; } int lvid_in_restricted_range(union lvid *lvid) { int i; for (i = 0; i < ID_LEN - 3; i++) if (lvid->id[1].uuid[i] != '0') return 0; for (i = ID_LEN - 3; i < ID_LEN; i++) if (!isdigit(lvid->id[1].uuid[i])) return 0; return 1; } int id_create(struct id *id) { unsigned i; size_t len = sizeof(id->uuid); memset(id->uuid, 0, len); if (!read_urandom(&id->uuid, len)) { return 0; } /* * Skip out the last 2 chars in randomized creation for LVM1 * backwards compatibility. */ for (i = 0; i < len; i++) id->uuid[i] = _c[id->uuid[i] % (sizeof(_c) - 3)]; return 1; } /* * The only validity check we have is that * the uuid just contains characters from * '_c'. A checksum would have been nice :( */ static void _build_inverse(void) { const char *ptr; if (_built_inverse) return; _built_inverse = 1; memset(_inverse_c, 0, sizeof(_inverse_c)); for (ptr = _c; *ptr; ptr++) _inverse_c[(int) *ptr] = (char) 0x1; } int id_valid(struct id *id) { int i; _build_inverse(); for (i = 0; i < ID_LEN; i++) if (!_inverse_c[id->uuid[i]]) { log_error("UUID contains invalid character"); return 0; } return 1; } int id_equal(const struct id *lhs, const struct id *rhs) { return !memcmp(lhs->uuid, rhs->uuid, sizeof(lhs->uuid)); } #define GROUPS (ID_LEN / 4) int id_write_format(const struct id *id, char *buffer, size_t size) { int i, tot; static const unsigned group_size[] = { 6, 4, 4, 4, 4, 4, 6 }; assert(ID_LEN == 32); /* split into groups separated by dashes */ if (size < (32 + 6 + 1)) { log_error("Couldn't write uuid, buffer too small."); return 0; } for (i = 0, tot = 0; i < 7; i++) { memcpy(buffer, id->uuid + tot, group_size[i]); buffer += group_size[i]; tot += group_size[i]; *buffer++ = '-'; } *--buffer = '\0'; return 1; } int id_read_format(struct id *id, const char *buffer) { int out = 0; /* just strip out any dashes */ while (*buffer) { if (*buffer == '-') { buffer++; continue; } if (out >= ID_LEN) { log_error("Too many characters to be uuid."); return 0; } id->uuid[out++] = *buffer++; } if (out != ID_LEN) { log_error("Couldn't read uuid: incorrect number of " "characters."); return 0; } return id_valid(id); } char *id_format_and_copy(struct dm_pool *mem, const struct id *id) { char *repstr = NULL; if (!(repstr = dm_pool_alloc(mem, 40))) { log_error("dm_pool_alloc failed"); return NULL; } if (!id_write_format(id, repstr, 40)) return_NULL; return repstr; } lvm2-2.02.98/lib/uuid/uuid.h0000640000175000017500000000305212037016272014343 0ustar blankblank/* * Copyright (C) 2001-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_UUID_H #define _LVM_UUID_H #define ID_LEN 32 #define ID_LEN_S "32" struct id { int8_t uuid[ID_LEN]; }; /* * Unique logical volume identifier * With format1 this is VG uuid + LV uuid + '\0' + padding */ union lvid { struct id id[2]; char s[2 * sizeof(struct id) + 1 + 7]; }; int lvid_from_lvnum(union lvid *lvid, struct id *vgid, uint32_t lv_num); int lvnum_from_lvid(union lvid *lvid); int lvid_in_restricted_range(union lvid *lvid); void uuid_from_num(char *uuid, uint32_t num); int lvid_create(union lvid *lvid, struct id *vgid); int id_create(struct id *id); int id_valid(struct id *id); int id_equal(const struct id *lhs, const struct id *rhs); /* * Fills 'buffer' with a more human readable form * of the uuid. */ int id_write_format(const struct id *id, char *buffer, size_t size); /* * Reads a formatted uuid. */ int id_read_format(struct id *id, const char *buffer); char *id_format_and_copy(struct dm_pool *mem, const struct id *id); #endif lvm2-2.02.98/lib/unknown/0000750000175000017500000000000012037016272013754 5ustar blankblanklvm2-2.02.98/lib/unknown/unknown.c0000640000175000017500000000577412037016272015635 0ustar blankblank/* * 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 "toolcontext.h" #include "segtype.h" #include "display.h" #include "text_export.h" #include "config.h" #include "activate.h" static const char *_unknown_name(const struct lv_segment *seg) { return seg->segtype->name; } static int _unknown_text_import(struct lv_segment *seg, const struct dm_config_node *sn, struct dm_hash_table *pv_hash) { struct dm_config_node *new, *last = NULL, *head = NULL; const struct dm_config_node *current; log_verbose("importing unknown segment"); for (current = sn; current != NULL; current = current->sib) { if (!strcmp(current->key, "type") || !strcmp(current->key, "start_extent") || !strcmp(current->key, "tags") || !strcmp(current->key, "extent_count")) continue; new = dm_config_clone_node_with_mem(seg->lv->vg->vgmem, current, 0); if (!new) return_0; if (last) last->sib = new; if (!head) head = new; last = new; } seg->segtype_private = head; return 1; } static int _unknown_text_export(const struct lv_segment *seg, struct formatter *f) { struct dm_config_node *cn = seg->segtype_private; return out_config_node(f, cn); } #ifdef DEVMAPPER_SUPPORT static int _unknown_add_target_line(struct dev_manager *dm __attribute__((unused)), struct dm_pool *mem __attribute__((unused)), struct cmd_context *cmd __attribute__((unused)), void **target_state __attribute__((unused)), struct lv_segment *seg __attribute__((unused)), const struct lv_activate_opts *laopts __attribute__((unused)), struct dm_tree_node *node, uint64_t len, uint32_t *pvmove_mirror_count __attribute__((unused))) { return dm_tree_node_add_error_target(node, len); } #endif static void _unknown_destroy(struct segment_type *segtype) { dm_free(segtype); } static struct segtype_handler _unknown_ops = { .name = _unknown_name, .text_import = _unknown_text_import, .text_export = _unknown_text_export, #ifdef DEVMAPPER_SUPPORT .add_target_line = _unknown_add_target_line, #endif .destroy = _unknown_destroy, }; struct segment_type *init_unknown_segtype(struct cmd_context *cmd, const char *name) { struct segment_type *segtype = dm_zalloc(sizeof(*segtype)); if (!segtype) { log_error("Failed to allocate memory for unknown segtype"); return NULL; } segtype->cmd = cmd; segtype->ops = &_unknown_ops; segtype->name = dm_pool_strdup(cmd->mem, name); segtype->private = NULL; segtype->flags = SEG_UNKNOWN | SEG_VIRTUAL | SEG_CANNOT_BE_ZEROED; log_very_verbose("Initialised segtype: %s", segtype->name); return segtype; } lvm2-2.02.98/lib/label/0000750000175000017500000000000012037016272013334 5ustar blankblanklvm2-2.02.98/lib/label/label.h0000640000175000017500000000525612037016272014575 0ustar blankblank/* * 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 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_LABEL_H #define _LVM_LABEL_H #include "uuid.h" #include "device.h" #define LABEL_ID "LABELONE" #define LABEL_SIZE SECTOR_SIZE /* Think very carefully before changing this */ #define LABEL_SCAN_SECTORS 4L #define LABEL_SCAN_SIZE (LABEL_SCAN_SECTORS << SECTOR_SHIFT) struct labeller; void allow_reads_with_lvmetad(void); /* On disk - 32 bytes */ struct label_header { int8_t id[8]; /* LABELONE */ uint64_t sector_xl; /* Sector number of this label */ uint32_t crc_xl; /* From next field to end of sector */ uint32_t offset_xl; /* Offset from start of struct to contents */ int8_t type[8]; /* LVM2 001 */ } __attribute__ ((packed)); /* In core */ struct label { char type[8]; uint64_t sector; struct labeller *labeller; void *info; }; struct labeller; struct label_ops { /* * Is the device labelled with this format ? */ int (*can_handle) (struct labeller * l, void *buf, uint64_t sector); /* * Write a label to a volume. */ int (*write) (struct label * label, void *buf); /* * Read a label from a volume. */ int (*read) (struct labeller * l, struct device * dev, void *buf, struct label ** label); /* * Additional consistency checks for the paranoid. */ int (*verify) (struct labeller * l, void *buf, uint64_t sector); /* * Populate label_type etc. */ int (*initialise_label) (struct labeller * l, struct label * label); /* * Destroy a previously read label. */ void (*destroy_label) (struct labeller * l, struct label * label); /* * Destructor. */ void (*destroy) (struct labeller * l); }; struct labeller { struct label_ops *ops; const void *private; }; int label_init(void); void label_exit(void); int label_register_handler(const char *name, struct labeller *handler); struct labeller *label_get_handler(const char *name); int label_remove(struct device *dev); int label_read(struct device *dev, struct label **result, uint64_t scan_sector); int label_write(struct device *dev, struct label *label); int label_verify(struct device *dev); struct label *label_create(struct labeller *labeller); void label_destroy(struct label *label); #endif lvm2-2.02.98/lib/label/label.c0000640000175000017500000002174612037016272014572 0ustar blankblank/* * 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 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 "label.h" #include "crc.h" #include "xlate.h" #include "lvmcache.h" #include "lvmetad.h" #include "metadata.h" #include #include #include /* FIXME Allow for larger labels? Restricted to single sector currently */ /* * Internal labeller struct. */ struct labeller_i { struct dm_list list; struct labeller *l; char name[0]; }; static struct dm_list _labellers; static struct labeller_i *_alloc_li(const char *name, struct labeller *l) { struct labeller_i *li; size_t len; len = sizeof(*li) + strlen(name) + 1; if (!(li = dm_malloc(len))) { log_error("Couldn't allocate memory for labeller list object."); return NULL; } li->l = l; strcpy(li->name, name); return li; } int label_init(void) { dm_list_init(&_labellers); return 1; } void label_exit(void) { struct labeller_i *li, *tli; dm_list_iterate_items_safe(li, tli, &_labellers) { dm_list_del(&li->list); li->l->ops->destroy(li->l); dm_free(li); } dm_list_init(&_labellers); } int label_register_handler(const char *name, struct labeller *handler) { struct labeller_i *li; if (!(li = _alloc_li(name, handler))) return_0; dm_list_add(&_labellers, &li->list); return 1; } struct labeller *label_get_handler(const char *name) { struct labeller_i *li; dm_list_iterate_items(li, &_labellers) if (!strcmp(li->name, name)) return li->l; return NULL; } static struct labeller *_find_labeller(struct device *dev, char *buf, uint64_t *label_sector, uint64_t scan_sector) { struct labeller_i *li; struct labeller *r = NULL; struct label_header *lh; struct lvmcache_info *info; uint64_t sector; int found = 0; char readbuf[LABEL_SCAN_SIZE] __attribute__((aligned(8))); if (!dev_read(dev, scan_sector << SECTOR_SHIFT, LABEL_SCAN_SIZE, readbuf)) { log_debug("%s: Failed to read label area", dev_name(dev)); goto out; } /* Scan a few sectors for a valid label */ for (sector = 0; sector < LABEL_SCAN_SECTORS; sector += LABEL_SIZE >> SECTOR_SHIFT) { lh = (struct label_header *) (readbuf + (sector << SECTOR_SHIFT)); if (!strncmp((char *)lh->id, LABEL_ID, sizeof(lh->id))) { if (found) { log_error("Ignoring additional label on %s at " "sector %" PRIu64, dev_name(dev), sector + scan_sector); } if (xlate64(lh->sector_xl) != sector + scan_sector) { log_info("%s: Label for sector %" PRIu64 " found at sector %" PRIu64 " - ignoring", dev_name(dev), (uint64_t)xlate64(lh->sector_xl), sector + scan_sector); continue; } if (calc_crc(INITIAL_CRC, (uint8_t *)&lh->offset_xl, LABEL_SIZE - ((uint8_t *) &lh->offset_xl - (uint8_t *) lh)) != xlate32(lh->crc_xl)) { log_info("Label checksum incorrect on %s - " "ignoring", dev_name(dev)); continue; } if (found) continue; } dm_list_iterate_items(li, &_labellers) { if (li->l->ops->can_handle(li->l, (char *) lh, sector + scan_sector)) { log_very_verbose("%s: %s label detected at " "sector %" PRIu64, dev_name(dev), li->name, sector + scan_sector); if (found) { log_error("Ignoring additional label " "on %s at sector %" PRIu64, dev_name(dev), sector + scan_sector); continue; } r = li->l; memcpy(buf, lh, LABEL_SIZE); if (label_sector) *label_sector = sector + scan_sector; found = 1; break; } } } out: if (!found) { if ((info = lvmcache_info_from_pvid(dev->pvid, 0))) lvmcache_update_vgname_and_id(info, lvmcache_fmt(info)->orphan_vg_name, lvmcache_fmt(info)->orphan_vg_name, 0, NULL); log_very_verbose("%s: No label detected", dev_name(dev)); } return r; } /* FIXME Also wipe associated metadata area headers? */ int label_remove(struct device *dev) { char buf[LABEL_SIZE] __attribute__((aligned(8))); char readbuf[LABEL_SCAN_SIZE] __attribute__((aligned(8))); int r = 1; uint64_t sector; int wipe; struct labeller_i *li; struct label_header *lh; memset(buf, 0, LABEL_SIZE); log_very_verbose("Scanning for labels to wipe from %s", dev_name(dev)); if (!dev_open(dev)) return_0; /* * We flush the device just in case someone is stupid * enough to be trying to import an open pv into lvm. */ dev_flush(dev); if (!dev_read(dev, UINT64_C(0), LABEL_SCAN_SIZE, readbuf)) { log_debug("%s: Failed to read label area", dev_name(dev)); goto out; } /* Scan first few sectors for anything looking like a label */ for (sector = 0; sector < LABEL_SCAN_SECTORS; sector += LABEL_SIZE >> SECTOR_SHIFT) { lh = (struct label_header *) (readbuf + (sector << SECTOR_SHIFT)); wipe = 0; if (!strncmp((char *)lh->id, LABEL_ID, sizeof(lh->id))) { if (xlate64(lh->sector_xl) == sector) wipe = 1; } else { dm_list_iterate_items(li, &_labellers) { if (li->l->ops->can_handle(li->l, (char *) lh, sector)) { wipe = 1; break; } } } if (wipe) { log_info("%s: Wiping label at sector %" PRIu64, dev_name(dev), sector); if (!dev_write(dev, sector << SECTOR_SHIFT, LABEL_SIZE, buf)) { log_error("Failed to remove label from %s at " "sector %" PRIu64, dev_name(dev), sector); r = 0; } } } out: if (!dev_close(dev)) stack; return r; } int label_read(struct device *dev, struct label **result, uint64_t scan_sector) { char buf[LABEL_SIZE] __attribute__((aligned(8))); struct labeller *l; uint64_t sector; struct lvmcache_info *info; int r = 0; if ((info = lvmcache_info_from_pvid(dev->pvid, 1))) { log_debug("Using cached label for %s", dev_name(dev)); *result = lvmcache_get_label(info); return 1; } if (!dev_open_readonly(dev)) { stack; if ((info = lvmcache_info_from_pvid(dev->pvid, 0))) lvmcache_update_vgname_and_id(info, lvmcache_fmt(info)->orphan_vg_name, lvmcache_fmt(info)->orphan_vg_name, 0, NULL); return r; } if (!(l = _find_labeller(dev, buf, §or, scan_sector))) goto out; if ((r = (l->ops->read)(l, dev, buf, result)) && result && *result) (*result)->sector = sector; out: if (!dev_close(dev)) stack; return r; } /* Caller may need to use label_get_handler to create label struct! */ int label_write(struct device *dev, struct label *label) { char buf[LABEL_SIZE] __attribute__((aligned(8))); struct label_header *lh = (struct label_header *) buf; int r = 1; if (!label->labeller->ops->write) { log_error("Label handler does not support label writes"); return 0; } if ((LABEL_SIZE + (label->sector << SECTOR_SHIFT)) > LABEL_SCAN_SIZE) { log_error("Label sector %" PRIu64 " beyond range (%ld)", label->sector, LABEL_SCAN_SECTORS); return 0; } memset(buf, 0, LABEL_SIZE); strncpy((char *)lh->id, LABEL_ID, sizeof(lh->id)); lh->sector_xl = xlate64(label->sector); lh->offset_xl = xlate32(sizeof(*lh)); if (!(label->labeller->ops->write)(label, buf)) return_0; lh->crc_xl = xlate32(calc_crc(INITIAL_CRC, (uint8_t *)&lh->offset_xl, LABEL_SIZE - ((uint8_t *) &lh->offset_xl - (uint8_t *) lh))); if (!dev_open(dev)) return_0; log_info("%s: Writing label to sector %" PRIu64 " with stored offset %" PRIu32 ".", dev_name(dev), label->sector, xlate32(lh->offset_xl)); if (!dev_write(dev, label->sector << SECTOR_SHIFT, LABEL_SIZE, buf)) { log_debug("Failed to write label to %s", dev_name(dev)); r = 0; } if (!dev_close(dev)) stack; return r; } /* Unused */ int label_verify(struct device *dev) { struct labeller *l; char buf[LABEL_SIZE] __attribute__((aligned(8))); uint64_t sector; struct lvmcache_info *info; int r = 0; if (!dev_open_readonly(dev)) { if ((info = lvmcache_info_from_pvid(dev->pvid, 0))) lvmcache_update_vgname_and_id(info, lvmcache_fmt(info)->orphan_vg_name, lvmcache_fmt(info)->orphan_vg_name, 0, NULL); return_0; } if (!(l = _find_labeller(dev, buf, §or, UINT64_C(0)))) goto out; r = l->ops->verify ? l->ops->verify(l, buf, sector) : 1; out: if (!dev_close(dev)) stack; return r; } void label_destroy(struct label *label) { label->labeller->ops->destroy_label(label->labeller, label); dm_free(label); } struct label *label_create(struct labeller *labeller) { struct label *label; if (!(label = dm_zalloc(sizeof(*label)))) { log_error("label allocaction failed"); return NULL; } label->labeller = labeller; labeller->ops->initialise_label(labeller, label); return label; } lvm2-2.02.98/python/0000750000175000017500000000000012037016272013030 5ustar blankblanklvm2-2.02.98/python/example.py0000640000175000017500000000652012037016272015041 0ustar blankblank# # Copyright (C) 2012 Red Hat, Inc. All rights reserved. # # This file is part of LVM2. # # This program 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 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 Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . # #----------------------------- # Python example code: #----------------------------- import lvm # Note: This example will create a logical unit, tag it and # delete it, don't run this on production box! #Dump information about PV def print_pv(pv): print 'PV name: ', pv.getName(), ' ID: ', pv.getUuid(), 'Size: ', pv.getSize() #Dump some information about a specific volume group def print_vg(h, vg_name): #Open read only vg = h.vgOpen(vg_name, 'r') print 'Volume group:', vg_name, 'Size: ', vg.getSize() #Retrieve a list of Physical volumes for this volume group pv_list = vg.listPVs() #Print out the physical volumes for p in pv_list: print_pv(p) #Get a list of logical volumes in this volume group lv_list = vg.listLVs() if len(lv_list): for l in lv_list: print 'LV name: ', l.getName(), ' ID: ', l.getUuid() else: print 'No logical volumes present!' vg.close() #Returns the name of a vg with space available def find_vg_with_free_space(h): free_space = 0 rc = None vg_names = l.listVgNames() for v in vg_names: vg = h.vgOpen(v, 'r') c_free = vg.getFreeSize() if c_free > free_space: free_space = c_free rc = v vg.close() return rc #Walk through the volume groups and fine one with space in which we can #create a new logical volume def create_delete_logical_volume(h): vg_name = find_vg_with_free_space(h) print 'Using volume group ', vg_name, ' for example' if vg_name: vg = h.vgOpen(vg_name, 'w') lv = vg.createLvLinear('python_lvm_ok_to_delete', vg.getFreeSize()) if lv: print 'New lv, id= ', lv.getUuid() #Create a tag lv.addTag('Demo_tag') #Get the tags tags = lv.getTags() for t in tags: #Remove tag lv.removeTag(t) #Try to rename lv.rename("python_lvm_ok_to_be_removed_shortly") print 'LV name= ', lv.getName() lv.deactivate() lv.remove() vg.close() else: print 'No free space available to create demo lv!' if __name__ == '__main__': #Create a new LVM instance l = lvm.Liblvm() #What version print 'lvm version=', l.getVersion() #Get a list of volume group names vg_names = l.listVgNames() #For each volume group display some information about each of them for vg_i in vg_names: print_vg(l, vg_i) #Demo creating a logical volume create_delete_logical_volume(l) #Close l.close() lvm2-2.02.98/python/setup.py.in0000640000175000017500000000245312037016272015154 0ustar blankblank# # Copyright (C) 2012 Red Hat, Inc. All rights reserved. # # This file is part of LVM2. # # This program 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 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 Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . from distutils.core import setup, Extension liblvm = Extension('lvm', sources = ['liblvm_python.c'], libraries= ['lvm2app'], library_dirs= ['@top_builddir@/liblvm'], include_dirs= ['@top_builddir@/include']) setup (name='lvm', version=@LVM_VERSION@, description='Python bindings for liblvm2', license="LGPLv2+", maintainer='LVM2 maintainers', maintainer_email='linux-lvm@redhat.com', url='http://sourceware.org/lvm2/', ext_modules=[liblvm], ) lvm2-2.02.98/python/Makefile.in0000640000175000017500000000176012037016272015102 0ustar blankblank# # Copyright (C) 2011-2012 Red Hat, Inc. # # This file is part of LVM2. # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions # of the GNU Lesser General Public License v.2.1. # # You should have received a copy of the GNU Lesser General Public License # along with this program; if not, write to the Free Software Foundation, # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA srcdir = @srcdir@ top_srcdir = @top_srcdir@ top_builddir = @top_builddir@ python_bindings: .liblvm_built .liblvm_built: liblvm_python.c $(PYTHON) setup.py build touch $@ liblvm_python.c: $(LN_S) $(srcdir)/liblvm.c $@ include $(top_builddir)/make.tmpl install_python_bindings: python_bindings $(PYTHON) setup.py install --skip-build --root $(rootdir) install_lvm2: install_python_bindings install: install_lvm2 CLEAN_TARGETS += .liblvm_built liblvm_python.c DISTCLEAN_DIRS += build DISTCLEAN_TARGETS += setup.py lvm2-2.02.98/python/liblvm.c0000640000175000017500000011132012037016272014460 0ustar blankblank/* * Liblvm -- Python interface to LVM2 API. * * Copyright (C) 2010, 2012 Red Hat, Inc. All rights reserved. * * This program 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 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 Lesser General Public License for more details. * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authors: Lars Sjostrom (lars sjostrom redhat com) * Andy Grover (agrover redhat com) * Tony Asleson (tasleson redhat com) */ #include #include "lvm2app.h" typedef struct { PyObject_HEAD lvm_t libh; /* lvm lib handle */ } lvmobject; typedef struct { PyObject_HEAD vg_t vg; /* vg handle */ lvmobject *lvm_obj; } vgobject; typedef struct { PyObject_HEAD lv_t lv; /* lv handle */ lvmobject *lvm_obj; } lvobject; typedef struct { PyObject_HEAD pv_t pv; /* pv handle */ lvmobject *lvm_obj; } pvobject; typedef struct { PyObject_HEAD lvseg_t lv_seg; /* lv segment handle */ lvmobject *lvm_obj; } lvsegobject; typedef struct { PyObject_HEAD pvseg_t pv_seg; /* pv segment handle */ lvmobject *lvm_obj; } pvsegobject; static PyTypeObject LibLVMvgType; static PyTypeObject LibLVMlvType; static PyTypeObject LibLVMpvType; static PyTypeObject LibLVMlvsegType; static PyTypeObject LibLVMpvsegType; static PyObject *LibLVMError; /* ---------------------------------------------------------------------- * LVM object initialization/deallocation */ static int liblvm_init(lvmobject *self, PyObject *arg) { char *systemdir = NULL; if (!PyArg_ParseTuple(arg, "|s", &systemdir)) return -1; self->libh = lvm_init(systemdir); if (lvm_errno(self->libh)) { PyErr_SetFromErrno(PyExc_OSError); return -1; } return 0; } static void liblvm_dealloc(lvmobject *self) { /* if already closed, don't reclose it */ if (self->libh != NULL){ lvm_quit(self->libh); } PyObject_Del(self); } #define LVM_VALID(lvmobject) \ do { \ if (!lvmobject->libh) { \ PyErr_SetString(PyExc_UnboundLocalError, "LVM object invalid"); \ return NULL; \ } \ } while (0) static PyObject * liblvm_get_last_error(lvmobject *self) { PyObject *info; LVM_VALID(self); if((info = PyTuple_New(2)) == NULL) return NULL; PyTuple_SetItem(info, 0, PyInt_FromLong((long) lvm_errno(self->libh))); PyTuple_SetItem(info, 1, PyString_FromString(lvm_errmsg(self->libh))); return info; } static PyObject * liblvm_library_get_version(lvmobject *self) { LVM_VALID(self); return Py_BuildValue("s", lvm_library_get_version()); } static PyObject * liblvm_close(lvmobject *self) { LVM_VALID(self); /* if already closed, don't reclose it */ if (self->libh != NULL) lvm_quit(self->libh); self->libh = NULL; Py_INCREF(Py_None); return Py_None; } static PyObject * liblvm_lvm_list_vg_names(lvmobject *self) { struct dm_list *vgnames; struct lvm_str_list *strl; PyObject * pytuple; int i = 0; LVM_VALID(self); vgnames = lvm_list_vg_names(self->libh); if (!vgnames) { PyErr_SetObject(LibLVMError, liblvm_get_last_error(self)); return NULL; } pytuple = PyTuple_New(dm_list_size(vgnames)); if (!pytuple) return NULL; dm_list_iterate_items(strl, vgnames) { PyTuple_SET_ITEM(pytuple, i, PyString_FromString(strl->str)); i++; } return pytuple; } static PyObject * liblvm_lvm_list_vg_uuids(lvmobject *self) { struct dm_list *uuids; struct lvm_str_list *strl; PyObject * pytuple; int i = 0; LVM_VALID(self); uuids = lvm_list_vg_uuids(self->libh); if (!uuids) { PyErr_SetObject(LibLVMError, liblvm_get_last_error(self)); return NULL; } pytuple = PyTuple_New(dm_list_size(uuids)); if (!pytuple) return NULL; dm_list_iterate_items(strl, uuids) { PyTuple_SET_ITEM(pytuple, i, PyString_FromString(strl->str)); i++; } return pytuple; } static PyObject * liblvm_lvm_percent_to_float(lvmobject *self, PyObject *arg) { double converted; int percent; LVM_VALID(self); if (!PyArg_ParseTuple(arg, "i", &percent)) return NULL; converted = lvm_percent_to_float(percent); return Py_BuildValue("d", converted); } static PyObject * liblvm_lvm_vgname_from_pvid(lvmobject *self, PyObject *arg) { const char *pvid; const char *vgname; LVM_VALID(self); if (!PyArg_ParseTuple(arg, "s", &pvid)) return NULL; if((vgname = lvm_vgname_from_pvid(self->libh, pvid)) == NULL) { PyErr_SetObject(LibLVMError, liblvm_get_last_error(self)); return NULL; } return Py_BuildValue("s", vgname); } static PyObject * liblvm_lvm_vgname_from_device(lvmobject *self, PyObject *arg) { const char *device; const char *vgname; LVM_VALID(self); if (!PyArg_ParseTuple(arg, "s", &device)) return NULL; if((vgname = lvm_vgname_from_device(self->libh, device)) == NULL) { PyErr_SetObject(LibLVMError, liblvm_get_last_error(self)); return NULL; } return Py_BuildValue("s", vgname); } static PyObject * liblvm_lvm_config_find_bool(lvmobject *self, PyObject *arg) { const char *config; int rval; PyObject *rc; LVM_VALID(self); if (!PyArg_ParseTuple(arg, "s", &config)) return NULL; if ((rval = lvm_config_find_bool(self->libh, config, -10)) == -10) { /* Retrieving error information yields no error in this case */ PyErr_Format(PyExc_ValueError, "config path not found"); return NULL; } rc = (rval) ? Py_True: Py_False; Py_INCREF(rc); return rc; } static PyObject * liblvm_lvm_config_reload(lvmobject *self) { int rval; LVM_VALID(self); if((rval = lvm_config_reload(self->libh)) == -1) { PyErr_SetObject(LibLVMError, liblvm_get_last_error(self)); return NULL; } Py_INCREF(Py_None); return Py_None; } static PyObject * liblvm_lvm_scan(lvmobject *self) { int rval; LVM_VALID(self); if((rval = lvm_scan(self->libh)) == -1) { PyErr_SetObject(LibLVMError, liblvm_get_last_error(self)); return NULL; } Py_INCREF(Py_None); return Py_None; } static PyObject * liblvm_lvm_config_override(lvmobject *self, PyObject *arg) { const char *config; int rval; LVM_VALID(self); if (!PyArg_ParseTuple(arg, "s", &config)) return NULL; if ((rval = lvm_config_override(self->libh, config)) == -1) { PyErr_SetObject(LibLVMError, liblvm_get_last_error(self)); return NULL; } Py_INCREF(Py_None); return Py_None; } /* ---------------------------------------------------------------------- * VG object initialization/deallocation */ static PyObject * liblvm_lvm_vg_open(lvmobject *lvm, PyObject *args) { const char *vgname; const char *mode = NULL; vgobject *self; LVM_VALID(lvm); if (!PyArg_ParseTuple(args, "s|s", &vgname, &mode)) { return NULL; } if (mode == NULL) mode = "r"; if ((self = PyObject_New(vgobject, &LibLVMvgType)) == NULL) return NULL; if ((self->vg = lvm_vg_open(lvm->libh, vgname, mode, 0))== NULL) { PyErr_SetObject(LibLVMError, liblvm_get_last_error(lvm)); Py_DECREF(self); return NULL; } self->lvm_obj = lvm; return (PyObject *)self; } static PyObject * liblvm_lvm_vg_create(lvmobject *lvm, PyObject *args) { const char *vgname; vgobject *self; LVM_VALID(lvm); if (!PyArg_ParseTuple(args, "s", &vgname)) { return NULL; } if ((self = PyObject_New(vgobject, &LibLVMvgType)) == NULL) return NULL; if ((self->vg = lvm_vg_create(lvm->libh, vgname))== NULL) { PyErr_SetObject(LibLVMError, liblvm_get_last_error(lvm)); Py_DECREF(self); return NULL; } self->lvm_obj = lvm; return (PyObject *)self; } static void liblvm_vg_dealloc(vgobject *self) { /* if already closed, don't reclose it */ if (self->vg != NULL) lvm_vg_close(self->vg); PyObject_Del(self); } /* VG Methods */ #define VG_VALID(vgobject) \ do { \ if (!vgobject->vg) { \ PyErr_SetString(PyExc_UnboundLocalError, "VG object invalid"); \ return NULL; \ } \ } while (0) static PyObject * liblvm_lvm_vg_close(vgobject *self) { /* if already closed, don't reclose it */ if (self->vg != NULL) lvm_vg_close(self->vg); self->vg = NULL; Py_INCREF(Py_None); return Py_None; } static PyObject * liblvm_lvm_vg_get_name(vgobject *self) { VG_VALID(self); return Py_BuildValue("s", lvm_vg_get_name(self->vg)); } static PyObject * liblvm_lvm_vg_get_uuid(vgobject *self) { VG_VALID(self); return Py_BuildValue("s", lvm_vg_get_uuid(self->vg)); } static PyObject * liblvm_lvm_vg_remove(vgobject *self) { int rval; VG_VALID(self); if ((rval = lvm_vg_remove(self->vg)) == -1) goto error; if (lvm_vg_write(self->vg) == -1) goto error; self->vg = NULL; Py_INCREF(Py_None); return Py_None; error: PyErr_SetObject(LibLVMError, liblvm_get_last_error(self->lvm_obj)); return NULL; } static PyObject * liblvm_lvm_vg_extend(vgobject *self, PyObject *args) { const char *device; int rval; VG_VALID(self); if (!PyArg_ParseTuple(args, "s", &device)) { return NULL; } if ((rval = lvm_vg_extend(self->vg, device)) == -1) goto error; if (lvm_vg_write(self->vg) == -1) goto error; Py_INCREF(Py_None); return Py_None; error: PyErr_SetObject(LibLVMError, liblvm_get_last_error(self->lvm_obj)); return NULL; } static PyObject * liblvm_lvm_vg_reduce(vgobject *self, PyObject *args) { const char *device; int rval; VG_VALID(self); if (!PyArg_ParseTuple(args, "s", &device)) { return NULL; } if ((rval = lvm_vg_reduce(self->vg, device)) == -1) goto error; if (lvm_vg_write(self->vg) == -1) goto error; Py_INCREF(Py_None); return Py_None; error: PyErr_SetObject(LibLVMError, liblvm_get_last_error(self->lvm_obj)); return NULL; } static PyObject * liblvm_lvm_vg_add_tag(vgobject *self, PyObject *args) { const char *tag; int rval; VG_VALID(self); if (!PyArg_ParseTuple(args, "s", &tag)) { return NULL; } if ((rval = lvm_vg_add_tag(self->vg, tag)) == -1) goto error; if (lvm_vg_write(self->vg) == -1) goto error; return Py_BuildValue("i", rval); error: PyErr_SetObject(LibLVMError, liblvm_get_last_error(self->lvm_obj)); return NULL; } static PyObject * liblvm_lvm_vg_remove_tag(vgobject *self, PyObject *args) { const char *tag; int rval; VG_VALID(self); if (!PyArg_ParseTuple(args, "s", &tag)) { return NULL; } if ((rval = lvm_vg_remove_tag(self->vg, tag)) == -1) goto error; if (lvm_vg_write(self->vg) == -1) goto error; Py_INCREF(Py_None); return Py_None; error: PyErr_SetObject(LibLVMError, liblvm_get_last_error(self->lvm_obj)); return NULL; } static PyObject * liblvm_lvm_vg_is_clustered(vgobject *self) { PyObject *rval; VG_VALID(self); rval = ( lvm_vg_is_clustered(self->vg) == 1) ? Py_True : Py_False; Py_INCREF(rval); return rval; } static PyObject * liblvm_lvm_vg_is_exported(vgobject *self) { PyObject *rval; VG_VALID(self); rval = ( lvm_vg_is_exported(self->vg) == 1) ? Py_True : Py_False; Py_INCREF(rval); return rval; } static PyObject * liblvm_lvm_vg_is_partial(vgobject *self) { PyObject *rval; VG_VALID(self); rval = ( lvm_vg_is_partial(self->vg) == 1) ? Py_True : Py_False; Py_INCREF(rval); return rval; } static PyObject * liblvm_lvm_vg_get_seqno(vgobject *self) { VG_VALID(self); return Py_BuildValue("l", lvm_vg_get_seqno(self->vg)); } static PyObject * liblvm_lvm_vg_get_size(vgobject *self) { VG_VALID(self); return Py_BuildValue("l", lvm_vg_get_size(self->vg)); } static PyObject * liblvm_lvm_vg_get_free_size(vgobject *self) { VG_VALID(self); return Py_BuildValue("l", lvm_vg_get_free_size(self->vg)); } static PyObject * liblvm_lvm_vg_get_extent_size(vgobject *self) { VG_VALID(self); return Py_BuildValue("l", lvm_vg_get_extent_size(self->vg)); } static PyObject * liblvm_lvm_vg_get_extent_count(vgobject *self) { VG_VALID(self); return Py_BuildValue("l", lvm_vg_get_extent_count(self->vg)); } static PyObject * liblvm_lvm_vg_get_free_extent_count(vgobject *self) { VG_VALID(self); return Py_BuildValue("l", lvm_vg_get_free_extent_count(self->vg)); } /* Builds a python tuple ([string|number], bool) from a struct lvm_property_value */ static PyObject * get_property(lvmobject *h, struct lvm_property_value *prop) { PyObject *pytuple; PyObject *setable; if( !prop->is_valid ) { PyErr_SetObject(LibLVMError, liblvm_get_last_error(h)); return NULL; } pytuple = PyTuple_New(2); if (!pytuple) return NULL; if( prop->is_integer ) { PyTuple_SET_ITEM(pytuple, 0, Py_BuildValue("K", prop->value.integer)); } else { PyTuple_SET_ITEM(pytuple, 0, PyString_FromString(prop->value.string)); } if (prop->is_settable) { setable = Py_True; } else { setable = Py_False; } Py_INCREF(setable); PyTuple_SET_ITEM(pytuple, 1, setable); return pytuple; } /* This will return a tuple of (value, bool) with the value being a string or integer and bool indicating if property is settable */ static PyObject * liblvm_lvm_vg_get_property(vgobject *self, PyObject *args) { const char *name; struct lvm_property_value prop_value; VG_VALID(self); if (!PyArg_ParseTuple(args, "s", &name)) return NULL; prop_value = lvm_vg_get_property(self->vg, name); return get_property(self->lvm_obj, &prop_value); } static PyObject * liblvm_lvm_vg_set_property(vgobject *self, PyObject *args) { const char *property_name = NULL; PyObject *variant_type_arg = NULL; struct lvm_property_value lvm_property; char *string_value = NULL; VG_VALID(self); if (!PyArg_ParseTuple(args, "sO", &property_name, &variant_type_arg)) return NULL; lvm_property = lvm_vg_get_property(self->vg, property_name); if( !lvm_property.is_valid ) { goto lvmerror; } if(PyObject_IsInstance(variant_type_arg, (PyObject*)&PyString_Type)) { if (!lvm_property.is_string) { PyErr_Format(PyExc_ValueError, "Property requires string value"); goto bail; } /* Based on cursory code inspection this path may cause a memory leak when calling into set_property, need to verify*/ string_value = strdup(PyString_AsString(variant_type_arg)); lvm_property.value.string = string_value; if(!lvm_property.value.string) { PyErr_NoMemory(); goto bail; } } else { if (!lvm_property.is_integer) { PyErr_Format(PyExc_ValueError, "Property requires numeric value"); goto bail; } if(PyObject_IsInstance(variant_type_arg, (PyObject*)&PyInt_Type)) { int temp_py_int = PyInt_AsLong(variant_type_arg); /* -1 could be valid, need to see if an exception was gen. */ if( -1 == temp_py_int ) { if( PyErr_Occurred() ) { goto bail; } } if (temp_py_int < 0) { PyErr_Format(PyExc_ValueError, "Positive integers only!"); goto bail; } lvm_property.value.integer = temp_py_int; } else if(PyObject_IsInstance(variant_type_arg, (PyObject*)&PyLong_Type)){ /* This will fail on negative numbers */ unsigned long long temp_py_long = PyLong_AsUnsignedLongLong(variant_type_arg); if( (unsigned long long)-1 == temp_py_long ) { goto bail; } lvm_property.value.integer = temp_py_long; } else { PyErr_Format(PyExc_ValueError, "supported value types are numeric and string"); goto bail; } } if( -1 == lvm_vg_set_property(self->vg, property_name, &lvm_property) ) { goto lvmerror; } if( -1 == lvm_vg_write(self->vg)) { goto lvmerror; } Py_DECREF(variant_type_arg); Py_INCREF(Py_None); return Py_None; lvmerror: PyErr_SetObject(LibLVMError, liblvm_get_last_error(self->lvm_obj)); bail: free(string_value); if( variant_type_arg ) { Py_DECREF(variant_type_arg); variant_type_arg = NULL; } return NULL; } static PyObject * liblvm_lvm_vg_get_pv_count(vgobject *self) { VG_VALID(self); return Py_BuildValue("l", lvm_vg_get_pv_count(self->vg)); } static PyObject * liblvm_lvm_vg_get_max_pv(vgobject *self) { VG_VALID(self); return Py_BuildValue("l", lvm_vg_get_max_pv(self->vg)); } static PyObject * liblvm_lvm_vg_get_max_lv(vgobject *self) { VG_VALID(self); return Py_BuildValue("l", lvm_vg_get_max_lv(self->vg)); } static PyObject * liblvm_lvm_vg_set_extent_size(vgobject *self, PyObject *args) { uint32_t new_size; int rval; VG_VALID(self); if (!PyArg_ParseTuple(args, "l", &new_size)) { return NULL; } if ((rval = lvm_vg_set_extent_size(self->vg, new_size)) == -1) { PyErr_SetObject(LibLVMError, liblvm_get_last_error(self->lvm_obj)); return NULL; } Py_INCREF(Py_None); return Py_None; } static PyObject * liblvm_lvm_vg_list_lvs(vgobject *vg) { struct dm_list *lvs; struct lvm_lv_list *lvl; PyObject * pytuple; lvobject * self; int i = 0; VG_VALID(vg); /* unlike other LVM api calls, if there are no results, we get NULL */ lvs = lvm_vg_list_lvs(vg->vg); if (!lvs) return Py_BuildValue("()"); pytuple = PyTuple_New(dm_list_size(lvs)); if (!pytuple) return NULL; dm_list_iterate_items(lvl, lvs) { /* Create and initialize the object */ self = PyObject_New(lvobject, &LibLVMlvType); if (!self) { Py_DECREF(pytuple); return NULL; } self->lv = lvl->lv; self->lvm_obj = vg->lvm_obj; PyTuple_SET_ITEM(pytuple, i, (PyObject *) self); i++; } return pytuple; } static PyObject * liblvm_lvm_vg_get_tags(vgobject *self) { struct dm_list *tags; struct lvm_str_list *strl; PyObject * pytuple; int i = 0; VG_VALID(self); tags = lvm_vg_get_tags(self->vg); if (!tags) { PyErr_SetObject(LibLVMError, liblvm_get_last_error(self->lvm_obj)); return NULL; } pytuple = PyTuple_New(dm_list_size(tags)); if (!pytuple) return NULL; dm_list_iterate_items(strl, tags) { PyTuple_SET_ITEM(pytuple, i, PyString_FromString(strl->str)); i++; } return pytuple; } static PyObject * liblvm_lvm_vg_create_lv_linear(vgobject *vg, PyObject *args) { const char *vgname; uint64_t size; lvobject *self; VG_VALID(vg); if (!PyArg_ParseTuple(args, "sl", &vgname, &size)) { return NULL; } if ((self = PyObject_New(lvobject, &LibLVMlvType)) == NULL) return NULL; if ((self->lv = lvm_vg_create_lv_linear(vg->vg, vgname, size))== NULL) { PyErr_SetObject(LibLVMError, liblvm_get_last_error(vg->lvm_obj)); Py_DECREF(self); return NULL; } self->lvm_obj = vg->lvm_obj; return (PyObject *)self; } static void liblvm_lv_dealloc(lvobject *self) { PyObject_Del(self); } static PyObject * liblvm_lvm_vg_list_pvs(vgobject *vg) { struct dm_list *pvs; struct lvm_pv_list *pvl; PyObject * pytuple; pvobject * self; int i = 0; VG_VALID(vg); /* unlike other LVM api calls, if there are no results, we get NULL */ pvs = lvm_vg_list_pvs(vg->vg); if (!pvs) return Py_BuildValue("()"); pytuple = PyTuple_New(dm_list_size(pvs)); if (!pytuple) return NULL; dm_list_iterate_items(pvl, pvs) { /* Create and initialize the object */ self = PyObject_New(pvobject, &LibLVMpvType); if (!self) { Py_DECREF(pytuple); return NULL; } self->pv = pvl->pv; self->lvm_obj = vg->lvm_obj; PyTuple_SET_ITEM(pytuple, i, (PyObject *) self); i++; } return pytuple; } typedef lv_t (*lv_fetch_by_N)(vg_t vg, const char *id); typedef pv_t (*pv_fetch_by_N)(vg_t vg, const char *id); static PyObject * liblvm_lvm_lv_from_N(vgobject *self, PyObject *arg, lv_fetch_by_N method) { const char *id; lvobject *rc; lv_t lv = NULL; VG_VALID(self); if (!PyArg_ParseTuple(arg, "s", &id)) return NULL; lv = method(self->vg, id); if( !lv ) { PyErr_SetObject(LibLVMError, liblvm_get_last_error(self->lvm_obj)); return NULL; } rc = PyObject_New(lvobject, &LibLVMlvType); if( !rc ) { return NULL; } rc->lv = lv; rc->lvm_obj = self->lvm_obj; return (PyObject *)rc; } static PyObject * liblvm_lvm_lv_from_name(vgobject *self, PyObject *arg) { return liblvm_lvm_lv_from_N(self, arg, lvm_lv_from_name); } static PyObject * liblvm_lvm_lv_from_uuid(vgobject *self, PyObject *arg) { return liblvm_lvm_lv_from_N(self, arg, lvm_lv_from_uuid); } static PyObject * liblvm_lvm_pv_from_N(vgobject *self, PyObject *arg, pv_fetch_by_N method) { const char *id; pvobject *rc; pv_t pv = NULL; VG_VALID(self); if (!PyArg_ParseTuple(arg, "s", &id)) return NULL; pv = method(self->vg, id); if( !pv ) { PyErr_SetObject(LibLVMError, liblvm_get_last_error(self->lvm_obj)); return NULL; } rc = PyObject_New(pvobject, &LibLVMpvType); if( !rc ) { return NULL; } rc->pv = pv; rc->lvm_obj = self->lvm_obj; return (PyObject *)rc; } static PyObject * liblvm_lvm_pv_from_name(vgobject *self, PyObject *arg) { return liblvm_lvm_pv_from_N(self, arg, lvm_pv_from_name); } static PyObject * liblvm_lvm_pv_from_uuid(vgobject *self, PyObject *arg) { return liblvm_lvm_pv_from_N(self, arg, lvm_pv_from_uuid); } static void liblvm_pv_dealloc(pvobject *self) { PyObject_Del(self); } /* LV Methods */ #define LV_VALID(lvobject) \ do { \ if (!lvobject->lv) { \ PyErr_SetString(PyExc_UnboundLocalError, "LV object invalid"); \ return NULL; \ } \ } while (0) static PyObject * liblvm_lvm_lv_get_name(lvobject *self) { LV_VALID(self); return Py_BuildValue("s", lvm_lv_get_name(self->lv)); } static PyObject * liblvm_lvm_lv_get_uuid(lvobject *self) { LV_VALID(self); return Py_BuildValue("s", lvm_lv_get_uuid(self->lv)); } static PyObject * liblvm_lvm_lv_activate(lvobject *self) { int rval; LV_VALID(self); if ((rval = lvm_lv_activate(self->lv)) == -1) { PyErr_SetObject(LibLVMError, liblvm_get_last_error(self->lvm_obj)); return NULL; } Py_INCREF(Py_None); return Py_None; } static PyObject * liblvm_lvm_lv_deactivate(lvobject *self) { int rval; LV_VALID(self); if ((rval = lvm_lv_deactivate(self->lv)) == -1) { PyErr_SetObject(LibLVMError, liblvm_get_last_error(self->lvm_obj)); return NULL; } Py_INCREF(Py_None); return Py_None; } static PyObject * liblvm_lvm_vg_remove_lv(lvobject *self) { int rval; LV_VALID(self); if ((rval = lvm_vg_remove_lv(self->lv)) == -1) { PyErr_SetObject(LibLVMError, liblvm_get_last_error(self->lvm_obj)); return NULL; } self->lv = NULL; Py_INCREF(Py_None); return Py_None; } /* This will return a tuple of (value, bool) with the value being a string or integer and bool indicating if property is settable */ static PyObject * liblvm_lvm_lv_get_property(lvobject *self, PyObject *args) { const char *name; struct lvm_property_value prop_value; LV_VALID(self); if (!PyArg_ParseTuple(args, "s", &name)) return NULL; prop_value = lvm_lv_get_property(self->lv, name); return get_property(self->lvm_obj, &prop_value); } static PyObject * liblvm_lvm_lv_get_size(lvobject *self) { LV_VALID(self); return Py_BuildValue("l", lvm_lv_get_size(self->lv)); } static PyObject * liblvm_lvm_lv_is_active(lvobject *self) { PyObject *rval; LV_VALID(self); rval = ( lvm_lv_is_active(self->lv) == 1) ? Py_True : Py_False; Py_INCREF(rval); return rval; } static PyObject * liblvm_lvm_lv_is_suspended(lvobject *self) { PyObject *rval; LV_VALID(self); rval = ( lvm_lv_is_suspended(self->lv) == 1) ? Py_True : Py_False; Py_INCREF(rval); return rval; } static PyObject * liblvm_lvm_lv_add_tag(lvobject *self, PyObject *args) { const char *tag; int rval; LV_VALID(self); if (!PyArg_ParseTuple(args, "s", &tag)) { return NULL; } if ((rval = lvm_lv_add_tag(self->lv, tag)) == -1) { PyErr_SetObject(LibLVMError, liblvm_get_last_error(self->lvm_obj)); return NULL; } Py_INCREF(Py_None); return Py_None; } static PyObject * liblvm_lvm_lv_remove_tag(lvobject *self, PyObject *args) { const char *tag; int rval; LV_VALID(self); if (!PyArg_ParseTuple(args, "s", &tag)) { return NULL; } if ((rval = lvm_lv_remove_tag(self->lv, tag)) == -1) { PyErr_SetObject(LibLVMError, liblvm_get_last_error(self->lvm_obj)); return NULL; } Py_INCREF(Py_None); return Py_None; } static PyObject * liblvm_lvm_lv_get_tags(lvobject *self) { struct dm_list *tags; struct lvm_str_list *strl; PyObject * pytuple; int i = 0; LV_VALID(self); tags = lvm_lv_get_tags(self->lv); if (!tags) { PyErr_SetObject(LibLVMError, liblvm_get_last_error(self->lvm_obj)); return NULL; } pytuple = PyTuple_New(dm_list_size(tags)); if (!pytuple) return NULL; dm_list_iterate_items(strl, tags) { PyTuple_SET_ITEM(pytuple, i, PyString_FromString(strl->str)); i++; } return pytuple; } static PyObject * liblvm_lvm_lv_rename(lvobject *self, PyObject *args) { const char *new_name; int rval; LV_VALID(self); if (!PyArg_ParseTuple(args, "s", &new_name)) return NULL; if ((rval = lvm_lv_rename(self->lv, new_name)) == -1) { PyErr_SetObject(LibLVMError, liblvm_get_last_error(self->lvm_obj)); return NULL; } Py_INCREF(Py_None); return Py_None; } static PyObject * liblvm_lvm_lv_resize(lvobject *self, PyObject *args) { uint64_t new_size; int rval; LV_VALID(self); if (!PyArg_ParseTuple(args, "l", &new_size)) { return NULL; } if ((rval = lvm_lv_resize(self->lv, new_size)) == -1) { PyErr_SetObject(LibLVMError, liblvm_get_last_error(self->lvm_obj)); return NULL; } Py_INCREF(Py_None); return Py_None; } static PyObject * liblvm_lvm_lv_list_lvsegs(lvobject *lv) { struct dm_list *lvsegs; lvseg_list_t *lvsegl; PyObject * pytuple; lvsegobject *self; int i = 0; LV_VALID(lv); lvsegs = lvm_lv_list_lvsegs(lv->lv); if(!lvsegs) { return Py_BuildValue("()"); } pytuple = PyTuple_New(dm_list_size(lvsegs)); if (!pytuple) return NULL; dm_list_iterate_items(lvsegl, lvsegs) { /* Create and initialize the object */ self = PyObject_New(lvsegobject, &LibLVMlvsegType); if (!self) { Py_DECREF(pytuple); return NULL; } self->lv_seg = lvsegl->lvseg; self->lvm_obj = lv->lvm_obj; PyTuple_SET_ITEM(pytuple, i, (PyObject *) self); i++; } return pytuple; } /* PV Methods */ #define PV_VALID(pvobject) \ do { \ if (!pvobject->pv || !pvobject->lvm_obj) { \ PyErr_SetString(PyExc_UnboundLocalError, "PV object invalid"); \ return NULL; \ } \ } while (0) static PyObject * liblvm_lvm_pv_get_name(pvobject *self) { return Py_BuildValue("s", lvm_pv_get_name(self->pv)); } static PyObject * liblvm_lvm_pv_get_uuid(pvobject *self) { return Py_BuildValue("s", lvm_pv_get_uuid(self->pv)); } static PyObject * liblvm_lvm_pv_get_mda_count(pvobject *self) { return Py_BuildValue("l", lvm_pv_get_mda_count(self->pv)); } static PyObject * liblvm_lvm_pv_get_property(pvobject *self, PyObject *args) { const char *name; struct lvm_property_value prop_value; PV_VALID(self); if (!PyArg_ParseTuple(args, "s", &name)) return NULL; prop_value = lvm_pv_get_property(self->pv, name); return get_property(self->lvm_obj, &prop_value); } static PyObject * liblvm_lvm_pv_get_dev_size(pvobject *self) { return Py_BuildValue("l", lvm_pv_get_dev_size(self->pv)); } static PyObject * liblvm_lvm_pv_get_size(pvobject *self) { return Py_BuildValue("l", lvm_pv_get_size(self->pv)); } static PyObject * liblvm_lvm_pv_get_free(pvobject *self) { return Py_BuildValue("l", lvm_pv_get_free(self->pv)); } static PyObject * liblvm_lvm_pv_resize(pvobject *self, PyObject *args) { uint64_t new_size; int rval; if (!PyArg_ParseTuple(args, "l", &new_size)) { return NULL; } if ((rval = lvm_pv_resize(self->pv, new_size)) == -1) { PyErr_SetObject(LibLVMError, liblvm_get_last_error(self->lvm_obj)); return NULL; } Py_INCREF(Py_None); return Py_None; } static PyObject * liblvm_lvm_lv_list_pvsegs(pvobject *pv) { struct dm_list *pvsegs; pvseg_list_t *pvsegl; PyObject *pytuple; pvsegobject *self; int i = 0; PV_VALID(pv); pvsegs = lvm_pv_list_pvsegs(pv->pv); if(!pvsegs) { return Py_BuildValue("()"); } pytuple = PyTuple_New(dm_list_size(pvsegs)); if (!pytuple) return NULL; dm_list_iterate_items(pvsegl, pvsegs) { /* Create and initialize the object */ self = PyObject_New(pvsegobject, &LibLVMpvsegType); if (!self) { Py_DECREF(pytuple); return NULL; } self->pv_seg = pvsegl->pvseg; self->lvm_obj = pv->lvm_obj; PyTuple_SET_ITEM(pytuple, i, (PyObject *) self); i++; } return pytuple; } /* LV seg methods */ static void liblvm_lvseg_dealloc(lvsegobject *self) { PyObject_Del(self); } static PyObject * liblvm_lvm_lvseg_get_property(lvsegobject *self, PyObject *args) { const char *name; struct lvm_property_value prop_value; if (!PyArg_ParseTuple(args, "s", &name)) return NULL; prop_value = lvm_lvseg_get_property(self->lv_seg, name); return get_property(self->lvm_obj, &prop_value); } /* PV seg methods */ static void liblvm_pvseg_dealloc(pvsegobject *self) { PyObject_Del(self); } static PyObject * liblvm_lvm_pvseg_get_property(pvsegobject *self, PyObject *args) { const char *name; struct lvm_property_value prop_value; if (!PyArg_ParseTuple(args, "s", &name)) return NULL; prop_value = lvm_pvseg_get_property(self->pv_seg, name); return get_property(self->lvm_obj, &prop_value); } /* ---------------------------------------------------------------------- * Method tables and other bureaucracy */ static PyMethodDef Liblvm_methods[] = { /* LVM methods */ { "getVersion", (PyCFunction)liblvm_library_get_version, METH_NOARGS }, { "vgOpen", (PyCFunction)liblvm_lvm_vg_open, METH_VARARGS }, { "vgCreate", (PyCFunction)liblvm_lvm_vg_create, METH_VARARGS }, { "close", (PyCFunction)liblvm_close, METH_NOARGS }, { "configFindBool", (PyCFunction)liblvm_lvm_config_find_bool, METH_VARARGS }, { "configReload", (PyCFunction)liblvm_lvm_config_reload, METH_NOARGS }, { "configOverride", (PyCFunction)liblvm_lvm_config_override, METH_VARARGS }, { "scan", (PyCFunction)liblvm_lvm_scan, METH_NOARGS }, { "listVgNames", (PyCFunction)liblvm_lvm_list_vg_names, METH_NOARGS }, { "listVgUuids", (PyCFunction)liblvm_lvm_list_vg_uuids, METH_NOARGS }, { "percentToFloat", (PyCFunction)liblvm_lvm_percent_to_float, METH_VARARGS }, { "vgNameFromPvid", (PyCFunction)liblvm_lvm_vgname_from_pvid, METH_VARARGS }, { "vgNameFromDevice", (PyCFunction)liblvm_lvm_vgname_from_device, METH_VARARGS }, { NULL, NULL} /* sentinel */ }; static PyMethodDef liblvm_vg_methods[] = { /* vg methods */ { "getName", (PyCFunction)liblvm_lvm_vg_get_name, METH_NOARGS }, { "getUuid", (PyCFunction)liblvm_lvm_vg_get_uuid, METH_NOARGS }, { "close", (PyCFunction)liblvm_lvm_vg_close, METH_NOARGS }, { "remove", (PyCFunction)liblvm_lvm_vg_remove, METH_NOARGS }, { "extend", (PyCFunction)liblvm_lvm_vg_extend, METH_VARARGS }, { "reduce", (PyCFunction)liblvm_lvm_vg_reduce, METH_VARARGS }, { "addTag", (PyCFunction)liblvm_lvm_vg_add_tag, METH_VARARGS }, { "removeTag", (PyCFunction)liblvm_lvm_vg_remove_tag, METH_VARARGS }, { "setExtentSize", (PyCFunction)liblvm_lvm_vg_set_extent_size, METH_VARARGS }, { "isClustered", (PyCFunction)liblvm_lvm_vg_is_clustered, METH_NOARGS }, { "isExported", (PyCFunction)liblvm_lvm_vg_is_exported, METH_NOARGS }, { "isPartial", (PyCFunction)liblvm_lvm_vg_is_partial, METH_NOARGS }, { "getSeqno", (PyCFunction)liblvm_lvm_vg_get_seqno, METH_NOARGS }, { "getSize", (PyCFunction)liblvm_lvm_vg_get_size, METH_NOARGS }, { "getFreeSize", (PyCFunction)liblvm_lvm_vg_get_free_size, METH_NOARGS }, { "getExtentSize", (PyCFunction)liblvm_lvm_vg_get_extent_size, METH_NOARGS }, { "getExtentCount", (PyCFunction)liblvm_lvm_vg_get_extent_count, METH_NOARGS }, { "getFreeExtentCount", (PyCFunction)liblvm_lvm_vg_get_free_extent_count, METH_NOARGS }, { "getProperty", (PyCFunction)liblvm_lvm_vg_get_property, METH_VARARGS }, { "setProperty", (PyCFunction)liblvm_lvm_vg_set_property, METH_VARARGS }, { "getPvCount", (PyCFunction)liblvm_lvm_vg_get_pv_count, METH_NOARGS }, { "getMaxPv", (PyCFunction)liblvm_lvm_vg_get_max_pv, METH_NOARGS }, { "getMaxLv", (PyCFunction)liblvm_lvm_vg_get_max_lv, METH_NOARGS }, { "listLVs", (PyCFunction)liblvm_lvm_vg_list_lvs, METH_NOARGS }, { "listPVs", (PyCFunction)liblvm_lvm_vg_list_pvs, METH_NOARGS }, { "lvFromName", (PyCFunction)liblvm_lvm_lv_from_name, METH_VARARGS }, { "lvFromUuid", (PyCFunction)liblvm_lvm_lv_from_uuid, METH_VARARGS }, { "pvFromName", (PyCFunction)liblvm_lvm_pv_from_name, METH_VARARGS }, { "pvFromUuid", (PyCFunction)liblvm_lvm_pv_from_uuid, METH_VARARGS }, { "getTags", (PyCFunction)liblvm_lvm_vg_get_tags, METH_NOARGS }, { "createLvLinear", (PyCFunction)liblvm_lvm_vg_create_lv_linear, METH_VARARGS }, { NULL, NULL} /* sentinel */ }; static PyMethodDef liblvm_lv_methods[] = { /* lv methods */ { "getName", (PyCFunction)liblvm_lvm_lv_get_name, METH_NOARGS }, { "getUuid", (PyCFunction)liblvm_lvm_lv_get_uuid, METH_NOARGS }, { "activate", (PyCFunction)liblvm_lvm_lv_activate, METH_NOARGS }, { "deactivate", (PyCFunction)liblvm_lvm_lv_deactivate, METH_NOARGS }, { "remove", (PyCFunction)liblvm_lvm_vg_remove_lv, METH_NOARGS }, { "getProperty", (PyCFunction)liblvm_lvm_lv_get_property, METH_VARARGS }, { "getSize", (PyCFunction)liblvm_lvm_lv_get_size, METH_NOARGS }, { "isActive", (PyCFunction)liblvm_lvm_lv_is_active, METH_NOARGS }, { "isSuspended", (PyCFunction)liblvm_lvm_lv_is_suspended, METH_NOARGS }, { "addTag", (PyCFunction)liblvm_lvm_lv_add_tag, METH_VARARGS }, { "removeTag", (PyCFunction)liblvm_lvm_lv_remove_tag, METH_VARARGS }, { "getTags", (PyCFunction)liblvm_lvm_lv_get_tags, METH_NOARGS }, { "rename", (PyCFunction)liblvm_lvm_lv_rename, METH_VARARGS }, { "resize", (PyCFunction)liblvm_lvm_lv_resize, METH_VARARGS }, { "listLVsegs", (PyCFunction)liblvm_lvm_lv_list_lvsegs, METH_NOARGS }, { NULL, NULL} /* sentinel */ }; static PyMethodDef liblvm_pv_methods[] = { /* pv methods */ { "getName", (PyCFunction)liblvm_lvm_pv_get_name, METH_NOARGS }, { "getUuid", (PyCFunction)liblvm_lvm_pv_get_uuid, METH_NOARGS }, { "getMdaCount", (PyCFunction)liblvm_lvm_pv_get_mda_count, METH_NOARGS }, { "getProperty", (PyCFunction)liblvm_lvm_pv_get_property, METH_VARARGS }, { "getSize", (PyCFunction)liblvm_lvm_pv_get_size, METH_NOARGS }, { "getDevSize", (PyCFunction)liblvm_lvm_pv_get_dev_size, METH_NOARGS }, { "getFree", (PyCFunction)liblvm_lvm_pv_get_free, METH_NOARGS }, { "resize", (PyCFunction)liblvm_lvm_pv_resize, METH_VARARGS }, { "listPVsegs", (PyCFunction)liblvm_lvm_lv_list_pvsegs, METH_NOARGS }, { NULL, NULL} /* sentinel */ }; static PyMethodDef liblvm_lvseg_methods[] = { { "getProperty", (PyCFunction)liblvm_lvm_lvseg_get_property, METH_VARARGS }, { NULL, NULL} /* sentinel */ }; static PyMethodDef liblvm_pvseg_methods[] = { { "getProperty", (PyCFunction)liblvm_lvm_pvseg_get_property, METH_VARARGS }, { NULL, NULL} /* sentinel */ }; static PyTypeObject LiblvmType = { PyObject_HEAD_INIT(&PyType_Type) .tp_name = "liblvm.Liblvm", .tp_basicsize = sizeof(lvmobject), .tp_new = PyType_GenericNew, .tp_dealloc = (destructor)liblvm_dealloc, .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, .tp_doc = "Liblvm objects", .tp_methods = Liblvm_methods, .tp_init = (initproc)liblvm_init, }; static PyTypeObject LibLVMvgType = { PyObject_HEAD_INIT(&PyType_Type) .tp_name = "liblvm.Liblvm_vg", .tp_basicsize = sizeof(vgobject), .tp_new = PyType_GenericNew, .tp_dealloc = (destructor)liblvm_vg_dealloc, .tp_flags = Py_TPFLAGS_DEFAULT, .tp_doc = "LVM Volume Group object", .tp_methods = liblvm_vg_methods, }; static PyTypeObject LibLVMlvType = { PyObject_HEAD_INIT(&PyType_Type) .tp_name = "liblvm.Liblvm_lv", .tp_basicsize = sizeof(lvobject), .tp_new = PyType_GenericNew, .tp_dealloc = (destructor)liblvm_lv_dealloc, .tp_flags = Py_TPFLAGS_DEFAULT, .tp_doc = "LVM Logical Volume object", .tp_methods = liblvm_lv_methods, }; static PyTypeObject LibLVMpvType = { PyObject_HEAD_INIT(&PyType_Type) .tp_name = "liblvm.Liblvm_pv", .tp_basicsize = sizeof(pvobject), .tp_new = PyType_GenericNew, .tp_dealloc = (destructor)liblvm_pv_dealloc, .tp_flags = Py_TPFLAGS_DEFAULT, .tp_doc = "LVM Physical Volume object", .tp_methods = liblvm_pv_methods, }; static PyTypeObject LibLVMlvsegType = { PyObject_HEAD_INIT(&PyType_Type) .tp_name = "liblvm.Liblvm_lvseg", .tp_basicsize = sizeof(lvsegobject), .tp_new = PyType_GenericNew, .tp_dealloc = (destructor)liblvm_lvseg_dealloc, .tp_flags = Py_TPFLAGS_DEFAULT, .tp_doc = "LVM Logical Volume Segment object", .tp_methods = liblvm_lvseg_methods, }; static PyTypeObject LibLVMpvsegType = { PyObject_HEAD_INIT(&PyType_Type) .tp_name = "liblvm.Liblvm_pvseg", .tp_basicsize = sizeof(pvsegobject), .tp_new = PyType_GenericNew, .tp_dealloc = (destructor)liblvm_pvseg_dealloc, .tp_flags = Py_TPFLAGS_DEFAULT, .tp_doc = "LVM Physical Volume Segment object", .tp_methods = liblvm_pvseg_methods, }; PyMODINIT_FUNC initlvm(void) { PyObject *m; if (PyType_Ready(&LiblvmType) < 0) return; if (PyType_Ready(&LibLVMvgType) < 0) return; if (PyType_Ready(&LibLVMlvType) < 0) return; if (PyType_Ready(&LibLVMpvType) < 0) return; if (PyType_Ready(&LibLVMlvsegType) < 0) return; if (PyType_Ready(&LibLVMpvsegType) < 0) return; m = Py_InitModule3("lvm", Liblvm_methods, "Liblvm module"); if (m == NULL) return; Py_INCREF(&LiblvmType); PyModule_AddObject(m, "Liblvm", (PyObject *)&LiblvmType); LibLVMError = PyErr_NewException("Liblvm.LibLVMError", NULL, NULL); if (LibLVMError) { /* Each call to PyModule_AddObject decrefs it; compensate: */ Py_INCREF(LibLVMError); Py_INCREF(LibLVMError); PyModule_AddObject(m, "error", LibLVMError); PyModule_AddObject(m, "LibLVMError", LibLVMError); } } lvm2-2.02.98/report-generators/0000750000175000017500000000000012037016272015171 5ustar blankblanklvm2-2.02.98/report-generators/lib/0000750000175000017500000000000012037016272015737 5ustar blankblanklvm2-2.02.98/report-generators/lib/schedule_file.rb0000640000175000017500000000257312037016272021067 0ustar blankblank# 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 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 # Parses the simple colon delimited test schedule files. ScheduledTest = Struct.new(:desc, :command_line, :status, :output) class Schedule attr_reader :dir, :schedules def initialize(dir, ss) @dir = dir @schedules = ss end def run Dir::chdir(@dir.to_s) do @schedules.each do |s| reader, writer = IO.pipe print "#{s.desc} ... " pid = spawn(s.command_line, [ STDERR, STDOUT ] => writer) writer.close _, s.status = Process::waitpid2(pid) puts (s.status.success? ? "pass" : "fail") s.output = reader.read end end end def self.read(dir, io) ss = Array.new io.readlines.each do |line| case line.strip when /^\#.*/ next when /([^:]+):(.*)/ ss << ScheduledTest.new($1.strip, $2.strip) else raise RuntimeError, "badly formatted schedule line" end end Schedule.new(dir, ss) end end lvm2-2.02.98/report-generators/lib/report_templates.rb0000640000175000017500000000223612037016272021661 0ustar blankblank# 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 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 # Policy for the location of report templates require 'string-store' class TemplateStringStore < StringStore def initialize() super(['report-generators/templates']) end end module ReportTemplates def generate_report(report, bs, dest_path = nil) include Reports reports = ReportRegister.new template_store = TemplateStringStore.new report = reports.get_report(report) erb = ERB.new(template_store.lookup(report.template)) body = erb.result(bs) title = report.short_desc erb = ERB.new(template_store.lookup("boiler_plate.rhtml")) txt = erb.result(binding) dest_path = dest_path.nil? ? report.path : dest_path dest_path.open("w") do |out| out.puts txt end end end lvm2-2.02.98/report-generators/lib/log.rb0000640000175000017500000000150412037016272017046 0ustar blankblank# 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 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 # Merely wraps the logger library with a bit of standard policy. require 'logger' module Log $log = Logger.new(STDERR) def init(io_) $log = Logger.new(io_) end end def fatal(*args) $log.fatal(*args) end def error(*args) $log.error(*args) end def info(*args) $log.info(*args) end def warning(*args) $log.warn(*args) end def debug(*args) $log.debug(*args) end lvm2-2.02.98/report-generators/lib/string-store.rb0000640000175000017500000000204012037016272020721 0ustar blankblank# 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 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 # Provides a simple way of accessing the contents of files by a symbol # name. Useful for erb templates. require 'pathname' class StringStore attr_accessor :path def initialize(p) @paths = p.nil? ? Array.new : p # FIXME: do we need to copy p ? end def lookup(sym) files = expansions(sym) @paths.each do |p| files.each do |f| pn = Pathname.new("#{p}/#{f}") if pn.file? return pn.read end end end raise RuntimeError, "unknown string entry: #{sym}" end private def expansions(sym) ["#{sym}", "#{sym}.txt"] end end lvm2-2.02.98/report-generators/lib/reports.rb0000640000175000017500000000323012037016272017761 0ustar blankblank# 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 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 # Data about the various reports we support require 'log' require 'pathname' module Reports Report = Struct.new(:short_desc, :desc, :path, :template) class ReportRegister attr_reader :reports private def add_report(sym, *args) @reports[sym] = Report.new(*args) end public def initialize() @reports = Hash.new add_report(:unit_test, "Unit Tests", "unit tests", Pathname.new("reports/unit.html"), Pathname.new("unit_test.rhtml")) add_report(:memcheck, "Memory Tests", "unit tests with valgrind memory checking", Pathname.new("reports/memcheck.html"), Pathname.new("memcheck.rhtml")) add_report(:unit_detail, "Unit Test Detail", "unit test detail", Pathname.new("reports/unit_detail.html"), # FIXME replace this with a lambda Pathname.new("unit_detail.rhtml")) end def get_report(sym) raise RuntimeError, "unknown report '#{sym}'" unless @reports.member?(sym) @reports[sym] end def each(&block) @reports.each(&block) end end end lvm2-2.02.98/report-generators/test/0000750000175000017500000000000012037016272016150 5ustar blankblanklvm2-2.02.98/report-generators/test/tc_string_store.rb0000640000175000017500000000170012037016272021704 0ustar blankblank# 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 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 require 'string-store' require 'test/unit' class TestStringStore < Test::Unit::TestCase def setup @ss = StringStore.new(['report-generators/test/strings', 'report-generators/test/strings/more_strings']) end def test_lookup assert_equal("Hello, world!\n", @ss.lookup(:test1)) assert_equal("one\ntwo\nthree", @ss.lookup(:test2)) assert_equal("lorem\n", @ss.lookup(:test3)) assert_raises(RuntimeError) do @ss.lookup(:unlikely_name) end end end lvm2-2.02.98/report-generators/test/example.schedule0000640000175000017500000000022312037016272021317 0ustar blankblank# This is a comment description number 1:$TEST_TOOL ls foo bar: $TEST_TOOL du -hs . this comment is prefixed with whitespace: $TEST_TOOL datelvm2-2.02.98/report-generators/test/tc_schedule_file.rb0000640000175000017500000000217512037016272021764 0ustar blankblank# 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 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 require 'test/unit' require 'pathname' require 'schedule_file' class TestScheduleFile < Test::Unit::TestCase def test_reading p = Pathname.new("report-generators/test/example.schedule") p.open do |f| s = Schedule.read(p.dirname, f) assert_equal(3, s.schedules.size) assert_equal(s.schedules[2].desc, "this comment is prefixed with whitespace") assert_equal(s.schedules[0].command_line, "$TEST_TOOL ls") end end def test_running p = Pathname.new("report-generators/test/example.schedule") p.open do |f| s = Schedule.read(p.dirname, f) s.run s.schedules.each do |t| assert(t.status.success?) end end end end lvm2-2.02.98/report-generators/test/tc_log.rb0000640000175000017500000000162212037016272017746 0ustar blankblank# 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 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 require 'test/unit' require 'stringio' require 'log' class TestLog < Test::Unit::TestCase include Log private def remove_timestamps(l) l.gsub(/\[[^\]]*\]/, '') end public def test_log StringIO.open do |out| init(out) info("msg1") warning("msg2") debug("msg3") assert_equal("I, INFO -- : msg1\nW, WARN -- : msg2\nD, DEBUG -- : msg3\n", remove_timestamps(out.string)) end end end lvm2-2.02.98/report-generators/test/ts.rb0000640000175000017500000000101112037016272017115 0ustar blankblank# 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 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 require 'tc_log' require 'tc_string_store' require 'tc_schedule_file' lvm2-2.02.98/report-generators/test/strings/0000750000175000017500000000000012037016272017641 5ustar blankblanklvm2-2.02.98/report-generators/test/strings/test1.txt0000640000175000017500000000001612037016272021440 0ustar blankblankHello, world! lvm2-2.02.98/report-generators/test/strings/more_strings/0000750000175000017500000000000012037016272022354 5ustar blankblanklvm2-2.02.98/report-generators/test/strings/more_strings/test3.txt0000640000175000017500000000000612037016272024154 0ustar blankblanklorem lvm2-2.02.98/report-generators/test/strings/test20000640000175000017500000000001512037016272020622 0ustar blankblankone two threelvm2-2.02.98/report-generators/templates/0000750000175000017500000000000012037016272017167 5ustar blankblanklvm2-2.02.98/report-generators/templates/unit_test.rhtml0000640000175000017500000000132512037016272022257 0ustar blankblank
Tests passedTests failed
<%= total_passed %>><%= total_failed %>
<% schedules.each do |s| %>

<%= s.dir.sub('./unit-tests/', '') %>

<% s.schedules.each do |t| %> <% if t.status.success? %> <% else %> <% end %> <% end %>
TestResult
<%= t.desc %> passfail
<% end %> lvm2-2.02.98/report-generators/templates/index.rhtml0000640000175000017500000000067312037016272021355 0ustar blankblank <% [:unit_test, :memcheck].each do |sym| %> <% r = reports.get_report(sym) %> <% end %>
ReportGeneration time
<% if r.path.file? %> <%= r.short_desc %> <% else %> <%= r.short_desc %> <% end %> <%= safe_mtime(r) %>
lvm2-2.02.98/report-generators/templates/boiler_plate.rhtml0000640000175000017500000000107512037016272022704 0ustar blankblank <%= title %> lvm2-2.02.98/report-generators/templates/unit_detail.rhtml0000640000175000017500000000120012037016272022532 0ustar blankblank <% if t.status.success? %> <% else %> <% end %>
TestResult
<%= t.desc %> passfail
Command line
<%= t.command_line %>
  
Output
<%= t.output %>
  
lvm2-2.02.98/report-generators/templates/memcheck.rhtml0000640000175000017500000000176012037016272022020 0ustar blankblank
Tests passedTests failed
<%= total_passed %>><%= total_failed %>
<% schedules.each do |s| %>

<%= s.dir.sub('./unit-tests/', '') %>

<% s.schedules.each do |t| %> <% if t.status.success? %> <% else %> <% end %> <% stats = extract_stats(t) %> <% end %>
TestResultDefinitely lostindirectly lostpossibly loststill reachable
<%= t.desc %> passfail<%= stats.definitely_lost %> <%= stats.indirectly_lost %> <%= stats.possibly_lost %> <%= stats.reachable %>
<% end %> lvm2-2.02.98/report-generators/memcheck.rb0000640000175000017500000000433212037016272017275 0ustar blankblank# 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 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 # Reads the schedule files given on the command line. Runs them and # generates the reports. # FIXME: a lot of duplication with unit_test.rb require 'schedule_file' require 'pathname' require 'reports' require 'erb' require 'report_templates' include ReportTemplates schedules = ARGV.map do |f| p = Pathname.new(f) Schedule.read(p.dirname, p) end total_passed = 0 total_failed = 0 # We need to make sure the lvm shared libs are in the LD_LIBRARY_PATH ENV['LD_LIBRARY_PATH'] = `pwd`.strip + "/libdm:" + (ENV['LD_LIBRARY_PATH'] || '') ENV['TEST_TOOL'] = "valgrind --leak-check=full --show-reachable=yes" schedules.each do |s| s.run s.schedules.each do |t| if t.status.success? total_passed += 1 else total_failed += 1 end end end def mangle(txt) txt.gsub(/\s+/, '_') end MemcheckStats = Struct.new(:definitely_lost, :indirectly_lost, :possibly_lost, :reachable) def format(bytes, blocks) "#{bytes} bytes, #{blocks} blocks" end # Examines the output for details of leaks def extract_stats(t) d = i = p = r = '-' t.output.split("\n").each do |l| case l when /==\d+== definitely lost: ([0-9,]+) bytes in ([0-9,]+) blocks/ d = format($1, $2) when /==\d+== indirectly lost: ([0-9,]+) bytes in ([0-9,]+) blocks/ i = format($1, $2) when /==\d+== possibly lost: ([0-9,]+) bytes in ([0-9,]+) blocks/ p = format($1, $2) when /==\d+== still reachable: ([0-9,]+) bytes in ([0-9,]+) blocks/ r = format($1, $2) end end MemcheckStats.new(d, i, p, r) end generate_report(:memcheck, binding) # now we generate a detail report for each schedule schedules.each do |s| s.schedules.each do |t| generate_report(:unit_detail, binding, Pathname.new("reports/memcheck_#{mangle(t.desc)}.html")) end end lvm2-2.02.98/report-generators/unit_test.rb0000640000175000017500000000256312037016272017543 0ustar blankblank# 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 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 # Reads the schedule files given on the command line. Runs them and # generates the reports. require 'schedule_file' require 'pathname' require 'reports' require 'erb' require 'report_templates' include ReportTemplates schedules = ARGV.map do |f| p = Pathname.new(f) Schedule.read(p.dirname, p) end total_passed = 0 total_failed = 0 # We need to make sure the lvm shared libs are in the LD_LIBRARY_PATH ENV['LD_LIBRARY_PATH'] = `pwd`.strip + "/libdm:" + (ENV['LD_LIBRARY_PATH'] || '') schedules.each do |s| s.run s.schedules.each do |t| if t.status.success? total_passed += 1 else total_failed += 1 end end end def mangle(txt) txt.gsub(/\s+/, '_') end generate_report(:unit_test, binding) # now we generate a detail report for each schedule schedules.each do |s| s.schedules.each do |t| generate_report(:unit_detail, binding, Pathname.new("reports/detail_#{mangle(t.desc)}.html")) end end lvm2-2.02.98/report-generators/title_page.rb0000640000175000017500000000210212037016272017627 0ustar blankblank# 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 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 # This generates the index for the reports, including generation # times. require 'log' require 'string-store' require 'reports' require 'erb' require 'report_templates' include Reports reports = ReportRegister.new def safe_mtime(r) r.path.file? ? r.path.mtime.to_s : "not generated" end template_store = TemplateStringStore.new # FIXME: use generate_report() method erb = ERB.new(template_store.lookup("index.rhtml")) body = erb.result(binding) title = "Generation times" erb = ERB.new(template_store.lookup("boiler_plate.rhtml")) txt = erb.result(binding) Pathname.new("reports/index.html").open("w") do |f| f.puts txt end lvm2-2.02.98/include/0000750000175000017500000000000012037016273013133 5ustar blankblanklvm2-2.02.98/include/.symlinks.in0000640000175000017500000000511412037016272015413 0ustar blankblank@top_srcdir@/daemons/clvmd/clvm.h @top_srcdir@/daemons/dmeventd/libdevmapper-event.h @top_srcdir@/daemons/lvmetad/lvmetad-client.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/cache/lvmetad.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-mpath.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@/libdaemon/client/daemon-client.h @top_srcdir@/libdaemon/client/daemon-io.h @top_srcdir@/libdaemon/client/config-util.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 lvm2-2.02.98/include/Makefile.in0000640000175000017500000000174112037016272015203 0ustar blankblank# # 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 lvm2-2.02.98/COPYING.LIB0000640000175000017500000006350412037016272013160 0ustar blankblank 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. Copyright (C) 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. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! lvm2-2.02.98/libdaemon/0000750000175000017500000000000012037016272013441 5ustar blankblanklvm2-2.02.98/libdaemon/client/0000750000175000017500000000000012037016272014717 5ustar blankblanklvm2-2.02.98/libdaemon/client/config-util.c0000640000175000017500000001611612037016272017311 0ustar blankblank/* * Copyright (C) 2011-2012 Red Hat, Inc. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU Lesser General Public License v.2.1. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include "dm-logging.h" #include "config-util.h" #include "libdevmapper.h" int buffer_append_vf(struct buffer *buf, va_list ap) { char *append; char *next; int keylen; int64_t value; char *string; char *block; while ((next = va_arg(ap, char *))) { append = NULL; if (!strchr(next, '=')) { log_error(INTERNAL_ERROR "Bad format string at '%s'", next); goto fail; } keylen = strchr(next, '=') - next; if (strstr(next, "%d") || strstr(next, "%" PRId64)) { value = va_arg(ap, int64_t); if (dm_asprintf(&append, "%.*s= %" PRId64 "\n", keylen, next, value) < 0) goto fail; } else if (strstr(next, "%s")) { string = va_arg(ap, char *); if (dm_asprintf(&append, "%.*s= \"%s\"\n", keylen, next, string) < 0) goto fail; } else if (strstr(next, "%b")) { if (!(block = va_arg(ap, char *))) continue; if (dm_asprintf(&append, "%.*s%s", keylen, next, block) < 0) goto fail; } else if (dm_asprintf(&append, "%s", next) < 0) goto fail; if (!append || !buffer_append(buf, append)) goto fail; dm_free(append); } return 1; fail: dm_free(append); return 0; } int buffer_append_f(struct buffer *buf, ...) { int res; va_list ap; va_start(ap, buf); res = buffer_append_vf(buf, ap); va_end(ap); return res; } int set_flag(struct dm_config_tree *cft, struct dm_config_node *parent, const char *field, const char *flag, int want) { struct dm_config_value *value = NULL, *pred = NULL; struct dm_config_node *node = dm_config_find_node(parent->child, field); struct dm_config_value *new; if (node) value = node->v; while (value && value->type != DM_CFG_EMPTY_ARRAY && strcmp(value->v.str, flag)) { pred = value; value = value->next; } if (value && want) return 1; if (!value && !want) return 1; if (value && !want) { if (pred) { pred->next = value->next; } else if (value == node->v && value->next) { node->v = value->next; } else { node->v->type = DM_CFG_EMPTY_ARRAY; } } if (!value && want) { if (!node) { if (!(node = dm_config_create_node(cft, field))) return 0; node->sib = parent->child; if (!(node->v = dm_config_create_value(cft))) return 0; node->v->type = DM_CFG_EMPTY_ARRAY; node->parent = parent; parent->child = node; } if (!(new = dm_config_create_value(cft))) { /* FIXME error reporting */ return 0; } new->type = DM_CFG_STRING; new->v.str = flag; new->next = node->v; node->v = new; } return 1; } static void chain_node(struct dm_config_node *cn, struct dm_config_node *parent, struct dm_config_node *pre_sib) { cn->parent = parent; cn->sib = NULL; if (parent && parent->child && !pre_sib) { /* find the last one */ pre_sib = parent->child; while (pre_sib && pre_sib->sib) pre_sib = pre_sib->sib; } if (parent && !parent->child) parent->child = cn; if (pre_sib) { cn->sib = pre_sib->sib; pre_sib->sib = cn; } } struct dm_config_node *make_config_node(struct dm_config_tree *cft, const char *key, struct dm_config_node *parent, struct dm_config_node *pre_sib) { struct dm_config_node *cn; if (!(cn = dm_config_create_node(cft, key))) return NULL; cn->v = NULL; cn->child = NULL; chain_node(cn, parent, pre_sib); return cn; } struct dm_config_node *make_text_node(struct dm_config_tree *cft, const char *key, const char *value, struct dm_config_node *parent, struct dm_config_node *pre_sib) { struct dm_config_node *cn; if (!(cn = make_config_node(cft, key, parent, pre_sib)) || !(cn->v = dm_config_create_value(cft))) return NULL; cn->v->type = DM_CFG_STRING; cn->v->v.str = value; return cn; } struct dm_config_node *make_int_node(struct dm_config_tree *cft, const char *key, int64_t value, struct dm_config_node *parent, struct dm_config_node *pre_sib) { struct dm_config_node *cn; if (!(cn = make_config_node(cft, key, parent, pre_sib)) || !(cn->v = dm_config_create_value(cft))) return NULL; cn->v->type = DM_CFG_INT; cn->v->v.i = value; return cn; } struct dm_config_node *config_make_nodes_v(struct dm_config_tree *cft, struct dm_config_node *parent, struct dm_config_node *pre_sib, va_list ap) { const char *next; struct dm_config_node *first = NULL; struct dm_config_node *cn; const char *fmt, *key; while ((next = va_arg(ap, char *))) { cn = NULL; fmt = strchr(next, '='); if (!fmt) { log_error(INTERNAL_ERROR "Bad format string '%s'", fmt); return_NULL; } fmt += 2; key = dm_pool_strdup(cft->mem, next); *strchr(key, '=') = 0; if (!strcmp(fmt, "%d") || !strcmp(fmt, "%" PRId64)) { int64_t value = va_arg(ap, int64_t); if (!(cn = make_int_node(cft, key, value, parent, pre_sib))) return 0; } else if (!strcmp(fmt, "%s")) { char *value = va_arg(ap, char *); if (!(cn = make_text_node(cft, key, value, parent, pre_sib))) return 0; } else if (!strcmp(fmt, "%t")) { struct dm_config_tree *tree = va_arg(ap, struct dm_config_tree *); cn = dm_config_clone_node(cft, tree->root, 1); if (!cn) return 0; cn->key = key; chain_node(cn, parent, pre_sib); } else { log_error(INTERNAL_ERROR "Bad format string '%s'", fmt); return_NULL; } if (!first) first = cn; if (cn) pre_sib = cn; } return first; } struct dm_config_node *config_make_nodes(struct dm_config_tree *cft, struct dm_config_node *parent, struct dm_config_node *pre_sib, ...) { struct dm_config_node *res; va_list ap; va_start(ap, pre_sib); res = config_make_nodes_v(cft, parent, pre_sib, ap); va_end(ap); return res; } int buffer_realloc(struct buffer *buf, int needed) { char *new; int alloc = buf->allocated; if (alloc < needed) alloc = needed; buf->allocated += alloc; new = realloc(buf->mem, buf->allocated); if (new) buf->mem = new; else { /* utter failure */ dm_free(buf->mem); buf->mem = 0; buf->allocated = buf->used = 0; return 0; } return 1; } int buffer_append(struct buffer *buf, const char *string) { int len = strlen(string); if ((buf->allocated - buf->used <= len) && !buffer_realloc(buf, len + 1)) return 0; strcpy(buf->mem + buf->used, string); buf->used += len; return 1; } int buffer_line(const char *line, void *baton) { struct buffer *buf = baton; if (!buffer_append(buf, line)) return 0; if (!buffer_append(buf, "\n")) return 0; return 1; } void buffer_destroy(struct buffer *buf) { dm_free(buf->mem); buffer_init(buf); } void buffer_init(struct buffer *buf) { buf->allocated = buf->used = 0; buf->mem = 0; } lvm2-2.02.98/libdaemon/client/daemon-io.h0000640000175000017500000000152612037016272016745 0ustar blankblank/* * Copyright (C) 2011-2012 Red Hat, Inc. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU Lesser General Public License v.2.1. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _LVM_DAEMON_IO_H #define _LVM_DAEMON_IO_H #include "configure.h" #include "config-util.h" #include "libdevmapper.h" #define _REENTRANT #define _GNU_SOURCE #define _FILE_OFFSET_BITS 64 /* TODO function names */ int buffer_read(int fd, struct buffer *buffer); int buffer_write(int fd, struct buffer *buffer); #endif /* _LVM_DAEMON_SHARED_H */ lvm2-2.02.98/libdaemon/client/Makefile.in0000640000175000017500000000132012037016272016761 0ustar blankblank# Copyright (C) 2011 Red Hat, Inc. All rights reserved. # # This file is part of the device-mapper userspace tools. # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions # of the GNU Lesser General Public License v.2.1. # # You should have received a copy of the GNU Lesser General Public License # along with this program; if not, write to the Free Software Foundation, # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA srcdir = @srcdir@ top_srcdir = @top_srcdir@ top_builddir = @top_builddir@ LIB_STATIC = libdaemonclient.a SOURCES = daemon-io.c config-util.c daemon-client.c include $(top_builddir)/make.tmpl lvm2-2.02.98/libdaemon/client/daemon-client.h0000640000175000017500000000733412037016272017617 0ustar blankblank/* * Copyright (C) 2011-2012 Red Hat, Inc. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU Lesser General Public License v.2.1. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _LVM_DAEMON_COMMON_CLIENT_H #define _LVM_DAEMON_COMMON_CLIENT_H #include "libdevmapper.h" #include "config-util.h" typedef struct { int socket_fd; /* the fd we use to talk to the daemon */ const char *protocol; int protocol_version; /* version of the protocol the daemon uses */ int error; } daemon_handle; typedef struct { const char *path; /* the binary of the daemon */ const char *socket; /* path to the comms socket */ unsigned autostart:1; /* start the daemon if not running? */ /* * If the following are not NULL/0, an attempt to talk to a daemon which * uses a different protocol or version will fail. */ const char *protocol; int protocol_version; } daemon_info; typedef struct { struct buffer buffer; /* * The request looks like this: * request = "id" * arg_foo = "something" * arg_bar = 3 * arg_wibble { * something_special = "here" * amount = 75 * knobs = [ "twiddle", "tweak" ] * } */ struct dm_config_tree *cft; } daemon_request; typedef struct { int error; /* 0 for success */ struct buffer buffer; struct dm_config_tree *cft; /* parsed reply, if available */ } daemon_reply; /* * Open the communication channel to the daemon. If the daemon is not running, * it may be autostarted based on the binary path provided in the info (this * will only happen if autostart is set to true). If the call fails for any * reason, daemon_handle_valid(h) for the response will return false. Otherwise, * the connection is good to start serving requests. */ daemon_handle daemon_open(daemon_info i); /* * Send a request to the daemon, waiting for the reply. All communication with * the daemon is synchronous. The function handles the IO details and parses the * response, handling common error conditions. See "daemon_reply" for details. * * In case the request contains a non-NULL buffer pointer, this buffer is sent * *verbatim* to the server. In this case, the cft pointer may be NULL (but will * be ignored even if non-NULL). If the buffer is NULL, the cft is required to * be a valid pointer, and is used to build up the request. */ daemon_reply daemon_send(daemon_handle h, daemon_request r); /* * A simple interface to daemon_send. This function just takes the command id * and possibly a list of parameters (of the form "name = %?", "value"). The * type (string, integer) of the value is indicated by a character substituted * for ? in %?: d for integer, s for string. */ daemon_reply daemon_send_simple(daemon_handle h, const char *id, ...); daemon_reply daemon_send_simple_v(daemon_handle h, const char *id, va_list ap); daemon_request daemon_request_make(const char *id); int daemon_request_extend(daemon_request r, ...); int daemon_request_extend_v(daemon_request r, va_list ap); void daemon_request_destroy(daemon_request r); void daemon_reply_destroy(daemon_reply r); static inline int64_t daemon_reply_int(daemon_reply r, const char *path, int64_t def) { return dm_config_find_int64(r.cft->root, path, def); } static inline const char *daemon_reply_str(daemon_reply r, const char *path, const char *def) { return dm_config_find_str(r.cft->root, path, def); } /* Shut down the communication to the daemon. Compulsory. */ void daemon_close(daemon_handle h); #endif lvm2-2.02.98/libdaemon/client/daemon-io.c0000640000175000017500000000513612037016272016741 0ustar blankblank/* * Copyright (C) 2011-2012 Red Hat, Inc. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU Lesser General Public License v.2.1. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include "daemon-io.h" #include "libdevmapper.h" /* * Read a single message from a (socket) filedescriptor. Messages are delimited * by blank lines. This call will block until all of a message is received. The * memory will be allocated from heap. Upon error, all memory is freed and the * buffer pointer is set to NULL. * * See also write_buffer about blocking (read_buffer has identical behaviour). */ int buffer_read(int fd, struct buffer *buffer) { if (!buffer_realloc(buffer, 32)) /* ensure we have some space */ goto fail; while (1) { int result = read(fd, buffer->mem + buffer->used, buffer->allocated - buffer->used); if (result > 0) { buffer->used += result; if (!strncmp((buffer->mem) + buffer->used - 4, "\n##\n", 4)) { *(buffer->mem + buffer->used - 4) = 0; buffer->used -= 4; break; /* success, we have the full message now */ } if (buffer->used - buffer->allocated < 32) if (!buffer_realloc(buffer, 1024)) goto fail; continue; } if (result == 0) { errno = ECONNRESET; goto fail; /* we should never encounter EOF here */ } if (result < 0 && errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) goto fail; /* TODO call select here if we encountered EAGAIN/EWOULDBLOCK/EINTR */ } return 1; fail: return 0; } /* * Write a buffer to a filedescriptor. Keep trying. Blocks (even on * SOCK_NONBLOCK) until all of the write went through. * * TODO use select on EWOULDBLOCK/EAGAIN/EINTR to avoid useless spinning */ int buffer_write(int fd, struct buffer *buffer) { struct buffer terminate = { .mem = (char *) "\n##\n", .used = 4 }; int done = 0; int written = 0; struct buffer *use = buffer; write: while (1) { int result = write(fd, use->mem + written, use->used - written); if (result > 0) written += result; if (result < 0 && errno != EWOULDBLOCK && errno != EAGAIN && errno != EINTR) return 0; /* too bad */ if (written == use->used) { if (done) return 1; else break; /* done */ } } use = &terminate; written = 0; done = 1; goto write; } lvm2-2.02.98/libdaemon/client/daemon-client.c0000640000175000017500000001020512037016272017601 0ustar blankblank/* * Copyright (C) 2011-2012 Red Hat, Inc. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU Lesser General Public License v.2.1. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "daemon-io.h" #include "config-util.h" #include "daemon-client.h" #include "dm-logging.h" #include #include #include #include #include #include #include // ENOMEM daemon_handle daemon_open(daemon_info i) { daemon_handle h = { .protocol_version = 0, .error = 0 }; daemon_reply r = { .cft = NULL }; struct sockaddr_un sockaddr = { .sun_family = AF_UNIX }; if ((h.socket_fd = socket(PF_UNIX, SOCK_STREAM /* | SOCK_NONBLOCK */, 0)) < 0) goto error; if (!dm_strncpy(sockaddr.sun_path, i.socket, sizeof(sockaddr.sun_path))) { fprintf(stderr, "%s: daemon socket path too long.\n", i.socket); goto error; } if (connect(h.socket_fd,(struct sockaddr *) &sockaddr, sizeof(sockaddr))) goto error; r = daemon_send_simple(h, "hello", NULL); if (r.error || strcmp(daemon_reply_str(r, "response", "unknown"), "OK")) goto error; h.protocol = daemon_reply_str(r, "protocol", NULL); if (h.protocol) h.protocol = dm_strdup(h.protocol); /* keep around */ h.protocol_version = daemon_reply_int(r, "version", 0); if (i.protocol && (!h.protocol || strcmp(h.protocol, i.protocol))) goto error; if (i.protocol_version && h.protocol_version != i.protocol_version) goto error; daemon_reply_destroy(r); return h; error: h.error = errno; if (h.socket_fd >= 0) if (close(h.socket_fd)) log_sys_error("close", "daemon_open"); if (r.cft) daemon_reply_destroy(r); h.socket_fd = -1; return h; } daemon_reply daemon_send(daemon_handle h, daemon_request rq) { struct buffer buffer; daemon_reply reply = { .cft = NULL, .error = 0 }; assert(h.socket_fd >= 0); buffer = rq.buffer; if (!buffer.mem) dm_config_write_node(rq.cft->root, buffer_line, &buffer); assert(buffer.mem); if (!buffer_write(h.socket_fd, &buffer)) reply.error = errno; if (buffer_read(h.socket_fd, &reply.buffer)) { reply.cft = dm_config_from_string(reply.buffer.mem); if (!reply.cft) reply.error = EPROTO; } else reply.error = errno; if (buffer.mem != rq.buffer.mem) buffer_destroy(&buffer); return reply; } void daemon_reply_destroy(daemon_reply r) { if (r.cft) dm_config_destroy(r.cft); buffer_destroy(&r.buffer); } daemon_reply daemon_send_simple_v(daemon_handle h, const char *id, va_list ap) { static const daemon_reply err = { .error = ENOMEM, .buffer = { 0, 0, NULL }, .cft = NULL }; daemon_request rq = { .cft = NULL }; daemon_reply repl; if (!buffer_append_f(&rq.buffer, "request = %s", id, NULL) || !buffer_append_vf(&rq.buffer, ap)) { buffer_destroy(&rq.buffer); return err; } repl = daemon_send(h, rq); buffer_destroy(&rq.buffer); return repl; } daemon_reply daemon_send_simple(daemon_handle h, const char *id, ...) { daemon_reply r; va_list ap; va_start(ap, id); r = daemon_send_simple_v(h, id, ap); va_end(ap); return r; } void daemon_close(daemon_handle h) { dm_free((char *)h.protocol); } daemon_request daemon_request_make(const char *id) { daemon_request r; r.cft = NULL; buffer_init(&r.buffer); if (!(r.cft = dm_config_create())) goto bad; if (!(r.cft->root = make_text_node(r.cft, "request", id, NULL, NULL))) goto bad; return r; bad: if (r.cft) dm_config_destroy(r.cft); r.cft = NULL; return r; } int daemon_request_extend_v(daemon_request r, va_list ap) { if (!r.cft) return 0; if (!config_make_nodes_v(r.cft, NULL, r.cft->root, ap)) return 0; return 1; } int daemon_request_extend(daemon_request r, ...) { int res; va_list ap; va_start(ap, r); res = daemon_request_extend_v(r, ap); va_end(ap); return res; } void daemon_request_destroy(daemon_request r) { if (r.cft) dm_config_destroy(r.cft); buffer_destroy(&r.buffer); } lvm2-2.02.98/libdaemon/client/config-util.h0000640000175000017500000000406412037016272017315 0ustar blankblank/* * Copyright (C) 2011-2012 Red Hat, Inc. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU Lesser General Public License v.2.1. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _LVM_DAEMON_CONFIG_UTIL_H #define _LVM_DAEMON_CONFIG_UTIL_H #include "configure.h" #include "libdevmapper.h" #include struct buffer { int allocated; int used; char *mem; }; int buffer_append_vf(struct buffer *buf, va_list ap); int buffer_append_f(struct buffer *buf, ...); int buffer_append(struct buffer *buf, const char *string); void buffer_init(struct buffer *buf); void buffer_destroy(struct buffer *buf); int buffer_realloc(struct buffer *buf, int required); int buffer_line(const char *line, void *baton); int set_flag(struct dm_config_tree *cft, struct dm_config_node *parent, const char *field, const char *flag, int want); struct dm_config_node *make_config_node(struct dm_config_tree *cft, const char *key, struct dm_config_node *parent, struct dm_config_node *pre_sib); struct dm_config_node *make_text_node(struct dm_config_tree *cft, const char *key, const char *value, struct dm_config_node *parent, struct dm_config_node *pre_sib); struct dm_config_node *make_int_node(struct dm_config_tree *cft, const char *key, int64_t value, struct dm_config_node *parent, struct dm_config_node *pre_sib); struct dm_config_node *config_make_nodes_v(struct dm_config_tree *cft, struct dm_config_node *parent, struct dm_config_node *pre_sib, va_list ap); struct dm_config_node *config_make_nodes(struct dm_config_tree *cft, struct dm_config_node *parent, struct dm_config_node *pre_sib, ...); #endif /* _LVM_DAEMON_SHARED_H */ lvm2-2.02.98/libdaemon/Makefile.in0000640000175000017500000000141412037016272015507 0ustar blankblank# # Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved. # # This file is part of LVM2. # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions # of the GNU General Public License v.2. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation, # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA srcdir = @srcdir@ top_srcdir = @top_srcdir@ top_builddir = @top_builddir@ .PHONY: client server SUBDIRS += client ifeq ("@BUILD_LVMETAD@", "yes") SUBDIRS += server server: client endif ifeq ($(MAKECMDGOALS),distclean) SUBDIRS = client server endif include $(top_builddir)/make.tmpl lvm2-2.02.98/libdaemon/server/0000750000175000017500000000000012037016272014747 5ustar blankblanklvm2-2.02.98/libdaemon/server/daemon-log.h0000640000175000017500000000250212037016272017142 0ustar blankblank/* * Copyright (C) 2012 Red Hat, Inc. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU Lesser General Public License v.2.1. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _LVM_DAEMON_LOG_H #define _LVM_DAEMON_LOG_H enum { DAEMON_LOG_FATAL = 0 /* usually preceding daemon death */ , DAEMON_LOG_ERROR = 1 /* something serious has happened */ , DAEMON_LOG_WARN = 2 /* something unusual has happened */ , DAEMON_LOG_INFO = 3 /* thought you might be interested */ , DAEMON_LOG_WIRE = 4 /* dump traffic on client sockets */ , DAEMON_LOG_DEBUG = 5 /* unsorted debug stuff */ }; #define DEBUGLOG(s, x...) daemon_logf((s)->log, DAEMON_LOG_DEBUG, x) #define DEBUGLOG_cft(s, i, n) daemon_log_cft((s)->log, DAEMON_LOG_DEBUG, i, n) #define WARN(s, x...) daemon_logf((s)->log, DAEMON_LOG_WARN, x) #define INFO(s, x...) daemon_logf((s)->log, DAEMON_LOG_INFO, x) #define ERROR(s, x...) daemon_logf((s)->log, DAEMON_LOG_ERROR, x) #define FATAL(s, x...) daemon_logf((s)->log, DAEMON_LOG_FATAL, x) #endif lvm2-2.02.98/libdaemon/server/Makefile.in0000640000175000017500000000133312037016272017015 0ustar blankblank# Copyright (C) 2011 Red Hat, Inc. All rights reserved. # # This file is part of the device-mapper userspace tools. # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions # of the GNU Lesser General Public License v.2.1. # # You should have received a copy of the GNU Lesser General Public License # along with this program; if not, write to the Free Software Foundation, # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA srcdir = @srcdir@ top_srcdir = @top_srcdir@ top_builddir = @top_builddir@ LIB_STATIC = libdaemonserver.a SOURCES = daemon-server.c daemon-log.c include $(top_builddir)/make.tmpl LIBS += $(DAEMON_LIBS) lvm2-2.02.98/libdaemon/server/daemon-server.h0000640000175000017500000001204012037016272017665 0ustar blankblank/* * Copyright (C) 2011-2012 Red Hat, Inc. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU Lesser General Public License v.2.1. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _LVM_DAEMON_COMMON_SERVER_H #define _LVM_DAEMON_COMMON_SERVER_H #include "daemon-client.h" typedef struct { int socket_fd; /* the fd we use to talk to the client */ pthread_t thread_id; char *read_buf; void *private; /* this holds per-client state */ } client_handle; typedef struct { struct dm_config_tree *cft; struct buffer buffer; } request; typedef struct { int error; struct dm_config_tree *cft; struct buffer buffer; } response; struct daemon_state; /* * Craft a simple reply, without the need to construct a config_tree. See * daemon_send_simple in daemon-client.h for the description of the parameters. */ response daemon_reply_simple(const char *id, ...); static inline int daemon_request_int(request r, const char *path, int def) { if (!r.cft) return def; return dm_config_find_int(r.cft->root, path, def); } static inline const char *daemon_request_str(request r, const char *path, const char *def) { if (!r.cft) return def; return dm_config_find_str(r.cft->root, path, def); } /* * The callback. Called once per request issued, in the respective client's * thread. It is presented by a parsed request (in the form of a config tree). * The output is a new config tree that is serialised and sent back to the * client. The client blocks until the request processing is done and reply is * sent. */ typedef response (*handle_request)(struct daemon_state s, client_handle h, request r); typedef struct { uint32_t log_config[32]; void *backend_state[32]; const char *name; } log_state; typedef struct daemon_state { /* * The maximal stack size for individual daemon threads. This is * essential for daemons that need to be locked into memory, since * pthread's default is 10M per thread. */ int thread_stack_size; /* Flags & attributes affecting the behaviour of the daemon. */ unsigned avoid_oom:1; unsigned foreground:1; const char *name; const char *pidfile; const char *socket_path; const char *protocol; int protocol_version; handle_request handler; int (*daemon_init)(struct daemon_state *st); int (*daemon_fini)(struct daemon_state *st); /* Global runtime info maintained by the framework. */ int socket_fd; log_state *log; void *private; /* the global daemon state */ } daemon_state; /* * Start serving the requests. This does all the daemonisation, socket setup * work and so on. This function takes over the process, and upon failure, it * will terminate execution. It may be called at most once. */ void daemon_start(daemon_state s); /* * Take over from an already running daemon. This function handles connecting * to the running daemon and telling it we are going to take over. The takeover * request may be customised by passing in a non-NULL request. * * The takeover sequence: the old daemon stops accepting new clients, then it * waits until all current client connections are closed. When that happens, it * serializes its current state and sends that as a reply, which is then * returned by this function (therefore, this function won't return until the * previous instance has shut down). * * The daemon, after calling daemon_takeover is expected to set up its * daemon_state using the reply from this function and call daemon_start as * usual. */ daemon_reply daemon_takeover(daemon_info i, daemon_request r); /* Call this to request a clean shutdown of the daemon. Async safe. */ void daemon_stop(void); enum { DAEMON_LOG_OUTLET_SYSLOG = 1, DAEMON_LOG_OUTLET_STDERR = 2, DAEMON_LOG_OUTLET_SOCKET = 4 }; /* Log a message of a given type. */ void daemon_log(log_state *s, int type, const char *message); /* Log a config (sub)tree, using a given message type, each line prefixed with "prefix". */ void daemon_log_cft(log_state *s, int type, const char *prefix, const struct dm_config_node *n); /* Log a multi-line block, prefixing each line with "prefix". */ void daemon_log_multi(log_state *s, int type, const char *prefix, const char *message); /* Log a formatted message as "type". See also daemon-log.h. */ void daemon_logf(log_state *s, int type, const char *format, ...); /* * Configure log_state to send messages of type "type" to the log outlet * "outlet", iff "enable" is true. */ void daemon_log_enable(log_state *s, int outlet, int type, int enable); /* * Set up logging on a given outlet using a list of message types (comma * separated) to log using that outlet. The list is expected to look like this, * "all,wire,debug". Returns 0 upon encountering an unknown message type. */ int daemon_log_parse(log_state *s, int outlet, const char *types, int enable); #endif lvm2-2.02.98/libdaemon/server/daemon-server.c0000640000175000017500000003063212037016272017667 0ustar blankblank/* * Copyright (C) 2011-2012 Red Hat, Inc. * * 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 "daemon-io.h" #include "config-util.h" #include "daemon-server.h" #include "daemon-log.h" #include #include #include #include #include #include #include #include #include #include #include #include #include /* FIXME. For the global closelog(). */ #if 0 /* Create a device monitoring thread. */ static int _pthread_create(pthread_t *t, void *(*fun)(void *), void *arg, int stacksize) { pthread_attr_t attr; pthread_attr_init(&attr); /* * We use a smaller stack since it gets preallocated in its entirety */ pthread_attr_setstacksize(&attr, stacksize); return pthread_create(t, &attr, fun, arg); } #endif static volatile sig_atomic_t _shutdown_requested = 0; static int _systemd_activation = 0; static void _exit_handler(int sig __attribute__((unused))) { _shutdown_requested = 1; } #ifdef linux #include /* * Kernel version 2.6.36 and higher has * new OOM killer adjustment interface. */ # define OOM_ADJ_FILE_OLD "/proc/self/oom_adj" # define OOM_ADJ_FILE "/proc/self/oom_score_adj" /* From linux/oom.h */ /* Old interface */ # define OOM_DISABLE (-17) # define OOM_ADJUST_MIN (-16) /* New interface */ # define OOM_SCORE_ADJ_MIN (-1000) /* Systemd on-demand activation support */ # define SD_ACTIVATION_ENV_VAR_NAME "SD_ACTIVATION" # define SD_LISTEN_PID_ENV_VAR_NAME "LISTEN_PID" # define SD_LISTEN_FDS_ENV_VAR_NAME "LISTEN_FDS" # define SD_LISTEN_FDS_START 3 # define SD_FD_SOCKET_SERVER SD_LISTEN_FDS_START # include static int _set_oom_adj(const char *oom_adj_path, int val) { FILE *fp; if (!(fp = fopen(oom_adj_path, "w"))) { perror("oom_adj: fopen failed"); return 0; } fprintf(fp, "%i", val); if (dm_fclose(fp)) perror("oom_adj: fclose failed"); return 1; } /* * Protection against OOM killer if kernel supports it */ static int _protect_against_oom_killer(void) { struct stat st; if (stat(OOM_ADJ_FILE, &st) == -1) { if (errno != ENOENT) perror(OOM_ADJ_FILE ": stat failed"); /* Try old oom_adj interface as a fallback */ if (stat(OOM_ADJ_FILE_OLD, &st) == -1) { if (errno == ENOENT) perror(OOM_ADJ_FILE_OLD " not found"); else perror(OOM_ADJ_FILE_OLD ": stat failed"); return 1; } return _set_oom_adj(OOM_ADJ_FILE_OLD, OOM_DISABLE) || _set_oom_adj(OOM_ADJ_FILE_OLD, OOM_ADJUST_MIN); } return _set_oom_adj(OOM_ADJ_FILE, OOM_SCORE_ADJ_MIN); } union sockaddr_union { struct sockaddr sa; struct sockaddr_un un; }; static int _handle_preloaded_socket(int fd, const char *path) { struct stat st_fd; union sockaddr_union sockaddr = { .sa.sa_family = 0 }; int type = 0; socklen_t len = sizeof(type); size_t path_len = strlen(path); if (fd < 0) return 0; if (fstat(fd, &st_fd) < 0 || !S_ISSOCK(st_fd.st_mode)) return 0; if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &len) < 0 || len != sizeof(type) || type != SOCK_STREAM) return 0; len = sizeof(sockaddr); if (getsockname(fd, &sockaddr.sa, &len) < 0 || len < sizeof(sa_family_t) || sockaddr.sa.sa_family != PF_UNIX) return 0; if (!(len >= offsetof(struct sockaddr_un, sun_path) + path_len + 1 && memcmp(path, sockaddr.un.sun_path, path_len) == 0)) return 0; return 1; } static int _systemd_handover(struct daemon_state *ds) { const char *e; char *p; unsigned long env_pid, env_listen_fds; int r = 0; /* SD_ACTIVATION must be set! */ if (!(e = getenv(SD_ACTIVATION_ENV_VAR_NAME)) || strcmp(e, "1")) goto out; /* LISTEN_PID must be equal to our PID! */ if (!(e = getenv(SD_LISTEN_PID_ENV_VAR_NAME))) goto out; errno = 0; env_pid = strtoul(e, &p, 10); if (errno || !p || *p || env_pid <= 0 || getpid() != (pid_t) env_pid) goto out; /* LISTEN_FDS must be 1 and the fd must be a socket! */ if (!(e = getenv(SD_LISTEN_FDS_ENV_VAR_NAME))) goto out; errno = 0; env_listen_fds = strtoul(e, &p, 10); if (errno || !p || *p || env_listen_fds != 1) goto out; /* Check and handle the socket passed in */ if ((r = _handle_preloaded_socket(SD_FD_SOCKET_SERVER, ds->socket_path))) ds->socket_fd = SD_FD_SOCKET_SERVER; out: unsetenv(SD_ACTIVATION_ENV_VAR_NAME); unsetenv(SD_LISTEN_PID_ENV_VAR_NAME); unsetenv(SD_LISTEN_FDS_ENV_VAR_NAME); return r; } #endif static int _open_socket(daemon_state s) { int fd = -1; struct sockaddr_un sockaddr = { .sun_family = AF_UNIX }; mode_t old_mask; (void) dm_prepare_selinux_context(s.socket_path, S_IFSOCK); old_mask = umask(0077); /* Open local socket */ fd = socket(PF_UNIX, SOCK_STREAM, 0); if (fd < 0) { perror("Can't create local socket."); goto error; } /* Set Close-on-exec & non-blocking */ if (fcntl(fd, F_SETFD, 1)) fprintf(stderr, "setting CLOEXEC on socket fd %d failed: %s\n", fd, strerror(errno)); if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK)) fprintf(stderr, "setting O_NONBLOCK on socket fd %d failed: %s\n", fd, strerror(errno)); fprintf(stderr, "[D] creating %s\n", s.socket_path); if (!dm_strncpy(sockaddr.sun_path, s.socket_path, sizeof(sockaddr.sun_path))) { fprintf(stderr, "%s: daemon socket path too long.\n", s.socket_path); goto error; } if (bind(fd, (struct sockaddr *) &sockaddr, sizeof(sockaddr))) { perror("can't bind local socket."); goto error; } if (listen(fd, 1) != 0) { perror("listen local"); goto error; } out: umask(old_mask); (void) dm_prepare_selinux_context(NULL, 0); return fd; error: if (fd >= 0) { if (close(fd)) perror("close failed"); if (unlink(s.socket_path)) perror("unlink failed"); fd = -1; } goto out; } static void remove_lockfile(const char *file) { if (unlink(file)) perror("unlink failed"); } static void _daemonise(void) { int child_status; int fd; pid_t pid; struct rlimit rlim; struct timeval tval; sigset_t my_sigset; sigemptyset(&my_sigset); if (sigprocmask(SIG_SETMASK, &my_sigset, NULL) < 0) { fprintf(stderr, "Unable to restore signals.\n"); exit(EXIT_FAILURE); } signal(SIGTERM, &_exit_handler); switch (pid = fork()) { case -1: perror("fork failed:"); exit(EXIT_FAILURE); case 0: /* Child */ break; default: /* Wait for response from child */ while (!waitpid(pid, &child_status, WNOHANG) && !_shutdown_requested) { tval.tv_sec = 0; tval.tv_usec = 250000; /* .25 sec */ select(0, NULL, NULL, NULL, &tval); } if (_shutdown_requested) /* Child has signaled it is ok - we can exit now */ exit(0); /* Problem with child. Determine what it is by exit code */ fprintf(stderr, "Child exited with code %d\n", WEXITSTATUS(child_status)); exit(WEXITSTATUS(child_status)); } if (chdir("/")) exit(1); if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) fd = 256; /* just have to guess */ else fd = rlim.rlim_cur; for (--fd; fd >= 0; fd--) { #ifdef linux /* Do not close fds preloaded by systemd! */ if (_systemd_activation && fd == SD_FD_SOCKET_SERVER) continue; #endif (void) close(fd); } if ((open("/dev/null", O_RDONLY) < 0) || (open("/dev/null", O_WRONLY) < 0) || (open("/dev/null", O_WRONLY) < 0)) exit(1); setsid(); } response daemon_reply_simple(const char *id, ...) { va_list ap; response res = { .cft = NULL }; va_start(ap, id); buffer_init(&res.buffer); if (!buffer_append_f(&res.buffer, "response = %s", id, NULL)) { res.error = ENOMEM; goto end; } if (!buffer_append_vf(&res.buffer, ap)) { res.error = ENOMEM; goto end; } end: va_end(ap); return res; } struct thread_baton { daemon_state s; client_handle client; }; static response builtin_handler(daemon_state s, client_handle h, request r) { const char *rq = daemon_request_str(r, "request", "NONE"); response res = { .error = EPROTO }; if (!strcmp(rq, "hello")) { return daemon_reply_simple("OK", "protocol = %s", s.protocol ?: "default", "version = %" PRId64, (int64_t) s.protocol_version, NULL); } buffer_init(&res.buffer); return res; } static void *client_thread(void *baton) { struct thread_baton *b = baton; request req; response res; buffer_init(&req.buffer); while (1) { if (!buffer_read(b->client.socket_fd, &req.buffer)) goto fail; req.cft = dm_config_from_string(req.buffer.mem); if (!req.cft) fprintf(stderr, "error parsing request:\n %s\n", req.buffer.mem); else daemon_log_cft(b->s.log, DAEMON_LOG_WIRE, "<- ", req.cft->root); res = builtin_handler(b->s, b->client, req); if (res.error == EPROTO) /* Not a builtin, delegate to the custom handler. */ res = b->s.handler(b->s, b->client, req); if (!res.buffer.mem) { dm_config_write_node(res.cft->root, buffer_line, &res.buffer); if (!buffer_append(&res.buffer, "\n\n")) goto fail; dm_config_destroy(res.cft); } if (req.cft) dm_config_destroy(req.cft); buffer_destroy(&req.buffer); daemon_log_multi(b->s.log, DAEMON_LOG_WIRE, "-> ", res.buffer.mem); buffer_write(b->client.socket_fd, &res.buffer); buffer_destroy(&res.buffer); } fail: /* TODO what should we really do here? */ if (close(b->client.socket_fd)) perror("close"); buffer_destroy(&req.buffer); dm_free(baton); return NULL; } static int handle_connect(daemon_state s) { struct thread_baton *baton; struct sockaddr_un sockaddr; client_handle client = { .thread_id = 0 }; socklen_t sl = sizeof(sockaddr); client.socket_fd = accept(s.socket_fd, (struct sockaddr *) &sockaddr, &sl); if (client.socket_fd < 0) return 0; if (!(baton = malloc(sizeof(struct thread_baton)))) return 0; baton->s = s; baton->client = client; if (pthread_create(&baton->client.thread_id, NULL, client_thread, baton)) return 0; pthread_detach(baton->client.thread_id); return 1; } void daemon_start(daemon_state s) { int failed = 0; log_state _log = { { 0 } }; /* * Switch to C locale to avoid reading large locale-archive file used by * some glibc (on some distributions it takes over 100MB). Some daemons * need to use mlockall(). */ if (setenv("LANG", "C", 1)) perror("Cannot set LANG to C"); #ifdef linux _systemd_activation = _systemd_handover(&s); #endif if (!s.foreground) _daemonise(); s.log = &_log; s.log->name = s.name; /* Log important things to syslog by default. */ daemon_log_enable(s.log, DAEMON_LOG_OUTLET_SYSLOG, DAEMON_LOG_FATAL, 1); daemon_log_enable(s.log, DAEMON_LOG_OUTLET_SYSLOG, DAEMON_LOG_ERROR, 1); if (s.pidfile) { (void) dm_prepare_selinux_context(s.pidfile, S_IFREG); /* * NB. Take care to not keep stale locks around. Best not exit(...) * after this point. */ if (dm_create_lockfile(s.pidfile) == 0) exit(1); (void) dm_prepare_selinux_context(NULL, 0); } /* Set normal exit signals to request shutdown instead of dying. */ signal(SIGINT, &_exit_handler); signal(SIGHUP, &_exit_handler); signal(SIGQUIT, &_exit_handler); signal(SIGTERM, &_exit_handler); signal(SIGALRM, &_exit_handler); signal(SIGPIPE, SIG_IGN); #ifdef linux /* Systemd has adjusted oom killer for us already */ if (s.avoid_oom && !_systemd_activation && !_protect_against_oom_killer()) ERROR(&s, "Failed to protect against OOM killer"); #endif if (!_systemd_activation && s.socket_path) { s.socket_fd = _open_socket(s); if (s.socket_fd < 0) failed = 1; } /* Signal parent, letting them know we are ready to go. */ if (!s.foreground) kill(getppid(), SIGTERM); if (s.daemon_init) if (!s.daemon_init(&s)) failed = 1; while (!_shutdown_requested && !failed) { fd_set in; FD_ZERO(&in); FD_SET(s.socket_fd, &in); if (select(FD_SETSIZE, &in, NULL, NULL, NULL) < 0 && errno != EINTR) perror("select error"); if (FD_ISSET(s.socket_fd, &in)) if (!_shutdown_requested && !handle_connect(s)) ERROR(&s, "Failed to handle a client connection."); } /* If activated by systemd, do not unlink the socket - systemd takes care of that! */ if (!_systemd_activation && s.socket_fd >= 0) if (unlink(s.socket_path)) perror("unlink error"); if (s.daemon_fini) if (!s.daemon_fini(&s)) failed = 1; INFO(&s, "%s shutting down", s.name); closelog(); /* FIXME */ if (s.pidfile) remove_lockfile(s.pidfile); if (failed) exit(1); } lvm2-2.02.98/libdaemon/server/daemon-log.c0000640000175000017500000000724212037016272017143 0ustar blankblank#include "daemon-server.h" #include "daemon-log.h" #include #include struct backend { int id; void (*log)(log_state *s, void **state, int type, const char *message); }; static void log_syslog(log_state *s, void **state, int type, const char *message) { int prio; if (!*state) { /* initialize */ *state = (void *)1; openlog(s->name, LOG_PID, LOG_DAEMON); } switch (type) { case DAEMON_LOG_INFO: prio = LOG_INFO; break; case DAEMON_LOG_WARN: prio = LOG_WARNING; break; case DAEMON_LOG_FATAL: prio = LOG_CRIT; break; default: prio = LOG_DEBUG; break; } syslog(prio, "%s", message); } static void log_stderr(log_state *s, void **state, int type, const char *message) { const char *prefix; switch (type) { case DAEMON_LOG_INFO: prefix = "I: "; break; case DAEMON_LOG_WARN: prefix = "W: " ; break; case DAEMON_LOG_ERROR: /* fall through */ case DAEMON_LOG_FATAL: prefix = "E: " ; break; default: prefix = ""; break; } fprintf(stderr, "%s%s\n", prefix, message); } struct backend backend[] = { { DAEMON_LOG_OUTLET_SYSLOG, log_syslog }, { DAEMON_LOG_OUTLET_STDERR, log_stderr }, { 0, 0 } }; void daemon_log(log_state *s, int type, const char *message) { int i = 0; while ( backend[i].id ) { if ( (s->log_config[type] & backend[i].id) == backend[i].id ) backend[i].log( s, &s->backend_state[i], type, message ); ++ i; } } static int _type_interesting(log_state *s, int type) { int i = 0; while ( backend[i].id ) { if ( (s->log_config[type] & backend[i].id) == backend[i].id ) return 1; ++ i; } return 0; } void daemon_logf(log_state *s, int type, const char *fmt, ...) { char *buf; va_list ap; va_start(ap, fmt); if (dm_vasprintf(&buf, fmt, ap) >= 0) { daemon_log(s, type, buf); dm_free(buf); } /* else return_0 */ va_end(ap); } struct log_line_baton { log_state *s; int type; const char *prefix; }; static int _log_line(const char *line, void *baton) { struct log_line_baton *b = baton; daemon_logf(b->s, b->type, "%s%s", b->prefix, line); return 0; } void daemon_log_cft(log_state *s, int type, const char *prefix, const struct dm_config_node *n) { struct log_line_baton b = { .s = s, .type = type, .prefix = prefix }; if (!_type_interesting(s, type)) return; dm_config_write_node(n, &_log_line, &b); } void daemon_log_multi(log_state *s, int type, const char *prefix, const char *msg) { struct log_line_baton b = { .s = s, .type = type, .prefix = prefix }; char *buf; char *pos; if (!_type_interesting(s, type)) return; buf = dm_strdup(msg); pos = buf; if (!buf) return; /* _0 */ while (pos) { char *next = strchr(pos, '\n'); if (next) *next = 0; _log_line(pos, &b); pos = next ? next + 1 : 0; } dm_free(buf); } void daemon_log_enable(log_state *s, int outlet, int type, int enable) { assert(type < 32); if (enable) s->log_config[type] |= outlet; else s->log_config[type] &= ~outlet; } static int _parse_one(log_state *s, int outlet, const char *type, int enable) { int i; if (!strcmp(type, "all")) for (i = 0; i < 32; ++i) daemon_log_enable(s, outlet, i, enable); else if (!strcmp(type, "wire")) daemon_log_enable(s, outlet, DAEMON_LOG_WIRE, enable); else if (!strcmp(type, "debug")) daemon_log_enable(s, outlet, DAEMON_LOG_DEBUG, enable); else return 0; return 1; } int daemon_log_parse(log_state *s, int outlet, const char *types, int enable) { char *buf; char *pos; if (!types || !types[0]) return 1; if (!(buf = dm_strdup(types))) return 0; pos = buf; while (pos) { char *next = strchr(pos, ','); if (next) *next = 0; if (!_parse_one(s, outlet, pos, enable)) { dm_free(buf); return 0; } pos = next ? next + 1 : 0; } dm_free(buf); return 1; } lvm2-2.02.98/configure.in0000640000175000017500000015621112037016272014027 0ustar blankblank############################################################################### ## Copyright (C) 2000-2004 Sistina Software, Inc. All rights reserved. ## Copyright (C) 2004-2012 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 ################################################################################ AC_PREREQ(2.61) ################################################################################ dnl -- Process this file with autoconf to produce a configure script. AC_INIT AC_CONFIG_SRCDIR([lib/device/dev-cache.h]) AC_CONFIG_HEADERS([lib/misc/configure.h]) ################################################################################ dnl -- Setup the directory where autoconf has auxilary files AC_CONFIG_AUX_DIR(autoconf) ################################################################################ dnl -- Get system type AC_CANONICAL_TARGET([]) case "$host_os" in linux*) CFLAGS="$CFLAGS" COPTIMISE_FLAG="-O2" CLDFLAGS="$CLDFLAGS -Wl,--version-script,.export.sym" ELDFLAGS="-Wl,--export-dynamic" # FIXME Generate list and use --dynamic-list=.dlopen.sym CLDWHOLEARCHIVE="-Wl,-whole-archive" CLDNOWHOLEARCHIVE="-Wl,-no-whole-archive" LDDEPS="$LDDEPS .export.sym" LIB_SUFFIX=so DEVMAPPER=yes LVMETAD=no ODIRECT=yes DM_IOCTLS=yes SELINUX=yes CLUSTER=internal FSADM=yes BLKDEACTIVATE=yes ;; darwin*) CFLAGS="$CFLAGS -no-cpp-precomp -fno-common" COPTIMISE_FLAG="-O2" CLDFLAGS="$CLDFLAGS" ELDFLAGS= CLDWHOLEARCHIVE="-all_load" CLDNOWHOLEARCHIVE= LIB_SUFFIX=dylib DEVMAPPER=yes ODIRECT=no DM_IOCTLS=no SELINUX=no CLUSTER=none FSADM=no BLKDEACTIVATE=no ;; esac ################################################################################ dnl -- Checks for programs. AC_PROG_SED AC_PROG_AWK AC_PROG_CC dnl probably no longer needed in 2008, but... AC_PROG_GCC_TRADITIONAL AC_PROG_INSTALL AC_PROG_LN_S AC_PROG_MAKE_SET AC_PROG_MKDIR_P AC_PROG_RANLIB AC_PATH_PROG(CFLOW_CMD, cflow) AC_PATH_PROG(CSCOPE_CMD, cscope) ################################################################################ dnl -- Check for header files. AC_HEADER_DIRENT AC_HEADER_MAJOR AC_HEADER_STDC AC_HEADER_SYS_WAIT AC_HEADER_TIME AC_CHECK_HEADERS([locale.h stddef.h syslog.h sys/file.h sys/time.h assert.h \ langinfo.h libgen.h signal.h sys/mman.h sys/resource.h sys/utsname.h \ sys/wait.h time.h], , [AC_MSG_ERROR(bailing out)]) case "$host_os" in linux*) AC_CHECK_HEADERS(asm/byteorder.h linux/fs.h malloc.h,,AC_MSG_ERROR(bailing out)) ;; darwin*) AC_CHECK_HEADERS(machine/endian.h sys/disk.h,,AC_MSG_ERROR(bailing out)) ;; esac AC_CHECK_HEADERS([ctype.h dirent.h errno.h fcntl.h getopt.h inttypes.h limits.h \ stdarg.h stdio.h stdlib.h string.h sys/ioctl.h sys/param.h sys/stat.h \ sys/types.h unistd.h], , [AC_MSG_ERROR(bailing out)]) AC_CHECK_HEADERS(termios.h sys/statvfs.h) ################################################################################ dnl -- Check for typedefs, structures, and compiler characteristics. AC_C_CONST AC_C_INLINE AC_CHECK_MEMBERS([struct stat.st_rdev]) AC_TYPE_OFF_T AC_TYPE_PID_T AC_TYPE_SIGNAL AC_TYPE_SIZE_T AC_TYPE_MODE_T AC_TYPE_INT8_T AC_TYPE_INT16_T AC_TYPE_INT32_T AC_TYPE_INT64_T AC_TYPE_SSIZE_T AC_TYPE_UID_T AC_TYPE_UINT8_T AC_TYPE_UINT16_T AC_TYPE_UINT32_T AC_TYPE_UINT64_T AC_CHECK_MEMBERS([struct stat.st_rdev]) AC_STRUCT_TM ################################################################################ dnl -- Check for functions AC_CHECK_FUNCS([ftruncate gethostname getpagesize \ gettimeofday memset mkdir mkfifo rmdir munmap nl_langinfo setenv setlocale \ strcasecmp strchr strcspn strspn strdup strncasecmp strerror strrchr \ strstr strtol strtoul uname], , [AC_MSG_ERROR(bailing out)]) AC_CHECK_FUNCS(siginterrupt) AC_FUNC_ALLOCA AC_FUNC_CLOSEDIR_VOID AC_FUNC_CHOWN AC_FUNC_FORK AC_FUNC_LSTAT AC_FUNC_MALLOC AC_FUNC_MEMCMP AC_FUNC_MMAP AC_FUNC_REALLOC AC_FUNC_STAT AC_FUNC_STRTOD AC_FUNC_VPRINTF ################################################################################ dnl -- Enables statically-linked tools AC_MSG_CHECKING(whether to use static linking) AC_ARG_ENABLE(static_link, AC_HELP_STRING([--enable-static_link], [use this to link the tools to their libraries statically (default is dynamic linking]), STATIC_LINK=$enableval, STATIC_LINK=no) AC_MSG_RESULT($STATIC_LINK) ################################################################################ dnl -- Prefix is /usr by default, the exec_prefix default is setup later AC_PREFIX_DEFAULT(/usr) ################################################################################ dnl -- Setup the ownership of the files AC_MSG_CHECKING(file owner) AC_ARG_WITH(user, AC_HELP_STRING([--with-user=USER], [set the owner of installed files [[USER=]]]), OWNER=$withval) AC_MSG_RESULT($OWNER) if test x$OWNER != x; then INSTALL="$INSTALL -o $OWNER" fi ################################################################################ dnl -- Setup the group ownership of the files AC_MSG_CHECKING(group owner) AC_ARG_WITH(group, AC_HELP_STRING([--with-group=GROUP], [set the group owner of installed files [[GROUP=]]]), GROUP=$withval) AC_MSG_RESULT($GROUP) if test x$GROUP != x; then INSTALL="$INSTALL -g $GROUP" fi ################################################################################ dnl -- Setup device node ownership AC_MSG_CHECKING(device node uid) AC_ARG_WITH(device-uid, AC_HELP_STRING([--with-device-uid=UID], [set the owner used for new device nodes [[UID=0]]]), DM_DEVICE_UID=$withval, DM_DEVICE_UID=0) AC_MSG_RESULT($DM_DEVICE_UID) ################################################################################ dnl -- Setup device group ownership AC_MSG_CHECKING(device node gid) AC_ARG_WITH(device-gid, AC_HELP_STRING([--with-device-gid=GID], [set the group used for new device nodes [[GID=0]]]), DM_DEVICE_GID=$withval, DM_DEVICE_GID=0) AC_MSG_RESULT($DM_DEVICE_GID) ################################################################################ dnl -- Setup device mode AC_MSG_CHECKING(device node mode) AC_ARG_WITH(device-mode, AC_HELP_STRING([--with-device-mode=MODE], [set the mode used for new device nodes [[MODE=0600]]]), DM_DEVICE_MODE=$withval, DM_DEVICE_MODE=0600) AC_MSG_RESULT($DM_DEVICE_MODE) AC_MSG_CHECKING(when to create device nodes) AC_ARG_WITH(device-nodes-on, AC_HELP_STRING([--with-device-nodes-on=ON], [create nodes on resume or create [[ON=resume]]]), ADD_NODE=$withval, ADD_NODE=resume) case "$ADD_NODE" in resume) add_on=DM_ADD_NODE_ON_RESUME;; create) add_on=DM_ADD_NODE_ON_CREATE;; *) AC_MSG_ERROR([--with-device-nodes-on parameter invalid]);; esac AC_MSG_RESULT(on $ADD_NODE) AC_DEFINE_UNQUOTED([DEFAULT_DM_ADD_NODE], $add_on, [Define default node creation behavior with dmsetup create]) AC_MSG_CHECKING(default name mangling) AC_ARG_WITH(default-name-mangling, AC_HELP_STRING([--with-default-name-mangling=MANGLING], [default name mangling: auto/none/hex [[MANGLING=auto]]]), MANGLING=$withval, MANGLING=auto) case "$MANGLING" in auto) mangling=DM_STRING_MANGLING_AUTO;; disabled) mangling=DM_STRING_MANGLING_NONE;; hex) mangling=DM_STRING_MANGLING_HEX;; *) AC_MSG_ERROR([--with-default-name-mangling parameter invalid]);; esac AC_MSG_RESULT($MANGLING) AC_DEFINE_UNQUOTED([DEFAULT_DM_NAME_MANGLING], $mangling, [Define default name mangling behaviour]) ################################################################################ dnl -- LVM1 tool fallback option AC_MSG_CHECKING(whether to enable lvm1 fallback) AC_ARG_ENABLE(lvm1_fallback, AC_HELP_STRING([--enable-lvm1_fallback], [use this to fall back and use LVM1 binaries if device-mapper is missing from the kernel]), LVM1_FALLBACK=$enableval, LVM1_FALLBACK=no) AC_MSG_RESULT($LVM1_FALLBACK) if test x$LVM1_FALLBACK = xyes; then AC_DEFINE([LVM1_FALLBACK], 1, [Define to 1 if 'lvm' should fall back to using LVM1 binaries if device-mapper is missing from the kernel]) fi ################################################################################ dnl -- format1 inclusion type AC_MSG_CHECKING(whether to include support for lvm1 metadata) AC_ARG_WITH(lvm1, AC_HELP_STRING([--with-lvm1=TYPE], [LVM1 metadata support: internal/shared/none [[TYPE=internal]]]), LVM1=$withval, LVM1=internal) AC_MSG_RESULT($LVM1) if [[ "x$LVM1" != xnone -a "x$LVM1" != xinternal -a "x$LVM1" != xshared ]]; then AC_MSG_ERROR( --with-lvm1 parameter invalid ) fi; if test x$LVM1 = xinternal; then AC_DEFINE([LVM1_INTERNAL], 1, [Define to 1 to include built-in support for LVM1 metadata.]) fi ################################################################################ dnl -- format_pool inclusion type AC_MSG_CHECKING(whether to include support for GFS pool metadata) AC_ARG_WITH(pool, AC_HELP_STRING([--with-pool=TYPE], [GFS pool read-only support: internal/shared/none [[TYPE=internal]]]), POOL=$withval, POOL=internal) AC_MSG_RESULT($POOL) if [[ "x$POOL" != xnone -a "x$POOL" != xinternal -a "x$POOL" != xshared ]]; then AC_MSG_ERROR( --with-pool parameter invalid ) fi; if test x$POOL = xinternal; then AC_DEFINE([POOL_INTERNAL], 1, [Define to 1 to include built-in support for GFS pool metadata.]) fi ################################################################################ dnl -- cluster_locking inclusion type AC_MSG_CHECKING(whether to include support for cluster locking) AC_ARG_WITH(cluster, AC_HELP_STRING([--with-cluster=TYPE], [cluster LVM locking support: internal/shared/none [[TYPE=internal]]]), CLUSTER=$withval) AC_MSG_RESULT($CLUSTER) if [[ "x$CLUSTER" != xnone -a "x$CLUSTER" != xinternal -a "x$CLUSTER" != xshared ]]; then AC_MSG_ERROR( --with-cluster parameter invalid ) fi; if test x$CLUSTER = xinternal; then AC_DEFINE([CLUSTER_LOCKING_INTERNAL], 1, [Define to 1 to include built-in support for clustered LVM locking.]) fi ################################################################################ dnl -- snapshots inclusion type AC_MSG_CHECKING(whether to include snapshots) AC_ARG_WITH(snapshots, AC_HELP_STRING([--with-snapshots=TYPE], [snapshot support: internal/shared/none [[TYPE=internal]]]), SNAPSHOTS=$withval, SNAPSHOTS=internal) AC_MSG_RESULT($SNAPSHOTS) if [[ "x$SNAPSHOTS" != xnone -a "x$SNAPSHOTS" != xinternal -a "x$SNAPSHOTS" != xshared ]]; then AC_MSG_ERROR( --with-snapshots parameter invalid ) fi; if test x$SNAPSHOTS = xinternal; then AC_DEFINE([SNAPSHOT_INTERNAL], 1, [Define to 1 to include built-in support for snapshots.]) fi ################################################################################ dnl -- mirrors inclusion type AC_MSG_CHECKING(whether to include mirrors) AC_ARG_WITH(mirrors, AC_HELP_STRING([--with-mirrors=TYPE], [mirror support: internal/shared/none [[TYPE=internal]]]), MIRRORS=$withval, MIRRORS=internal) AC_MSG_RESULT($MIRRORS) if [[ "x$MIRRORS" != xnone -a "x$MIRRORS" != xinternal -a "x$MIRRORS" != xshared ]]; then AC_MSG_ERROR( --with-mirrors parameter invalid ) fi; if test x$MIRRORS = xinternal; then AC_DEFINE([MIRRORED_INTERNAL], 1, [Define to 1 to include built-in support for mirrors.]) fi ################################################################################ dnl -- raid inclusion type AC_MSG_CHECKING(whether to include raid) AC_ARG_WITH(raid, AC_HELP_STRING([--with-raid=TYPE], [mirror support: internal/shared/none [[TYPE=internal]]]), RAID=$withval, RAID=internal) AC_MSG_RESULT($RAID) if [[ "x$RAID" != xnone -a "x$RAID" != xinternal -a "x$RAID" != xshared ]]; then AC_MSG_ERROR( --with-raid parameter invalid ) fi; if test x$RAID = xinternal; then AC_DEFINE([RAID_INTERNAL], 1, [Define to 1 to include built-in support for raid.]) fi ################################################################################ dnl -- asynchronous volume replicator inclusion type AC_MSG_CHECKING(whether to include replicators) AC_ARG_WITH(replicators, AC_HELP_STRING([--with-replicators=TYPE], [replicator support: internal/shared/none [[TYPE=none]]]), REPLICATORS=$withval, REPLICATORS=none) AC_MSG_RESULT($REPLICATORS) case "$REPLICATORS" in none|shared) ;; internal) AC_DEFINE([REPLICATOR_INTERNAL], 1, [Define to 1 to include built-in support for replicators.]) ;; *) AC_MSG_ERROR([--with-replicators parameter invalid ($REPLICATORS)]) ;; esac ################################################################################ dnl -- thin provisioning AC_MSG_CHECKING(whether to include thin provisioning) AC_ARG_WITH(thin, AC_HELP_STRING([--with-thin=TYPE], [thin provisioning support: internal/shared/none [[TYPE=none]]]), THIN=$withval, THIN=none) AC_MSG_RESULT($THIN) case "$THIN" in none|shared) ;; internal) AC_DEFINE([THIN_INTERNAL], 1, [Define to 1 to include built-in support for thin provisioning.]) ;; *) AC_MSG_ERROR([--with-thin parameter invalid ($THIN)]) ;; esac case "$THIN" in internal|shared) AC_ARG_WITH(thin-check, AC_HELP_STRING([--with-thin-check=PATH], [thin_check tool: [[autodetect]]]), THIN_CHECK_CMD=$withval, THIN_CHECK_CMD="autodetect") # Empty means a config way to ignore thin checking if test "$THIN_CHECK_CMD" = "autodetect"; then AC_PATH_PROG(THIN_CHECK_CMD, thin_check) test -z "$THIN_CHECK_CMD" && AC_MSG_ERROR(thin_check not found in path $PATH) fi ;; esac AC_DEFINE_UNQUOTED([THIN_CHECK_CMD], ["$THIN_CHECK_CMD"], [The path to 'thin_check', if available.]) ################################################################################ dnl -- Disable readline AC_MSG_CHECKING(whether to enable readline) AC_ARG_ENABLE([readline], AC_HELP_STRING([--disable-readline], [disable readline support]), READLINE=$enableval, READLINE=maybe) AC_MSG_RESULT($READLINE) ################################################################################ dnl -- Disable realtime clock support AC_MSG_CHECKING(whether to enable realtime support) AC_ARG_ENABLE(realtime, AC_HELP_STRING([--enable-realtime], [enable realtime clock support]), REALTIME=$enableval) AC_MSG_RESULT($REALTIME) ################################################################################ dnl -- disable OCF resource agents AC_MSG_CHECKING(whether to enable OCF resource agents) AC_ARG_ENABLE(ocf, AC_HELP_STRING([--enable-ocf], [enable Open Cluster Framework (OCF) compliant resource agents]), OCF=$enableval, OCF=no) AC_MSG_RESULT($OCF) AC_ARG_WITH(ocfdir, AC_HELP_STRING([--with-ocfdir=DIR], [install OCF files in DIR [[PREFIX/lib/ocf/resource.d/lvm2]]]), OCFDIR=$withval, OCFDIR='${prefix}/lib/ocf/resource.d/lvm2') ################################################################################ dnl -- Init pkg-config with dummy invokation: dnl -- this is required because PKG_CHECK_MODULES macro is expanded dnl -- to initialize the pkg-config environment only at the first invokation, dnl -- that would be conditional in this configure.in. pkg_config_init() { PKG_CHECK_MODULES(PKGCONFIGINIT, pkgconfiginit, [], [AC_MSG_RESULT([pkg-config initialized])]) PKGCONFIG_INIT=1 } ################################################################################ dnl -- Set up pidfile and run directory AH_TEMPLATE(DEFAULT_PID_DIR) AC_ARG_WITH(default-pid-dir, AC_HELP_STRING([--with-default-pid-dir=PID_DIR], [Default directory to keep PID files in. [[/var/run]]]), DEFAULT_PID_DIR="$withval", DEFAULT_PID_DIR="/var/run") AC_DEFINE_UNQUOTED(DEFAULT_PID_DIR, ["$DEFAULT_PID_DIR"], [Default directory to keep PID files in.]) AH_TEMPLATE(DEFAULT_DM_RUN_DIR, [Name of default DM run directory.]) AC_ARG_WITH(default-dm-run-dir, AC_HELP_STRING([--with-default-dm-run-dir=DM_RUN_DIR], [ Default DM run directory. [[/var/run]]]), DEFAULT_DM_RUN_DIR="$withval", DEFAULT_DM_RUN_DIR="/var/run") AC_DEFINE_UNQUOTED(DEFAULT_DM_RUN_DIR, ["$DEFAULT_DM_RUN_DIR"], [Default DM run directory.]) AH_TEMPLATE(DEFAULT_RUN_DIR, [Name of default LVM run directory.]) AC_ARG_WITH(default-run-dir, AC_HELP_STRING([--with-default-run-dir=RUN_DIR], [Default LVM run directory. [[/var/run/lvm]]]), DEFAULT_RUN_DIR="$withval", DEFAULT_RUN_DIR="/var/run/lvm") AC_DEFINE_UNQUOTED(DEFAULT_RUN_DIR, ["$DEFAULT_RUN_DIR"], [Default LVM run directory.]) ################################################################################ dnl -- Build cluster LVM daemon AC_MSG_CHECKING(whether to build cluster LVM daemon) AC_ARG_WITH(clvmd, [ --with-clvmd=TYPE build cluster LVM Daemon The following cluster manager combinations are valid: * cman (RHEL5 or equivalent) * cman,corosync,openais (or selection of them) * singlenode (localhost only) * all (autodetect) * none (disable build) [[TYPE=none]]], CLVMD=$withval, CLVMD=none) if test x$CLVMD = xyes; then CLVMD=all fi AC_MSG_RESULT($CLVMD) dnl -- If clvmd enabled without cluster locking, automagically include it if test x$CLVMD != xnone && test x$CLUSTER = xnone; then CLUSTER=internal fi dnl -- init pkgconfig if required if test x$CLVMD != xnone && test x$PKGCONFIG_INIT != x1; then pkg_config_init fi dnl -- Express clvmd init script Required-Start / Required-Stop CLVMD_CMANAGERS="" dnl -- On RHEL4/RHEL5, qdiskd is started from a separate init script. dnl -- Enable if we are build for cman. CLVMD_NEEDS_QDISKD=no dnl -- define build types if [[ `expr x"$CLVMD" : '.*gulm.*'` != 0 ]]; then AC_MSG_ERROR([Since version 2.02.87 GULM locking is no longer supported.]); fi if [[ `expr x"$CLVMD" : '.*cman.*'` != 0 ]]; then BUILDCMAN=yes CLVMD_CMANAGERS="$CLVMD_CMANAGERS cman" CLVMD_NEEDS_QDISKD=yes fi if [[ `expr x"$CLVMD" : '.*corosync.*'` != 0 ]]; then BUILDCOROSYNC=yes CLVMD_CMANAGERS="$CLVMD_CMANAGERS corosync" fi if [[ `expr x"$CLVMD" : '.*openais.*'` != 0 ]]; then BUILDOPENAIS=yes CLVMD_CMANAGERS="$CLVMD_CMANAGERS openais" fi if test x$CLVMD_NEEDS_QDISKD != xno; then CLVMD_CMANAGERS="$CLVMD_CMANAGERS qdiskd" fi dnl -- define a soft bailout if we are autodetecting soft_bailout() { NOTFOUND=1 } hard_bailout() { AC_MSG_ERROR([bailing out]) } dnl -- if clvmd=all then set soft_bailout (we don't want to error) dnl -- and set all builds to yes. We need to do this here dnl -- to skip the openais|corosync sanity check above. if test x$CLVMD = xall; then bailout=soft_bailout BUILDCMAN=yes BUILDCOROSYNC=yes BUILDOPENAIS=yes else bailout=hard_bailout fi dnl -- helper macro to check libs without adding them to LIBS check_lib_no_libs() { lib_no_libs_arg1=$1 shift lib_no_libs_arg2=$1 shift lib_no_libs_args=$@ AC_CHECK_LIB([$lib_no_libs_arg1], [$lib_no_libs_arg2],, [$bailout], [$lib_no_libs_args]) LIBS=$ac_check_lib_save_LIBS } dnl -- Look for cman libraries if required. if test x$BUILDCMAN = xyes; then PKG_CHECK_MODULES(CMAN, libcman, [HAVE_CMAN=yes], [NOTFOUND=0 AC_CHECK_HEADERS(libcman.h,,$bailout) check_lib_no_libs cman cman_init if test $NOTFOUND = 0; then AC_MSG_RESULT([no pkg for libcman, using -lcman]) CMAN_LIBS="-lcman" HAVE_CMAN=yes fi]) CHECKCONFDB=yes CHECKDLM=yes fi dnl -- Look for corosync that's required also for openais build dnl -- only enough recent version of corosync ship pkg-config files. dnl -- We can safely rely on that to detect the correct bits. if test x$BUILDCOROSYNC = xyes || \ test x$BUILDOPENAIS = xyes; then PKG_CHECK_MODULES(COROSYNC, corosync, [HAVE_COROSYNC=yes], $bailout) CHECKCONFDB=yes CHECKCMAP=yes fi dnl -- Look for corosync libraries if required. if test x$BUILDCOROSYNC = xyes; then PKG_CHECK_MODULES(QUORUM, libquorum, [HAVE_QUORUM=yes], $bailout) CHECKCPG=yes CHECKDLM=yes fi dnl -- Look for openais libraries if required. if test x$BUILDOPENAIS = xyes; then PKG_CHECK_MODULES(SALCK, libSaLck, [HAVE_SALCK=yes], $bailout) CHECKCPG=yes fi dnl -- Below are checks for libraries common to more than one build. dnl -- Check confdb library. dnl -- mandatory for corosync < 2.0 build. dnl -- optional for openais/cman build. if test x$CHECKCONFDB = xyes; then PKG_CHECK_MODULES(CONFDB, libconfdb, [HAVE_CONFDB=yes], [HAVE_CONFDB=no]) AC_CHECK_HEADERS(corosync/confdb.h, [HAVE_CONFDB_H=yes], [HAVE_CONFDB_H=no]) if test x$HAVE_CONFDB != xyes && \ test x$HAVE_CONFDB_H = xyes; then check_lib_no_libs confdb confdb_initialize AC_MSG_RESULT([no pkg for confdb, using -lconfdb]) CONFDB_LIBS="-lconfdb" HAVE_CONFDB=yes fi fi dnl -- Check cmap library dnl -- mandatory for corosync >= 2.0 build. if test x$CHECKCMAP = xyes; then PKG_CHECK_MODULES(CMAP, libcmap, [HAVE_CMAP=yes], [HAVE_CMAP=no]) AC_CHECK_HEADERS(corosync/cmap.h, [HAVE_CMAP_H=yes], [HAVE_CMAP_H=no]) if test x$HAVE_CMAP != xyes && \ test x$HAVE_CMAP_H = xyes; then check_lib_no_libs cmap cmap_initialize AC_MSG_RESULT([no pkg for cmap, using -lcmap]) CMAP_LIBS="-lcmap" HAVE_CMAP=yes fi fi if test x$BUILDCOROSYNC = xyes; then if test x$HAVE_CMAP != xyes && \ test x$HAVE_CONFDB != xyes && \ test x$CLVMD != xall; then AC_MSG_ERROR([bailing out... cmap (corosync >= 2.0) or confdb (corosync < 2.0) library is required]) fi fi dnl -- Check cpg library. if test x$CHECKCPG = xyes; then PKG_CHECK_MODULES(CPG, libcpg, [HAVE_CPG=yes], $bailout) fi dnl -- Check dlm library. if test x$CHECKDLM = xyes; then PKG_CHECK_MODULES(DLM, libdlm, [HAVE_DLM=yes], [NOTFOUND=0 AC_CHECK_HEADERS(libdlm.h,,$bailout) check_lib_no_libs dlm dlm_lock -lpthread if test $NOTFOUND = 0; then AC_MSG_RESULT([no pkg for libdlm, using -ldlm]) DLM_LIBS="-ldlm -lpthread" HAVE_DLM=yes fi]) fi dnl -- If we are autodetecting, we need to re-create dnl -- the depedencies checks and set a proper CLVMD, dnl -- together with init script Required-Start/Stop entries. if test x$CLVMD = xall; then CLVMD=none CLVMD_CMANAGERS="" CLVMD_NEEDS_QDISKD=no if test x$HAVE_CMAN = xyes && \ test x$HAVE_DLM = xyes; then AC_MSG_RESULT([Enabling clvmd cman cluster manager]) CLVMD="$CLVMD,cman" CLVMD_CMANAGERS="$CLVMD_CMANAGERS cman" CLVMD_NEEDS_QDISKD=yes fi if test x$HAVE_COROSYNC = xyes && \ test x$HAVE_QUORUM = xyes && \ test x$HAVE_CPG = xyes && \ test x$HAVE_DLM = xyes; then if test x$HAVE_CONFDB = xyes || test x$HAVE_CMAP = xyes; then AC_MSG_RESULT([Enabling clvmd corosync cluster manager]) CLVMD="$CLVMD,corosync" CLVMD_CMANAGERS="$CLVMD_CMANAGERS corosync" fi fi if test x$HAVE_COROSYNC = xyes && \ test x$HAVE_CPG = xyes && \ test x$HAVE_SALCK = xyes; then AC_MSG_RESULT([Enabling clvmd openais cluster manager]) CLVMD="$CLVMD,openais" CLVMD_CMANAGERS="$CLVMD_CMANAGERS openais" fi if test x$CLVMD_NEEDS_QDISKD != xno; then CLVMD_CMANAGERS="$CLVMD_CMANAGERS qdiskd" fi if test x$CLVMD = xnone; then AC_MSG_RESULT([Disabling clvmd build. No cluster manager detected.]) fi fi dnl -- Fixup CLVMD_CMANAGERS with new corosync dnl -- clvmd built with corosync >= 2.0 needs dlm (either init or systemd service) dnl -- to be started. if [[ `expr x"$CLVMD" : '.*corosync.*'` != 0 ]]; then if test x$HAVE_CMAP = xyes; then CLVMD_CMANAGERS="$CLVMD_CMANAGERS dlm" fi fi ################################################################################ dnl -- clvmd pidfile if test "x$CLVMD" != xnone; then AC_ARG_WITH(clvmd-pidfile, AC_HELP_STRING([--with-clvmd-pidfile=PATH], [clvmd pidfile [[PID_DIR/clvmd.pid]]]), CLVMD_PIDFILE=$withval, CLVMD_PIDFILE="$DEFAULT_PID_DIR/clvmd.pid") AC_DEFINE_UNQUOTED(CLVMD_PIDFILE, ["$CLVMD_PIDFILE"], [Path to clvmd pidfile.]) fi ################################################################################ dnl -- Build cluster mirror log daemon AC_MSG_CHECKING(whether to build cluster mirror log daemon) AC_ARG_ENABLE(cmirrord, AC_HELP_STRING([--enable-cmirrord], [enable the cluster mirror log daemon]), CMIRRORD=$enableval, CMIRRORD=no) AC_MSG_RESULT($CMIRRORD) BUILD_CMIRRORD=$CMIRRORD ################################################################################ dnl -- cmirrord pidfile if test "x$BUILD_CMIRRORD" = xyes; then AC_ARG_WITH(cmirrord-pidfile, AC_HELP_STRING([--with-cmirrord-pidfile=PATH], [cmirrord pidfile [[PID_DIR/cmirrord.pid]]]), CMIRRORD_PIDFILE=$withval, CMIRRORD_PIDFILE="$DEFAULT_PID_DIR/cmirrord.pid") AC_DEFINE_UNQUOTED(CMIRRORD_PIDFILE, ["$CMIRRORD_PIDFILE"], [Path to cmirrord pidfile.]) fi ################################################################################ dnl -- Look for corosync libraries if required. if [[ "x$BUILD_CMIRRORD" = xyes ]]; then dnl -- init pkgconfig if required if test x$PKGCONFIG_INIT != x1; then pkg_config_init fi AC_DEFINE([CMIRROR_HAS_CHECKPOINT], 1, [Define to 1 to include libSaCkpt.]) PKG_CHECK_MODULES(SACKPT, libSaCkpt, [HAVE_SACKPT=yes], [AC_MSG_RESULT([no libSaCkpt, compiling without it]) AC_DEFINE([CMIRROR_HAS_CHECKPOINT], 0, [Define to 0 to exclude libSaCkpt.])]) if test x$HAVE_CPG != xyes; then PKG_CHECK_MODULES(CPG, libcpg) fi fi ################################################################################ dnl -- Enable debugging AC_MSG_CHECKING(whether to enable debugging) AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug], [enable debugging]), DEBUG=$enableval, DEBUG=no) AC_MSG_RESULT($DEBUG) dnl -- Normally turn off optimisation for debug builds if test x$DEBUG = xyes; then COPTIMISE_FLAG= else CSCOPE_CMD= fi ################################################################################ dnl -- Override optimisation AC_MSG_CHECKING(for C optimisation flag) AC_ARG_WITH(optimisation, AC_HELP_STRING([--with-optimisation=OPT], [C optimisation flag [[OPT=-O2]]]), COPTIMISE_FLAG=$withval) AC_MSG_RESULT($COPTIMISE_FLAG) ################################################################################ dnl -- Enable profiling AC_MSG_CHECKING(whether to gather gcov profiling data) AC_ARG_ENABLE(profiling, AC_HELP_STRING(--enable-profiling, [gather gcov profiling data]), PROFILING=$enableval, PROFILING=no) AC_MSG_RESULT($PROFILING) if test "x$PROFILING" = xyes; then COPTIMISE_FLAG="$COPTIMISE_FLAG -fprofile-arcs -ftest-coverage" AC_PATH_PROG(LCOV, lcov) AC_PATH_PROG(GENHTML, genhtml) if test -z "$LCOV" -o -z "$GENHTML"; then AC_MSG_ERROR([lcov and genhtml are required for profiling]) fi AC_PATH_PROG(GENPNG, genpng) if test -n "$GENPNG"; then AC_MSG_CHECKING([whether $GENPNG has all required modules]) if $GENPNG --help > /dev/null 2>&1 ; then AC_MSG_RESULT(ok) GENHTML="$GENHTML --frames" else AC_MSG_RESULT(not supported) AC_MSG_WARN([GD.pm perl module is not installed]) GENPNG= fi fi fi ################################################################################ dnl -- Enable testing AC_MSG_CHECKING(whether to enable unit testing) AC_ARG_ENABLE(testing, AC_HELP_STRING(--enable-testing, [enable testing targets in the makefile]), TESTING=$enableval, TESTING=no) AC_MSG_RESULT($TESTING) if test "$TESTING" = yes; then if test x$PKGCONFIG_INIT != x1; then pkg_config_init fi PKG_CHECK_MODULES(CUNIT, cunit >= 2.0) fi ################################################################################ dnl -- Enable valgrind awareness of memory pools AC_MSG_CHECKING(whether to enable valgrind awareness of pools) AC_ARG_ENABLE(valgrind_pool, AC_HELP_STRING(--enable-valgrind-pool, [enable valgrind awareness of pools]), VALGRIND_POOL=$enableval, VALGRIND_POOL=no) AC_MSG_RESULT($VALGRIND_POOL) if test "$VALGRIND_POOL" = yes; then PKG_CHECK_MODULES(VALGRIND, valgrind, [], [AC_MSG_ERROR(bailing out)]) AC_DEFINE([VALGRIND_POOL], 1, [Enable a valgrind aware build of pool]) AC_SUBST(VALGRIND_POOL) AC_SUBST(VALGRIND_CFLAGS) fi ################################################################################ dnl -- Disable devmapper AC_MSG_CHECKING(whether to use device-mapper) AC_ARG_ENABLE(devmapper, AC_HELP_STRING([--disable-devmapper], [disable LVM2 device-mapper interaction]), DEVMAPPER=$enableval) AC_MSG_RESULT($DEVMAPPER) if test x$DEVMAPPER = xyes; then AC_DEFINE([DEVMAPPER_SUPPORT], 1, [Define to 1 to enable LVM2 device-mapper interaction.]) fi ################################################################################ dnl -- Build lvmetad AC_MSG_CHECKING(whether to build LVMetaD) AC_ARG_ENABLE(lvmetad, AC_HELP_STRING([--enable-lvmetad], [enable the LVM Metadata Daemon]), LVMETAD=$enableval) AC_MSG_RESULT($LVMETAD) BUILD_LVMETAD=$LVMETAD if test x$BUILD_LVMETAD = xyes; then AC_DEFINE([LVMETAD_SUPPORT], 1, [Define to 1 to include code that uses lvmetad.]) AC_ARG_WITH(lvmetad-pidfile, AC_HELP_STRING([--with-lvmetad-pidfile=PATH], [lvmetad pidfile [[PID_DIR/lvmetad.pid]]]), LVMETAD_PIDFILE=$withval, LVMETAD_PIDFILE="$DEFAULT_PID_DIR/lvmetad.pid") AC_DEFINE_UNQUOTED(LVMETAD_PIDFILE, ["$LVMETAD_PIDFILE"], [Path to lvmetad pidfile.]) fi ################################################################################ dnl -- Enable udev synchronisation AC_MSG_CHECKING(whether to enable synchronisation with udev processing) AC_ARG_ENABLE(udev_sync, AC_HELP_STRING([--enable-udev_sync], [enable synchronisation with udev processing]), UDEV_SYNC=$enableval, UDEV_SYNC=no) AC_MSG_RESULT($UDEV_SYNC) if test x$UDEV_SYNC = xyes; then dnl -- init pkgconfig if required if test x$PKGCONFIG_INIT != x1; then pkg_config_init fi PKG_CHECK_MODULES(UDEV, libudev >= 143, [UDEV_PC="libudev"]) AC_DEFINE([UDEV_SYNC_SUPPORT], 1, [Define to 1 to enable synchronisation with udev processing.]) fi dnl -- Enable udev rules AC_MSG_CHECKING(whether to enable installation of udev rules required for synchronisation) AC_ARG_ENABLE(udev_rules, AC_HELP_STRING([--enable-udev_rules], [install rule files needed for udev synchronisation]), UDEV_RULES=$enableval, UDEV_RULES=$UDEV_SYNC) AC_MSG_RESULT($UDEV_RULES) AC_MSG_CHECKING(whether to enable executable path detection in udev rules) AC_ARG_ENABLE(udev_rule_exec_detection, AC_HELP_STRING([--enable-udev-rule-exec-detection], [enable executable path detection in udev rules]), UDEV_RULE_EXEC_DETECTION=$enableval, UDEV_RULE_EXEC_DETECTION=no) AC_MSG_RESULT($UDEV_RULE_EXEC_DETECTION) dnl -- Check support for built-in blkid against target udev version AC_MSG_CHECKING(whether udev supports built-in blkid) test x$PKGCONFIG_INIT != x1 && pkg_config_init if $($PKG_CONFIG --atleast-version=176 libudev); then UDEV_HAS_BUILTIN_BLKID=yes else UDEV_HAS_BUILTIN_BLKID=no fi AC_MSG_RESULT($UDEV_HAS_BUILTIN_BLKID) ################################################################################ dnl -- Compatibility mode AC_ARG_ENABLE(compat, AC_HELP_STRING([--enable-compat], [enable support for old device-mapper versions]), DM_COMPAT=$enableval, DM_COMPAT=no) if test x$DM_COMPAT = xyes; then AC_MSG_ERROR( [--enable-compat is not currently supported. Since device-mapper version 1.02.66, only one version (4) of the device-mapper ioctl protocol is supported.] ) fi ################################################################################ dnl -- Compatible units suffix mode AC_ARG_ENABLE(units-compat, AC_HELP_STRING([--enable-units-compat], [enable output compatibility with old versions that that do not use KiB-style unit suffixes]), UNITS_COMPAT=$enableval, UNITS_COMPAT=no) if test x$UNITS_COMPAT = xyes; then AC_DEFINE([DEFAULT_SI_UNIT_CONSISTENCY], 0, [Define to 0 to reinstate the pre-2.02.54 handling of unit suffixes.]) fi ################################################################################ dnl -- Disable ioctl AC_ARG_ENABLE(ioctl, AC_HELP_STRING([--disable-driver], [disable calls to device-mapper in the kernel]), DM_IOCTLS=$enableval) ################################################################################ dnl -- Disable O_DIRECT AC_MSG_CHECKING(whether to enable O_DIRECT) AC_ARG_ENABLE(o_direct, AC_HELP_STRING([--disable-o_direct], [disable O_DIRECT]), ODIRECT=$enableval) AC_MSG_RESULT($ODIRECT) if test x$ODIRECT = xyes; then AC_DEFINE([O_DIRECT_SUPPORT], 1, [Define to 1 to enable O_DIRECT support.]) fi ################################################################################ dnl -- Enable liblvm2app.so AC_MSG_CHECKING(whether to build liblvm2app.so application library) AC_ARG_ENABLE(applib, AC_HELP_STRING([--enable-applib], [build application library]), APPLIB=$enableval, APPLIB=no) AC_MSG_RESULT($APPLIB) AC_SUBST([LVM2APP_LIB]) test x$APPLIB = xyes \ && LVM2APP_LIB=-llvm2app \ || LVM2APP_LIB= ################################################################################ dnl -- Enable cmdlib AC_MSG_CHECKING(whether to compile liblvm2cmd.so) AC_ARG_ENABLE(cmdlib, AC_HELP_STRING([--enable-cmdlib], [build shared command library]), CMDLIB=$enableval, CMDLIB=no) AC_MSG_RESULT($CMDLIB) AC_SUBST([LVM2CMD_LIB]) test x$CMDLIB = xyes \ && LVM2CMD_LIB=-llvm2cmd \ || LVM2CMD_LIB= ################################################################################ dnl -- Enable Python liblvm2app bindings AC_MSG_CHECKING(whether to build Python wrapper for liblvm2app.so) AC_ARG_ENABLE(python_bindings, AC_HELP_STRING([--enable-python_bindings], [build Python applib bindings]), PYTHON_BINDINGS=$enableval, PYTHON_BINDINGS=no) AC_MSG_RESULT($PYTHON_BINDINGS) if test x$PYTHON_BINDINGS = xyes; then if test x$APPLIB != xyes; then AC_MSG_ERROR( --enable-python_bindings requires --enable-applib ) fi AC_PATH_PROG(PYTHON, python, notfound) if test x$PYTHON == xnotfound; then AC_MSG_ERROR( [python is required for --enable-python_bindings but cannot be found] ) fi AC_PATH_PROG(PYTHON_CONFIG, python-config, notfound) if test x$PYTHON_CONFIG == xnotfound; then AC_MSG_ERROR( [python headers are required for --enable-python_bindings but cannot be found] ) fi PYTHON_INCDIRS=`$PYTHON_CONFIG --includes` PYTHON_LIBDIRS=`$PYTHON_CONFIG --libs` fi ################################################################################ dnl -- Enable pkg-config AC_ARG_ENABLE(pkgconfig, AC_HELP_STRING([--enable-pkgconfig], [install pkgconfig support]), PKGCONFIG=$enableval, PKGCONFIG=no) ################################################################################ dnl -- Enable installation of writable files by user AC_ARG_ENABLE(write_install, AC_HELP_STRING([--enable-write_install], [install user writable files]), WRITE_INSTALL=$enableval, WRITE_INSTALL=no) ################################################################################ dnl -- Enable fsadm AC_MSG_CHECKING(whether to install fsadm) AC_ARG_ENABLE(fsadm, AC_HELP_STRING([--disable-fsadm], [disable fsadm]), FSADM=$enableval) AC_MSG_RESULT($FSADM) ################################################################################ dnl -- Enable blkdeactivate AC_MSG_CHECKING(whether to install blkdeactivate) AC_ARG_ENABLE(blkdeactivate, AC_HELP_STRING([--disable-blkdeactivate], [disable blkdeactivate]), BLKDEACTIVATE=$enableval) AC_MSG_RESULT($BLKDEACTIVATE) ################################################################################ dnl -- enable dmeventd handling AC_MSG_CHECKING(whether to use dmeventd) AC_ARG_ENABLE(dmeventd, AC_HELP_STRING([--enable-dmeventd], [enable the device-mapper event daemon]), DMEVENTD=$enableval) AC_MSG_RESULT($DMEVENTD) BUILD_DMEVENTD=$DMEVENTD dnl -- dmeventd currently requires internal mirror support if test x$DMEVENTD = xyes; then if test x$MIRRORS != xinternal; then AC_MSG_ERROR( --enable-dmeventd currently requires --with-mirrors=internal ) fi if test x$CMDLIB = xno; then AC_MSG_ERROR( --enable-dmeventd requires --enable-cmdlib to be used as well ) fi fi if test x$DMEVENTD = xyes; then AC_DEFINE([DMEVENTD], 1, [Define to 1 to enable the device-mapper event daemon.]) fi ################################################################################ dnl -- getline included in recent libc AC_CHECK_LIB(c, getline, AC_DEFINE([HAVE_GETLINE], 1, [Define to 1 if getline is available.])) ################################################################################ dnl -- canonicalize_file_name included in recent libc AC_CHECK_LIB(c, canonicalize_file_name, AC_DEFINE([HAVE_CANONICALIZE_FILE_NAME], 1, [Define to 1 if canonicalize_file_name is available.])) ################################################################################ dnl -- Clear default exec_prefix - install into /sbin rather than /usr/sbin if [[ "x$exec_prefix" = xNONE -a "x$prefix" = xNONE ]]; then exec_prefix=""; fi; ################################################################################ dnl -- Check for dlopen AC_CHECK_LIB(dl, dlopen, [ AC_DEFINE([HAVE_LIBDL], 1, [Define to 1 if dynamic libraries are available.]) DL_LIBS="-ldl" HAVE_LIBDL=yes ], [ DL_LIBS= HAVE_LIBDL=no ]) ################################################################################ dnl -- Check for shared/static conflicts if [[ \( "x$LVM1" = xshared -o "x$POOL" = xshared -o "x$CLUSTER" = xshared \ -o "x$SNAPSHOTS" = xshared -o "x$MIRRORS" = xshared \ -o "x$RAID" = xshared \ \) -a "x$STATIC_LINK" = xyes ]]; then AC_MSG_ERROR( Features cannot be 'shared' when building statically ) fi ################################################################################ if [[ "$DMEVENTD" = yes -o "$CLVMD" != none ]] ; then AC_CHECK_LIB([pthread], [pthread_mutex_lock], [PTHREAD_LIBS="-lpthread"], hard_bailout) fi ################################################################################ dnl -- Disable selinux AC_MSG_CHECKING(whether to enable selinux support) AC_ARG_ENABLE(selinux, AC_HELP_STRING([--disable-selinux], [disable selinux support]), SELINUX=$enableval) AC_MSG_RESULT($SELINUX) ################################################################################ dnl -- Check for selinux if test x$SELINUX = xyes; then AC_CHECK_LIB([sepol], [sepol_check_context], [ AC_DEFINE([HAVE_SEPOL], 1, [Define to 1 if sepol_check_context is available.]) SELINUX_LIBS="-lsepol"]) AC_CHECK_LIB([selinux], [is_selinux_enabled], [ AC_CHECK_HEADERS([selinux/selinux.h],, hard_bailout) AC_CHECK_HEADERS([selinux/label.h]) AC_DEFINE([HAVE_SELINUX], 1, [Define to 1 to include support for selinux.]) SELINUX_LIBS="-lselinux $SELINUX_LIBS" SELINUX_PC="libselinux" HAVE_SELINUX=yes ], [ AC_MSG_WARN(Disabling selinux) SELINUX_LIBS= SELINUX_PC= HAVE_SELINUX=no ]) fi ################################################################################ dnl -- Check for realtime clock support if test x$REALTIME = xyes; then AC_CHECK_LIB(rt, clock_gettime, HAVE_REALTIME=yes, HAVE_REALTIME=no) if test x$HAVE_REALTIME = xyes; then AC_DEFINE([HAVE_REALTIME], 1, [Define to 1 to include support for realtime clock.]) LIBS="-lrt $LIBS" else AC_MSG_WARN(Disabling realtime clock) fi fi ################################################################################ dnl -- Check for getopt AC_CHECK_HEADERS(getopt.h, AC_DEFINE([HAVE_GETOPTLONG], 1, [Define to 1 if getopt_long is available.])) ################################################################################ dnl -- Check for readline (Shamelessly copied from parted 1.4.17) if test x$READLINE != xno; then lvm_saved_libs=$LIBS AC_SEARCH_LIBS([tgetent], [tinfo ncurses curses termcap termlib], READLINE_LIBS=$ac_cv_search_tgetent, [ if test "$READLINE" = yes; then AC_MSG_ERROR( [termcap could not be found which is required for the --enable-readline option (which is enabled by default). Either disable readline support with --disable-readline or download and install termcap from: ftp.gnu.org/gnu/termcap Note: if you are using precompiled packages you will also need the development package as well (which may be called termcap-devel or something similar). Note: (n)curses also seems to work as a substitute for termcap. This was not found either - but you could try installing that as well.]) fi]) dnl -- Old systems may need extra termcap dependency explicitly in LIBS AC_CHECK_LIB([readline], [readline], [ AC_DEFINE([READLINE_SUPPORT], 1, [Define to 1 to include the LVM readline shell.]) dnl -- Try only with -lreadline and check for different symbol LIBS=$lvm_saved_libs AC_CHECK_LIB([readline], [rl_line_buffer], [ READLINE_LIBS="-lreadline" ], [ AC_MSG_RESULT([linking -lreadline with $READLINE_LIBS needed]) READLINE_LIBS="-lreadline $READLINE_LIBS" ]) ], [ READLINE_LIBS= if test "$READLINE" = yes; then AC_MSG_ERROR( [GNU Readline could not be found which is required for the --enable-readline option (which is enabled by default). Either disable readline support with --disable-readline or download and install readline from: ftp.gnu.org/gnu/readline Note: if you are using precompiled packages you will also need the development package as well (which may be called readline-devel or something similar).]) fi ]) LIBS="$READLINE_LIBS $lvm_saved_libs" AC_CHECK_FUNCS([rl_completion_matches]) LIBS=$lvm_saved_libs fi ################################################################################ dnl -- Internationalisation stuff AC_MSG_CHECKING(whether to enable internationalisation) AC_ARG_ENABLE(nls, AC_HELP_STRING([--enable-nls], [enable Native Language Support]), INTL=$enableval, INTL=no) AC_MSG_RESULT($INTL) if test x$INTL = xyes; then # FIXME - Move this - can be device-mapper too INTL_PACKAGE="lvm2" AC_PATH_PROG(MSGFMT, msgfmt) if [[ "x$MSGFMT" == x ]]; then AC_MSG_ERROR( msgfmt not found in path $PATH ) fi; AC_ARG_WITH(localedir, AC_HELP_STRING([--with-localedir=DIR], [translation files in DIR [[PREFIX/share/locale]]]), LOCALEDIR=$withval, LOCALEDIR='${prefix}/share/locale') fi ################################################################################ AC_ARG_WITH(confdir, AC_HELP_STRING([--with-confdir=DIR], [configuration files in DIR [[/etc]]]), CONFDIR=$withval, CONFDIR="/etc") AC_ARG_WITH(staticdir, AC_HELP_STRING([--with-staticdir=DIR], [static binaries in DIR [[EPREFIX/sbin]]]), STATICDIR=$withval, STATICDIR='${exec_prefix}/sbin') AC_ARG_WITH(usrlibdir, AC_HELP_STRING([--with-usrlibdir=DIR], [usrlib in DIR [[PREFIX/lib]]]), usrlibdir=$withval, usrlibdir='${prefix}/lib') AC_ARG_WITH(usrsbindir, AC_HELP_STRING([--with-usrsbindir=DIR], [usrsbin executables in DIR [[PREFIX/sbin]]]), usrsbindir=$withval, usrsbindir='${prefix}/sbin') ################################################################################ AC_ARG_WITH(udev_prefix, AC_HELP_STRING([--with-udev-prefix=UPREFIX], [install udev rule files in UPREFIX [[EPREFIX]]]), udev_prefix=$withval, udev_prefix='${exec_prefix}') AC_ARG_WITH(udevdir, AC_HELP_STRING([--with-udevdir=DIR], [udev rules in DIR [[UPREFIX/lib/udev/rules.d]]]), udevdir=$withval, udevdir='${udev_prefix}/lib/udev/rules.d') ################################################################################ dnl -- Get the systemd system unit dir value from pkg_config automatically if value not given explicitly. dnl -- This follows the recommendation for systemd integration best practices mentioned in daemon(7) manpage. AC_ARG_WITH(systemdsystemunitdir, AC_HELP_STRING([--with-systemdsystemunitdir=DIR], [systemd service files in DIR]), systemdsystemunitdir=$withval, dnl -- init pkgconfig if required test x$PKGCONFIG_INIT != x1 && pkg_config_init pkg_systemdsystemunitdir=$($PKG_CONFIG --variable=systemdsystemunitdir systemd)) if test -n "$pkg_systemdsystemunitdir"; then systemdsystemunitdir=$pkg_systemdsystemunitdir; fi if test -z "$systemdsystemunitdir"; then systemdsystemunitdir='${exec_prefix}/lib/systemd/system'; fi systemdutildir=$($PKG_CONFIG --variable=systemdutildir systemd) if test -z "$systemdutildir"; then systemdutildir='${exec_prefix}/lib/systemd'; fi ################################################################################ AC_ARG_WITH(tmpfilesdir, AC_HELP_STRING([--with-tmpfilesdir=DIR], [install configuration files for management of volatile files and directories in DIR [[PREFIX/lib/tmpfiles.d]]]), tmpfilesdir=$withval, tmpfilesdir='${prefix}/lib/tmpfiles.d') ################################################################################ dnl -- Ensure additional headers required if test x$READLINE = xyes; then AC_CHECK_HEADERS(readline/readline.h readline/history.h,,AC_MSG_ERROR(bailing out)) fi if test x$CLVMD != xnone; then AC_CHECK_HEADERS(mntent.h netdb.h netinet/in.h pthread.h search.h sys/mount.h sys/socket.h sys/uio.h sys/un.h utmpx.h,,AC_MSG_ERROR(bailing out)) AC_CHECK_FUNCS(dup2 getmntent memmove select socket,,AC_MSG_ERROR(bailing out)) AC_FUNC_GETMNTENT AC_FUNC_SELECT_ARGTYPES fi if test x$CLUSTER != xnone; then AC_CHECK_HEADERS(sys/socket.h sys/un.h,,AC_MSG_ERROR(bailing out)) AC_CHECK_FUNCS(socket,,AC_MSG_ERROR(bailing out)) fi if test x$DMEVENTD = xyes; then AC_CHECK_HEADERS(arpa/inet.h,,AC_MSG_ERROR(bailing out)) fi if test x$HAVE_LIBDL = xyes; then AC_CHECK_HEADERS(dlfcn.h,,AC_MSG_ERROR(bailing out)) fi if test x$INTL = xyes; then AC_CHECK_HEADERS(libintl.h,,AC_MSG_ERROR(bailing out)) fi if test x$UDEV_SYNC = xyes; then AC_CHECK_HEADERS(sys/ipc.h sys/sem.h,,AC_MSG_ERROR(bailing out)) fi ################################################################################ AC_PATH_PROG(MODPROBE_CMD, modprobe) if test x$MODPROBE_CMD != x; then AC_DEFINE_UNQUOTED([MODPROBE_CMD], ["$MODPROBE_CMD"], [The path to 'modprobe', if available.]) fi lvm_exec_prefix=$exec_prefix test "$lvm_exec_prefix" = NONE && lvm_exec_prefix=$prefix test "$lvm_exec_prefix" = NONE && lvm_exec_prefix=$ac_default_prefix LVM_PATH="$lvm_exec_prefix/sbin/lvm" AC_DEFINE_UNQUOTED(LVM_PATH, ["$LVM_PATH"], [Path to lvm binary.]) if test "$CLVMD" != none; then clvmd_prefix=$ac_default_prefix CLVMD_PATH="$clvmd_prefix/sbin/clvmd" test "$prefix" != NONE && clvmd_prefix=$prefix AC_DEFINE_UNQUOTED(CLVMD_PATH, ["$CLVMD_PATH"], [Path to clvmd binary.]) fi ################################################################################ dnl -- dmeventd pidfile and executable path if test "$BUILD_DMEVENTD" = yes; then AC_ARG_WITH(dmeventd-pidfile, AC_HELP_STRING([--with-dmeventd-pidfile=PATH], [dmeventd pidfile [[PID_DIR/dmeventd.pid]]]), DMEVENTD_PIDFILE=$withval, DMEVENTD_PIDFILE="$DEFAULT_PID_DIR/dmeventd.pid") AC_DEFINE_UNQUOTED(DMEVENTD_PIDFILE, ["$DMEVENTD_PIDFILE"], [Path to dmeventd pidfile.]) fi if test "$BUILD_DMEVENTD" = yes; then AC_ARG_WITH(dmeventd-path, AC_HELP_STRING([--with-dmeventd-path=PATH], [dmeventd path [[EPREFIX/sbin/dmeventd]]]), DMEVENTD_PATH=$withval, DMEVENTD_PATH="$lvm_exec_prefix/sbin/dmeventd") AC_DEFINE_UNQUOTED(DMEVENTD_PATH, ["$DMEVENTD_PATH"], [Path to dmeventd binary.]) fi ################################################################################ dnl -- various defaults AC_ARG_WITH(default-system-dir, AC_HELP_STRING([--with-default-system-dir=DIR], [default LVM system directory [[/etc/lvm]]]), DEFAULT_SYS_DIR=$withval, DEFAULT_SYS_DIR="/etc/lvm") AC_DEFINE_UNQUOTED(DEFAULT_SYS_DIR, ["$DEFAULT_SYS_DIR"], [Path to LVM system directory.]) AC_ARG_WITH(default-archive-subdir, AC_HELP_STRING([--with-default-archive-subdir=SUBDIR], [default metadata archive subdir [[archive]]]), DEFAULT_ARCHIVE_SUBDIR=$withval, DEFAULT_ARCHIVE_SUBDIR=archive) AC_DEFINE_UNQUOTED(DEFAULT_ARCHIVE_SUBDIR, ["$DEFAULT_ARCHIVE_SUBDIR"], [Name of default metadata archive subdirectory.]) AC_ARG_WITH(default-backup-subdir, AC_HELP_STRING([--with-default-backup-subdir=SUBDIR], [default metadata backup subdir [[backup]]]), DEFAULT_BACKUP_SUBDIR=$withval, DEFAULT_BACKUP_SUBDIR=backup) AC_DEFINE_UNQUOTED(DEFAULT_BACKUP_SUBDIR, ["$DEFAULT_BACKUP_SUBDIR"], [Name of default metadata backup subdirectory.]) AC_ARG_WITH(default-cache-subdir, AC_HELP_STRING([--with-default-cache-subdir=SUBDIR], [default metadata cache subdir [[cache]]]), DEFAULT_CACHE_SUBDIR=$withval, DEFAULT_CACHE_SUBDIR=cache) AC_DEFINE_UNQUOTED(DEFAULT_CACHE_SUBDIR, ["$DEFAULT_CACHE_SUBDIR"], [Name of default metadata cache subdirectory.]) AC_ARG_WITH(default-locking-dir, AC_HELP_STRING([--with-default-locking-dir=DIR], [default locking directory [[/var/lock/lvm]]]), DEFAULT_LOCK_DIR=$withval, DEFAULT_LOCK_DIR="/var/lock/lvm") AC_DEFINE_UNQUOTED(DEFAULT_LOCK_DIR, ["$DEFAULT_LOCK_DIR"], [Name of default locking directory.]) ################################################################################ dnl -- Setup default data alignment AC_ARG_WITH(default-data-alignment, AC_HELP_STRING([--with-default-data-alignment=NUM], [set the default data alignment in MiB [[1]]]), DEFAULT_DATA_ALIGNMENT=$withval, DEFAULT_DATA_ALIGNMENT=1) AC_DEFINE_UNQUOTED(DEFAULT_DATA_ALIGNMENT, [$DEFAULT_DATA_ALIGNMENT], [Default data alignment.]) ################################################################################ dnl -- which kernel interface to use (ioctl only) AC_MSG_CHECKING(for kernel interface choice) AC_ARG_WITH(interface, AC_HELP_STRING([--with-interface=IFACE], [choose kernel interface (ioctl) [[ioctl]]]), interface=$withval, interface=ioctl) if [[ "x$interface" != xioctl ]]; then AC_MSG_ERROR(--with-interface=ioctl required. fs no longer supported.) fi AC_MSG_RESULT($interface) ################################################################################ DM_LIB_VERSION="\"`cat "$srcdir"/VERSION_DM 2>/dev/null || echo Unknown`\"" AC_DEFINE_UNQUOTED(DM_LIB_VERSION, $DM_LIB_VERSION, [Library version]) DM_LIB_PATCHLEVEL=`cat "$srcdir"/VERSION_DM | $AWK -F '[[-. ]]' '{printf "%s.%s.%s",$1,$2,$3}'` LVM_VERSION="\"`cat "$srcdir"/VERSION 2>/dev/null || echo Unknown`\"" VER=`cat "$srcdir"/VERSION` LVM_RELEASE_DATE="\"`echo $VER | $SED 's/.* (//;s/).*//'`\"" VER=`echo "$VER" | $AWK '{print $1}'` LVM_RELEASE="\"`echo "$VER" | $AWK -F '-' '{print $2}'`\"" VER=`echo "$VER" | $AWK -F '-' '{print $1}'` LVM_MAJOR=`echo "$VER" | $AWK -F '.' '{print $1}'` LVM_MINOR=`echo "$VER" | $AWK -F '.' '{print $2}'` LVM_PATCHLEVEL=`echo "$VER" | $AWK -F '[[(.]]' '{print $3}'` LVM_LIBAPI=`echo "$VER" | $AWK -F '[[()]]' '{print $2}'` ################################################################################ AC_SUBST(APPLIB) AC_SUBST(AWK) AC_SUBST(BUILD_CMIRRORD) AC_SUBST(BUILD_DMEVENTD) AC_SUBST(BUILD_LVMETAD) AC_SUBST(CFLAGS) AC_SUBST(CFLOW_CMD) AC_SUBST(CLDFLAGS) AC_SUBST(CLDNOWHOLEARCHIVE) AC_SUBST(CLDWHOLEARCHIVE) AC_SUBST(CLUSTER) AC_SUBST(CLVMD) AC_SUBST(CLVMD_CMANAGERS) AC_SUBST(CLVMD_PATH) AC_SUBST(CMAN_CFLAGS) AC_SUBST(CMAN_LIBS) AC_SUBST(CMAP_CFLAGS) AC_SUBST(CMAP_LIBS) AC_SUBST(CMDLIB) AC_SUBST(CONFDB_CFLAGS) AC_SUBST(CONFDB_LIBS) AC_SUBST(CONFDIR) AC_SUBST(COPTIMISE_FLAG) AC_SUBST(CPG_CFLAGS) AC_SUBST(CPG_LIBS) AC_SUBST(CSCOPE_CMD) AC_SUBST(DEBUG) AC_SUBST(DEFAULT_SYS_DIR) AC_SUBST(DEFAULT_ARCHIVE_SUBDIR) AC_SUBST(DEFAULT_BACKUP_SUBDIR) AC_SUBST(DEFAULT_CACHE_SUBDIR) AC_SUBST(DEFAULT_DATA_ALIGNMENT) AC_SUBST(DEFAULT_LOCK_DIR) AC_SUBST(DEFAULT_DM_RUN_DIR) AC_SUBST(DEFAULT_RUN_DIR) AC_SUBST(DEVMAPPER) AC_SUBST(DLM_CFLAGS) AC_SUBST(DLM_LIBS) AC_SUBST(DL_LIBS) AC_SUBST(DMEVENTD) AC_SUBST(DMEVENTD_PATH) AC_SUBST(DM_COMPAT) AC_SUBST(DM_DEVICE_GID) AC_SUBST(DM_DEVICE_MODE) AC_SUBST(DM_DEVICE_UID) AC_SUBST(DM_IOCTLS) AC_SUBST(DM_LIB_VERSION) AC_SUBST(DM_LIB_PATCHLEVEL) AC_SUBST(ELDFLAGS) AC_SUBST(FSADM) AC_SUBST(BLKDEACTIVATE) AC_SUBST(HAVE_LIBDL) AC_SUBST(HAVE_REALTIME) AC_SUBST(INTL) AC_SUBST(INTL_PACKAGE) AC_SUBST(JOBS) AC_SUBST(LDDEPS) AC_SUBST(LIBS) AC_SUBST(LIB_SUFFIX) AC_SUBST(LOCALEDIR) AC_SUBST(LVM1) AC_SUBST(LVM1_FALLBACK) AC_SUBST(LVM_VERSION) AC_SUBST(LVM_LIBAPI) AC_SUBST(LVM_MAJOR) AC_SUBST(LVM_MINOR) AC_SUBST(LVM_PATCHLEVEL) AC_SUBST(LVM_PATH) AC_SUBST(LVM_RELEASE) AC_SUBST(LVM_RELEASE_DATE) AC_SUBST(MIRRORS) AC_SUBST(MSGFMT) AC_SUBST(OCF) AC_SUBST(OCFDIR) AC_SUBST(PKGCONFIG) AC_SUBST(POOL) AC_SUBST(PTHREAD_LIBS) AC_SUBST(PYTHON) AC_SUBST(PYTHON_BINDINGS) AC_SUBST(PYTHON_INCDIRS) AC_SUBST(PYTHON_LIBDIRS) AC_SUBST(QUORUM_CFLAGS) AC_SUBST(QUORUM_LIBS) AC_SUBST(RAID) AC_SUBST(READLINE_LIBS) AC_SUBST(REPLICATORS) AC_SUBST(SACKPT_CFLAGS) AC_SUBST(SACKPT_LIBS) AC_SUBST(SALCK_CFLAGS) AC_SUBST(SALCK_LIBS) AC_SUBST(SELINUX_LIBS) AC_SUBST(SELINUX_PC) AC_SUBST(SNAPSHOTS) AC_SUBST(STATICDIR) AC_SUBST(STATIC_LINK) AC_SUBST(TESTING) AC_SUBST(THIN) AC_SUBST(THIN_CHECK_CMD) AC_SUBST(UDEV_LIBS) AC_SUBST(UDEV_PC) AC_SUBST(UDEV_RULES) AC_SUBST(UDEV_SYNC) AC_SUBST(UDEV_RULE_EXEC_DETECTION) AC_SUBST(UDEV_HAS_BUILTIN_BLKID) AC_SUBST(CUNIT_LIBS) AC_SUBST(CUNIT_CFLAGS) AC_SUBST(WRITE_INSTALL) AC_SUBST(DMEVENTD_PIDFILE) AC_SUBST(LVMETAD_PIDFILE) AC_SUBST(interface) AC_SUBST(kerneldir) AC_SUBST(missingkernel) AC_SUBST(kernelvsn) AC_SUBST(tmpdir) AC_SUBST(udev_prefix) AC_SUBST(udevdir) AC_SUBST(systemdsystemunitdir) AC_SUBST(systemdutildir) AC_SUBST(tmpfilesdir) AC_SUBST(usrlibdir) AC_SUBST(usrsbindir) ################################################################################ dnl -- First and last lines should not contain files to generate in order to dnl -- keep utility scripts running properly AC_CONFIG_FILES([ Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile daemons/cmirrord/Makefile daemons/dmeventd/Makefile daemons/dmeventd/libdevmapper-event.pc daemons/dmeventd/plugins/Makefile daemons/dmeventd/plugins/lvm2/Makefile daemons/dmeventd/plugins/raid/Makefile daemons/dmeventd/plugins/mirror/Makefile daemons/dmeventd/plugins/snapshot/Makefile daemons/dmeventd/plugins/thin/Makefile daemons/lvmetad/Makefile doc/Makefile doc/example.conf include/.symlinks include/Makefile lib/Makefile lib/format1/Makefile lib/format_pool/Makefile lib/locking/Makefile lib/mirror/Makefile lib/replicator/Makefile lib/misc/lvm-version.h lib/raid/Makefile lib/snapshot/Makefile lib/thin/Makefile libdaemon/Makefile libdaemon/client/Makefile libdaemon/server/Makefile libdm/Makefile libdm/libdevmapper.pc liblvm/Makefile liblvm/liblvm2app.pc man/Makefile po/Makefile python/Makefile python/setup.py scripts/blkdeactivate.sh scripts/blk_availability_init_red_hat scripts/blk_availability_systemd_red_hat.service scripts/clvmd_init_red_hat scripts/cmirrord_init_red_hat scripts/lvm2_lvmetad_init_red_hat scripts/lvm2_lvmetad_systemd_red_hat.socket scripts/lvm2_lvmetad_systemd_red_hat.service scripts/lvm2_monitoring_init_red_hat scripts/dm_event_systemd_red_hat.socket scripts/dm_event_systemd_red_hat.service scripts/lvm2_monitoring_systemd_red_hat.service scripts/lvm2_tmpfiles_red_hat.conf scripts/Makefile test/Makefile test/api/Makefile test/unit/Makefile tools/Makefile udev/Makefile unit-tests/datastruct/Makefile unit-tests/regex/Makefile unit-tests/mm/Makefile ]) AC_OUTPUT if test x$ODIRECT != xyes; then AC_MSG_WARN(Warning: O_DIRECT disabled: low-memory pvmove may lock up) fi lvm2-2.02.98/test/0000750000175000017500000000000012037016273012467 5ustar blankblanklvm2-2.02.98/test/api/0000750000175000017500000000000012037016272013237 5ustar blankblanklvm2-2.02.98/test/api/percent.c0000640000175000017500000000305012037016272015042 0ustar blankblank/* * 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 */ #undef NDEBUG #include "lvm2app.h" #include "assert.h" int main(int argc, char *argv[]) { lvm_t handle; vg_t vg = NULL; lv_t lv; struct lvm_property_value v; struct lvm_property_value d; handle = lvm_init(NULL); assert(handle); vg = lvm_vg_open(handle, argv[1], "r", 0); assert(vg); lv = lvm_lv_from_name(vg, "snap"); assert(lv); v = lvm_lv_get_property(lv, "snap_percent"); assert(v.is_valid); assert(v.value.integer == PERCENT_0); lv = lvm_lv_from_name(vg, "mirr"); assert(lv); v = lvm_lv_get_property(lv, "copy_percent"); assert(v.is_valid); assert(v.value.integer == PERCENT_100); lv = lvm_lv_from_name(vg, "snap2"); assert(lv); v = lvm_lv_get_property(lv, "snap_percent"); assert(v.is_valid); assert(v.value.integer == 50 * PERCENT_1); d = lvm_lv_get_property(lv, "data_percent"); assert(d.is_valid); assert(d.value.integer == v.value.integer); lvm_vg_close(vg); lvm_quit(handle); return 0; } lvm2-2.02.98/test/api/lvtest.sh0000640000175000017500000000114012037016272015111 0ustar blankblank#!/bin/sh # Copyright (C) 2011 Red Hat, Inc. All rights reserved. # # This file is part of LVM2. # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions # of the GNU General Public License v.2. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation, # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA . lib/test aux prepare_vg 1 lvcreate -n test -l 5 $vg aux apitest lvtest $vg check lv_field $vg/test lv_name test lvm2-2.02.98/test/api/thin_percent.sh0000640000175000017500000000171512037016272016262 0ustar blankblank#!/bin/sh # Copyright (C) 2012 Red Hat, Inc. All rights reserved. # # This file is part of LVM2. # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions # of the GNU General Public License v.2. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation, # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA . lib/test aux have_thin 1 0 0 || skip # disable thin_check if not present in system which thin_check || aux lvmconf 'global/thin_check_executable = ""' aux prepare_devs 2 vgcreate -s 64k $vg $(cat DEVICES) lvcreate -L5M -T $vg/pool lvcreate -V1M -T $vg/pool -n thin dd if=/dev/urandom of="$DM_DEV_DIR/$vg/thin" count=2 bs=256K lvcreate -s $vg/thin -n snap dd if=/dev/urandom of="$DM_DEV_DIR/$vg/snap" count=3 bs=256K lvs $vg aux apitest thin_percent $vg vgremove -ff $vg lvm2-2.02.98/test/api/test.c0000640000175000017500000006407112037016272014373 0ustar blankblank/* * 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 #include #include #include #include "configure.h" #include "lvm2app.h" #ifdef READLINE_SUPPORT #include #define MAX_ARGS 64 static int lvm_split(char *str, int *argc, char **argv, int max) { char *b = str, *e; *argc = 0; while (*b) { while (*b && isspace(*b)) b++; if ((!*b) || ((*argc == 0)&&(*b == '#'))) break; e = b; while (*e && !isspace(*e)) e++; argv[(*argc)++] = b; if (!*e) break; *e++ = '\0'; b = e; if (*argc == max) break; } return *argc; } static void _show_help(void) { printf("'lv_activate vgname lvname: " "Activate an LV\n"); printf("'lv_deactivate vgname lvname: " "Deactivate an LV\n"); printf("'vg_remove_lv vgname lvname': " "Remove a LV\n"); printf("'vg_create_lv_linear vgname lvname size_in_bytes': " "Create a linear LV\n"); printf("'scan_vgs': " "Scan the system for LVM metadata\n"); printf("'list_vg_names': " "List the names of the VGs that exist in the system\n"); printf("'list_vg_ids': " "List the uuids of the VGs that exist in the system\n"); printf("'vg_list_pvs vgname': " "List the PVs that exist in VG vgname\n"); printf("'pv_list_pvsegs pvname': " "List the PV segments that exist in PV pvname\n"); printf("'vg_list_lvs vgname': " "List the LVs that exist in VG vgname\n"); printf("'lv_list_lvsegs vgname lvname': " "List the LV segments that exist in LV vgname/lvname\n"); printf("'vgs_open': " "List the VGs that are currently open\n"); printf("'vgs': " "List all VGs known to the system\n"); printf("'vg_extend vgname device: " "Issue a lvm_vg_extend() API call on VG 'vgname'\n"); printf("'vg_reduce vgname device: " "Issue a lvm_vg_reduce() API call on VG 'vgname'\n"); printf("'vg_open vgname ['r' | 'w']': " "Issue a lvm_vg_open() API call on VG 'vgname'\n"); printf("'vg_close vgname': " "Issue a lvm_vg_close() API call on VG 'vgname'\n"); printf("'vg_create vgname: " "Issue a lvm_vg_create() to create VG 'vgname'\n"); printf("'vg_remove vgname: " "Issue a lvm_vg_remove() to remove VG 'vgname'\n"); printf("'config_reload': " "Issue a lvm_config_reload() API to reload LVM config\n"); printf("'config_override' device: " "Issue a lvm_config_override() with accept device filter\n"); printf("'vg_get_tags vgname': " "List the tags of a VG\n"); printf("'lv_get_property vgname lvname property_name': " "Display the value of LV property\n"); printf("'vg_get_property vgname property_name': " "Display the value of VG property\n"); printf("'pv_get_property pvname property_name': " "Display the value of PV property\n"); printf("'vg_set_property vgname property_name': " "Set the value of VG property\n"); printf("'lv_get_tags vgname lvname': " "List the tags of a LV\n"); printf("'vg_{add|remove}_tag vgname tag': " "Add/remove a tag from a VG\n"); printf("'lv_{add|remove}_tag vgname lvname tag': " "Add/remove a tag from a LV\n"); printf("'vgname_from_devname device': " "Lookup a vgname from a device name\n"); printf("'vgname_from_pvid pvid': " "Lookup a vgname from a pvid\n"); printf("'lv_from_uuid vgname lvuuid': " "Lookup an LV from an LV uuid\n"); printf("'lv_from_name vgname lvname': " "Lookup an LV from an LV name\n"); printf("'pv_from_uuid vgname pvuuid': " "Lookup an LV from an LV uuid\n"); printf("'pv_from_name vgname pvname': " "Lookup an LV from an LV name\n"); printf("'quit': exit the program\n"); } static struct dm_hash_table *_vgid_hash = NULL; static struct dm_hash_table *_vgname_hash = NULL; static struct dm_hash_table *_pvname_hash = NULL; static struct dm_hash_table *_lvname_hash = NULL; static void _hash_destroy_single(struct dm_hash_table **htable) { if (htable && *htable) { dm_hash_destroy(*htable); *htable = NULL; } } static void _hash_destroy(void) { _hash_destroy_single(&_vgname_hash); _hash_destroy_single(&_vgid_hash); _hash_destroy_single(&_pvname_hash); _hash_destroy_single(&_lvname_hash); } static int _hash_create(void) { if (!(_vgname_hash = dm_hash_create(128))) return 0; if (!(_pvname_hash = dm_hash_create(128))) { _hash_destroy_single(&_vgname_hash); return 0; } if (!(_lvname_hash = dm_hash_create(128))) { _hash_destroy_single(&_vgname_hash); _hash_destroy_single(&_pvname_hash); return 0; } if (!(_vgid_hash = dm_hash_create(128))) { _hash_destroy_single(&_vgname_hash); _hash_destroy_single(&_pvname_hash); _hash_destroy_single(&_lvname_hash); return 0; } return 1; } /* FIXME: this should be per vg */ static lv_t _lookup_lv_by_name(const char *name) { lv_t lv; if (!name) { printf ("Invalid LV name\n"); return NULL; } if (!(lv = dm_hash_lookup(_lvname_hash, name))) { printf ("Can't find %s in LVs - run vg_create_lv first\n", name); return NULL; } return lv; } static vg_t _lookup_vg_by_name(char **argv, int argc) { vg_t vg; if (argc < 2) { printf ("Please enter vg_name\n"); return NULL; } if (!(vg = dm_hash_lookup(_vgid_hash, argv[1])) && !(vg = dm_hash_lookup(_vgname_hash, argv[1]))) { printf ("Can't find %s in open VGs - run vg_open first\n", argv[1]); return NULL; } return vg; } static pv_t _lookup_pv_by_name(const char *name) { pv_t pv; if (!(pv = dm_hash_lookup(_pvname_hash, name))) { printf ("Can't find %s in open PVs - run vg_open first\n", name); return NULL; } return pv; } static void _add_lvs_to_lvname_hash(struct dm_list *lvs) { struct lvm_lv_list *lvl; dm_list_iterate_items(lvl, lvs) { /* Concatenate VG name with LV name */ dm_hash_insert(_lvname_hash, lvm_lv_get_name(lvl->lv), lvl->lv); } } static void _add_pvs_to_pvname_hash(struct dm_list *pvs) { struct lvm_pv_list *pvl; dm_list_iterate_items(pvl, pvs) { dm_hash_insert(_pvname_hash, lvm_pv_get_name(pvl->pv), pvl->pv); } } static void _remove_device_from_pvname_hash(struct dm_list *pvs, const char *name) { struct lvm_pv_list *pvl; dm_list_iterate_items(pvl, pvs) { if (!strncmp(lvm_pv_get_name(pvl->pv), name, strlen(name))) dm_hash_remove(_pvname_hash, name); } } static void _add_device_to_pvname_hash(struct dm_list *pvs, const char *name) { struct lvm_pv_list *pvl; dm_list_iterate_items(pvl, pvs) { if (!strncmp(lvm_pv_get_name(pvl->pv), name, strlen(name))) dm_hash_insert(_pvname_hash, name, pvl->pv); } } static void _vg_reduce(char **argv, int argc, lvm_t libh) { vg_t vg; struct dm_list *pvs; if (argc < 2) { printf ("Please enter vg_name\n"); return; } if (!(vg = dm_hash_lookup(_vgid_hash, argv[1])) && !(vg = dm_hash_lookup(_vgname_hash, argv[1]))) { printf ("VG not open\n"); return; } if (lvm_vg_reduce(vg, argv[2])) { printf("Error reducing %s by %s\n", argv[1], argv[2]); return; } printf("Success reducing vg %s by %s\n", argv[1], argv[2]); /* * Add the device into the hashes for lookups */ pvs = lvm_vg_list_pvs(vg); if (pvs && !dm_list_empty(pvs)) _remove_device_from_pvname_hash(pvs, argv[2]); } /* Print "Error" or "Success" depending on lvm status */ static int _lvm_status_to_pass_fail(int rc) { if (rc) printf("Error "); else printf("Success "); return rc; } static void _config_override(char **argv, int argc, lvm_t libh) { int rc; char tmp[64]; if (argc < 2) { printf ("Please enter device\n"); return; } snprintf(tmp, 63, "devices{filter=[\"a|%s|\", \"r|.*|\"]}", argv[1]); rc = lvm_config_override(libh, tmp); _lvm_status_to_pass_fail(rc); printf("overriding LVM configuration\n"); } static void _config_reload(char **argv, int argc, lvm_t libh) { int rc; rc = lvm_config_reload(libh); _lvm_status_to_pass_fail(rc); printf("reloading LVM configuration\n"); } static void _vg_extend(char **argv, int argc, lvm_t libh) { vg_t vg; struct dm_list *pvs; if (argc < 2) { printf ("Please enter vg_name\n"); return; } if (!(vg = dm_hash_lookup(_vgid_hash, argv[1])) && !(vg = dm_hash_lookup(_vgname_hash, argv[1]))) { printf ("VG not open\n"); return; } if (lvm_vg_extend(vg, argv[2])) { printf("Error extending %s with %s\n", argv[1], argv[2]); return; } printf("Success extending vg %s with %s\n", argv[1], argv[2]); /* * Add the device into the hashes for lookups */ pvs = lvm_vg_list_pvs(vg); if (pvs && !dm_list_empty(pvs)) _add_device_to_pvname_hash(pvs, argv[2]); } static void _vg_open(char **argv, int argc, lvm_t libh) { vg_t vg; struct dm_list *lvs; struct dm_list *pvs; if (argc < 2) { printf ("Please enter vg_name\n"); return; } if ((vg = dm_hash_lookup(_vgid_hash, argv[1])) || (vg = dm_hash_lookup(_vgname_hash, argv[1]))) { printf ("VG already open\n"); return; } if (argc < 3) vg = lvm_vg_open(libh, argv[1], "r", 0); else vg = lvm_vg_open(libh, argv[1], argv[2], 0); if (!vg || !lvm_vg_get_name(vg)) { printf("Error opening %s\n", argv[1]); return; } printf("Success opening vg %s\n", argv[1]); dm_hash_insert(_vgname_hash, lvm_vg_get_name(vg), vg); dm_hash_insert(_vgid_hash, lvm_vg_get_uuid(vg), vg); /* * Add the LVs and PVs into the hashes for lookups */ lvs = lvm_vg_list_lvs(vg); if (lvs && !dm_list_empty(lvs)) _add_lvs_to_lvname_hash(lvs); pvs = lvm_vg_list_pvs(vg); if (pvs && !dm_list_empty(pvs)) _add_pvs_to_pvname_hash(pvs); } /* Lookup the vg and remove it from the vgname and vgid hashes */ static vg_t _lookup_and_remove_vg(const char *vgname) { vg_t vg=NULL; if ((vg = dm_hash_lookup(_vgname_hash, vgname))) { dm_hash_remove(_vgid_hash, lvm_vg_get_uuid(vg)); dm_hash_remove(_vgname_hash, lvm_vg_get_name(vg)); } if (!vg && (vg = dm_hash_lookup(_vgid_hash, vgname))) { dm_hash_remove(_vgid_hash, lvm_vg_get_uuid(vg)); dm_hash_remove(_vgname_hash, lvm_vg_get_name(vg)); } return vg; } static void _vg_write(char **argv, int argc) { vg_t vg; int rc = 0; if (argc < 2) { printf ("Please enter vg_name\n"); return; } vg = _lookup_vg_by_name(argv, argc); if (!vg) { printf("Can't find vg_name %s\n", argv[1]); return; } rc = lvm_vg_write(vg); _lvm_status_to_pass_fail(rc); printf("writing VG %s\n", lvm_vg_get_name(vg)); } static void _vg_create(char **argv, int argc, lvm_t libh) { vg_t vg; if (argc < 2) { printf ("Please enter vg_name\n"); return; } vg = lvm_vg_create(libh, argv[1]); if (!vg || !lvm_vg_get_name(vg)) { printf("Error creating %s\n", argv[1]); return; } printf("Success creating vg %s\n", argv[1]); dm_hash_insert(_vgname_hash, lvm_vg_get_name(vg), vg); dm_hash_insert(_vgid_hash, lvm_vg_get_uuid(vg), vg); } static void _vg_remove(char **argv, int argc) { vg_t vg; int rc = 0; if (argc < 2) { printf ("Please enter vg_name\n"); return; } vg = _lookup_vg_by_name(argv, argc); if (!vg) { printf("Can't find vg_name %s\n", argv[1]); return; } rc = lvm_vg_remove(vg); _lvm_status_to_pass_fail(rc); printf("removing VG\n"); } static void _vg_close(char **argv, int argc) { vg_t vg; int rc = 0; if (argc < 2) { printf ("Please enter vg_name\n"); return; } vg = _lookup_and_remove_vg(argv[1]); if (!vg) { printf("Can't find vg_name %s\n", argv[1]); return; } rc = lvm_vg_close(vg); _lvm_status_to_pass_fail(rc); printf("closing VG\n"); } static void _show_one_vg(vg_t vg) { printf("%s (%s): sz=%"PRIu64", free=%"PRIu64", #pv=%"PRIu64 ", seq#=%"PRIu64"\n", lvm_vg_get_name(vg), lvm_vg_get_uuid(vg), lvm_vg_get_size(vg), lvm_vg_get_free_size(vg), lvm_vg_get_pv_count(vg), lvm_vg_get_seqno(vg)); } static void _print_pv(pv_t pv) { if (!pv) return; printf("%s (%s): size=%"PRIu64", free=%"PRIu64 ", dev_size=%"PRIu64", mda_count=%"PRIu64"\n", lvm_pv_get_name(pv), lvm_pv_get_uuid(pv), lvm_pv_get_size(pv), lvm_pv_get_free(pv), lvm_pv_get_dev_size(pv), lvm_pv_get_mda_count(pv)); } static void _print_lv(vg_t vg, lv_t lv) { if (!lv) return; printf("%s/%s (%s): size=%"PRIu64", %sACTIVE / %sSUSPENDED\n", lvm_vg_get_name(vg), lvm_lv_get_name(lv), lvm_lv_get_uuid(lv), lvm_lv_get_size(lv), lvm_lv_is_active(lv) ? "" : "IN", lvm_lv_is_suspended(lv) ? "" : "NOT "); } static void _list_open_vgs(void) { dm_hash_iter(_vgid_hash, (dm_hash_iterate_fn) _show_one_vg); } static void _pvs_in_vg(char **argv, int argc) { struct dm_list *pvs; struct lvm_pv_list *pvl; vg_t vg; if (!(vg = _lookup_vg_by_name(argv, argc))) return; pvs = lvm_vg_list_pvs(vg); if (!pvs || dm_list_empty(pvs)) { printf("No PVs in VG %s\n", lvm_vg_get_name(vg)); return; } printf("PVs in VG %s:\n", lvm_vg_get_name(vg)); dm_list_iterate_items(pvl, pvs) { _print_pv(pvl->pv); } } static void _print_property_value(const char *name, struct lvm_property_value v) { if (!v.is_valid) printf("%s = INVALID\n", name); else if (v.is_string) printf("%s = %s\n", name, v.value.string); else printf("%s = %"PRIu64"\n", name, v.value.integer); } static void _pvsegs_in_pv(char **argv, int argc) { struct dm_list *pvsegs; struct lvm_pvseg_list *pvl; pv_t pv; if (!(pv = _lookup_pv_by_name(argv[1]))) return; pvsegs = lvm_pv_list_pvsegs(pv); if (!pvsegs || dm_list_empty(pvsegs)) { printf("No PV segments in pv %s\n", argv[1]); return; } printf("PV segments in pv %s:\n", argv[1]); dm_list_iterate_items(pvl, pvsegs) { struct lvm_property_value v; v = lvm_pvseg_get_property(pvl->pvseg, "pvseg_start"); _print_property_value("pvseg_start", v); v = lvm_pvseg_get_property(pvl->pvseg, "pvseg_size"); _print_property_value("pvseg_size", v); } } static void _scan_vgs(lvm_t libh) { lvm_scan(libh); } static void _list_vg_names(lvm_t libh) { struct dm_list *list; struct lvm_str_list *strl; list = lvm_list_vg_names(libh); printf("VG names:\n"); dm_list_iterate_items(strl, list) { printf("%s\n", strl->str); } } static void _list_vg_ids(lvm_t libh) { struct dm_list *list; struct lvm_str_list *strl; list = lvm_list_vg_uuids(libh); printf("VG uuids:\n"); dm_list_iterate_items(strl, list) { printf("%s\n", strl->str); } } static void _display_tags(struct dm_list *list) { struct lvm_str_list *strl; if (dm_list_empty(list)) { printf("No tags exist\n"); return; } else if (!list) { printf("Error obtaining tags\n"); return; } dm_list_iterate_items(strl, list) { printf("%s\n", strl->str); } } static void _vg_get_tags(char **argv, int argc) { vg_t vg; if (!(vg = _lookup_vg_by_name(argv, argc))) return; printf("VG tags:\n"); _display_tags(lvm_vg_get_tags(vg)); } static void _vg_tag(char **argv, int argc, int add) { vg_t vg; if (argc < 3) { printf("Please enter vgname, tag\n"); return; } if (!(vg = _lookup_vg_by_name(argv, argc))) return; if (add && lvm_vg_add_tag(vg, argv[2])) printf("Error "); else if (!add && lvm_vg_remove_tag(vg, argv[2])){ printf("Error "); } else { printf("Success "); } printf("%s tag %s to VG %s\n", add ? "adding":"removing", argv[2], argv[1]); } static void _pv_get_property(char **argv, int argc) { pv_t pv; struct lvm_property_value v; if (argc < 3) { printf("Please enter pvname, field_id\n"); return; } if (!(pv = _lookup_pv_by_name(argv[1]))) return; v = lvm_pv_get_property(pv, argv[2]); _print_property_value(argv[2], v); } static void _vg_get_property(char **argv, int argc) { vg_t vg; struct lvm_property_value v; if (argc < 3) { printf("Please enter vgname, field_id\n"); return; } if (!(vg = _lookup_vg_by_name(argv, argc))) return; v = lvm_vg_get_property(vg, argv[2]); _print_property_value(argv[2], v); } static void _lv_get_property(char **argv, int argc) { lv_t lv; struct lvm_property_value v; if (argc < 4) { printf("Please enter vgname, lvname, field_id\n"); return; } if (!(lv = _lookup_lv_by_name(argv[2]))) return; v = lvm_lv_get_property(lv, argv[3]); _print_property_value(argv[3], v); } static void _vg_set_property(char **argv, int argc) { vg_t vg; struct lvm_property_value value; int rc; if (argc < 4) { printf("Please enter vgname, field_id, value\n"); return; } if (!(vg = _lookup_vg_by_name(argv, argc))) return; value = lvm_vg_get_property(vg, argv[2]); if (!value.is_valid) { printf("Error obtaining property value\n"); return; } if (value.is_string) value.value.string = argv[3]; else value.value.integer = atoi(argv[3]); rc = lvm_vg_set_property(vg, argv[2], &value); if (rc) printf("Error "); else printf("Success "); printf("setting value of property %s in VG %s\n", argv[2], argv[1]); } static void _lv_get_tags(char **argv, int argc) { lv_t lv; if (argc < 3) { printf("Please enter vgname, lvname\n"); return; } if (!(lv = _lookup_lv_by_name(argv[2]))) return; printf("LV tags:\n"); _display_tags(lvm_lv_get_tags(lv)); } static void _lv_tag(char **argv, int argc, int add) { lv_t lv; if (argc < 3) { printf("Please enter vgname, lvname\n"); return; } if (!(lv = _lookup_lv_by_name(argv[2]))) return; if (add && lvm_lv_add_tag(lv, argv[3])) printf("Error "); else if (!add && lvm_lv_remove_tag(lv, argv[3])){ printf("Error "); } else { printf("Success "); } printf("%s tag %s to LV %s\n", add ? "adding":"removing", argv[3], argv[2]); } static void _lv_from_uuid(char **argv, int argc) { vg_t vg; if (argc < 3) { printf("Please enter vgname, lv_uuid\n"); return; } if (!(vg = _lookup_vg_by_name(argv, argc))) return; _print_lv(vg, lvm_lv_from_uuid(vg, argv[2])); } static void _lv_from_name(char **argv, int argc) { vg_t vg; if (argc < 3) { printf("Please enter vgname, lv_uuid\n"); return; } if (!(vg = _lookup_vg_by_name(argv, argc))) return; _print_lv(vg, lvm_lv_from_name(vg, argv[2])); } static void _pv_from_uuid(char **argv, int argc) { vg_t vg; if (argc < 3) { printf("Please enter vgname, pv_uuid\n"); return; } if (!(vg = _lookup_vg_by_name(argv, argc))) return; _print_pv(lvm_pv_from_uuid(vg, argv[2])); } static void _pv_from_name(char **argv, int argc) { vg_t vg; if (argc < 3) { printf("Please enter vgname, pv_uuid\n"); return; } if (!(vg = _lookup_vg_by_name(argv, argc))) return; _print_pv(lvm_pv_from_name(vg, argv[2])); } static void _vgname_from_pvid(char **argv, int argc, lvm_t libh) { const char *vgname; if (argc < 1) { printf("Please enter pvid\n"); return; } if (!(vgname = lvm_vgname_from_pvid(libh, argv[1]))) { printf("Error "); } else { printf("Success "); } printf("looking up vgname=%s from PVID=%s\n", vgname, argv[1]); } static void _vgname_from_devname(char **argv, int argc, lvm_t libh) { const char *vgname; if (argc < 1) { printf("Please enter device\n"); return; } if (!(vgname = lvm_vgname_from_device(libh, argv[1]))) { printf("Error "); } else { printf("Success "); } printf("looking up vgname=%s from device name=%s\n", vgname, argv[1]); } static void _lvs_in_vg(char **argv, int argc) { struct dm_list *lvs; struct lvm_lv_list *lvl; vg_t vg; if (!(vg = _lookup_vg_by_name(argv, argc))) return; lvs = lvm_vg_list_lvs(vg); if (!lvs || dm_list_empty(lvs)) { printf("No LVs in VG %s\n", lvm_vg_get_name(vg)); return; } printf("LVs in VG %s:\n", lvm_vg_get_name(vg)); dm_list_iterate_items(lvl, lvs) { _print_lv(vg, lvl->lv); } } static void _lvsegs_in_lv(char **argv, int argc) { struct dm_list *lvsegs; struct lvm_lvseg_list *lvl; lv_t lv; if (!(lv = _lookup_lv_by_name(argv[2]))) return; lvsegs = lvm_lv_list_lvsegs(lv); if (!lvsegs || dm_list_empty(lvsegs)) { printf("No LV segments in lv %s\n", lvm_lv_get_name(lv)); return; } printf("LV segments in lv %s:\n", lvm_lv_get_name(lv)); dm_list_iterate_items(lvl, lvsegs) { struct lvm_property_value v; v = lvm_lvseg_get_property(lvl->lvseg, "segtype"); _print_property_value("segtype", v); v = lvm_lvseg_get_property(lvl->lvseg, "seg_start_pe"); _print_property_value("seg_start_pe", v); v = lvm_lvseg_get_property(lvl->lvseg, "seg_size"); _print_property_value("seg_size", v); v = lvm_lvseg_get_property(lvl->lvseg, "devices"); _print_property_value("devices", v); v = lvm_lvseg_get_property(lvl->lvseg, "seg_pe_ranges"); _print_property_value("seg_pe_ranges", v); } } static void _lv_deactivate(char **argv, int argc) { lv_t lv; int rc=0; if (argc < 3) { printf("Please enter vgname, lvname\n"); return; } if (!(lv = _lookup_lv_by_name(argv[2]))) return; rc = lvm_lv_deactivate(lv); _lvm_status_to_pass_fail(rc); printf("De-activating LV %s in VG %s\n", argv[2], argv[1]); } static void _lv_activate(char **argv, int argc) { lv_t lv; int rc=0; if (argc < 3) { printf("Please enter vgname, lvname\n"); return; } if (!(lv = _lookup_lv_by_name(argv[2]))) return; rc = lvm_lv_activate(lv); _lvm_status_to_pass_fail(rc); printf("activating LV %s in VG %s\n", argv[2], argv[1]); } static void _vg_remove_lv(char **argv, int argc) { lv_t lv; if (argc < 3) { printf("Please enter vgname, lvname\n"); return; } if (!(lv = _lookup_lv_by_name(argv[2]))) return; if (lvm_vg_remove_lv(lv)) printf("Error "); else { printf("Success "); dm_hash_remove(_lvname_hash, argv[2]); } printf("removing LV %s in VG %s\n", argv[2], argv[1]); } static void _vg_create_lv_linear(char **argv, int argc) { vg_t vg; lv_t lv; if (argc < 4) { printf("Please enter vgname, lvname, and size\n"); return; } if (!(vg = _lookup_vg_by_name(argv, argc))) return; lv = lvm_vg_create_lv_linear(vg, argv[2], atol(argv[3])); if (!lv) printf("Error "); else { printf("Success "); dm_hash_insert(_lvname_hash, argv[2], lv); } printf("creating LV %s in VG %s\n", argv[2], argv[1]); } static int lvmapi_test_shell(lvm_t libh) { int argc; char *input = NULL, *args[MAX_ARGS], **argv; _hash_create(); argc=0; while (1) { free(input); input = readline("liblvm> "); /* EOF */ if (!input) { printf("\n"); break; } /* empty line */ if (!*input) continue; argv = args; if (lvm_split(input, &argc, argv, MAX_ARGS) == MAX_ARGS) { printf("Too many arguments, sorry."); continue; } if (!strcmp(argv[0], "lvm")) { argv++; argc--; } if (!argc) continue; if (!strcmp(argv[0], "quit") || !strcmp(argv[0], "exit")) { printf("Exiting.\n"); break; } else if (!strcmp(argv[0], "?") || !strcmp(argv[0], "help")) { _show_help(); } else if (!strcmp(argv[0], "config_reload")) { _config_reload(argv, argc, libh); } else if (!strcmp(argv[0], "config_override")) { _config_override(argv, argc, libh); } else if (!strcmp(argv[0], "vg_extend")) { _vg_extend(argv, argc, libh); } else if (!strcmp(argv[0], "vg_reduce")) { _vg_reduce(argv, argc, libh); } else if (!strcmp(argv[0], "vg_write")) { _vg_write(argv, argc); } else if (!strcmp(argv[0], "vg_open")) { _vg_open(argv, argc, libh); } else if (!strcmp(argv[0], "vg_close")) { _vg_close(argv, argc); } else if (!strcmp(argv[0], "vg_create")) { _vg_create(argv, argc, libh); } else if (!strcmp(argv[0], "vg_remove")) { _vg_remove(argv, argc); } else if (!strcmp(argv[0], "lv_activate")) { _lv_activate(argv, argc); } else if (!strcmp(argv[0], "lv_deactivate")) { _lv_deactivate(argv, argc); } else if (!strcmp(argv[0], "vg_remove_lv")) { _vg_remove_lv(argv, argc); } else if (!strcmp(argv[0], "vgs_open")) { _list_open_vgs(); } else if (!strcmp(argv[0], "vg_list_pvs")) { _pvs_in_vg(argv, argc); } else if (!strcmp(argv[0], "pv_list_pvsegs")) { _pvsegs_in_pv(argv, argc); } else if (!strcmp(argv[0], "vg_list_lvs")) { _lvs_in_vg(argv, argc); } else if (!strcmp(argv[0], "lv_list_lvsegs")) { _lvsegs_in_lv(argv, argc); } else if (!strcmp(argv[0], "list_vg_names")) { _list_vg_names(libh); } else if (!strcmp(argv[0], "list_vg_ids")) { _list_vg_ids(libh); } else if (!strcmp(argv[0], "scan_vgs")) { _scan_vgs(libh); } else if (!strcmp(argv[0], "vg_create_lv_linear")) { _vg_create_lv_linear(argv, argc); } else if (!strcmp(argv[0], "vg_add_tag")) { _vg_tag(argv, argc, 1); } else if (!strcmp(argv[0], "vg_remove_tag")) { _vg_tag(argv, argc, 0); } else if (!strcmp(argv[0], "vg_get_tags")) { _vg_get_tags(argv, argc); } else if (!strcmp(argv[0], "lv_get_property")) { _lv_get_property(argv, argc); } else if (!strcmp(argv[0], "vg_get_property")) { _vg_get_property(argv, argc); } else if (!strcmp(argv[0], "pv_get_property")) { _pv_get_property(argv, argc); } else if (!strcmp(argv[0], "vg_set_property")) { _vg_set_property(argv, argc); } else if (!strcmp(argv[0], "lv_add_tag")) { _lv_tag(argv, argc, 1); } else if (!strcmp(argv[0], "lv_remove_tag")) { _lv_tag(argv, argc, 0); } else if (!strcmp(argv[0], "lv_get_tags")) { _lv_get_tags(argv, argc); } else if (!strcmp(argv[0], "vgname_from_devname")) { _vgname_from_devname(argv, argc, libh); } else if (!strcmp(argv[0], "vgname_from_pvid")) { _vgname_from_pvid(argv, argc, libh); } else if (!strcmp(argv[0], "lv_from_uuid")) { _lv_from_uuid(argv, argc); } else if (!strcmp(argv[0], "lv_from_name")) { _lv_from_name(argv, argc); } else if (!strcmp(argv[0], "pv_from_uuid")) { _pv_from_uuid(argv, argc); } else if (!strcmp(argv[0], "pv_from_name")) { _pv_from_name(argv, argc); } else { printf ("Unrecognized command %s\n", argv[0]); } } dm_hash_iter(_vgname_hash, (dm_hash_iterate_fn) lvm_vg_close); _hash_destroy(); free(input); return 0; } #else /* !READLINE_SUPPORT */ static int lvmapi_test_shell(lvm_t libh) { printf("Build without readline library, no interactive testing.\n"); return 1; } #endif int main (int argc, char *argv[]) { lvm_t libh; libh = lvm_init(NULL); if (!libh) { printf("Unable to open lvm library instance\n"); return 1; } printf("Library version: %s\n", lvm_library_get_version()); lvmapi_test_shell(libh); lvm_quit(libh); return 0; } lvm2-2.02.98/test/api/lvtest.c0000640000175000017500000000303612037016272014727 0ustar blankblank/* * 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 */ #undef NDEBUG #include "lvm2app.h" #include "assert.h" #define err(args...) \ do { fprintf(stderr, args); goto bad; } while (0) int main(int argc, char *argv[]) { lvm_t handle; vg_t vg; lv_t lv; int r = -1; if (!(handle = lvm_init(NULL))) return -1; if (!(vg = lvm_vg_open(handle, argv[1], "w", 0))) err("VG open %s failed.\n", argv[1]); if (!(lv = lvm_lv_from_name(vg, "test"))) err("LV test not found.\n"); if (lvm_lv_deactivate(lv)) err("LV test deactivation failed.\n"); if (lvm_lv_activate(lv)) err("LV test activation failed.\n"); if (lvm_lv_activate(lv)) err("LV test repeated activation failed.\n"); if (lvm_lv_rename(lv, "test1")) err("LV test rename to test1 failed.\n"); if (lvm_lv_rename(lv, "test2")) err("LV test1 rename to test2 failed.\n"); if (lvm_lv_rename(lv, "test")) err("LV test2 rename to test failed.\n"); if (lvm_vg_close(vg)) err("VG close failed.\n"); r = 0; bad: lvm_quit(handle); return r; } lvm2-2.02.98/test/api/Makefile.in0000640000175000017500000000264012037016272015307 0ustar blankblank# # Copyright (C) 2009-2012 Red Hat, Inc. All rights reserved. # # This file is part of LVM2. # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions # of the GNU 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@ TARGETS = ifeq ("@APPLIB@", "yes") TARGETS += test SOURCES = test.c TARGETS += \ lvtest.t \ percent.t \ pe_start.t \ thin_percent.t \ vgtest.t SOURCES2 = \ lvtest.c \ percent.c \ pe_start.c \ thin_percent.c \ vgtest.c endif include $(top_builddir)/make.tmpl DEFS += -D_REENTRANT DEPLIBS += $(top_builddir)/liblvm/liblvm2app.so $(top_builddir)/libdm/libdevmapper.so LDFLAGS += -L$(top_builddir)/liblvm LVMLIBS = @LVM2APP_LIB@ -ldevmapper ifeq ("@DMEVENTD@", "yes") LVMLIBS += -ldevmapper-event LDFLAGS += -L$(top_builddir)/daemons/dmeventd endif LVMLIBS += $(LIBS) %.t: %.o $(DEPLIBS) $(CC) -o $@ $(<) $(LDFLAGS) $(LVMLIBS) test: $(OBJECTS) $(DEPLIBS) $(CC) -o $@ $(OBJECTS) $(LDFLAGS) $(LVMLIBS) $(READLINE_LIBS) Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status cd $(top_builddir) && $(SHELL) ./config.status test/api/Makefile lvm2-2.02.98/test/api/thin_percent.c0000640000175000017500000000300112037016272016060 0ustar blankblank/* * Copyright (C) 2012 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU Lesser General Public License v.2.1. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #undef NDEBUG #include "lvm2app.h" #include "assert.h" int main(int argc, char *argv[]) { lvm_t handle; vg_t vg; lv_t lv; struct lvm_property_value v; handle = lvm_init(NULL); assert(handle); vg = lvm_vg_open(handle, argv[1], "r", 0); assert(vg); lv = lvm_lv_from_name(vg, "pool"); assert(lv); v = lvm_lv_get_property(lv, "data_percent"); assert(v.is_valid); assert(v.value.integer == 25 * PERCENT_1); lv = lvm_lv_from_name(vg, "thin"); assert(lv); v = lvm_lv_get_property(lv, "data_percent"); assert(v.is_valid); assert(v.value.integer == 50 * PERCENT_1); lv = lvm_lv_from_name(vg, "snap"); assert(lv); v = lvm_lv_get_property(lv, "data_percent"); assert(v.is_valid); assert(v.value.integer == 75 * PERCENT_1); v = lvm_lv_get_property(lv, "snap_percent"); assert(v.is_valid); assert(v.value.integer == PERCENT_INVALID); v = lvm_lv_get_property(lv, "origin"); assert(v.is_valid); assert(strcmp(v.value.string, "thin") == 0); lvm_vg_close(vg); lvm_quit(handle); return 0; } lvm2-2.02.98/test/api/pe_start.c0000640000175000017500000000216012037016272015224 0ustar blankblank/* * Copyright (C) 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 */ #undef NDEBUG #include "lvm2app.h" #include "assert.h" int main(int argc, char *argv[]) { lvm_t handle; vg_t vg = NULL; pv_t pv; struct lvm_property_value v; handle = lvm_init(NULL); assert(handle); vg = lvm_vg_create(handle, argv[1]); assert(vg); if (lvm_vg_extend(vg, argv[2])) abort(); pv = lvm_pv_from_name(vg, argv[2]); assert(pv); v = lvm_pv_get_property(pv, "pe_start"); assert(v.is_valid); fprintf(stderr, "pe_start = %d\n", (int)v.value.integer); assert(v.value.integer == 2048 * 512); lvm_vg_close(vg); lvm_quit(handle); return 0; } lvm2-2.02.98/test/api/vgtest.sh0000640000175000017500000000106112037016272015106 0ustar blankblank#!/bin/sh # Copyright (C) 2008 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 # # tests lvm2app library # . lib/test aux prepare_pvs 2 aux apitest vgtest $vg1 "$dev1" "$dev2" lvm2-2.02.98/test/api/vgtest.c0000640000175000017500000000771112037016272014726 0ustar blankblank/* * 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 */ /* * Unit test case for vgcreate and related APIs. * # gcc -g vgcreate.c -I../../liblvm -I../../include -L../../liblvm \ * -L../../libdm -ldevmapper -llvm2app * # export LD_LIBRARY_PATH=`pwd`/../../libdm:`pwd`/../../liblvm */ #include #include #include #include "lvm2app.h" lvm_t handle; vg_t vg; const char *vg_name; #define MAX_DEVICES 16 const char *device[MAX_DEVICES]; uint64_t size = 1024; #define vg_create(vg_name) \ printf("Creating VG %s\n", vg_name); \ vg = lvm_vg_create(handle, vg_name); \ if (!vg) { \ fprintf(stderr, "Error creating volume group %s\n", vg_name); \ goto bad; \ } #define vg_extend(vg, dev) \ printf("Extending VG %s by %s\n", vg_name, dev); \ status = lvm_vg_extend(vg, dev); \ if (status) { \ fprintf(stderr, "Error extending volume group %s " \ "with device %s\n", vg_name, dev); \ goto bad; \ } #define vg_commit(vg) \ printf("Committing VG %s to disk\n", vg_name); \ status = lvm_vg_write(vg); \ if (status) { \ fprintf(stderr, "Commit of volume group '%s' failed\n", \ lvm_vg_get_name(vg)); \ goto bad; \ } #define vg_open(vg_name, mode) \ printf("Opening VG %s %s\n", vg_name, mode); \ vg = lvm_vg_open(handle, vg_name, mode, 0); \ if (!vg) { \ fprintf(stderr, "Error opening volume group %s\n", vg_name); \ goto bad; \ } #define vg_close(vg) \ printf("Closing VG %s\n", vg_name); \ if (lvm_vg_close(vg)) { \ fprintf(stderr, "Error closing volume group %s\n", vg_name); \ goto bad; \ } #define vg_reduce(vg, dev) \ printf("Reducing VG %s by %s\n", vg_name, dev); \ status = lvm_vg_reduce(vg, dev); \ if (status) { \ fprintf(stderr, "Error reducing volume group %s " \ "by device %s\n", vg_name, dev); \ goto bad; \ } #define vg_remove(vg) \ printf("Removing VG %s from system\n", vg_name); \ status = lvm_vg_remove(vg); \ if (status) { \ fprintf(stderr, "Revmoval of volume group '%s' failed\n", \ vg_name); \ goto bad; \ } static int init_vgtest(int argc, char *argv[]) { int i; if (argc < 4) { fprintf(stderr, "Usage: %s [... ]", argv[0]); return -1; } vg_name = argv[1]; for(i=2; i"$DM_DEV_DIR/testnull" || \ die "Filesystem does support devices in $DM_DEV_DIR (mounted with nodev?)" mkdir "$DM_DEV_DIR/mapper" fi export DM_DEV_DIR LVM_SYSTEM_DIR cd "$TESTDIR" echo "$TESTNAME" >TESTNAME # Setting up symlink from $i to $TESTDIR/lib find "$abs_top_builddir/daemons/dmeventd/plugins/" -name '*.so' \ -exec ln -s -t lib "{}" + find "$abs_top_builddir/test/lib" ! \( -name '*.sh' -o -name '*.[cdo]' \ -o -name '*~' \) -exec ln -s -t lib "{}" + # Set vars from utils now that we have TESTDIR/PREFIX/... prepare_test_vars test -n "$BASH" && set -eE -o pipefail aux lvmconf aux prepare_clvmd test -n "$LVM_TEST_LVMETAD" && { aux prepare_lvmetad export LVM_LVMETAD_SOCKET="$TESTDIR/lvmetad.socket" } echo "@TESTDIR=$TESTDIR" echo "@PREFIX=$PREFIX" set -vx lvm2-2.02.98/test/lib/utils.sh0000640000175000017500000001255412037016272014740 0ustar blankblank#!/bin/bash # Copyright (C) 2011-2012 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 set -e MAX_TRIES=4 IFS_NL=' ' die() { echo "$@" >&2 return 1 } rand_bytes() { n=$1 chars="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" dev_rand="/dev/urandom" if test -r "$dev_rand"; then # Note: 256-length($chars) == 194; 3 copies of $chars is 186 + 8 = 194. head -c"$n" "$dev_rand" | tr -c "$chars" "01234567$chars$chars$chars" return fi cmds='date; date +%N; free; who -a; w; ps auxww; ps ef; netstat -n' data=$( (eval "$cmds") 2>&1 | gzip ) n_plus_50=$(expr $n + 50) # Ensure that $data has length at least 50+$n while :; do len=$(echo "$data" | wc -c) test $n_plus_50 -le $len && break; data=$( (echo "$data"; eval "$cmds") 2>&1 | gzip ) done echo "$data" | dd bs=1 skip=50 count=$n 2>/dev/null \ | tr -c "$chars" "01234567$chars$chars$chars" } mkdtemp() { case $# in 2) ;; *) die "Usage: mkdtemp DIR TEMPLATE";; esac destdir=$1 template=$2 case "$template" in *XXXX) ;; *) die "Invalid template: $template (must have a suffix of at least 4 X's)";; esac fail=0 # First, try to use mktemp. d=$(env -u TMPDIR mktemp -d -t -p "$destdir" "$template" 2>/dev/null) || fail=1 # The resulting name must be in the specified directory. case "$d" in "${destdir}"*);; *) fail=1;; esac # It must have created the directory. test -d "$d" || fail=1 # It must have 0700 permissions. perms=$(ls -dgo "$d" 2>/dev/null) || fail=1 case "$perms" in drwx------*) ;; *) fail=1;; esac test $fail = 0 && { echo "$d"; return; } # If we reach this point, we'll have to create a directory manually. # Get a copy of the template without its suffix of X's. base_template=$(echo "$template" | sed 's/XX*$//') # Calculate how many X's we've just removed. nx=$(expr length "$template" - length "$base_template") err= i=1 while :; do X=$(rand_bytes "$nx") candidate_dir="$destdir/$base_template$X" err=$(mkdir -m 0700 "$candidate_dir" 2>&1) && \ { echo "$candidate_dir"; return; } test $MAX_TRIES -le $i && break; i=$(expr $i + 1) done die "$err" } STACKTRACE() { trap - ERR local i=0 echo "## - $0:${BASH_LINENO[0]}" while FUNC=${FUNCNAME[$i]}; test "$FUNC" != "main"; do echo "## $i ${FUNC}() called from ${BASH_SOURCE[$i]}:${BASH_LINENO[$i]}" i=$(($i + 1)) done test ${LVM_TEST_PARALLEL:-0} -eq 1 -o -n "$RUNNING_DMEVENTD" -o -f LOCAL_DMEVENTD || { pgrep dmeventd &>/dev/null && \ die "** During test dmeventd has been started!" } # Get backtraces from coredumps if which gdb &>/dev/null; then echo bt full > gdb_commands.txt echo l >> gdb_commands.txt echo quit >> gdb_commands.txt for core in $(ls core* 2>/dev/null); do bin=$(gdb -batch -c "$core" 2>&1 | grep "generated by" | \ sed -e "s,.*generated by \`\([^ ']*\).*,\1,") gdb -batch -c "$core" -x gdb_commands.txt $(which "$bin") done fi test -z "$LVM_TEST_NODEBUG" -a -f debug.log && { sed -e "s,^,## DEBUG: ,;s,$top_srcdir/\?,," < debug.log } test -f SKIP_THIS_TEST && exit 200 } init_udev_transaction() { if test "$DM_UDEV_SYNCHRONISATION" = 1; then local cookie=$(dmsetup udevcreatecookie) # Cookie is not generated if udev is not running! test -z "$cookie" || export DM_UDEV_COOKIE=$cookie fi } finish_udev_transaction() { if test "$DM_UDEV_SYNCHRONISATION" = 1 -a -n "$DM_UDEV_COOKIE"; then dmsetup udevreleasecookie unset DM_UDEV_COOKIE fi } teardown_udev_cookies() { if test "$DM_UDEV_SYNCHRONISATION" = 1; then # Delete any cookies created more than 10 minutes ago # and not used in the last 10 minutes. # Log only non-zero semaphores count (dmsetup udevcomplete_all -y 10 | grep -v "^0 ") || true fi } dm_info() { should dmsetup info --noheadings -c -o "$@" } dm_table() { should dmsetup table "$@" } skip() { touch SKIP_THIS_TEST exit 200 } kernel_at_least() { local major=$(uname -r | cut -d. -f1) local minor=$(uname -r | cut -d. -f2 | cut -d- -f1) test "$major" -gt "$1" && return 0 test "$major" -eq "$1" || return 1 test "$minor" -gt "$2" && return 0 test "$minor" -eq "$2" || return 1 test -z "$3" && return 0 local minor2=$(uname -r | cut -d. -f3 | cut -d- -f1) test -z "$minor2" -a "$3" -ne 0 && return 1 test "$minor2" -ge "$3" 2>/dev/null || return 1 } prepare_test_vars() { vg="${PREFIX}vg" lv=LV for i in $(seq 1 16); do name="${PREFIX}pv$i" dev="$DM_DEV_DIR/mapper/$name" eval "dev$i=\"$dev\"" eval "lv$i=LV$i" eval "vg$i=${PREFIX}vg$i" done } # check if $abs_top_builddir was already set via 'lib/paths' test -n "${abs_top_builddir+varset}" || . lib/paths || die "you must run make first" case "$PATH" in *"$abs_top_builddir/test/lib"*) ;; *) PATH="$abs_top_builddir/test/lib":$PATH for d in daemons/dmeventd/plugins/mirror daemons/dmeventd/plugins/snapshot \ daemons/dmeventd/plugins/lvm2 daemons/dmeventd liblvm tools libdm; do LD_LIBRARY_PATH="$abs_top_builddir/$d":$LD_LIBRARY_PATH done export PATH LD_LIBRARY_PATH ;; esac test -z "$PREFIX" || prepare_test_vars lvm2-2.02.98/test/lib/lvm-wrapper.sh0000640000175000017500000000202312037016272016042 0ustar blankblank#!/bin/sh # Copyright (C) 2011-2012 Red Hat, Inc. # # 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 . lib/paths CMD=${0##*/} test "$CMD" != lvm || unset CMD # Multiple level of LVM_VALGRIND support # the higher level the more commands are traced if test -n "$LVM_VALGRIND"; then RUN_VALGRIND="aux run_valgrind"; case "$CMD" in lvs|pvs|vgs|vgck|vgscan) test "$LVM_VALGRIND" -gt 2 || unset RUN_VALGRIND ;; pvcreate|pvremove|lvremove|vgcreate|vgremove) test "$LVM_VALGRIND" -gt 1 || unset RUN_VALGRIND ;; *) test "$LVM_VALGRIND" -gt 0 || unset RUN_VALGRIND ;; esac fi $RUN_VALGRIND "$abs_top_builddir/tools/lvm" $CMD "$@" && \ rm -f debug.log # Remove log for successful command lvm2-2.02.98/test/lib/not.c0000640000175000017500000000303312037016272014200 0ustar blankblank/* * 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 */ #include #include #include #include #include #include static int finished(const char *cmd, int status) { if (!strcmp(cmd, "not")) return !status; if (!strcmp(cmd, "should")) { if (status) fprintf(stderr, "TEST WARNING: Ignoring command failure.\n"); return 0; } return 6; } int main(int args, char **argv) { pid_t pid; int status; int FAILURE = 6; if (args < 2) { fprintf(stderr, "Need args\n"); return FAILURE; } pid = fork(); if (pid == -1) { fprintf(stderr, "Could not fork\n"); return FAILURE; } else if (pid == 0) { /* child */ execvp(argv[1], &argv[1]); /* should not be accessible */ return FAILURE; } else { /* parent */ waitpid(pid, &status, 0); if (!WIFEXITED(status)) { if (WIFSIGNALED(status)) fprintf(stderr, "Process %d died of signal %d.\n", pid, WTERMSIG(status)); /* did not exit correctly */ return FAILURE; } return finished(argv[0], WEXITSTATUS(status)); } /* not accessible */ return FAILURE; } lvm2-2.02.98/test/lib/aux.sh0000640000175000017500000003346612037016272014402 0ustar blankblank#!/bin/bash # Copyright (C) 2011-2012 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 . lib/utils run_valgrind() { # Execute script which may use $TESTNAME for creating individual # log files for each execute command exec "${VALGRIND:-valg}" "$@" } expect_failure() { echo "TEST EXPECT FAILURE" } prepare_clvmd() { test "${LVM_TEST_LOCKING:-0}" -ne 3 && return # not needed if pgrep clvmd ; then echo "Cannot use fake cluster locking with real clvmd ($(pgrep clvmd)) running." skip fi # skip if we don't have our own clvmd... (which clvmd 2>/dev/null | grep "$abs_builddir") || skip # skip if we singlenode is not compiled in (clvmd --help 2>&1 | grep "Available cluster managers" | grep "singlenode") || skip # lvmconf "activation/monitoring = 1" local run_valgrind= test -z "$LVM_VALGRIND_CLVMD" || run_valgrind="run_valgrind" $run_valgrind lib/clvmd -Isinglenode -d 1 -f & local local_clvmd=$! sleep .3 # extra sleep for slow valgrind test -z "$LVM_VALGRIND_CLVMD" || sleep 7 # check that it is really running now ps $local_clvmd || die echo $local_clvmd > LOCAL_CLVMD } prepare_dmeventd() { if pgrep dmeventd ; then echo "Cannot test dmeventd with real dmeventd ($(pgrep dmeventd)) running." skip fi # skip if we don't have our own dmeventd... (which dmeventd 2>/dev/null | grep "$abs_builddir") || skip lvmconf "activation/monitoring = 1" dmeventd -f "$@" & echo $! > LOCAL_DMEVENTD # FIXME wait for pipe in /var/run instead sleep .3 } prepare_lvmetad() { # skip if we don't have our own lvmetad... (which lvmetad 2>/dev/null | grep "$abs_builddir") || skip lvmconf "global/use_lvmetad = 1" lvmconf "devices/md_component_detection = 0" local run_valgrind= test -z "$LVM_VALGRIND_LVMETAD" || run_valgrind="run_valgrind" echo "preparing lvmetad..." $run_valgrind lvmetad -f "$@" -s "$TESTDIR/lvmetad.socket" -l wire,debug & echo $! > LOCAL_LVMETAD while ! test -e "$TESTDIR/lvmetad.socket"; do echo -n .; sleep .1; done # wait for the socket echo ok } notify_lvmetad() { if test -e LOCAL_LVMETAD; then pvscan --cache "$@" || true fi } teardown_devs_prefixed() { local prefix=$1 local stray=${2:-0} local IFS=$IFS_NL local dm # Resume suspended devices first for dm in $(dm_info suspended,name | grep "^Suspended:.*$prefix"); do echo "dmsetup resume \"${dm#Suspended:}\"" dmsetup resume "${dm#Suspended:}" || true done local mounts=( $(grep "$prefix" /proc/mounts | cut -d' ' -f1) ) if test ${#mounts[@]} -gt 0; then test "$stray" -eq 0 || echo "Removing stray mounted devices containing $prefix: ${mounts[@]}" if umount -fl "${mounts[@]}"; then udev_wait fi fi # Remove devices, start with closed (sorted by open count) local remfail=no local need_udev_wait=0 init_udev_transaction for dm in $(dm_info name --sort open | grep "$prefix"); do dmsetup remove "$dm" &>/dev/null || remfail=yes need_udev_wait=1 done finish_udev_transaction test $need_udev_wait -eq 0 || udev_wait if test $remfail = yes; then local num_devs local num_remaining_devs=999 while num_devs=$(dm_table | grep "$prefix" | wc -l) && \ test $num_devs -lt $num_remaining_devs -a $num_devs -ne 0; do test "$stray" -eq 0 || echo "Removing $num_devs stray mapped devices with names beginning with $prefix: " for dm in $(dm_info name --sort open | grep "$prefix") ; do dmsetup remove -f "$dm" || true done num_remaining_devs=$num_devs done fi } teardown_devs() { # Delete any remaining dm/udev semaphores teardown_udev_cookies test -z "$PREFIX" || { rm -rf "$TESTDIR/dev/$PREFIX"* teardown_devs_prefixed "$PREFIX" } # NOTE: SCSI_DEBUG_DEV test must come before the LOOP test because # prepare_scsi_debug_dev() also sets LOOP to short-circuit prepare_loop() if test -f SCSI_DEBUG_DEV; then test ${LVM_TEST_PARALLEL:-0} -eq 1 || modprobe -r scsi_debug else test ! -f LOOP || losetup -d $(cat LOOP) || true test ! -f LOOPFILE || rm -f $(cat LOOPFILE) fi rm -f DEVICES # devs is set in prepare_devs() rm -f LOOP # Attempt to remove any loop devices that failed to get torn down if earlier tests aborted test ${LVM_TEST_PARALLEL:-0} -eq 1 -o -z "$COMMON_PREFIX" || { teardown_devs_prefixed "$COMMON_PREFIX" 1 local stray_loops=( $(losetup -a | grep "$COMMON_PREFIX" | cut -d: -f1) ) test ${#stray_loops[@]} -eq 0 || { echo "Removing stray loop devices containing $COMMON_PREFIX: ${stray_loops[@]}" losetup -d "${stray_loops[@]}" } } } teardown() { echo -n "## teardown..." test ! -s LOCAL_LVMETAD || \ (kill -TERM "$(cat LOCAL_LVMETAD)" && sleep 1 && kill -KILL "$(cat LOCAL_LVMETAD)" 2> /dev/null) || true dm_table | not egrep -q "$vg|$vg1|$vg2|$vg3|$vg4" || { # Avoid activation of dmeventd if there is no pid cfg=$(test -s LOCAL_DMEVENTD || echo "--config activation{monitoring=0}") vgremove -ff $cfg \ $vg $vg1 $vg2 $vg3 $vg4 &>/dev/null || rm -f debug.log } test -s LOCAL_CLVMD && { kill -INT "$(cat LOCAL_CLVMD)" test -z "$LVM_VALGRIND_CLVMD" || sleep 1 sleep .1 kill -9 "$(cat LOCAL_CLVMD)" &>/dev/null || true } echo -n . pgrep dmeventd || true test ! -s LOCAL_DMEVENTD || kill -9 "$(cat LOCAL_DMEVENTD)" || true echo -n . test -d "$DM_DEV_DIR/mapper" && teardown_devs echo -n . test -n "$TESTDIR" && { cd "$TESTOLDPWD" rm -rf "$TESTDIR" || echo BLA } echo "ok" test ${LVM_TEST_PARALLEL:-0} -eq 1 -o -n "$RUNNING_DMEVENTD" || not pgrep dmeventd #&>/dev/null } make_ioerror() { echo 0 10000000 error | dmsetup create -u ${PREFIX}-ioerror ioerror ln -s "$DM_DEV_DIR/mapper/ioerror" "$DM_DEV_DIR/ioerror" } prepare_loop() { local size=${1=32} local i local slash test -f LOOP && LOOP=$(cat LOOP) echo -n "## preparing loop device..." # skip if prepare_scsi_debug_dev() was used if test -f SCSI_DEBUG_DEV -a -f LOOP ; then echo "(skipped)" return 0 fi test ! -e LOOP test -n "$DM_DEV_DIR" for i in 0 1 2 3 4 5 6 7; do test -e "$DM_DEV_DIR/loop$i" || mknod "$DM_DEV_DIR/loop$i" b 7 $i done echo -n . local LOOPFILE="$PWD/test.img" dd if=/dev/zero of="$LOOPFILE" bs=$((1024*1024)) count=0 seek=$(($size-1)) 2> /dev/null if LOOP=$(losetup -s -f "$LOOPFILE" 2>/dev/null); then : elif LOOP=$(losetup -f) && losetup "$LOOP" "$LOOPFILE"; then # no -s support : else # no -f support # Iterate through $DM_DEV_DIR/loop{,/}{0,1,2,3,4,5,6,7} for slash in '' /; do for i in 0 1 2 3 4 5 6 7; do local dev="$DM_DEV_DIR/loop$slash$i" ! losetup "$dev" >/dev/null 2>&1 || continue # got a free losetup "$dev" "$LOOPFILE" LOOP=$dev break done test -z "$LOOP" || break done fi test -n "$LOOP" # confirm or fail echo "$LOOP" > LOOP echo "ok ($LOOP)" } # A drop-in replacement for prepare_loop() that uses scsi_debug to create # a ramdisk-based SCSI device upon which all LVM devices will be created # - scripts must take care not to use a DEV_SIZE that will enduce OOM-killer prepare_scsi_debug_dev() { local DEV_SIZE=$1 local SCSI_DEBUG_PARAMS=${@:2} test -f "SCSI_DEBUG_DEV" && return 0 test -z "$LOOP" test -n "$DM_DEV_DIR" # Skip test if awk isn't available (required for get_sd_devs_) which awk || skip # Skip test if scsi_debug module is unavailable or is already in use modprobe --dry-run scsi_debug || skip lsmod | grep -q scsi_debug && skip # Create the scsi_debug device and determine the new scsi device's name # NOTE: it will _never_ make sense to pass num_tgts param; # last param wins.. so num_tgts=1 is imposed modprobe scsi_debug dev_size_mb=$DEV_SIZE $SCSI_DEBUG_PARAMS num_tgts=1 || skip sleep 2 # allow for async Linux SCSI device registration local DEBUG_DEV="/dev/$(grep -H scsi_debug /sys/block/*/device/model | cut -f4 -d /)" test -b "$DEBUG_DEV" || return 1 # should not happen # Create symlink to scsi_debug device in $DM_DEV_DIR SCSI_DEBUG_DEV="$DM_DEV_DIR/$(basename $DEBUG_DEV)" echo "$SCSI_DEBUG_DEV" > SCSI_DEBUG_DEV echo "$SCSI_DEBUG_DEV" > LOOP # Setting $LOOP provides means for prepare_devs() override test "$LVM_TEST_DEVDIR" != "/dev" && ln -snf "$DEBUG_DEV" "$SCSI_DEBUG_DEV" } cleanup_scsi_debug_dev() { teardown_devs rm -f SCSI_DEBUG_DEV LOOP } prepare_devs() { local n=${1:-3} local devsize=${2:-34} local pvname=${3:-pv} local loopsz prepare_loop $(($n*$devsize)) echo -n "## preparing $n devices..." if ! loopsz=$(blockdev --getsz "$LOOP" 2>/dev/null); then loopsz=$(blockdev --getsize "$LOOP" 2>/dev/null) fi local size=$(($loopsz/$n)) devs= init_udev_transaction for i in $(seq 1 $n); do local name="${PREFIX}$pvname$i" local dev="$DM_DEV_DIR/mapper/$name" devs="$devs $dev" echo 0 $size linear "$LOOP" $((($i-1)*$size)) > "$name.table" dmsetup create -u "TEST-$name" "$name" "$name.table" done finish_udev_transaction #for i in `seq 1 $n`; do # local name="${PREFIX}$pvname$i" # dmsetup info -c $name #done #for i in `seq 1 $n`; do # local name="${PREFIX}$pvname$i" # dmsetup table $name #done echo $devs > DEVICES echo "ok" } disable_dev() { local dev init_udev_transaction for dev in "$@"; do maj=$(($(stat --printf=0x%t "$dev"))) min=$(($(stat --printf=0x%T "$dev"))) echo "Disabling device $dev ($maj:$min)" dmsetup remove -f "$dev" || true notify_lvmetad --major "$maj" --minor "$min" done finish_udev_transaction } enable_dev() { local dev init_udev_transaction for dev in "$@"; do local name=$(echo "$dev" | sed -e 's,.*/,,') dmsetup create -u "TEST-$name" "$name" "$name.table" || \ dmsetup load "$name" "$name.table" # using device name (since device path does not exists yes with udev) dmsetup resume "$name" notify_lvmetad "$dev" done finish_udev_transaction } backup_dev() { local dev for dev in "$@"; do dd if="$dev" of="$dev.backup" bs=1024 done } restore_dev() { local dev for dev in "$@"; do test -e "$dev.backup" || \ die "Internal error: $dev not backed up, can't restore!" dd of="$dev" if="$dev.backup" bs=1024 done } prepare_pvs() { prepare_devs "$@" pvcreate -ff $devs } prepare_vg() { teardown_devs prepare_pvs "$@" vgcreate -c n $vg $devs } lvmconf() { LVM_TEST_LOCKING=${LVM_TEST_LOCKING:-1} if test "$DM_DEV_DIR" = "/dev"; then LVM_VERIFY_UDEV=${LVM_VERIFY_UDEV:-0} else LVM_VERIFY_UDEV=${LVM_VERIFY_UDEV:-1} fi test -f CONFIG_VALUES || { cat > CONFIG_VALUES <<-EOF devices/dir = "$DM_DEV_DIR" devices/scan = "$DM_DEV_DIR" devices/filter = [ "a|$DM_DEV_DIR/mirror|", "a|$DM_DEV_DIR/mapper/.*pv[0-9_]*$|", "r|.*|" ] devices/cache_dir = "$TESTDIR/etc" devices/sysfs_scan = 0 devices/default_data_alignment = 1 devices/md_component_detection = 0 log/syslog = 0 log/indent = 1 log/level = 9 log/file = "$TESTDIR/debug.log" log/overwrite = 1 log/activation = 1 log/verbose = 0 activation/retry_deactivation = 1 backup/backup = 0 backup/archive = 0 global/abort_on_internal_errors = 1 global/detect_internal_vg_cache_corruption = 1 global/library_dir = "$TESTDIR/lib" global/locking_dir = "$TESTDIR/var/lock/lvm" global/locking_type=$LVM_TEST_LOCKING global/si_unit_consistency = 1 global/fallback_to_local_locking = 0 activation/checks = 1 activation/udev_sync = 1 activation/udev_rules = 1 activation/verify_udev_operations = $LVM_VERIFY_UDEV activation/polling_interval = 0 activation/snapshot_autoextend_percent = 50 activation/snapshot_autoextend_threshold = 50 activation/monitoring = 0 EOF } local v for v in "$@"; do echo "$v" >> CONFIG_VALUES done rm -f CONFIG local s for s in $(cat CONFIG_VALUES | cut -f1 -d/ | sort | uniq); do echo "$s {" >> CONFIG local k for k in $(grep ^"$s"/ CONFIG_VALUES | cut -f1 -d= | sed -e 's, *$,,' | sort | uniq); do grep "^$k" CONFIG_VALUES | tail -n 1 | sed -e "s,^$s/, ," >> CONFIG done echo "}" >> CONFIG echo >> CONFIG done mv -f CONFIG etc/lvm.conf } apitest() { local t=$1 shift test -x "$abs_top_builddir/test/api/$t.t" || skip "$abs_top_builddir/test/api/$t.t" "$@" && rm -f debug.log } api() { test -x "$abs_top_builddir/test/api/wrapper" || skip "$abs_top_builddir/test/api/wrapper" "$@" && rm -f debug.log } udev_wait() { pgrep udev >/dev/null || return 0 which udevadm >/dev/null || return 0 if test -n "$1" ; then udevadm settle --exit-if-exists="$1" || true else udevadm settle --timeout=15 || true fi } # wait_for_sync wait_for_sync() { local i for i in {1..500} ; do check in_sync $1 $2 && return sleep .2 done echo "Sync is taking too long - assume stuck" return 1 } # # Check wheter kernel [dm module] target exist # at least in expected version # # [dm-]target-name major minor revision # # i.e. dm_target_at_least dm-thin-pool 1 0 target_at_least() { case "$1" in dm-*) modprobe "$1" || true ;; esac local version=$(dmsetup targets 2>/dev/null | grep "${1##dm-} " 2>/dev/null) version=${version##* v} shift local major=$(echo "$version" | cut -d. -f1) test -z "$1" && return 0 test -n "$major" || return 1 test "$major" -gt "$1" && return 0 test "$major" -eq "$1" || return 1 test -z "$2" && return 0 local minor=$(echo "$version" | cut -d. -f2) test -n "$minor" || return 1 test "$minor" -gt "$2" && return 0 test "$minor" -eq "$2" || return 1 test -z "$3" && return 0 local revision=$(echo "$version" | cut -d. -f3) test "$revision" -ge "$3" 2>/dev/null || return 1 } have_thin() { target_at_least dm-thin-pool "$@" || exit 1 test "$THIN" = shared || test "$THIN" = internal || exit 1 # disable thin_check if not present in system which thin_check || lvmconf 'global/thin_check_executable = ""' } # check if lvm shell is build-in (needs readline) have_readline() { echo version | lvm &>/dev/null } test -f DEVICES && devs=$(cat DEVICES) #unset LVM_VALGRIND "$@" lvm2-2.02.98/test/lib/harness.c0000640000175000017500000002020312037016272015041 0ustar blankblank/* * Copyright (C) 2010-2012 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU General Public License v.2. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include static pid_t pid; static int fds[2]; #define MAX 1024 struct stats { int nfailed; int nskipped; int npassed; int nknownfail; int nwarned; int status[MAX]; }; static struct stats s; static char *readbuf = NULL; static int readbuf_sz = 0, readbuf_used = 0; static int die = 0; static int verbose = 0; /* >1 with timestamps */ static int interactive = 0; /* disable all redirections */ struct subst { const char *key; char *value; }; static struct subst subst[2]; #define PASSED 0 #define SKIPPED 1 #define FAILED 2 #define WARNED 3 #define KNOWNFAIL 4 static void handler( int sig ) { signal( sig, SIG_DFL ); kill( pid, sig ); die = sig; } static int outline(char *buf, int start, int force) { char *from = buf + start; char *next = strchr(buf + start, '\n'); if (!next && !force) /* not a complete line yet... */ return start; if (!next) next = from + strlen(from); else ++next; if (!strncmp(from, "@TESTDIR=", 9)) { subst[0].key = "@TESTDIR@"; subst[0].value = strndup(from + 9, next - from - 9 - 1); } else if (!strncmp(from, "@PREFIX=", 8)) { subst[1].key = "@PREFIX@"; subst[1].value = strndup(from + 8, next - from - 8 - 1); } else { char *line = strndup(from, next - from); char *a = line, *b; do { int idx = -1; int i; b = line + strlen(line); for ( i = 0; i < 2; ++i ) { if (subst[i].key) { // printf("trying: %s -> %s\n", subst[i].value, subst[i].key); char *stop = strstr(a, subst[i].value); if (stop && stop < b) { idx = i; b = stop; } } } fwrite(a, 1, b - a, stdout); a = b; if ( idx >= 0 ) { fprintf(stdout, "%s", subst[idx].key); a += strlen(subst[idx].value); } } while (b < line + strlen(line)); free(line); } return next - buf + (force ? 0 : 1); } static void dump(void) { int counter_last = -1, counter = 0; while ( counter < readbuf_used && counter != counter_last ) { counter_last = counter; counter = outline( readbuf, counter, 1 ); } } static void trickle(void) { static int counter_last = -1, counter = 0; if (counter_last > readbuf_used) { counter_last = -1; counter = 0; } while ( counter < readbuf_used && counter != counter_last ) { counter_last = counter; counter = outline( readbuf, counter, 1 ); } } static void clear(void) { readbuf_used = 0; } static int64_t _get_time_us(void) { struct timeval tv; (void) gettimeofday(&tv, 0); return (int64_t) tv.tv_sec * 1000000 + (int64_t) tv.tv_usec; } static void _append_buf(const char *buf, size_t len) { if ((readbuf_used + len) >= readbuf_sz) { readbuf_sz = readbuf_sz ? 2 * readbuf_sz : 4096; readbuf = realloc(readbuf, readbuf_sz); } if (!readbuf) exit(205); memcpy(readbuf + readbuf_used, buf, len); readbuf_used += len; } static const char *_append_with_stamp(const char *buf, int stamp) { static const char spaces[] = " "; static int64_t t_last; static int64_t t_start = 0; int64_t t_now; char stamp_buf[32]; /* Bigger to always fit both numbers */ const char *be; const char *bb = buf; size_t len; while ((be = strchr(bb, '\n'))) { if (stamp++ == 0) { t_now = _get_time_us(); if (!t_start) t_start = t_last = t_now; len = snprintf(stamp_buf, sizeof(stamp_buf), "%8.3f%8.4f ", (t_now - t_start) / 1000000.f, (t_now - t_last) / 1000000.f); _append_buf(stamp_buf, (len < (sizeof(spaces) - 1)) ? len : (sizeof(spaces) - 1)); t_last = t_now; } _append_buf(bb, be + 1 - bb); bb = be + 1; if (stamp > 0 && bb[0]) _append_buf(spaces, sizeof(spaces) - 1); } return bb; } static void drain(void) { char buf[4096]; const char *bp; int stamp = 0; int sz; while ((sz = read(fds[1], buf, sizeof(buf) - 1)) > 0) { buf[sz] = '\0'; bp = (verbose < 2) ? buf : _append_with_stamp(buf, stamp); if (sz > (bp - buf)) { _append_buf(bp, sz - (bp - buf)); stamp = -1; /* unfinished line */ } else stamp = 0; readbuf[readbuf_used] = 0; if (verbose) trickle(); } } static const char *duration(time_t start) { static char buf[16]; int t = (int)(time(NULL) - start); sprintf(buf, "%2d:%02d", t / 60, t % 60); return buf; } static void passed(int i, char *f, time_t t) { if (readbuf && strstr(readbuf, "TEST EXPECT FAIL")) { ++ s.npassed; s.status[i] = PASSED; printf("passed (UNEXPECTED). %s\n", duration(t)); } else if (readbuf && strstr(readbuf, "TEST WARNING")) { ++s.nwarned; s.status[i] = WARNED; printf("warnings %s\n", duration(t)); } else { ++ s.npassed; s.status[i] = PASSED; printf("passed. %s\n", duration(t)); } } static void skipped(int i, char *f) { ++ s.nskipped; s.status[i] = SKIPPED; printf("skipped.\n"); } static void failed(int i, char *f, int st) { if (readbuf && strstr(readbuf, "TEST EXPECT FAIL")) { printf("FAILED (expected).\n"); s.status[i] = KNOWNFAIL; ++ s.nknownfail; return; } ++ s.nfailed; s.status[i] = FAILED; if(die == 2) { printf("interrupted.\n"); return; } printf("FAILED.\n"); if (!verbose) { printf("-- FAILED %s ------------------------------------\n", f); dump(); printf("-- FAILED %s (end) ------------------------------\n", f); } } static void run(int i, char *f) { pid = fork(); if (pid < 0) { perror("Fork failed."); exit(201); } else if (pid == 0) { if (!interactive) { close(0); dup2(fds[0], 1); dup2(fds[0], 2); close(fds[0]); close(fds[1]); } execlp("bash", "bash", f, NULL); perror("execlp"); fflush(stderr); _exit(202); } else { int st, w; time_t start = time(NULL); char buf[128]; snprintf(buf, 128, "%s ...", f); buf[127] = 0; printf("Running %-50s ", buf); fflush(stdout); while ((w = waitpid(pid, &st, WNOHANG)) == 0) { drain(); usleep(20000); } if (w != pid) { perror("waitpid"); exit(206); } drain(); if (WIFEXITED(st)) { if (WEXITSTATUS(st) == 0) { passed(i, f, start); } else if (WEXITSTATUS(st) == 200) { skipped(i, f); } else { failed(i, f, st); } } else { failed(i, f, st); } clear(); } } int main(int argc, char **argv) { const char *be_verbose = getenv("VERBOSE"), *be_interactive = getenv("INTERACTIVE"); time_t start = time(NULL); int i; if (argc >= MAX) { fprintf(stderr, "Sorry, my head exploded. Please increase MAX.\n"); exit(1); } if (be_verbose) verbose = atoi(be_verbose); if (be_interactive) interactive = atoi(be_interactive); if (socketpair(PF_UNIX, SOCK_STREAM, 0, fds)) { perror("socketpair"); return 201; } if ( fcntl( fds[1], F_SETFL, O_NONBLOCK ) == -1 ) { perror("fcntl on socket"); return 202; } /* set up signal handlers */ for (i = 0; i <= 32; ++i) { if (i == SIGCHLD || i == SIGWINCH || i == SIGURG) continue; signal(i, handler); } /* run the tests */ for (i = 1; i < argc; ++ i) { run(i, argv[i]); if (die) break; } printf("\n## %d tests %s : %d OK, %d warnings, %d failures, %d known failures; %d skipped\n", s.nwarned + s.npassed + s.nfailed + s.nskipped, duration(start), s.npassed, s.nwarned, s.nfailed, s.nknownfail, s.nskipped); /* print out a summary */ if (s.nfailed || s.nskipped || s.nknownfail) { for (i = 1; i < argc; ++ i) { switch (s.status[i]) { case FAILED: printf("FAILED: %s\n", argv[i]); break; case KNOWNFAIL: printf("FAILED (expected): %s\n", argv[i]); break; case SKIPPED: printf("skipped: %s\n", argv[i]); break; } } printf("\n"); return s.nfailed > 0 || die; } free(readbuf); return die; } lvm2-2.02.98/test/lib/check.sh0000640000175000017500000001444612037016272014657 0ustar blankblank#!/bin/bash # Copyright (C) 2010-2012 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 # check.sh: assert various things about volumes # USAGE: # check linear VG LV # check lv_on VG LV PV # check mirror VG LV [LOGDEV|core] # check mirror_nonredundant VG LV # check mirror_legs VG LV N # check mirror_images_on VG LV DEV [DEV...] # ... test -z "$BASH" || set -e -o pipefail die() { echo "$@" >&2 return 1 } lvl() { lvs -a --noheadings "$@" } lvdevices() { get lv_devices "$@" } mirror_images_redundant() { local vg=$1 local lv=$vg/$2 lvs -a $vg -o+devices for i in $(lvdevices $lv); do echo "# $i:" lvdevices $vg/$i | sort | uniq done > check.tmp.all (grep -v ^# check.tmp.all || true) | sort | uniq -d > check.tmp test $(cat check.tmp | wc -l) -eq 0 || \ die "mirror images of $lv expected redundant, but are not:" \ $(cat check.tmp.all) } lv_on() { local lv=$1/$2 (lvdevices $lv | grep -F "$3") || \ die "LV $lv expected on $3 but is not:" \ $(lvdevices $lv) test $(lvdevices $lv | grep -vF "$3" | wc -l) -eq 0 || \ die "LV $lv contains unexpected devices:" \ $(lvdevices $lv) } mirror_images_on() { local vg=$1 local lv=$2 shift 2 for i in $(lvdevices $lv); do lv_on $vg $lv $1 shift done } mirror_log_on() { local vg=$1 local lv=$2 local where=$3 if test "$where" = "core"; then get lv_field $vg/$lv mirror_log | not grep mlog else lv_on $vg ${lv}_mlog "$where" fi } lv_is_contiguous() { local lv=$1/$2 test $(lvl --segments $lv | wc -l) -eq 1 || \ die "LV $lv expected to be contiguous, but is not:" \ $(lvl --segments $lv) } lv_is_clung() { local lv=$1/$2 test $(lvdevices $lv | sort | uniq | wc -l) -eq 1 || \ die "LV $lv expected to be clung, but is not:" \ $(lvdevices $lv | sort | uniq) } mirror_images_contiguous() { for i in $(lvdevices $1/$2); do lv_is_contiguous $1 $i done } mirror_images_clung() { for i in $(lvdevices $1/$2); do lv_is_clung $1 $i done } mirror() { mirror_nonredundant "$@" mirror_images_redundant $1 $2 } mirror_nonredundant() { local lv=$1/$2 local attr=$(get lv_field $lv attr) (echo "$attr" | grep "^m........$" >/dev/null) || { if (echo "$attr" | grep "^o........$" >/dev/null) && lvs -a | fgrep "[${2}_mimage" >/dev/null; then echo "TEST WARNING: $lv is a snapshot origin and looks like a mirror," echo "assuming it is actually a mirror" else die "$lv expected a mirror, but is not:" \ $(lvs $lv) fi } test -z "$3" || mirror_log_on $1 $2 "$3" } mirror_legs() { local expect=$3 test "$expect" -eq $(lvdevices $1/$2 | wc -w) } mirror_no_temporaries() { local vg=$1 local lv=$2 (lvl -o name $vg | grep $lv | not grep "tmp") || \ die "$lv has temporary mirror images unexpectedly:" \ $(lvl $vg | grep $lv) } linear() { local lv=$1/$2 test $(get lv_field $lv stripes -a) -eq 1 || \ die "$lv expected linear, but is not:" \ $(lvl $lv -o+devices) } # in_sync # Works for "mirror" and "raid*" in_sync() { local a local b local idx local type local lvm_name="$1/$2" local dm_name=$(echo $lvm_name | sed s:-:--: | sed s:/:-:) if ! a=(`dmsetup status $dm_name`); then die "Unable to get sync status of $1" elif [ ${a[2]} = "snapshot-origin" ]; then if ! a=(`dmsetup status ${dm_name}-real`); then die "Unable to get sync status of $1" fi fi if [ ${a[2]} = "raid" ]; then # Last argument is the sync ratio for RAID idx=$((${#a[@]} - 1)) type=${a[3]} elif [ ${a[2]} = "mirror" ]; then # 4th Arg tells us how far to the sync ratio idx=$((${a[3]} + 4)) type=${a[2]} else die "Unable to get sync ratio for target type '${a[2]}'" fi b=( $(echo ${a[$idx]} | sed s:/:' ':) ) if [ ${b[0]} != ${b[1]} ]; then echo "$lvm_name ($type) is not in-sync" return 1 fi if [[ ${a[$(($idx - 1))]} =~ a ]]; then die "$lvm_name in-sync, but 'a' characters in health status" fi echo "$lvm_name ($type) is in-sync" return 0 } active() { local lv=$1/$2 (get lv_field $lv attr | grep "^....a....$" >/dev/null) || \ die "$lv expected active, but lvs says it's not:" \ $(lvl $lv -o+devices) dmsetup info $1-$2 >/dev/null || die "$lv expected active, lvs thinks it is but there are no mappings!" } inactive() { local lv=$1/$2 (get lv_field $lv attr | grep "^....[-isd]....$" >/dev/null) || \ die "$lv expected inactive, but lvs says it's not:" \ $(lvl $lv -o+devices) not dmsetup info $1-$2 2>/dev/null || \ die "$lv expected inactive, lvs thinks it is but there are mappings!" } # Check for list of LVs from given VG lv_exists() { local vg=$1 local lv= while [ $# -gt 1 ]; do shift lv="$lv $vg/$1" done lvl $lv &>/dev/null || \ die "$lv expected to exist but does not" } pv_field() { local actual=$(get pv_field "$1" "$2" "${@:4}") test "$actual" = "$3" || \ die "pv_field: PV=\"$1\", field=\"$2\", actual=\"$actual\", expected=\"$3\"" } vg_field() { local actual=$(get vg_field $1 "$2" "${@:4}") test "$actual" = "$3" || \ die "vg_field: vg=$1, field=\"$2\", actual=\"$actual\", expected=\"$3\"" } lv_field() { local actual=$(get lv_field $1 "$2" "${@:4}") test "$actual" = "$3" || \ die "lv_field: lv=$lv, field=\"$2\", actual=\"$actual\", expected=\"$3\"" } compare_fields() { local cmd1=$1 local obj1=$2 local field1=$3 local cmd2=$4 local obj2=$5 local field2=$6 local val1=$($cmd1 --noheadings -o "$field1" "$obj1") local val2=$($cmd2 --noheadings -o "$field2" "$obj2") test "$val1" = "$val2" || \ die "compare_fields $obj1($field1): $val1 $obj2($field2): $val2" } compare_vg_field() { local vg1=$1 local vg2=$2 local field=$3 local val1=$(vgs --noheadings -o "$field" $vg1) local val2=$(vgs --noheadings -o "$field" $vg2) test "$val1" = "$val2" || \ die "compare_vg_field: $vg1: $val1, $vg2: $val2" } pvlv_counts() { local local_vg=$1 local num_pvs=$2 local num_lvs=$3 local num_snaps=$4 lvs -o+devices $local_vg vg_field $local_vg pv_count $num_pvs vg_field $local_vg lv_count $num_lvs vg_field $local_vg snap_count $num_snaps } unset LVM_VALGRIND "$@" lvm2-2.02.98/test/Makefile.in0000640000175000017500000001105412037016272014535 0ustar blankblank# Copyright (C) 2007-2012 Red Hat, Inc. All rights reserved. # # This file is part of LVM2. # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions # of the GNU General Public License v.2. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation, # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #TEST_OPTS=--verbose --debug SHELL_PATH ?= $(SHELL) RM ?= rm -f subdir = $(shell pwd|sed 's,.*/,,') srcdir = @srcdir@ top_srcdir = @top_srcdir@ top_builddir = @top_builddir@ abs_srcdir = "@abs_srcdir@" abs_builddir = "@abs_builddir@" abs_top_builddir = "@abs_top_builddir@" abs_top_srcdir = "@abs_top_srcdir@" SUBDIRS = api unit SOURCES = lib/not.c lib/harness.c include $(top_builddir)/make.tmpl T ?= . S ?= @ # never match anything by default VERBOSE ?= 0 ALL = $(shell find $(srcdir) \( -path \*/shell/\*.sh -or -path \*/api/\*.sh \) | sort) RUN = $(shell find $(srcdir) -regextype posix-egrep \( -path \*/shell/\*.sh -or -path \*/api/\*.sh \) -and -regex "$(srcdir)/.*($(T)).*" -and -not -regex "$(srcdir)/.*($(S)).*" | sort) RUN_BASE = $(subst $(srcdir)/,,$(RUN)) # Shell quote; SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) ifeq ("@UDEV_SYNC@", "yes") dm_udev_synchronisation = 1 endif all: check help: @echo -e "\nAvailable targets:" @echo " all Default target, run check." @echo " check Run all tests." @echo " check_local Run tests without clvmd and lvmetad." @echo " check_cluster Run tests with cluster daemon." @echo " check_lvmetad Run tests with lvmetad daemon." @echo " clean Clean dir." @echo " help Display callable targets." @echo -e "\nSupported variables:" @echo " LVM_TEST_DEVDIR Set to '/dev' to run on real /dev." @echo " LVM_TEST_DIR Where to create test files [TMPDIR]." @echo " LVM_TEST_LOCKING Normal (1), Cluster (3)." @echo " LVM_TEST_LVMETAD Start lvmetad (1)." @echo " LVM_TEST_NODEBUG Do not debug lvm commands." @echo " LVM_TEST_PARALLEL May skip agresive wipe of LVMTEST resources." @echo " LVM_VERIFY_UDEV Default verify state for lvm.conf." @echo " S Skip given test (regex)." @echo " T Run given test (regex)." @echo " VERBOSE Verbose output (1), timing (2)." check: check_local check_cluster check_lvmetad check_cluster: .tests-stamp @echo Testing with locking_type 3 VERBOSE=$(VERBOSE) LVM_TEST_LOCKING=3 ./lib/harness $(RUN_BASE) check_local: .tests-stamp @echo Testing with locking_type 1 VERBOSE=$(VERBOSE) LVM_TEST_LOCKING=1 ./lib/harness $(RUN_BASE) check_lvmetad: .tests-stamp @echo Testing with lvmetad on VERBOSE=$(VERBOSE) LVM_TEST_LVMETAD=1 ./lib/harness $(RUN_BASE) lib/should: lib/not ln -sf not lib/should lib/%: lib/%.o .lib-dir-stamp $(CC) $(LDFLAGS) -o $@ $< lib/%: $(srcdir)/lib/%.sh .lib-dir-stamp cp $< $@ chmod +x $@ lib/paths: $(srcdir)/Makefile.in .lib-dir-stamp $(RM) $@-t echo 'top_srcdir=$(top_srcdir)' >> $@-t echo 'abs_top_builddir=$(abs_top_builddir)' >> $@-t echo 'abs_top_srcdir=$(abs_top_srcdir)' >> $@-t echo 'abs_srcdir=$(abs_srcdir)' >> $@-t echo 'abs_builddir=$(abs_builddir)' >> $@-t echo 'export DM_UDEV_SYNCHRONISATION=$(dm_udev_synchronisation)' >> $@-t echo 'export THIN=@THIN@' >> $@-t echo 'export LVMETAD_PIDFILE=@LVMETAD_PIDFILE@' >> $@-t mv $@-t $@ LIB = lib/not lib/should lib/harness \ lib/check lib/aux lib/test lib/utils lib/get lib/lvm-wrapper \ lib/paths CMDS = lvm $(shell cat $(top_builddir)/tools/.commands) .tests-stamp: $(ALL) $(LIB) $(SUBDIRS) @if test "$(srcdir)" != . ; then \ echo "Linking tests to builddir."; \ $(MKDIR_P) shell; \ for f in $(subst $(srcdir)/,,$(ALL)); do \ ln -sf $(abs_top_srcdir)/test/$$f $$f; \ done; \ fi touch $@ .lib-dir-stamp: $(MKDIR_P) lib for i in $(CMDS); do ln -fs lvm-wrapper lib/$$i; done ln -fs $(abs_top_builddir)/tools/dmsetup lib/dmsetup ln -fs $(abs_top_builddir)/daemons/clvmd/clvmd lib/clvmd ln -fs $(abs_top_builddir)/daemons/dmeventd/dmeventd lib/dmeventd ln -fs $(abs_top_builddir)/daemons/lvmetad/lvmetad lib/lvmetad ln -fs $(abs_top_srcdir)/scripts/vgimportclone.sh lib/vgimportclone ln -fs $(abs_top_srcdir)/scripts/fsadm.sh lib/fsadm touch $@ clean: test "$(srcdir)" = . || $(RM) $(RUN_BASE) CLEAN_TARGETS += .lib-dir-stamp .tests-stamp $(LIB) $(addprefix lib/,$(CMDS)) \ lib/clvmd lib/dmeventd lib/dmsetup lib/lvmetad lib/fsadm lib/vgimportclone Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ .NOTPARALLEL: lvm2-2.02.98/test/unit/0000750000175000017500000000000012037016273013446 5ustar blankblanklvm2-2.02.98/test/unit/config_t.c0000640000175000017500000001213712037016273015407 0ustar blankblank/* * 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 */ #include "libdevmapper.h" #include int config_init(void); int config_fini(void); static struct dm_pool *mem; int config_init(void) { mem = dm_pool_create("config test", 1024); return mem == NULL; } int config_fini(void) { dm_pool_destroy(mem); return 0; } static const char *conf = "id = \"yada-yada\"\n" "seqno = 15\n" "status = [\"READ\", \"WRITE\"]\n" "flags = []\n" "extent_size = 8192\n" "physical_volumes {\n" " pv0 {\n" " id = \"abcd-efgh\"\n" " }\n" " pv1 {\n" " id = \"bbcd-efgh\"\n" " }\n" " pv2 {\n" " id = \"cbcd-efgh\"\n" " }\n" "}\n"; static const char *overlay = "id = \"yoda-soda\"\n" "flags = [\"FOO\"]\n" "physical_volumes {\n" " pv1 {\n" " id = \"hgfe-dcba\"\n" " }\n" " pv3 {\n" " id = \"dbcd-efgh\"\n" " }\n" "}\n"; static void test_parse(void) { struct dm_config_tree *tree = dm_config_from_string(conf); const struct dm_config_value *value; CU_ASSERT((long) tree); CU_ASSERT(dm_config_has_node(tree->root, "id")); CU_ASSERT(dm_config_has_node(tree->root, "physical_volumes")); CU_ASSERT(dm_config_has_node(tree->root, "physical_volumes/pv0")); CU_ASSERT(dm_config_has_node(tree->root, "physical_volumes/pv0/id")); CU_ASSERT(!strcmp(dm_config_find_str(tree->root, "id", "foo"), "yada-yada")); CU_ASSERT(!strcmp(dm_config_find_str(tree->root, "idt", "foo"), "foo")); CU_ASSERT(!strcmp(dm_config_find_str(tree->root, "physical_volumes/pv0/bb", "foo"), "foo")); CU_ASSERT(!strcmp(dm_config_find_str(tree->root, "physical_volumes/pv0/id", "foo"), "abcd-efgh")); CU_ASSERT(!dm_config_get_uint32(tree->root, "id", NULL)); CU_ASSERT(dm_config_get_uint32(tree->root, "extent_size", NULL)); /* FIXME: Currently everything parses as a list, even if it's not */ // CU_ASSERT(!dm_config_get_list(tree->root, "id", NULL)); // CU_ASSERT(!dm_config_get_list(tree->root, "extent_size", NULL)); CU_ASSERT(dm_config_get_list(tree->root, "flags", &value)); CU_ASSERT(value->next == NULL); /* an empty list */ CU_ASSERT(dm_config_get_list(tree->root, "status", &value)); CU_ASSERT(value->next != NULL); /* a non-empty list */ dm_config_destroy(tree); } static void test_clone(void) { struct dm_config_tree *tree = dm_config_from_string(conf); struct dm_config_node *n = dm_config_clone_node(tree, tree->root, 1); const struct dm_config_value *value; /* Check that the nodes are actually distinct. */ CU_ASSERT(n != tree->root); CU_ASSERT(n->sib != tree->root->sib); CU_ASSERT(dm_config_find_node(n, "physical_volumes") != NULL); CU_ASSERT(dm_config_find_node(tree->root, "physical_volumes") != NULL); CU_ASSERT(dm_config_find_node(n, "physical_volumes") != dm_config_find_node(tree->root, "physical_volumes")); CU_ASSERT(dm_config_has_node(n, "id")); CU_ASSERT(dm_config_has_node(n, "physical_volumes")); CU_ASSERT(dm_config_has_node(n, "physical_volumes/pv0")); CU_ASSERT(dm_config_has_node(n, "physical_volumes/pv0/id")); CU_ASSERT(!strcmp(dm_config_find_str(n, "id", "foo"), "yada-yada")); CU_ASSERT(!strcmp(dm_config_find_str(n, "idt", "foo"), "foo")); CU_ASSERT(!strcmp(dm_config_find_str(n, "physical_volumes/pv0/bb", "foo"), "foo")); CU_ASSERT(!strcmp(dm_config_find_str(n, "physical_volumes/pv0/id", "foo"), "abcd-efgh")); CU_ASSERT(!dm_config_get_uint32(n, "id", NULL)); CU_ASSERT(dm_config_get_uint32(n, "extent_size", NULL)); /* FIXME: Currently everything parses as a list, even if it's not */ // CU_ASSERT(!dm_config_get_list(tree->root, "id", NULL)); // CU_ASSERT(!dm_config_get_list(tree->root, "extent_size", NULL)); CU_ASSERT(dm_config_get_list(n, "flags", &value)); CU_ASSERT(value->next == NULL); /* an empty list */ CU_ASSERT(dm_config_get_list(n, "status", &value)); CU_ASSERT(value->next != NULL); /* a non-empty list */ dm_config_destroy(tree); } static void test_cascade(void) { struct dm_config_tree *t1 = dm_config_from_string(conf), *t2 = dm_config_from_string(overlay), *tree = dm_config_insert_cascaded_tree(t2, t1); CU_ASSERT(!strcmp(dm_config_tree_find_str(tree, "id", "foo"), "yoda-soda")); CU_ASSERT(!strcmp(dm_config_tree_find_str(tree, "idt", "foo"), "foo")); CU_ASSERT(!strcmp(dm_config_tree_find_str(tree, "physical_volumes/pv0/bb", "foo"), "foo")); CU_ASSERT(!strcmp(dm_config_tree_find_str(tree, "physical_volumes/pv1/id", "foo"), "hgfe-dcba")); CU_ASSERT(!strcmp(dm_config_tree_find_str(tree, "physical_volumes/pv3/id", "foo"), "dbcd-efgh")); dm_config_destroy(t1); dm_config_destroy(t2); } CU_TestInfo config_list[] = { { (char*)"parse", test_parse }, { (char*)"clone", test_clone }, { (char*)"cascade", test_cascade }, CU_TEST_INFO_NULL }; lvm2-2.02.98/test/unit/string_t.c0000640000175000017500000000351712037016273015452 0ustar blankblank/* * Copyright (C) 2012 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU General Public License v.2. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "libdevmapper.h" #include #include #include int string_init(void); int string_fini(void); static struct dm_pool *mem = NULL; int string_init(void) { mem = dm_pool_create("string test", 1024); return (mem == NULL); } int string_fini(void) { dm_pool_destroy(mem); return 0; } /* TODO: Add more string unit tests here */ static void test_strncpy(void) { const char st[] = "1234567890"; char buf[sizeof(st)]; CU_ASSERT_EQUAL(dm_strncpy(buf, st, sizeof(buf)), 1); CU_ASSERT_EQUAL(strcmp(buf, st), 0); CU_ASSERT_EQUAL(dm_strncpy(buf, st, sizeof(buf) - 1), 0); CU_ASSERT_EQUAL(strlen(buf) + 1, sizeof(buf) - 1); } static void test_asprint(void) { const char st0[] = ""; const char st1[] = "12345678901"; const char st2[] = "1234567890123456789012345678901234567890123456789012345678901234567"; char *buf; int a; a = dm_asprintf(&buf, "%s", st0); CU_ASSERT_EQUAL(strcmp(buf, st0), 0); CU_ASSERT_EQUAL(a, sizeof(st0)); free(buf); a = dm_asprintf(&buf, "%s", st1); CU_ASSERT_EQUAL(strcmp(buf, st1), 0); CU_ASSERT_EQUAL(a, sizeof(st1)); free(buf); a = dm_asprintf(&buf, "%s", st2); CU_ASSERT_EQUAL(a, sizeof(st2)); CU_ASSERT_EQUAL(strcmp(buf, st2), 0); free(buf); } CU_TestInfo string_list[] = { { (char*)"asprint", test_asprint }, { (char*)"strncpy", test_strncpy }, CU_TEST_INFO_NULL }; lvm2-2.02.98/test/unit/matcher_t.c0000640000175000017500000000406212037016273015563 0ustar blankblank/* * 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 */ #include "libdevmapper.h" #include "log.h" #include #include #include #include #include #include #include #include #include #include "matcher_data.h" int regex_init(void); int regex_fini(void); static struct dm_pool *mem = NULL; int regex_init(void) { mem = dm_pool_create("bitset test", 1024); return mem == NULL; } int regex_fini(void) { dm_pool_destroy(mem); return 0; } static struct dm_regex *make_scanner(const char **rx) { struct dm_regex *scanner; int nrx = 0; for (; rx[nrx]; ++nrx); scanner = dm_regex_create(mem, rx, nrx); CU_ASSERT_FATAL(scanner != NULL); return scanner; } static void test_fingerprints(void) { struct dm_regex *scanner; scanner = make_scanner(dev_patterns); CU_ASSERT_EQUAL(dm_regex_fingerprint(scanner), 0x7f556c09); scanner = make_scanner(random_patterns); CU_ASSERT_EQUAL(dm_regex_fingerprint(scanner), 0x9f11076c); } static void test_matching(void) { struct dm_regex *scanner; int i; scanner = make_scanner(dev_patterns); for (i = 0; devices[i].str; ++i) CU_ASSERT_EQUAL(dm_regex_match(scanner, devices[i].str), devices[i].expected - 1); scanner = make_scanner(nonprint_patterns); for (i = 0; nonprint[i].str; ++i) CU_ASSERT_EQUAL(dm_regex_match(scanner, nonprint[i].str), nonprint[i].expected - 1); } CU_TestInfo regex_list[] = { { (char*)"fingerprints", test_fingerprints }, { (char*)"matching", test_matching }, CU_TEST_INFO_NULL }; lvm2-2.02.98/test/unit/matcher_data.h0000640000175000017500000005775012037016273016252 0ustar blankblankstruct check_item { const char *str; int expected; }; static const char *dev_patterns[] = { "loop/[0-9]+", "hd[a-d][0-5]+", NULL }; static const char *nonprint_patterns[] = { "foo\x80" "bar", "foo\xc2" "b", "\x80", NULL }; static const struct check_item nonprint[] = { { "foo\x2e" "bar", 0 }, { "foo\x80" "bar", 3 }, { "foo\xc2" "b", 2 }, { "\x80", 3 }, { NULL, 0 } }; static const char *random_patterns[] = { "(((a?)(([Ub]*)|z))((([qr]|X)+)([Qn]*)))+", "[HZejtuw]*", "((B|s)*)|(((([Fv]l)(N+))(([el]|C)(tJ)))?)", "((([Ma]?)|(t*))*)|((([cm]E)|(M?))|(([BE][EV])|([Qj][Mh])))", "(((([bw]*)|([IO]*))((zK)*))|(((pU)|(i|q))|((z?)|([HL]?))))*", "((([Pt]?)|[Tr])?)((Hq)*)", "[HOXcfgikosvwxz]", "[BCEFGHNPTUWfjlprsy]", "((((aD)*)|([Xo]+))+)(([HKn](([Eq]|[JQ])(I*)))*)", "([LNWYeghv]|e)*", "(((y(L*))*)|((([EP]+)(W+))*))*", "U*", "((((R+)(W|[Qr]))|([py]+))+)([LM]*)", "(([DOjx](D(b?)))|([Ke]*))*", "((([ls](c|[FT]))*)([JS]*))*", "((l?)|(([Gz]+)|(D*)))*", "[ABgjn]", "(((q|[dg])?)|([Uk]*))((([Fl]?)|([Ry]+))|(([IR]|c)|(T?)))", "((([an]|P)|[Jw])((a*)|(m*)))*", "((((R[ht])(h+))?)|(([pz](n?))+))+", "(((([Dc]b)([Sp][Ii]))|((k|F)*))|[Uiovz])*", "[Res]*", "[Zl]|a", "^[ANZdf]$", "[En]|(((Q+)(U+))([pt]*))", "[ADEIMQUWXZhklrsvz]", "(((S(y*))*)|(j*))*", "n*", "[NUau]*", "((((Z*)(D|[Nd]))|(([np]|B)+))|(([Xy][Fi])*))+", "((([EZ]?)|(d[HR]))*)((([Hg]|q)(P+))*)", "q", "((m*)|(p|B))|((((x?)|(t+))(([Sb][PX])(O|[HM])))+)", "((((A*)(z[RS]))*)|(((z+)(Q*))+))*", "(((M*)([Uu]*))+)|[Uk]", "[imv]", "[GLSchtw](([Yw]((F[Dd])|([Tw]+)))?)", "([MOZj]*)(S|[Wknr])", "((G|q)*)[BHKN]", "((((NW)|([Ao]?))|((l|[UV])+))+)|((i|(z*))*)", "((((Z+)|([IR]?))|(L*))|([JKQ]+))+", "([Bdin](S*))+", "[HLNSTp]*", "(((J*)([Bq]|[Yu]))*)|([Kv]*)", "(((([BJ]|[Zy])(wI))*)(y*))+", "(((hF)+)|(H*))*", "((([QU][Pj])([GQ]?))+)|[PWo]", "(((([cq][BX])?)|((f[DI])*))*)(([GM]*)[SVYr])", "(([Zt]*)|((qx)|(([BV]+)(f?))))*", "[ILWYhsx]*", "(([Uy]*)|[sv])|([NSc]*)", "((c*)|([JUfhy]?))+", "(((q*)([So]*))(((g[jq])(j?))+))*", "((b+)|(((T+)([fw]T))?))*", "((([DS]?)|([Th]|u))(Q*))*", "[FKLX]|((([fw](L?))(([gq]*)|(O?)))?)", "((([HZ]+)u)*)|[APWijn]", "(e*)|(((v?)|((J+)(Hb)))?)", "(e|((w+)f))*", "[BEHKPQVdelnqy]", "((((B|N)(s*))|[Rr])(((g?)|([rv]+))+))+", "(((s*)|(K*))([AP]G))*", "[CELTp]", "(([Fq]?)|([Al]+))*", "((((r?)|(y[jx]))|([mp]*))+)|((B(S*))*)", "((([Eq]+)|(Y[ds]))|(x|(i|[Ku])))[IJNrvy]", "((([NO]*)[Ix])+)([Jenq]+)", "(((([HP]*)(j|y))*)[Ylqvy])*", "[PTv]+", "[AINSZhpx]|([EOYZ]*)", "([ABCFQv]*)((([Zx]|h)+)|([ej]*))", "((([pr]*)|(([Dq]|p)|(H?)))?)([NRUXmoq]*)", "(([er]*)|([mx]*))(((nV)([am]?))+)", "[BHPRlpu]", "(((([Ah]|[tx])|(e|[uy]))?)((([fl]+)([Vz]|v))*))*", "[AGdm]", "(((K*)^(O*)$)|(B?))*", "((([Ks]|[Ka])*)|([FSTab]?))?", "(([kw]+)[ei])(([Hy]*)(([Mc]*)|(G|f)))", "((((e*)|(Zf))|(R|[nq]))((([Jz]v)([Rj]+))+))*", "(((a?)|(e?))(([Uc]*)(S+)))*", "((((E+)([MZ]?))+)|(((s|[Az])|z)*))?", "((((i[MO])*)|((LH)*))|(((BA)|([AI]+))|[Ug]))*", "[EGHILcho]*", "(((Z[vw])?)((z|g)+))(((H|U)([iv]Q))|([qw]?))", "(([ehmr]|((L[Uw])*))+)((a+)I)", "[EKNSWYagj](((v|[TX])|([Uk]+))*)", "(((R[Mo])|(O*))|([Fm]|([qw]*)))((m*)|((S|[Ki])?))", "((((kP)|c)?)((([do]+)|([Gi]?))*))*", "((^(B|W)$|([Ww]+))([no]*))|((([iv]?)|(M*))|((x|L)?))", "[AEGPRSbcfhsy]", "[Wbcf]|((([MO]?)|([NT]|m))(([Oo]?)([Wg]*)))", "(((YZ)*)[PQVei])*", "[GJKYt][AEGWdegmnt]", "^[CDEGJKNUVYZagkv]$", "([DPWbx]*)|(((q|B)|(P|u))((M[Bq])*))", "[FHIJRTVYZdiorsuvz]*", "([MWoqvz]*)|^(l*)", "(((I|[Rx])*)((X[Mf])([Xa]L)))([Ha]|([HY]*))", "(((l|[Sd])*)((([Ix]+)|([XY]?))(Z*)))+", NULL }; struct check_item devices[] = { { "/dev", 0 }, { "/dev/.devfsd", 0 }, { "/dev/cpu", 0 }, { "/dev/cpu/mtrr", 0 }, { "/dev/netlink", 0 }, { "/dev/netlink/route", 0 }, { "/dev/netlink/skip", 0 }, { "/dev/netlink/USERSOCK", 0 }, { "/dev/netlink/fwmonitor", 0 }, { "/dev/netlink/ARPD", 0 }, { "/dev/netlink/ROUTE6", 0 }, { "/dev/netlink/IP6_FW", 0 }, { "/dev/netlink/tap0", 0 }, { "/dev/netlink/tap1", 0 }, { "/dev/netlink/tap2", 0 }, { "/dev/netlink/tap3", 0 }, { "/dev/netlink/tap4", 0 }, { "/dev/netlink/tap5", 0 }, { "/dev/netlink/tap6", 0 }, { "/dev/netlink/tap7", 0 }, { "/dev/netlink/tap8", 0 }, { "/dev/netlink/tap9", 0 }, { "/dev/netlink/tap10", 0 }, { "/dev/netlink/tap11", 0 }, { "/dev/netlink/tap12", 0 }, { "/dev/netlink/tap13", 0 }, { "/dev/netlink/tap14", 0 }, { "/dev/netlink/tap15", 0 }, { "/dev/shm", 0 }, { "/dev/mem", 0 }, { "/dev/kmem", 0 }, { "/dev/null", 0 }, { "/dev/port", 0 }, { "/dev/zero", 0 }, { "/dev/full", 0 }, { "/dev/random", 0 }, { "/dev/urandom", 0 }, { "/dev/tty", 0 }, { "/dev/console", 0 }, { "/dev/vc", 0 }, { "/dev/vc/1", 0 }, { "/dev/vc/2", 0 }, { "/dev/vc/3", 0 }, { "/dev/vc/4", 0 }, { "/dev/vc/5", 0 }, { "/dev/vc/6", 0 }, { "/dev/vc/7", 0 }, { "/dev/vc/8", 0 }, { "/dev/vc/9", 0 }, { "/dev/vc/10", 0 }, { "/dev/vc/11", 0 }, { "/dev/vc/12", 0 }, { "/dev/vc/13", 0 }, { "/dev/vc/14", 0 }, { "/dev/vc/15", 0 }, { "/dev/vc/16", 0 }, { "/dev/vc/17", 0 }, { "/dev/vc/18", 0 }, { "/dev/vc/19", 0 }, { "/dev/vc/20", 0 }, { "/dev/vc/21", 0 }, { "/dev/vc/22", 0 }, { "/dev/vc/23", 0 }, { "/dev/vc/24", 0 }, { "/dev/vc/25", 0 }, { "/dev/vc/26", 0 }, { "/dev/vc/27", 0 }, { "/dev/vc/28", 0 }, { "/dev/vc/29", 0 }, { "/dev/vc/30", 0 }, { "/dev/vc/31", 0 }, { "/dev/vc/32", 0 }, { "/dev/vc/33", 0 }, { "/dev/vc/34", 0 }, { "/dev/vc/35", 0 }, { "/dev/vc/36", 0 }, { "/dev/vc/37", 0 }, { "/dev/vc/38", 0 }, { "/dev/vc/39", 0 }, { "/dev/vc/40", 0 }, { "/dev/vc/41", 0 }, { "/dev/vc/42", 0 }, { "/dev/vc/43", 0 }, { "/dev/vc/44", 0 }, { "/dev/vc/45", 0 }, { "/dev/vc/46", 0 }, { "/dev/vc/47", 0 }, { "/dev/vc/48", 0 }, { "/dev/vc/49", 0 }, { "/dev/vc/50", 0 }, { "/dev/vc/51", 0 }, { "/dev/vc/52", 0 }, { "/dev/vc/53", 0 }, { "/dev/vc/54", 0 }, { "/dev/vc/55", 0 }, { "/dev/vc/56", 0 }, { "/dev/vc/57", 0 }, { "/dev/vc/58", 0 }, { "/dev/vc/59", 0 }, { "/dev/vc/60", 0 }, { "/dev/vc/61", 0 }, { "/dev/vc/62", 0 }, { "/dev/vc/63", 0 }, { "/dev/vc/0", 0 }, { "/dev/ptmx", 0 }, { "/dev/misc", 0 }, { "/dev/misc/psaux", 0 }, { "/dev/pty", 0 }, { "/dev/pty/m0", 0 }, { "/dev/pty/m1", 0 }, { "/dev/pty/m2", 0 }, { "/dev/pty/m3", 0 }, { "/dev/pty/m4", 0 }, { "/dev/pty/m5", 0 }, { "/dev/pty/m6", 0 }, { "/dev/pty/m7", 0 }, { "/dev/pty/m8", 0 }, { "/dev/pty/m9", 0 }, { "/dev/pty/m10", 0 }, { "/dev/pty/m11", 0 }, { "/dev/pty/m12", 0 }, { "/dev/pty/m13", 0 }, { "/dev/pty/m14", 0 }, { "/dev/pty/m15", 0 }, { "/dev/pty/m16", 0 }, { "/dev/pty/m17", 0 }, { "/dev/pty/m18", 0 }, { "/dev/pty/m19", 0 }, { "/dev/pty/m20", 0 }, { "/dev/pty/m21", 0 }, { "/dev/pty/m22", 0 }, { "/dev/pty/m23", 0 }, { "/dev/pty/m24", 0 }, { "/dev/pty/m25", 0 }, { "/dev/pty/m26", 0 }, { "/dev/pty/m27", 0 }, { "/dev/pty/m28", 0 }, { "/dev/pty/m29", 0 }, { "/dev/pty/m30", 0 }, { "/dev/pty/m31", 0 }, { "/dev/pty/m32", 0 }, { "/dev/pty/m33", 0 }, { "/dev/pty/m34", 0 }, { "/dev/pty/m35", 0 }, { "/dev/pty/m36", 0 }, { "/dev/pty/m37", 0 }, { "/dev/pty/m38", 0 }, { "/dev/pty/m39", 0 }, { "/dev/pty/m40", 0 }, { "/dev/pty/m41", 0 }, { "/dev/pty/m42", 0 }, { "/dev/pty/m43", 0 }, { "/dev/pty/m44", 0 }, { "/dev/pty/m45", 0 }, { "/dev/pty/m46", 0 }, { "/dev/pty/m47", 0 }, { "/dev/pty/m48", 0 }, { "/dev/pty/m49", 0 }, { "/dev/pty/m50", 0 }, { "/dev/pty/m51", 0 }, { "/dev/pty/m52", 0 }, { "/dev/pty/m53", 0 }, { "/dev/pty/m54", 0 }, { "/dev/pty/m55", 0 }, { "/dev/pty/m56", 0 }, { "/dev/pty/m57", 0 }, { "/dev/pty/m58", 0 }, { "/dev/pty/m59", 0 }, { "/dev/pty/m60", 0 }, { "/dev/pty/m61", 0 }, { "/dev/pty/m62", 0 }, { "/dev/pty/m63", 0 }, { "/dev/pty/m64", 0 }, { "/dev/pty/m65", 0 }, { "/dev/pty/m66", 0 }, { "/dev/pty/m67", 0 }, { "/dev/pty/m68", 0 }, { "/dev/pty/m69", 0 }, { "/dev/pty/m70", 0 }, { "/dev/pty/m71", 0 }, { "/dev/pty/m72", 0 }, { "/dev/pty/m73", 0 }, { "/dev/pty/m74", 0 }, { "/dev/pty/m75", 0 }, { "/dev/pty/m76", 0 }, { "/dev/pty/m77", 0 }, { "/dev/pty/m78", 0 }, { "/dev/pty/m79", 0 }, { "/dev/pty/m80", 0 }, { "/dev/pty/m81", 0 }, { "/dev/pty/m82", 0 }, { "/dev/pty/m83", 0 }, { "/dev/pty/m84", 0 }, { "/dev/pty/m85", 0 }, { "/dev/pty/m86", 0 }, { "/dev/pty/m87", 0 }, { "/dev/pty/m88", 0 }, { "/dev/pty/m89", 0 }, { "/dev/pty/m90", 0 }, { "/dev/pty/m91", 0 }, { "/dev/pty/m92", 0 }, { "/dev/pty/m93", 0 }, { "/dev/pty/m94", 0 }, { "/dev/pty/m95", 0 }, { "/dev/pty/m96", 0 }, { "/dev/pty/m97", 0 }, { "/dev/pty/m98", 0 }, { "/dev/pty/m99", 0 }, { "/dev/pty/m100", 0 }, { "/dev/pty/m101", 0 }, { "/dev/pty/m102", 0 }, { "/dev/pty/m103", 0 }, { "/dev/pty/m104", 0 }, { "/dev/pty/m105", 0 }, { "/dev/pty/m106", 0 }, { "/dev/pty/m107", 0 }, { "/dev/pty/m108", 0 }, { "/dev/pty/m109", 0 }, { "/dev/pty/m110", 0 }, { "/dev/pty/m111", 0 }, { "/dev/pty/m112", 0 }, { "/dev/pty/m113", 0 }, { "/dev/pty/m114", 0 }, { "/dev/pty/m115", 0 }, { "/dev/pty/m116", 0 }, { "/dev/pty/m117", 0 }, { "/dev/pty/m118", 0 }, { "/dev/pty/m119", 0 }, { "/dev/pty/m120", 0 }, { "/dev/pty/m121", 0 }, { "/dev/pty/m122", 0 }, { "/dev/pty/m123", 0 }, { "/dev/pty/m124", 0 }, { "/dev/pty/m125", 0 }, { "/dev/pty/m126", 0 }, { "/dev/pty/m127", 0 }, { "/dev/pty/m128", 0 }, { "/dev/pty/m129", 0 }, { "/dev/pty/m130", 0 }, { "/dev/pty/m131", 0 }, { "/dev/pty/m132", 0 }, { "/dev/pty/m133", 0 }, { "/dev/pty/m134", 0 }, { "/dev/pty/m135", 0 }, { "/dev/pty/m136", 0 }, { "/dev/pty/m137", 0 }, { "/dev/pty/m138", 0 }, { "/dev/pty/m139", 0 }, { "/dev/pty/m140", 0 }, { "/dev/pty/m141", 0 }, { "/dev/pty/m142", 0 }, { "/dev/pty/m143", 0 }, { "/dev/pty/m144", 0 }, { "/dev/pty/m145", 0 }, { "/dev/pty/m146", 0 }, { "/dev/pty/m147", 0 }, { "/dev/pty/m148", 0 }, { "/dev/pty/m149", 0 }, { "/dev/pty/m150", 0 }, { "/dev/pty/m151", 0 }, { "/dev/pty/m152", 0 }, { "/dev/pty/m153", 0 }, { "/dev/pty/m154", 0 }, { "/dev/pty/m155", 0 }, { "/dev/pty/m156", 0 }, { "/dev/pty/m157", 0 }, { "/dev/pty/m158", 0 }, { "/dev/pty/m159", 0 }, { "/dev/pty/m160", 0 }, { "/dev/pty/m161", 0 }, { "/dev/pty/m162", 0 }, { "/dev/pty/m163", 0 }, { "/dev/pty/m164", 0 }, { "/dev/pty/m165", 0 }, { "/dev/pty/m166", 0 }, { "/dev/pty/m167", 0 }, { "/dev/pty/m168", 0 }, { "/dev/pty/m169", 0 }, { "/dev/pty/m170", 0 }, { "/dev/pty/m171", 0 }, { "/dev/pty/m172", 0 }, { "/dev/pty/m173", 0 }, { "/dev/pty/m174", 0 }, { "/dev/pty/m175", 0 }, { "/dev/pty/m176", 0 }, { "/dev/pty/m177", 0 }, { "/dev/pty/m178", 0 }, { "/dev/pty/m179", 0 }, { "/dev/pty/m180", 0 }, { "/dev/pty/m181", 0 }, { "/dev/pty/m182", 0 }, { "/dev/pty/m183", 0 }, { "/dev/pty/m184", 0 }, { "/dev/pty/m185", 0 }, { "/dev/pty/m186", 0 }, { "/dev/pty/m187", 0 }, { "/dev/pty/m188", 0 }, { "/dev/pty/m189", 0 }, { "/dev/pty/m190", 0 }, { "/dev/pty/m191", 0 }, { "/dev/pty/m192", 0 }, { "/dev/pty/m193", 0 }, { "/dev/pty/m194", 0 }, { "/dev/pty/m195", 0 }, { "/dev/pty/m196", 0 }, { "/dev/pty/m197", 0 }, { "/dev/pty/m198", 0 }, { "/dev/pty/m199", 0 }, { "/dev/pty/m200", 0 }, { "/dev/pty/m201", 0 }, { "/dev/pty/m202", 0 }, { "/dev/pty/m203", 0 }, { "/dev/pty/m204", 0 }, { "/dev/pty/m205", 0 }, { "/dev/pty/m206", 0 }, { "/dev/pty/m207", 0 }, { "/dev/pty/m208", 0 }, { "/dev/pty/m209", 0 }, { "/dev/pty/m210", 0 }, { "/dev/pty/m211", 0 }, { "/dev/pty/m212", 0 }, { "/dev/pty/m213", 0 }, { "/dev/pty/m214", 0 }, { "/dev/pty/m215", 0 }, { "/dev/pty/m216", 0 }, { "/dev/pty/m217", 0 }, { "/dev/pty/m218", 0 }, { "/dev/pty/m219", 0 }, { "/dev/pty/m220", 0 }, { "/dev/pty/m221", 0 }, { "/dev/pty/m222", 0 }, { "/dev/pty/m223", 0 }, { "/dev/pty/m224", 0 }, { "/dev/pty/m225", 0 }, { "/dev/pty/m226", 0 }, { "/dev/pty/m227", 0 }, { "/dev/pty/m228", 0 }, { "/dev/pty/m229", 0 }, { "/dev/pty/m230", 0 }, { "/dev/pty/m231", 0 }, { "/dev/pty/m232", 0 }, { "/dev/pty/m233", 0 }, { "/dev/pty/m234", 0 }, { "/dev/pty/m235", 0 }, { "/dev/pty/m236", 0 }, { "/dev/pty/m237", 0 }, { "/dev/pty/m238", 0 }, { "/dev/pty/m239", 0 }, { "/dev/pty/m240", 0 }, { "/dev/pty/m241", 0 }, { "/dev/pty/m242", 0 }, { "/dev/pty/m243", 0 }, { "/dev/pty/m244", 0 }, { "/dev/pty/m245", 0 }, { "/dev/pty/m246", 0 }, { "/dev/pty/m247", 0 }, { "/dev/pty/m248", 0 }, { "/dev/pty/m249", 0 }, { "/dev/pty/m250", 0 }, { "/dev/pty/m251", 0 }, { "/dev/pty/m252", 0 }, { "/dev/pty/m253", 0 }, { "/dev/pty/m254", 0 }, { "/dev/pty/m255", 0 }, { "/dev/pts", 0 }, { "/dev/pts/0", 0 }, { "/dev/pts/1", 0 }, { "/dev/pts/2", 0 }, { "/dev/pts/3", 0 }, { "/dev/pts/4", 0 }, { "/dev/pts/5", 0 }, { "/dev/pts/6", 0 }, { "/dev/pts/7", 0 }, { "/dev/vcc", 0 }, { "/dev/vcc/0", 0 }, { "/dev/vcc/a", 0 }, { "/dev/vcc/1", 0 }, { "/dev/vcc/a1", 0 }, { "/dev/vcc/2", 0 }, { "/dev/vcc/a2", 0 }, { "/dev/vcc/3", 0 }, { "/dev/vcc/a3", 0 }, { "/dev/vcc/5", 0 }, { "/dev/vcc/a5", 0 }, { "/dev/vcc/4", 0 }, { "/dev/vcc/a4", 0 }, { "/dev/vcc/6", 0 }, { "/dev/vcc/a6", 0 }, { "/dev/vcc/7", 0 }, { "/dev/vcc/a7", 0 }, { "/dev/tts", 0 }, { "/dev/tts/0", 0 }, { "/dev/cua", 0 }, { "/dev/cua/0", 0 }, { "/dev/ide", 0 }, { "/dev/ide/host0", 0 }, { "/dev/ide/host0/bus0", 0 }, { "/dev/ide/host0/bus0/target0", 0 }, { "/dev/ide/host0/bus0/target0/lun0", 0 }, { "/dev/ide/host0/bus0/target0/lun0/disc", 0 }, { "/dev/ide/host0/bus0/target0/lun0/part1", 0 }, { "/dev/ide/host0/bus0/target0/lun0/part2", 0 }, { "/dev/ide/host0/bus0/target0/lun0/part3", 0 }, { "/dev/ide/host0/bus0/target0/lun0/part4", 0 }, { "/dev/ide/host0/bus0/target0/lun0/part5", 0 }, { "/dev/ide/host0/bus0/target0/lun0/part6", 0 }, { "/dev/ide/host0/bus0/target0/lun0/part7", 0 }, { "/dev/ide/host0/bus0/target0/lun0/part8", 0 }, { "/dev/ide/host0/bus0/target1", 0 }, { "/dev/ide/host0/bus0/target1/lun0", 0 }, { "/dev/ide/host0/bus0/target1/lun0/disc", 0 }, { "/dev/ide/host0/bus0/target1/lun0/part1", 0 }, { "/dev/ide/host0/bus1", 0 }, { "/dev/ide/host0/bus1/target0", 0 }, { "/dev/ide/host0/bus1/target0/lun0", 0 }, { "/dev/ide/host0/bus1/target0/lun0/disc", 0 }, { "/dev/ide/host0/bus1/target0/lun0/part1", 0 }, { "/dev/ide/host0/bus1/target1", 0 }, { "/dev/ide/host0/bus1/target1/lun0", 0 }, { "/dev/discs", 0 }, { "/dev/discs/disc0", 0 }, { "/dev/discs/disc1", 0 }, { "/dev/discs/disc2", 0 }, { "/dev/floppy", 0 }, { "/dev/floppy/0u1440", 0 }, { "/dev/floppy/0u1680", 0 }, { "/dev/floppy/0u1722", 0 }, { "/dev/floppy/0u1743", 0 }, { "/dev/floppy/0u1760", 0 }, { "/dev/floppy/0u1920", 0 }, { "/dev/floppy/0u1840", 0 }, { "/dev/floppy/0u1600", 0 }, { "/dev/floppy/0u360", 0 }, { "/dev/floppy/0u720", 0 }, { "/dev/floppy/0u820", 0 }, { "/dev/floppy/0u830", 0 }, { "/dev/floppy/0u1040", 0 }, { "/dev/floppy/0u1120", 0 }, { "/dev/floppy/0u800", 0 }, { "/dev/floppy/0", 0 }, { "/dev/loop", 0 }, { "/dev/loop/0", 1 }, { "/dev/loop/1", 1 }, { "/dev/loop/2", 1 }, { "/dev/loop/3", 1 }, { "/dev/loop/4", 1 }, { "/dev/loop/5", 1 }, { "/dev/loop/6", 1 }, { "/dev/loop/7", 1 }, { "/dev/cdroms", 0 }, { "/dev/sound", 0 }, { "/dev/sound/dsp", 0 }, { "/dev/sound/dsp1", 0 }, { "/dev/sound/mixer", 0 }, { "/dev/sound/midi", 0 }, { "/dev/usb", 0 }, { "/dev/root", 0 }, { "/dev/initctl", 0 }, { "/dev/xconsole", 0 }, { "/dev/fd", 0 }, { "/dev/stdin", 0 }, { "/dev/stdout", 0 }, { "/dev/stderr", 0 }, { "/dev/route", 0 }, { "/dev/skip", 0 }, { "/dev/USERSOCK", 0 }, { "/dev/fwmonitor", 0 }, { "/dev/ARPD", 0 }, { "/dev/ROUTE6", 0 }, { "/dev/IP6_FW", 0 }, { "/dev/tap0", 0 }, { "/dev/tap1", 0 }, { "/dev/tap2", 0 }, { "/dev/tap3", 0 }, { "/dev/tap4", 0 }, { "/dev/tap5", 0 }, { "/dev/tap6", 0 }, { "/dev/tap7", 0 }, { "/dev/tap8", 0 }, { "/dev/tap9", 0 }, { "/dev/tap10", 0 }, { "/dev/tap11", 0 }, { "/dev/tap12", 0 }, { "/dev/tap13", 0 }, { "/dev/tap14", 0 }, { "/dev/tap15", 0 }, { "/dev/tty1", 0 }, { "/dev/tty2", 0 }, { "/dev/tty3", 0 }, { "/dev/tty4", 0 }, { "/dev/tty5", 0 }, { "/dev/tty6", 0 }, { "/dev/tty7", 0 }, { "/dev/tty8", 0 }, { "/dev/tty9", 0 }, { "/dev/tty10", 0 }, { "/dev/tty11", 0 }, { "/dev/tty12", 0 }, { "/dev/tty13", 0 }, { "/dev/tty14", 0 }, { "/dev/tty15", 0 }, { "/dev/tty16", 0 }, { "/dev/tty17", 0 }, { "/dev/tty18", 0 }, { "/dev/tty19", 0 }, { "/dev/tty20", 0 }, { "/dev/tty21", 0 }, { "/dev/tty22", 0 }, { "/dev/tty23", 0 }, { "/dev/tty24", 0 }, { "/dev/tty25", 0 }, { "/dev/tty26", 0 }, { "/dev/tty27", 0 }, { "/dev/tty28", 0 }, { "/dev/tty29", 0 }, { "/dev/tty30", 0 }, { "/dev/tty31", 0 }, { "/dev/tty32", 0 }, { "/dev/tty33", 0 }, { "/dev/tty34", 0 }, { "/dev/tty35", 0 }, { "/dev/tty36", 0 }, { "/dev/tty37", 0 }, { "/dev/tty38", 0 }, { "/dev/tty39", 0 }, { "/dev/tty40", 0 }, { "/dev/tty41", 0 }, { "/dev/tty42", 0 }, { "/dev/tty43", 0 }, { "/dev/tty44", 0 }, { "/dev/tty45", 0 }, { "/dev/tty46", 0 }, { "/dev/tty47", 0 }, { "/dev/tty48", 0 }, { "/dev/tty49", 0 }, { "/dev/tty50", 0 }, { "/dev/tty51", 0 }, { "/dev/tty52", 0 }, { "/dev/tty53", 0 }, { "/dev/tty54", 0 }, { "/dev/tty55", 0 }, { "/dev/tty56", 0 }, { "/dev/tty57", 0 }, { "/dev/tty58", 0 }, { "/dev/tty59", 0 }, { "/dev/tty60", 0 }, { "/dev/tty61", 0 }, { "/dev/tty62", 0 }, { "/dev/tty63", 0 }, { "/dev/tty0", 0 }, { "/dev/psaux", 0 }, { "/dev/ptyp0", 0 }, { "/dev/ptyp1", 0 }, { "/dev/ptyp2", 0 }, { "/dev/ptyp3", 0 }, { "/dev/ptyp4", 0 }, { "/dev/ptyp5", 0 }, { "/dev/ptyp6", 0 }, { "/dev/ptyp7", 0 }, { "/dev/ptyp8", 0 }, { "/dev/ptyp9", 0 }, { "/dev/ptypa", 0 }, { "/dev/ptypb", 0 }, { "/dev/ptypc", 0 }, { "/dev/ptypd", 0 }, { "/dev/ptype", 0 }, { "/dev/ptypf", 0 }, { "/dev/ptyq0", 0 }, { "/dev/ptyq1", 0 }, { "/dev/ptyq2", 0 }, { "/dev/ptyq3", 0 }, { "/dev/ptyq4", 0 }, { "/dev/ptyq5", 0 }, { "/dev/ptyq6", 0 }, { "/dev/ptyq7", 0 }, { "/dev/ptyq8", 0 }, { "/dev/ptyq9", 0 }, { "/dev/ptyqa", 0 }, { "/dev/ptyqb", 0 }, { "/dev/ptyqc", 0 }, { "/dev/ptyqd", 0 }, { "/dev/ptyqe", 0 }, { "/dev/ptyqf", 0 }, { "/dev/ptyr0", 0 }, { "/dev/ptyr1", 0 }, { "/dev/ptyr2", 0 }, { "/dev/ptyr3", 0 }, { "/dev/ptyr4", 0 }, { "/dev/ptyr5", 0 }, { "/dev/ptyr6", 0 }, { "/dev/ptyr7", 0 }, { "/dev/ptyr8", 0 }, { "/dev/ptyr9", 0 }, { "/dev/ptyra", 0 }, { "/dev/ptyrb", 0 }, { "/dev/ptyrc", 0 }, { "/dev/ptyrd", 0 }, { "/dev/ptyre", 0 }, { "/dev/ptyrf", 0 }, { "/dev/ptys0", 0 }, { "/dev/ptys1", 0 }, { "/dev/ptys2", 0 }, { "/dev/ptys3", 0 }, { "/dev/ptys4", 0 }, { "/dev/ptys5", 0 }, { "/dev/ptys6", 0 }, { "/dev/ptys7", 0 }, { "/dev/ptys8", 0 }, { "/dev/ptys9", 0 }, { "/dev/ptysa", 0 }, { "/dev/ptysb", 0 }, { "/dev/ptysc", 0 }, { "/dev/ptysd", 0 }, { "/dev/ptyse", 0 }, { "/dev/ptysf", 0 }, { "/dev/ptyt0", 0 }, { "/dev/ptyt1", 0 }, { "/dev/ptyt2", 0 }, { "/dev/ptyt3", 0 }, { "/dev/ptyt4", 0 }, { "/dev/ptyt5", 0 }, { "/dev/ptyt6", 0 }, { "/dev/ptyt7", 0 }, { "/dev/ptyt8", 0 }, { "/dev/ptyt9", 0 }, { "/dev/ptyta", 0 }, { "/dev/ptytb", 0 }, { "/dev/ptytc", 0 }, { "/dev/ptytd", 0 }, { "/dev/ptyte", 0 }, { "/dev/ptytf", 0 }, { "/dev/ptyu0", 0 }, { "/dev/ptyu1", 0 }, { "/dev/ptyu2", 0 }, { "/dev/ptyu3", 0 }, { "/dev/ptyu4", 0 }, { "/dev/ptyu5", 0 }, { "/dev/ptyu6", 0 }, { "/dev/ptyu7", 0 }, { "/dev/ptyu8", 0 }, { "/dev/ptyu9", 0 }, { "/dev/ptyua", 0 }, { "/dev/ptyub", 0 }, { "/dev/ptyuc", 0 }, { "/dev/ptyud", 0 }, { "/dev/ptyue", 0 }, { "/dev/ptyuf", 0 }, { "/dev/ptyv0", 0 }, { "/dev/ptyv1", 0 }, { "/dev/ptyv2", 0 }, { "/dev/ptyv3", 0 }, { "/dev/ptyv4", 0 }, { "/dev/ptyv5", 0 }, { "/dev/ptyv6", 0 }, { "/dev/ptyv7", 0 }, { "/dev/ptyv8", 0 }, { "/dev/ptyv9", 0 }, { "/dev/ptyva", 0 }, { "/dev/ptyvb", 0 }, { "/dev/ptyvc", 0 }, { "/dev/ptyvd", 0 }, { "/dev/ptyve", 0 }, { "/dev/ptyvf", 0 }, { "/dev/ptyw0", 0 }, { "/dev/ptyw1", 0 }, { "/dev/ptyw2", 0 }, { "/dev/ptyw3", 0 }, { "/dev/ptyw4", 0 }, { "/dev/ptyw5", 0 }, { "/dev/ptyw6", 0 }, { "/dev/ptyw7", 0 }, { "/dev/ptyw8", 0 }, { "/dev/ptyw9", 0 }, { "/dev/ptywa", 0 }, { "/dev/ptywb", 0 }, { "/dev/ptywc", 0 }, { "/dev/ptywd", 0 }, { "/dev/ptywe", 0 }, { "/dev/ptywf", 0 }, { "/dev/ptyx0", 0 }, { "/dev/ptyx1", 0 }, { "/dev/ptyx2", 0 }, { "/dev/ptyx3", 0 }, { "/dev/ptyx4", 0 }, { "/dev/ptyx5", 0 }, { "/dev/ptyx6", 0 }, { "/dev/ptyx7", 0 }, { "/dev/ptyx8", 0 }, { "/dev/ptyx9", 0 }, { "/dev/ptyxa", 0 }, { "/dev/ptyxb", 0 }, { "/dev/ptyxc", 0 }, { "/dev/ptyxd", 0 }, { "/dev/ptyxe", 0 }, { "/dev/ptyxf", 0 }, { "/dev/ptyy0", 0 }, { "/dev/ptyy1", 0 }, { "/dev/ptyy2", 0 }, { "/dev/ptyy3", 0 }, { "/dev/ptyy4", 0 }, { "/dev/ptyy5", 0 }, { "/dev/ptyy6", 0 }, { "/dev/ptyy7", 0 }, { "/dev/ptyy8", 0 }, { "/dev/ptyy9", 0 }, { "/dev/ptyya", 0 }, { "/dev/ptyyb", 0 }, { "/dev/ptyyc", 0 }, { "/dev/ptyyd", 0 }, { "/dev/ptyye", 0 }, { "/dev/ptyyf", 0 }, { "/dev/ptyz0", 0 }, { "/dev/ptyz1", 0 }, { "/dev/ptyz2", 0 }, { "/dev/ptyz3", 0 }, { "/dev/ptyz4", 0 }, { "/dev/ptyz5", 0 }, { "/dev/ptyz6", 0 }, { "/dev/ptyz7", 0 }, { "/dev/ptyz8", 0 }, { "/dev/ptyz9", 0 }, { "/dev/ptyza", 0 }, { "/dev/ptyzb", 0 }, { "/dev/ptyzc", 0 }, { "/dev/ptyzd", 0 }, { "/dev/ptyze", 0 }, { "/dev/ptyzf", 0 }, { "/dev/ptya0", 0 }, { "/dev/ptya1", 0 }, { "/dev/ptya2", 0 }, { "/dev/ptya3", 0 }, { "/dev/ptya4", 0 }, { "/dev/ptya5", 0 }, { "/dev/ptya6", 0 }, { "/dev/ptya7", 0 }, { "/dev/ptya8", 0 }, { "/dev/ptya9", 0 }, { "/dev/ptyaa", 0 }, { "/dev/ptyab", 0 }, { "/dev/ptyac", 0 }, { "/dev/ptyad", 0 }, { "/dev/ptyae", 0 }, { "/dev/ptyaf", 0 }, { "/dev/ptyb0", 0 }, { "/dev/ptyb1", 0 }, { "/dev/ptyb2", 0 }, { "/dev/ptyb3", 0 }, { "/dev/ptyb4", 0 }, { "/dev/ptyb5", 0 }, { "/dev/ptyb6", 0 }, { "/dev/ptyb7", 0 }, { "/dev/ptyb8", 0 }, { "/dev/ptyb9", 0 }, { "/dev/ptyba", 0 }, { "/dev/ptybb", 0 }, { "/dev/ptybc", 0 }, { "/dev/ptybd", 0 }, { "/dev/ptybe", 0 }, { "/dev/ptybf", 0 }, { "/dev/ptyc0", 0 }, { "/dev/ptyc1", 0 }, { "/dev/ptyc2", 0 }, { "/dev/ptyc3", 0 }, { "/dev/ptyc4", 0 }, { "/dev/ptyc5", 0 }, { "/dev/ptyc6", 0 }, { "/dev/ptyc7", 0 }, { "/dev/ptyc8", 0 }, { "/dev/ptyc9", 0 }, { "/dev/ptyca", 0 }, { "/dev/ptycb", 0 }, { "/dev/ptycc", 0 }, { "/dev/ptycd", 0 }, { "/dev/ptyce", 0 }, { "/dev/ptycf", 0 }, { "/dev/ptyd0", 0 }, { "/dev/ptyd1", 0 }, { "/dev/ptyd2", 0 }, { "/dev/ptyd3", 0 }, { "/dev/ptyd4", 0 }, { "/dev/ptyd5", 0 }, { "/dev/ptyd6", 0 }, { "/dev/ptyd7", 0 }, { "/dev/ptyd8", 0 }, { "/dev/ptyd9", 0 }, { "/dev/ptyda", 0 }, { "/dev/ptydb", 0 }, { "/dev/ptydc", 0 }, { "/dev/ptydd", 0 }, { "/dev/ptyde", 0 }, { "/dev/ptydf", 0 }, { "/dev/ptye0", 0 }, { "/dev/ptye1", 0 }, { "/dev/ptye2", 0 }, { "/dev/ptye3", 0 }, { "/dev/ptye4", 0 }, { "/dev/ptye5", 0 }, { "/dev/ptye6", 0 }, { "/dev/ptye7", 0 }, { "/dev/ptye8", 0 }, { "/dev/ptye9", 0 }, { "/dev/ptyea", 0 }, { "/dev/ptyeb", 0 }, { "/dev/ptyec", 0 }, { "/dev/ptyed", 0 }, { "/dev/ptyee", 0 }, { "/dev/ptyef", 0 }, { "/dev/vcs", 0 }, { "/dev/vcsa", 0 }, { "/dev/vcs1", 0 }, { "/dev/vcsa1", 0 }, { "/dev/ttyS0", 0 }, { "/dev/cua0", 0 }, { "/dev/hda", 0 }, { "/dev/hda1", 2 }, { "/dev/hda2", 2 }, { "/dev/hda3", 2 }, { "/dev/hda4", 2 }, { "/dev/hda5", 2 }, { "/dev/hda6", 0 }, { "/dev/hda7", 0 }, { "/dev/hda8", 0 }, { "/dev/hdb", 0 }, { "/dev/hdb1", 2 }, { "/dev/hdc", 0 }, { "/dev/hdc1", 2 }, { "/dev/fd0u1440", 0 }, { "/dev/fd0u1680", 0 }, { "/dev/fd0u1722", 0 }, { "/dev/fd0u1743", 0 }, { "/dev/fd0u1760", 0 }, { "/dev/fd0u1920", 0 }, { "/dev/fd0u1840", 0 }, { "/dev/fd0u1600", 0 }, { "/dev/fd0u360", 0 }, { "/dev/fd0u720", 0 }, { "/dev/fd0u820", 0 }, { "/dev/fd0u830", 0 }, { "/dev/fd0u1040", 0 }, { "/dev/fd0u1120", 0 }, { "/dev/fd0u800", 0 }, { "/dev/fd0", 0 }, { "/dev/loop0", 0 }, { "/dev/loop1", 0 }, { "/dev/loop2", 0 }, { "/dev/loop3", 0 }, { "/dev/loop4", 0 }, { "/dev/loop5", 0 }, { "/dev/loop6", 0 }, { "/dev/loop7", 0 }, { "/dev/dsp", 0 }, { "/dev/dsp1", 0 }, { "/dev/mixer", 0 }, { "/dev/midi", 0 }, { "/dev/lvm", 0 }, { "/dev/vg0", 0 }, { "/dev/vg0/group", 0 }, { "/dev/vg0/packages", 0 }, { "/dev/vg0/photos", 0 }, { "/dev/vg0/music", 0 }, { "/dev/log", 0 }, { "/dev/MAKEDEV", 0 }, { "/dev/printer", 0 }, { "/dev/vcs2", 0 }, { "/dev/vcsa2", 0 }, { "/dev/vcs3", 0 }, { "/dev/vcsa3", 0 }, { "/dev/vcs5", 0 }, { "/dev/vcsa5", 0 }, { "/dev/vcs4", 0 }, { "/dev/vcsa4", 0 }, { "/dev/vcs6", 0 }, { "/dev/vcsa6", 0 }, { "/dev/nvidia0", 0 }, { "/dev/nvidia1", 0 }, { "/dev/nvidia2", 0 }, { "/dev/nvidia3", 0 }, { "/dev/nvidiactl", 0 }, { "/dev/vcs7", 0 }, { "/dev/vcsa7", 0 }, { NULL, 0 } }; lvm2-2.02.98/test/unit/Makefile.in0000640000175000017500000000163412037016273015520 0ustar blankblank# Copyright (C) 2011-2012 Red Hat, Inc. All rights reserved. # # This file is part of LVM2. # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions # of the GNU General Public License v.2. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation, # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA srcdir = @srcdir@ top_srcdir = @top_srcdir@ top_builddir = @top_builddir@ VPATH = $(srcdir) ifeq ("@TESTING@", "yes") SOURCES = bitset_t.c matcher_t.c config_t.c string_t.c run.c TARGETS = run endif include $(top_builddir)/make.tmpl ifeq ("$(TESTING)", "yes") LDLIBS += -ldevmapper @CUNIT_LIBS@ CFLAGS += @CUNIT_CFLAGS@ check: unit unit: $(TARGETS) @echo Running unit tests LD_LIBRARY_PATH=$(top_builddir)/libdm ./$(TARGETS) endif lvm2-2.02.98/test/unit/bitset_t.c0000640000175000017500000000657012037016273015440 0ustar blankblank/* * 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 */ #include "libdevmapper.h" #include int bitset_init(void); int bitset_fini(void); enum { NR_BITS = 137 }; static struct dm_pool *mem; int bitset_init(void) { mem = dm_pool_create("bitset test", 1024); return mem == NULL; } int bitset_fini(void) { dm_pool_destroy(mem); return 0; } static void test_get_next(void) { int i, j, last = 0, first; dm_bitset_t bs = dm_bitset_create(mem, NR_BITS); for (i = 0; i < NR_BITS; i++) CU_ASSERT(!dm_bit(bs, i)); for (i = 0, j = 1; i < NR_BITS; i += j, j++) dm_bit_set(bs, i); first = 1; for (i = 0, j = 1; i < NR_BITS; i += j, j++) { if (first) { last = dm_bit_get_first(bs); first = 0; } else last = dm_bit_get_next(bs, last); CU_ASSERT(last == i); } CU_ASSERT(dm_bit_get_next(bs, last) == -1); } static void bit_flip(dm_bitset_t bs, int bit) { int old = dm_bit(bs, bit); if (old) dm_bit_clear(bs, bit); else dm_bit_set(bs, bit); } static void test_equal(void) { dm_bitset_t bs1 = dm_bitset_create(mem, NR_BITS); dm_bitset_t bs2 = dm_bitset_create(mem, NR_BITS); int i, j; for (i = 0, j = 1; i < NR_BITS; i += j, j++) { dm_bit_set(bs1, i); dm_bit_set(bs2, i); } CU_ASSERT(dm_bitset_equal(bs1, bs2)); CU_ASSERT(dm_bitset_equal(bs2, bs1)); for (i = 0; i < NR_BITS; i++) { bit_flip(bs1, i); CU_ASSERT(!dm_bitset_equal(bs1, bs2)); CU_ASSERT(!dm_bitset_equal(bs2, bs1)); CU_ASSERT(dm_bitset_equal(bs1, bs1)); /* comparing with self */ bit_flip(bs1, i); } } static void test_and(void) { dm_bitset_t bs1 = dm_bitset_create(mem, NR_BITS); dm_bitset_t bs2 = dm_bitset_create(mem, NR_BITS); dm_bitset_t bs3 = dm_bitset_create(mem, NR_BITS); int i, j; for (i = 0, j = 1; i < NR_BITS; i += j, j++) { dm_bit_set(bs1, i); dm_bit_set(bs2, i); } dm_bit_and(bs3, bs1, bs2); CU_ASSERT(dm_bitset_equal(bs1, bs2)); CU_ASSERT(dm_bitset_equal(bs1, bs3)); CU_ASSERT(dm_bitset_equal(bs2, bs3)); dm_bit_clear_all(bs1); dm_bit_clear_all(bs2); for (i = 0; i < NR_BITS; i++) { if (i % 2) dm_bit_set(bs1, i); else dm_bit_set(bs2, i); } dm_bit_and(bs3, bs1, bs2); for (i = 0; i < NR_BITS; i++) CU_ASSERT(!dm_bit(bs3, i)); } CU_TestInfo bitset_list[] = { { (char*)"get_next", test_get_next }, { (char*)"equal", test_equal }, { (char*)"and", test_and }, CU_TEST_INFO_NULL }; lvm2-2.02.98/test/unit/run.c0000640000175000017500000000107012037016273014415 0ustar blankblank#include #include #define DECL(n) \ extern CU_TestInfo n ## _list[]; \ int n ## _init(void); \ int n ## _fini(void); #define USE(n) { (char*) #n, n##_init, n##_fini, n##_list } DECL(bitset); DECL(regex); DECL(config); DECL(string); CU_SuiteInfo suites[] = { USE(bitset), USE(regex), USE(config), USE(string), CU_SUITE_INFO_NULL }; int main(int argc, char **argv) { CU_initialize_registry(); CU_register_suites(suites); CU_basic_set_mode(CU_BRM_VERBOSE); CU_basic_run_tests(); return CU_get_number_of_failures() != 0; } lvm2-2.02.98/test/shell/0000750000175000017500000000000012037016273013576 5ustar blankblanklvm2-2.02.98/test/shell/lvmetad-restart.sh0000640000175000017500000000116412037016273017253 0ustar blankblank#!/bin/sh # Copyright (C) 2012 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 . lib/test test -e LOCAL_LVMETAD || skip aux prepare_pvs 2 vgcreate $vg1 $dev1 $dev2 vgs | grep $vg1 kill $(cat LOCAL_LVMETAD) aux prepare_lvmetad vgs | grep $vg1 lvm2-2.02.98/test/shell/lvcreate-small-snap.sh0000640000175000017500000000204712037016273020010 0ustar blankblank#!/bin/sh # 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 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 . lib/test aux prepare_pvs 3 vgcreate -c n -s 1k $vg $(cat DEVICES) lvcreate -n one -l 10 $vg lvcreate -s -l 8 -n snapA $vg/one lvcreate -s -c 4k -l 8 -n snapX1 $vg/one lvcreate -s -c 8k -l 16 -n snapX2 $vg/one # Check that snapshots that are too small are caught with correct error. not lvcreate -s -c 8k -l 8 -n snapX3 $vg/one 2>&1 | tee lvcreate.out not grep "suspend origin one" lvcreate.out grep "Unable to create a snapshot" lvcreate.out not lvcreate -s -l 4 -n snapB $vg/one 2>&1 | tee lvcreate.out not grep "suspend origin one" lvcreate.out grep "Unable to create a snapshot" lvcreate.out lvm2-2.02.98/test/shell/lvresize-usage.sh0000640000175000017500000000116312037016273017101 0ustar blankblank#!/bin/sh # Copyright (C) 2007-2008 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 . lib/test aux prepare_vg 2 lvcreate -L 10M -n lv -i2 $vg lvresize -l +4 $vg/lv lvremove -ff $vg lvcreate -L 64M -n $lv -i2 $vg not lvresize -v -l +4 xxx/$lv lvm2-2.02.98/test/shell/lvconvert-mirror.sh0000640000175000017500000002073412037016272017472 0ustar blankblank#!/bin/sh # 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 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 . lib/test aux prepare_pvs 5 10 # FIXME - test fails with extent size < 512k vgcreate -c n -s 512k $vg $(cat DEVICES) # convert from linear to 2-way mirror lvcreate -l2 -n $lv1 $vg "$dev1" lvconvert -i1 -m+1 $vg/$lv1 "$dev2" "$dev3:0-1" check mirror $vg $lv1 "$dev3" lvremove -ff $vg # convert from linear to 2-way mirror - with tags and volume_list (bz683270) lvcreate -l2 -n $lv1 $vg --addtag hello lvconvert -i1 -m+1 $vg/$lv1 \ --config 'activation { volume_list = [ "@hello" ] }' lvremove -ff $vg # convert from 2-way to 3-way mirror - with tags and volume_list (bz683270) lvcreate -l2 -m1 -n $lv1 $vg --addtag hello lvconvert -i1 -m+1 $vg/$lv1 \ --config 'activation { volume_list = [ "@hello" ] }' lvremove -ff $vg # convert from 2-way mirror to linear lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3:0-1" lvconvert -m-1 $vg/$lv1 check linear $vg $lv1 lvremove -ff $vg # and now try removing a specific leg (bz453643) lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3:0-1" lvconvert -m0 $vg/$lv1 "$dev2" check lv_on $vg $lv1 "$dev1" lvremove -ff $vg # convert from disklog to corelog, active lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3:0-1" lvconvert -f --mirrorlog core $vg/$lv1 check mirror $vg $lv1 core lvremove -ff $vg # convert from corelog to disklog, active lvcreate -l2 -m1 --mirrorlog core -n $lv1 $vg "$dev1" "$dev2" lvconvert --mirrorlog disk $vg/$lv1 "$dev3:0-1" check mirror $vg $lv1 "$dev3" lvremove -ff $vg # bz192865: lvconvert log of an inactive mirror lv # convert from disklog to corelog, inactive lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3:0-1" lvchange -an $vg/$lv1 echo y | lvconvert -f --mirrorlog core $vg/$lv1 check mirror $vg $lv1 core lvremove -ff $vg # convert from corelog to disklog, inactive lvcreate -l2 -m1 --mirrorlog core -n $lv1 $vg "$dev1" "$dev2" lvchange -an $vg/$lv1 lvconvert --mirrorlog disk $vg/$lv1 "$dev3:0-1" check mirror $vg $lv1 "$dev3" lvremove -ff $vg # convert linear to 2-way mirror with 1 PV lvcreate -l2 -n $lv1 $vg "$dev1" not lvconvert -m+1 --mirrorlog core $vg/$lv1 "$dev1" lvremove -ff $vg # Start w/ 3-way mirror # Test pulling primary image before mirror in-sync (should fail) # Test pulling primary image after mirror in-sync (should work) # Test that the correct devices remain in the mirror lvcreate -l2 -m2 -n $lv1 $vg "$dev1" "$dev2" "$dev4" "$dev3:0" # FIXME: # This is somewhat timing dependent - sync /could/ finish before # we get a chance to have this command fail should not lvconvert -m-1 $vg/$lv1 "$dev1" lvconvert $vg/$lv1 # wait lvconvert -m2 $vg/$lv1 "$dev1" "$dev2" "$dev4" "$dev3:0" # If the above "should" failed... aux wait_for_sync $vg $lv1 lvconvert -m-1 $vg/$lv1 "$dev1" check mirror_images_on $lv1 "$dev2" "$dev4" lvconvert -m-1 $vg/$lv1 "$dev2" check linear $vg $lv1 check lv_on $vg $lv1 "$dev4" lvremove -ff $vg # No parallel lvconverts on a single LV please lvcreate -l5 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3:0" check mirror $vg $lv1 check mirror_legs $vg $lv1 2 lvconvert -m+1 -b $vg/$lv1 "$dev4" # Next convert should fail b/c we can't have 2 at once should not lvconvert -m+1 $vg/$lv1 "$dev5" lvconvert $vg/$lv1 # wait lvconvert -m2 $vg/$lv1 # In case the above "should" actually failed check mirror $vg $lv1 "$dev3" check mirror_no_temporaries $vg $lv1 check mirror_legs $vg $lv1 3 lvremove -ff $vg # add 1 mirror to core log mirror, but # implicitly keep log as 'core' lvcreate -l2 -m1 --mirrorlog core -n $lv1 $vg "$dev1" "$dev2" lvconvert -m +1 -i1 $vg/$lv1 check mirror $vg $lv1 core check mirror_no_temporaries $vg $lv1 check mirror_legs $vg $lv1 3 lvremove -ff $vg # remove 1 mirror from corelog'ed mirror; should retain 'core' log type lvcreate -l2 -m2 --corelog -n $lv1 $vg lvconvert -m -1 -i1 $vg/$lv1 check mirror $vg $lv1 core check mirror_no_temporaries $vg $lv1 check mirror_legs $vg $lv1 2 lvremove -ff $vg # add 1 mirror then add 1 more mirror during conversion # FIXME this has been explicitly forbidden? #lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3":0 #lvconvert -m+1 -b $vg/$lv1 "$dev4" #lvconvert -m+1 $vg/$lv1 "$dev5" # #check mirror $vg $lv1 "$dev3" #check mirror_no_temporaries $vg $lv1 #check mirror_legs $vg $lv1 4 #lvremove -ff $vg # Linear to mirror with mirrored log using --alloc anywhere lvcreate -l2 -n $lv1 $vg "$dev1" lvconvert -m +1 --mirrorlog mirrored --alloc anywhere $vg/$lv1 "$dev1" "$dev2" should check mirror $vg $lv1 lvremove -ff $vg # convert inactive mirror and start polling lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3:0" lvchange -an $vg/$lv1 lvconvert -m+1 $vg/$lv1 "$dev4" lvchange -ay $vg/$lv1 lvconvert $vg/$lv1 # wait check mirror $vg $lv1 "$dev3" check mirror_no_temporaries $vg $lv1 lvremove -ff $vg # --------------------------------------------------------------------- # removal during conversion # "remove newly added mirror" lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3:0" lvconvert -m+1 -b $vg/$lv1 "$dev4" lvconvert -m-1 $vg/$lv1 "$dev4" lvconvert $vg/$lv1 # wait check mirror $vg $lv1 "$dev3" check mirror_no_temporaries $vg $lv1 check mirror_legs $vg $lv1 2 lvremove -ff $vg # "remove one of newly added mirrors" lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3:0" lvconvert -m+2 -b $vg/$lv1 "$dev4" "$dev5" lvconvert -m-1 $vg/$lv1 "$dev4" lvconvert $vg/$lv1 # wait check mirror $vg $lv1 "$dev3" check mirror_no_temporaries $vg $lv1 check mirror_legs $vg $lv1 3 lvremove -ff $vg # "remove from original mirror (the original is still mirror)" lvcreate -l2 -m2 -n $lv1 $vg "$dev1" "$dev2" "$dev5" "$dev3:0" lvconvert -m+1 -b $vg/$lv1 "$dev4" lvconvert -m-1 $vg/$lv1 "$dev2" lvconvert $vg/$lv1 check mirror $vg $lv1 "$dev3" check mirror_no_temporaries $vg $lv1 check mirror_legs $vg $lv1 3 lvremove -ff $vg # "remove from original mirror (the original becomes linear)" lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3:0" lvconvert -m+1 -b $vg/$lv1 "$dev4" lvconvert -m-1 $vg/$lv1 "$dev2" lvconvert $vg/$lv1 check mirror $vg $lv1 "$dev3" check mirror_no_temporaries $vg $lv1 check mirror_legs $vg $lv1 2 lvremove -ff $vg # --------------------------------------------------------------------- # "rhbz440405: lvconvert -m0 incorrectly fails if all PEs allocated" lvcreate -l`pvs --noheadings -ope_count "$dev1"` -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3:0" aux wait_for_sync $vg $lv1 lvconvert -m0 $vg/$lv1 "$dev1" check linear $vg $lv1 lvremove -ff $vg # "rhbz264241: lvm mirror doesn't lose it's "M" --nosync attribute after being down and the up converted" lvcreate -l2 -m1 -n$lv1 --nosync $vg lvconvert -m0 $vg/$lv1 lvconvert -m1 $vg/$lv1 lvs --noheadings -o attr $vg/$lv1 | grep '^ *m' lvremove -ff $vg # lvconvert from linear (on multiple PVs) to mirror lvcreate -l 8 -n $lv1 $vg "$dev1:0-3" "$dev2:0-3" lvconvert -m1 $vg/$lv1 should check mirror $vg $lv1 check mirror_legs $vg $lv1 2 lvremove -ff $vg # BZ 463272: disk log mirror convert option is lost if downconvert option is also given lvcreate -l1 -m2 --corelog -n $lv1 $vg "$dev1" "$dev2" "$dev3" aux wait_for_sync $vg $lv1 lvconvert -m1 --mirrorlog disk $vg/$lv1 check mirror $vg $lv1 not check mirror $vg $lv1 core lvremove -ff $vg # --- # add mirror and disk log # "add 1 mirror and disk log" lvcreate -l2 -m1 --mirrorlog core -n $lv1 $vg "$dev1" "$dev2" # FIXME on next line, specifying $dev3:0 $dev4 (i.e log device first) fails (!) lvconvert -m+1 --mirrorlog disk -i1 $vg/$lv1 "$dev4" "$dev3:0" check mirror $vg $lv1 "$dev3" check mirror_no_temporaries $vg $lv1 check mirror_legs $vg $lv1 3 lvremove -ff $vg # simple mirrored stripe lvcreate -i2 -l10 -n $lv1 $vg lvconvert -m1 -i1 $vg/$lv1 lvreduce -f -l1 $vg/$lv1 lvextend -f -l10 $vg/$lv1 lvremove -ff $vg/$lv1 # extents must be divisible lvcreate -l15 -n $lv1 $vg not lvconvert -m1 --corelog --stripes 2 $vg/$lv1 lvremove -ff $vg # Should not be able to add images to --nosync mirror # but should be able to after 'lvchange --resync' lvcreate -m 1 -l1 -n $lv1 $vg --nosync not lvconvert -m +1 $vg/$lv1 lvchange --resync -y $vg/$lv1 lvconvert -m +1 $vg/$lv1 lvremove -ff $vg lvcreate -m 1 --corelog -l1 -n $lv1 $vg --nosync not lvconvert -m +1 $vg/$lv1 lvchange --resync -y $vg/$lv1 lvconvert -m +1 $vg/$lv1 lvremove -ff $vg lvm2-2.02.98/test/shell/snapshot-autoumount-dmeventd.sh0000640000175000017500000000223512037016273022016 0ustar blankblank#!/bin/bash # Copyright (C) 2010-2012 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 # no automatic extensions please . lib/test which mkfs.ext2 || skip aux lvmconf "activation/snapshot_autoextend_percent = 0" \ "activation/snapshot_autoextend_threshold = 100" aux prepare_dmeventd aux prepare_vg 2 mntdir="${PREFIX}mnt" lvcreate -l 8 -n base $vg mkfs.ext2 "$DM_DEV_DIR/$vg/base" lvcreate -s -l 4 -n snap $vg/base lvchange --monitor y $vg/snap mkdir "$mntdir" mount "$DM_DEV_DIR/mapper/$vg-snap" "$mntdir" mount cat /proc/mounts | grep "$mntdir" dd if=/dev/zero of="$mntdir/file$1" bs=1M count=16 sync #dmeventd only checks every 10 seconds :( for i in {1..10}; do cat /proc/mounts | grep "$mntdir" || break sleep 1 done cat /proc/mounts | not grep "$mntdir" vgremove -f $vg lvm2-2.02.98/test/shell/pv-duplicate.sh0000640000175000017500000000127512037016273016535 0ustar blankblank#!/bin/sh # Copyright (C) 2011 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 # 'Exercise duplicate metadata diagnostics' . lib/test aux prepare_devs 3 vgcreate -c n --metadatasize 128k $vg1 "$dev1" # copy mda dd if="$dev1" of="$dev2" bs=256K count=1 dd if="$dev1" of="$dev3" bs=256K count=1 pvs "$dev1" vgs $vg1 lvm2-2.02.98/test/shell/dmeventd-restart.sh0000640000175000017500000000271112037016272017423 0ustar blankblank#!/bin/sh # Copyright (C) 2008 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 . lib/test aux prepare_dmeventd aux prepare_vg 5 lvcreate -m 3 --ig -L 1 -n 4way $vg lvchange --monitor y $vg/4way lvcreate -m 2 --ig -L 1 -n 3way $vg lvchange --monitor y $vg/3way dmeventd -R -f & echo $! >LOCAL_DMEVENTD sleep 2 # wait a bit, so we talk to the new dmeventd later lvchange --monitor y --verbose $vg/3way 2>&1 | tee lvchange.out grep 'already monitored' lvchange.out lvchange --monitor y --verbose $vg/4way 2>&1 | tee lvchange.out grep 'already monitored' lvchange.out # now try what happens if no dmeventd is running kill -9 $(cat LOCAL_DMEVENTD) rm LOCAL_DMEVENTD dmeventd -R -f & echo $! >LOCAL_DMEVENTD # wait longer as tries to communicate with killed daemon sleep 7 # now dmeventd should not be running not pgrep dmeventd rm LOCAL_DMEVENTD # set dmeventd path aux lvmconf "dmeventd/executable=\"$abs_top_builddir/test/lib/dmeventd\"" lvchange --monitor y --verbose $vg/3way 2>&1 | tee lvchange.out pgrep dmeventd >LOCAL_DMEVENTD not grep 'already monitored' lvchange.out vgremove -ff $vg lvm2-2.02.98/test/shell/pvcreate-usage.sh0000640000175000017500000001422712037016273017054 0ustar blankblank#!/bin/sh # Copyright (C) 2008 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 test_description='Test pvcreate option values' PAGESIZE=$(getconf PAGESIZE) . lib/test aux prepare_devs 4 #COMM 'pvcreate rejects negative setphysicalvolumesize' not pvcreate --setphysicalvolumesize -1024 "$dev1" #COMM 'pvcreate rejects negative metadatasize' not pvcreate --metadatasize -1024 "$dev1" # x. metadatasize 0, defaults to 255 # FIXME: unable to check default value, not in reporting cmds # should default to 255 according to code # check pv_field pv_mda_size 255 #COMM 'pvcreate accepts metadatasize 0' pvcreate --metadatasize 0 "$dev1" pvremove "$dev1" #Verify vg_mda_size is smaller pv_mda_size pvcreate --metadatasize 512k "$dev1" pvcreate --metadatasize 96k "$dev2" vgcreate $vg "$dev1" "$dev2" check compare_fields vgs $vg vg_mda_size pvs "$dev2" pv_mda_size vgremove $vg # x. metadatasize too large # For some reason we allow this, even though there's no room for data? ##COMM 'pvcreate rejects metadatasize too large' #not pvcreate --metadatasize 100000000000000 "$dev1" #COMM 'pvcreate rejects metadatacopies < 0' not pvcreate --metadatacopies -1 "$dev1" #COMM 'pvcreate accepts metadatacopies = 0, 1, 2' for j in metadatacopies pvmetadatacopies do pvcreate --$j 0 "$dev1" pvcreate --$j 1 "$dev2" pvcreate --$j 2 "$dev3" check pv_field "$dev1" pv_mda_count 0 check pv_field "$dev2" pv_mda_count 1 check pv_field "$dev3" pv_mda_count 2 pvremove "$dev1" "$dev2" "$dev3" done #COMM 'pvcreate rejects metadatacopies > 2' not pvcreate --metadatacopies 3 "$dev1" #COMM 'pvcreate rejects invalid device' not pvcreate "$dev1"bogus #COMM 'pvcreate rejects labelsector < 0' not pvcreate --labelsector -1 "$dev1" #COMM 'pvcreate rejects labelsector > 1000000000000' not pvcreate --labelsector 1000000000000 "$dev1" # other possibilites based on code inspection (not sure how hard) # x. device too small (min of 512 * 1024 KB) # x. device filtered out # x. unable to open /dev/urandom RDONLY # x. device too large (pe_count > UINT32_MAX) # x. device read-only # x. unable to open device readonly # x. BLKGETSIZE64 fails # x. set size to value inconsistent with device / PE size #COMM 'pvcreate basic dataalignment sanity checks' not pvcreate --dataalignment -1 "$dev1" not pvcreate -M 1 --dataalignment 1 "$dev1" not pvcreate --dataalignment 1e "$dev1" #COMM 'pvcreate always rounded up to page size for start of device' #pvcreate --metadatacopies 0 --dataalignment 1 "$dev1" # amuse shell experts #check pv_field "$dev1" pe_start $(($(getconf PAGESIZE)/1024))".00k" #COMM 'pvcreate sets data offset directly' pvcreate --dataalignment 512k "$dev1" check pv_field "$dev1" pe_start "512.00k" #COMM 'vgcreate/vgremove do not modify data offset of existing PV' vgcreate $vg "$dev1" --config 'devices { data_alignment = 1024 }' check pv_field "$dev1" pe_start "512.00k" vgremove $vg --config 'devices { data_alignment = 1024 }' check pv_field "$dev1" pe_start "512.00k" #COMM 'pvcreate sets data offset next to mda area' pvcreate --metadatasize 100k --dataalignment 100k "$dev1" check pv_field "$dev1" pe_start "200.00k" # metadata area start is aligned according to pagesize case "$PAGESIZE" in 65536) pv_align="192.50k" ;; 8192) pv_align="136.50k" ;; *) pv_align="133.00k" ;; esac pvcreate --metadatasize 128k --dataalignment 3.5k "$dev1" check pv_field "$dev1" pe_start $pv_align pvcreate --metadatasize 128k --metadatacopies 2 --dataalignment 3.5k "$dev1" check pv_field "$dev1" pe_start $pv_align # data area is aligned to 1M by default, # data area start is shifted by the specified alignment_offset pv_align=1052160B # 1048576 + (7*512) pvcreate --metadatasize 128k --dataalignmentoffset 7s "$dev1" check pv_field "$dev1" pe_start $pv_align --units b # 2nd metadata area is created without problems when # data area start is shifted by the specified alignment_offset pvcreate --metadatasize 128k --metadatacopies 2 --dataalignmentoffset 7s "$dev1" check pv_field "$dev1" pv_mda_count 2 # FIXME: compare start of 2nd mda with and without --dataalignmentoffset #COMM 'pv with LVM1 compatible data alignment can be convereted' #compatible == LVM1_PE_ALIGN == 64k pvcreate --dataalignment 256k "$dev1" vgcreate -s 1m $vg "$dev1" vgconvert -M1 $vg vgconvert -M2 $vg check pv_field "$dev1" pe_start 256.00k vgremove $vg #COMM 'pv with LVM1 incompatible data alignment cannot be convereted' pvcreate --dataalignment 10k "$dev1" vgcreate -s 1m $vg "$dev1" not vgconvert -M1 $vg vgremove $vg #COMM 'vgcfgrestore allows pe_start=0' #basically it produces nonsense, but it tests vgcfgrestore, #not that final cfg is usable... pvcreate --metadatacopies 0 "$dev1" pvcreate "$dev2" vgcreate $vg "$dev1" "$dev2" vgcfgbackup -f backup.$$ $vg sed 's/pe_start = [0-9]*/pe_start = 0/' backup.$$ > backup.$$1 vgcfgrestore -f backup.$$1 $vg check pv_field "$dev1" pe_start "0" check pv_field "$dev2" pe_start "0" vgremove $vg echo "test pvcreate --metadataignore" for pv_in_vg in 1 0; do for mdacp in 1 2; do for ignore in y n; do echo "pvcreate --metadataignore has proper mda_count and mda_used_count" pvcreate --metadatacopies $mdacp --metadataignore $ignore "$dev1" "$dev2" check pv_field "$dev1" pv_mda_count "$mdacp" check pv_field "$dev2" pv_mda_count "$mdacp" if [ $ignore = y ]; then check pv_field "$dev1" pv_mda_used_count "0" check pv_field "$dev2" pv_mda_used_count "0" else check pv_field "$dev1" pv_mda_used_count "$mdacp" check pv_field "$dev2" pv_mda_used_count "$mdacp" fi echo "vgcreate has proper vg_mda_count and vg_mda_used_count" if [ $pv_in_vg = 1 ]; then vgcreate -c n $vg "$dev1" "$dev2" check vg_field $vg vg_mda_count "$(($mdacp * 2))" if [ $ignore = y ]; then check vg_field $vg vg_mda_used_count "1" else check vg_field $vg vg_mda_used_count "$(($mdacp * 2))" fi check vg_field $vg vg_mda_copies "unmanaged" vgremove $vg fi done done done lvm2-2.02.98/test/shell/unknown-segment.sh0000640000175000017500000000205312037016273017272 0ustar blankblank#!/bin/sh # Copyright (C) 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 . lib/test aux prepare_vg 4 lvcreate -l 1 -n $lv1 $vg lvcreate -l 2 -m 1 -n $lv2 $vg vgcfgbackup -f bak0 $vg sed -e 's,striped,unstriped,;s,mirror,unmirror,' -i.orig bak0 vgcfgrestore -f bak0 $vg # we have on-disk metadata with unknown segments now not lvchange -a y $vg/$lv1 # check that activation is refused vgcfgbackup -f bak1 $vg cat bak1 sed -e 's,unstriped,striped,;s,unmirror,mirror,' -i.orig bak1 vgcfgrestore -f bak1 $vg vgcfgbackup -f bak2 $vg egrep -v 'description|seqno|creation_time|Generated' < bak0.orig > a egrep -v 'description|seqno|creation_time|Generated' < bak2 > b diff -u a b lvm2-2.02.98/test/shell/vgsplit-operation.sh0000640000175000017500000002040212037016273017617 0ustar blankblank#!/bin/sh # Copyright (C) 2007 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 # Test vgsplit operation, including different LV types . lib/test COMM() { LAST_TEST="$@" } create_vg_() { vgcreate -c n -s 64k "$@" } aux prepare_pvs 5 10 # FIXME: paramaterize lvm1 vs lvm2 metadata; most of these tests should run # fine with lvm1 metadata as well; for now, just add disks 5 and 6 as lvm1 # metadata # # vgsplit can be done into a new or existing VG # for i in new existing do # # We can have PVs or LVs on the cmdline # for j in PV LV do COMM "vgsplit correctly splits single linear LV into $i VG ($j args)" create_vg_ $vg1 "$dev1" "$dev2" test $i = existing && create_vg_ $vg2 "$dev3" "$dev4" lvcreate -l 4 -n $lv1 $vg1 "$dev1" vgchange -an $vg1 if [ $j = PV ]; then vgsplit $vg1 $vg2 "$dev1" else vgsplit -n $lv1 $vg1 $vg2 fi check pvlv_counts $vg1 1 0 0 if [ $i = existing ]; then check pvlv_counts $vg2 3 1 0 else check pvlv_counts $vg2 1 1 0 fi lvremove -f $vg2/$lv1 vgremove -f $vg2 $vg1 COMM "vgsplit correctly splits single striped LV into $i VG ($j args)" create_vg_ $vg1 "$dev1" "$dev2" test $i = existing && create_vg_ $vg2 "$dev3" "$dev4" lvcreate -l 4 -i 2 -n $lv1 $vg1 "$dev1" "$dev2" vgchange -an $vg1 if [ $j = PV ]; then vgsplit $vg1 $vg2 "$dev1" "$dev2" else vgsplit -n $lv1 $vg1 $vg2 fi if [ $i = existing ]; then check pvlv_counts $vg2 4 1 0 else check pvlv_counts $vg2 2 1 0 fi lvremove -f $vg2/$lv1 vgremove -f $vg2 COMM "vgsplit correctly splits mirror LV into $i VG ($j args)" create_vg_ $vg1 "$dev1" "$dev2" "$dev3" test $i = existing && create_vg_ $vg2 "$dev4" lvcreate -l 64 -m1 -n $lv1 $vg1 "$dev1" "$dev2" "$dev3" vgchange -an $vg1 if [ $j = PV ]; then vgsplit $vg1 $vg2 "$dev1" "$dev2" "$dev3" else vgsplit -n $lv1 $vg1 $vg2 fi if [ $i = existing ]; then check pvlv_counts $vg2 4 1 0 else check pvlv_counts $vg2 3 1 0 fi lvremove -f $vg2/$lv1 vgremove -f $vg2 # FIXME: ensure split /doesn't/ work when not all devs of mirror specified COMM "vgsplit correctly splits mirror LV with mirrored log into $i VG ($j args)" create_vg_ $vg1 "$dev1" "$dev2" "$dev3" "$dev4" test $i = existing && create_vg_ $vg2 "$dev5" lvcreate -l 64 --mirrorlog mirrored -m1 -n $lv1 $vg1 \ "$dev1" "$dev2" "$dev3" "$dev4" vgchange -an $vg1 if [ $j = PV ]; then vgsplit $vg1 $vg2 "$dev1" "$dev2" "$dev3" "$dev4" else vgsplit -n $lv1 $vg1 $vg2 fi if [ $i = existing ]; then check pvlv_counts $vg2 5 1 0 else check pvlv_counts $vg2 4 1 0 fi lvremove -f $vg2/$lv1 vgremove -f $vg2 # FIXME: ensure split /doesn't/ work when not all devs of mirror specified COMM "vgsplit correctly splits origin and snapshot LV into $i VG ($j args)" create_vg_ $vg1 "$dev1" "$dev2" test $i = existing && create_vg_ $vg2 "$dev3" "$dev4" lvcreate -l 64 -i 2 -n $lv1 $vg1 "$dev1" "$dev2" lvcreate -l 4 -i 2 -s -n $lv2 $vg1/$lv1 vgchange -an $vg1 if [ $j = PV ]; then vgsplit $vg1 $vg2 "$dev1" "$dev2" else vgsplit -n $lv1 $vg1 $vg2 fi if [ $i = existing ]; then check pvlv_counts $vg2 4 2 1 else check pvlv_counts $vg2 2 2 1 fi lvremove -f $vg2/$lv2 lvremove -f $vg2/$lv1 vgremove -f $vg2 COMM "vgsplit correctly splits linear LV but not snap+origin LV into $i VG ($j args)" create_vg_ $vg1 "$dev1" "$dev2" test $i = existing && create_vg_ $vg2 "$dev3" lvcreate -l 64 -i 2 -n $lv1 $vg1 lvcreate -l 4 -i 2 -s -n $lv2 $vg1/$lv1 vgextend $vg1 "$dev4" lvcreate -l 64 -n $lv3 $vg1 "$dev4" vgchange -an $vg1 if [ $j = PV ]; then vgsplit $vg1 $vg2 "$dev4" else vgsplit -n $lv3 $vg1 $vg2 fi if [ $i = existing ]; then check pvlv_counts $vg2 2 1 0 check pvlv_counts $vg1 2 2 1 else check pvlv_counts $vg2 1 1 0 check pvlv_counts $vg1 2 2 1 fi lvremove -f $vg1/$lv2 lvremove -f $vg1/$lv1 $vg2/$lv3 vgremove -f $vg1 $vg2 COMM "vgsplit correctly splits linear LV but not mirror LV into $i VG ($j args)" create_vg_ $vg1 "$dev1" "$dev2" "$dev3" test $i = existing && create_vg_ $vg2 "$dev5" lvcreate -l 64 -m1 -n $lv1 $vg1 "$dev1" "$dev2" "$dev3" vgextend $vg1 "$dev4" lvcreate -l 64 -n $lv2 $vg1 "$dev4" vgchange -an $vg1 if [ $j = PV ]; then vgsplit $vg1 $vg2 "$dev4" else vgsplit -n $lv2 $vg1 $vg2 fi if [ $i = existing ]; then check pvlv_counts $vg1 3 1 0 check pvlv_counts $vg2 2 1 0 else check pvlv_counts $vg1 3 1 0 check pvlv_counts $vg2 1 1 0 fi vgremove -f $vg1 $vg2 done done # # Test more complex setups where the code has to find associated PVs and # LVs to split the VG correctly # COMM "vgsplit fails splitting 3 striped LVs into VG when only 1 LV specified" create_vg_ $vg1 "$dev1" "$dev2" "$dev3" "$dev4" lvcreate -l 4 -n $lv1 -i 2 $vg1 "$dev1" "$dev2" lvcreate -l 4 -n $lv2 -i 2 $vg1 "$dev2" "$dev3" lvcreate -l 4 -n $lv3 -i 2 $vg1 "$dev3" "$dev4" vgchange -an $vg1 not vgsplit -n $lv1 $vg1 $vg2 vgremove -f $vg1 COMM "vgsplit fails splitting one LV with 2 snapshots, only origin LV specified" create_vg_ $vg1 "$dev1" "$dev2" "$dev3" "$dev4" lvcreate -l 16 -n $lv1 $vg1 "$dev1" "$dev2" lvcreate -l 4 -n $lv2 -s $vg1/$lv1 "$dev3" lvcreate -l 4 -n $lv3 -s $vg1/$lv1 "$dev4" check pvlv_counts $vg1 4 3 2 vgchange -an $vg1 not vgsplit -n $lv1 $vg1 $vg2; lvremove -f $vg1/$lv2 $vg1/$lv3 lvremove -f $vg1/$lv1 vgremove -f $vg1 COMM "vgsplit fails splitting one LV with 2 snapshots, only snapshot LV specified" create_vg_ $vg1 "$dev1" "$dev2" "$dev3" "$dev4" lvcreate -l 16 -n $lv1 $vg1 "$dev1" "$dev2" lvcreate -l 4 -n $lv2 -s $vg1/$lv1 "$dev3" lvcreate -l 4 -n $lv3 -s $vg1/$lv1 "$dev4" check pvlv_counts $vg1 4 3 2 vgchange -an $vg1 not vgsplit -n $lv2 $vg1 $vg2 lvremove -f $vg1/$lv2 $vg1/$lv3 lvremove -f $vg1/$lv1 vgremove -f $vg1 COMM "vgsplit fails splitting one mirror LV, only one PV specified" create_vg_ $vg1 "$dev1" "$dev2" "$dev3" "$dev4" lvcreate -l 16 -n $lv1 -m1 $vg1 "$dev1" "$dev2" "$dev3" check pvlv_counts $vg1 4 1 0 vgchange -an $vg1 not vgsplit $vg1 $vg2 "$dev2" vgremove -ff $vg1 COMM "vgsplit fails splitting 1 mirror + 1 striped LV, only striped LV specified" create_vg_ $vg1 "$dev1" "$dev2" "$dev3" "$dev4" lvcreate -l 16 -n $lv1 -m1 $vg1 "$dev1" "$dev2" "$dev3" lvcreate -l 16 -n $lv2 -i 2 $vg1 "$dev3" "$dev4" check pvlv_counts $vg1 4 2 0 vgchange -an $vg1 not vgsplit -n $lv2 $vg1 $vg2 2>err vgremove -f $vg1 # # Verify vgsplit rejects active LVs only when active LVs involved in split # COMM "vgsplit fails, active mirror involved in split" create_vg_ $vg1 "$dev1" "$dev2" "$dev3" "$dev4" lvcreate -l 16 -n $lv1 -m1 $vg1 "$dev1" "$dev2" "$dev3" lvcreate -l 16 -n $lv2 $vg1 "$dev4" lvchange -an $vg1/$lv2 check pvlv_counts $vg1 4 2 0 not vgsplit -n $lv1 $vg1 $vg2; check pvlv_counts $vg1 4 2 0 vgremove -f $vg1 COMM "vgsplit succeeds, active mirror not involved in split" create_vg_ $vg1 "$dev1" "$dev2" "$dev3" "$dev4" lvcreate -l 16 -n $lv1 -m1 $vg1 "$dev1" "$dev2" "$dev3" lvcreate -l 16 -n $lv2 $vg1 "$dev4" lvchange -an $vg1/$lv2 check pvlv_counts $vg1 4 2 0 vgsplit -n $lv2 $vg1 $vg2 check pvlv_counts $vg1 3 1 0 check pvlv_counts $vg2 1 1 0 vgremove -f $vg1 $vg2 COMM "vgsplit fails, active snapshot involved in split" create_vg_ $vg1 "$dev1" "$dev2" "$dev3" "$dev4" lvcreate -l 64 -i 2 -n $lv1 $vg1 "$dev1" "$dev2" lvcreate -l 4 -i 2 -s -n $lv2 $vg1/$lv1 lvcreate -l 64 -i 2 -n $lv3 $vg1 "$dev3" "$dev4" lvchange -an $vg1/$lv3 check pvlv_counts $vg1 4 3 1 not vgsplit -n $lv2 $vg1 $vg2; check pvlv_counts $vg1 4 3 1 lvremove -f $vg1/$lv2 vgremove -f $vg1 COMM "vgsplit succeeds, active snapshot not involved in split" create_vg_ $vg1 "$dev1" "$dev2" "$dev3" lvcreate -l 64 -i 2 -n $lv1 $vg1 "$dev1" "$dev2" lvcreate -l 4 -s -n $lv2 $vg1/$lv1 vgextend $vg1 "$dev4" lvcreate -l 64 -n $lv3 $vg1 "$dev4" lvchange -an $vg1/$lv3 check pvlv_counts $vg1 4 3 1 vgsplit -n $lv3 $vg1 $vg2 check pvlv_counts $vg1 3 2 1 check pvlv_counts $vg2 1 1 0 vgchange -an $vg1 lvremove -f $vg1/$lv2 vgremove -f $vg1 $vg2 lvm2-2.02.98/test/shell/lvextend-snapshot-policy.sh0000640000175000017500000000205312037016273021116 0ustar blankblank#!/bin/sh # 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 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 . lib/test which mkfs.ext2 || skip extend() { lvextend --use-policies --config "activation { snapshot_autoextend_threshold = $1 }" $vg/snap } write() { mount "$DM_DEV_DIR/$vg/snap" mnt dd if=/dev/zero of="mnt/file$1" bs=1k count=$2 umount mnt } percent() { get lv_field $vg/snap snap_percent | cut -d. -f1 } aux prepare_dmeventd aux prepare_vg 2 lvcreate -l 8 -n base $vg mkfs.ext2 "$DM_DEV_DIR/$vg/base" lvcreate -s -l 4 -n snap $vg/base mkdir mnt write 1 4096 pre=$(percent) extend 50 test $pre -eq $(percent) write 2 4096 pre=$(percent) extend 50 test $pre -gt $(percent) vgremove -f $vg lvm2-2.02.98/test/shell/vgchange-partial.sh0000640000175000017500000000212412037016273017346 0ustar blankblank#!/bin/bash # Copyright (C) 2012 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 . lib/test aux prepare_vg 2 aux disable_dev "$dev1" # # Test for allowable metadata changes # addtag_ARG # deltag_ARG vgchange --addtag foo $vg vgchange --deltag foo $vg # # Test for disallowed metadata changes # # maxphysicalvolumes_ARG not vgchange -p 10 $vg # resizeable_ARG not vgchange -x n $vg # uuid_ARG not vgchange -u $vg # physicalextentsize_ARG not vgchange -s 2M $vg # clustered_ARG not vgchange -c y $vg # alloc_ARG not vgchange --alloc anywhere $vg # vgmetadatacopies_ARG not vgchange --vgmetadatacopies 2 $vg # # Ensure that allowed args don't cause disallowed args to get through # not vgchange -p 10 --addtag foo $vg lvm2-2.02.98/test/shell/lvconvert-mirror-basic-3.sh0000640000175000017500000000077512037016272020714 0ustar blankblank#!/bin/sh # 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 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 . ./shell/lvconvert-mirror-basic.sh test_many 3 lvm2-2.02.98/test/shell/lvconvert-twostep.sh0000640000175000017500000000161712037016273017665 0ustar blankblank#!/bin/sh # 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 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 . lib/test aux prepare_vg 4 lvcreate -m 1 --mirrorlog disk --ig -L 1 -n mirror $vg not lvconvert -m 2 --mirrorlog core $vg/mirror "$dev3" 2>&1 | tee errs grep "two steps" errs lvconvert -m 2 $vg/mirror "$dev3" lvconvert --mirrorlog core $vg/mirror not lvconvert -m 1 --mirrorlog disk $vg/mirror "$dev3" 2>&1 | tee errs grep "two steps" errs not lvconvert -m 1 --mirrorlog mirrored $vg/mirror "$dev3" "$dev4" 2>&1 | tee errs grep "two steps" errs lvm2-2.02.98/test/shell/lvcreate-operation.sh0000640000175000017500000000241212037016273017735 0ustar blankblank#!/bin/sh # Copyright (C) 2008 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 # 'Exercise some lvcreate diagnostics' . lib/test cleanup_lvs() { lvremove -ff $vg (dm_table | not grep $vg) || \ die "ERROR: lvremove did leave some some mappings in DM behind!" } aux prepare_pvs 2 aux pvcreate --metadatacopies 0 "$dev1" aux vgcreate -c n $vg $(cat DEVICES) # --- # Create snapshots of LVs on --metadatacopies 0 PV (bz450651) lvcreate -n$lv1 -l4 $vg "$dev1" lvcreate -n$lv2 -l4 -s $vg/$lv1 lvcreate -n$lv3 -l4 --permission r -s $vg/$lv1 cleanup_lvs # --- # Create mirror on two devices with mirrored log using --alloc anywhere lvcreate -m 1 -l4 -n $lv1 --mirrorlog mirrored $vg --alloc anywhere "$dev1" "$dev2" cleanup_lvs # -- # Create mirror on one dev with mirrored log using --alloc anywhere, should fail not lvcreate -m 1 -l4 -n $lv1 --mirrorlog mirrored $vg --alloc anywhere "$dev1" cleanup_lvs lvm2-2.02.98/test/shell/lvresize-mirror.sh0000640000175000017500000000223012037016273017303 0ustar blankblank#!/bin/sh # 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 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 . lib/test aux prepare_vg 5 80 # extend 2-way mirror lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3":0-1 lvchange -an $vg/$lv1 lvextend -l+2 $vg/$lv1 check mirror $vg $lv1 "$dev3" check mirror_images_contiguous $vg $lv1 lvremove -ff $vg # reduce 2-way mirror lvcreate -l4 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3":0-1 lvchange -an $vg/$lv1 lvreduce -l-2 $vg/$lv1 check mirror $vg $lv1 "$dev3" lvremove -ff $vg # extend 2-way mirror (cling if not contiguous) lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3":0-1 lvcreate -l1 -n $lv2 $vg "$dev1" lvcreate -l1 -n $lv3 $vg "$dev2" lvchange -an $vg/$lv1 lvextend -l+2 $vg/$lv1 check mirror $vg $lv1 "$dev3" check mirror_images_clung $vg $lv1 lvremove -ff $vg lvm2-2.02.98/test/shell/lvcreate-mirror.sh0000640000175000017500000000274212037016273017255 0ustar blankblank#!/bin/sh # 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 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 . lib/test aux prepare_vg 5 80 aux lvmconf 'allocation/maximise_cling = 0' aux lvmconf 'allocation/mirror_logs_require_separate_pvs = 1' # 2-way mirror with corelog, 2 PVs lvcreate -l2 -m1 --mirrorlog core -n $lv1 $vg "$dev1" "$dev2" check mirror_images_redundant $vg $lv1 lvremove -ff $vg # 2-way mirror with disklog, 3 PVs lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3":0-1 check mirror_images_redundant $vg $lv1 check mirror_log_on $vg $lv1 "$dev3" lvremove -ff $vg # 3-way mirror with disklog, 4 PVs lvcreate -l2 -m2 --mirrorlog disk -n $lv1 $vg "$dev1" "$dev2" "$dev4" "$dev3":0-1 check mirror_images_redundant $vg $lv1 check mirror_log_on $vg $lv1 "$dev3" lvremove -ff $vg # lvcreate --nosync is in 100% sync after creation (bz429342) lvcreate -l2 -m1 --nosync -n $lv1 $vg "$dev1" "$dev2" "$dev3":0-1 2>out grep "New mirror won't be synchronised." out lvs -o copy_percent --noheadings $vg/$lv1 | grep 100.00 lvremove -ff $vg # creating 2-way mirror with disklog from 2 PVs fails not lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" lvm2-2.02.98/test/shell/lvcreate-large.sh0000640000175000017500000000222112037016273017025 0ustar blankblank#!/bin/sh # Copyright (C) 2011 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 # 'Exercise some lvcreate diagnostics' . lib/test aux prepare_vg 4 lvcreate -s -l 100%FREE -n $lv $vg --virtualsize 1024T #FIXME this should be 1024T #check lv_field $vg/$lv size "128.00m" aux lvmconf 'devices/filter = [ "a/dev\/mapper\/.*$/", "a/dev\/LVMTEST/", "r/.*/" ]' pvcreate $DM_DEV_DIR/$vg/$lv vgcreate -c n $vg1 $DM_DEV_DIR/$vg/$lv lvcreate -l 100%FREE -n $lv1 $vg1 check lv_field $vg1/$lv1 size "1024.00t" lvresize -f -l 72%VG $vg1/$lv1 check lv_field $vg1/$lv1 size "737.28t" lvremove -ff $vg1/$lv1 lvcreate -l 100%VG -n $lv1 $vg1 check lv_field $vg1/$lv1 size "1024.00t" lvresize -f -l 72%VG $vg1/$lv1 check lv_field $vg1/$lv1 size "737.28t" lvremove -ff $vg1/$lv1 lvremove -ff $vg/$lv lvm2-2.02.98/test/shell/pv-range-overflow.sh0000640000175000017500000000221512037016273017513 0ustar blankblank#!/bin/sh # Copyright (C) 2008-2011 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 # 'Ensure that pvmove diagnoses PE-range values 2^32 and larger.' . lib/test aux prepare_vg 2 lvcreate -L4 -n"$lv" $vg # Test for the bogus diagnostic reported in BZ 284771 # http://bugzilla.redhat.com/284771. # 'run pvmove with an unrecognized LV name to show bad diagnostic' not pvmove -v -nbogus "$dev1" "$dev2" 2> err grep "Logical volume bogus not found." err # With lvm-2.02.28 and earlier, on a system with 64-bit "long int", # the PE range parsing code would accept values up to 2^64-1, but would # silently truncate them to int32_t. I.e., $dev1:$(echo 2^32|bc) would be # treated just like $dev1:0. # 'run the offending pvmove command' not pvmove -v -n$lv "$dev1":4294967296 "$dev2" lvm2-2.02.98/test/shell/thin-autoumount-dmeventd.sh0000640000175000017500000000310412037016273021115 0ustar blankblank#!/bin/bash # Copyright (C) 2012 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 # no automatic extensions, just umount is_dir_mounted_() { cat /proc/mounts | sed 's:\\040: :g' | grep "$1" } . lib/test # # Main # which mkfs.ext2 || skip aux have_thin 1 0 0 || skip aux prepare_dmeventd aux lvmconf "activation/thin_pool_autoextend_percent = 0" \ "activation/thin_pool_autoextend_threshold = 70" aux prepare_vg 2 mntdir="${PREFIX}mnt with space" mntusedir="${PREFIX}mntuse" lvcreate -L8M -V8M -n $lv1 -T $vg/pool lvcreate -V8M -n $lv2 -T $vg/pool mkfs.ext2 "$DM_DEV_DIR/$vg/$lv1" mkfs.ext2 "$DM_DEV_DIR/$vg/$lv2" lvchange --monitor y $vg/pool mkdir "$mntdir" "$mntusedir" mount "$DM_DEV_DIR/mapper/$vg-$lv1" "$mntdir" mount "$DM_DEV_DIR/mapper/$vg-$lv2" "$mntusedir" is_dir_mounted_ "$mntdir" # fill above 70% dd if=/dev/zero of="$mntdir/file$$" bs=1M count=6 touch "$mntusedir/file$$" tail -f "$mntusedir/file$$" & PID_TAIL=$! sync lvs -a $vg sleep 12 # dmeventd only checks every 10 seconds :( lvs -a $vg # both dirs should be unmounted not is_dir_mounted "$mntdir" not is_dir_mounted "$mntusedir" # running tail keeps the block device still in use kill $PID_TAIL lvs -a $vg vgremove -f $vg lvm2-2.02.98/test/shell/lvconvert-mirror-basic-0.sh0000640000175000017500000000077512037016272020711 0ustar blankblank#!/bin/sh # 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 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 . ./shell/lvconvert-mirror-basic.sh test_many 0 lvm2-2.02.98/test/shell/snapshots-of-mirrors.sh0000640000175000017500000000224312037016273020253 0ustar blankblank#!/bin/sh # 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 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 . lib/test aux prepare_vg 4 # Attempt to create snapshot of a mirror origin - should fail lvcreate -m 1 -L 10M -n lv $vg lvcreate -s $vg/lv -L 10M -n snap # Down-convert (mirror -> linear) under a snapshot lvconvert -m0 $vg/lv # Up-convert (linear -> mirror) lvconvert -m2 $vg/lv # Down-convert (mirror -> mirror) lvconvert -m1 $vg/lv # Up-convert (mirror -> mirror) -- Not supported! not lvconvert -m2 $vg/lv # Log conversion (disk -> core) lvconvert --mirrorlog core $vg/lv # Log conversion (core -> mirrored) lvconvert --mirrorlog mirrored $vg/lv # Log conversion (mirrored -> core) lvconvert --mirrorlog core $vg/lv # Log conversion (core -> disk) lvconvert --mirrorlog disk $vg/lv ## Clean-up vgremove -f $vg lvm2-2.02.98/test/shell/lvcreate-repair.sh0000640000175000017500000000472612037016273017231 0ustar blankblank#!/bin/sh # Copyright (C) 2011-2012 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 . lib/test aux prepare_vg 3 # fail multiple devices for i in "$dev1" "$dev2" "$dev3" ; do for j in "$dev2" "$dev3" ; do if test "$i" = "$j" ; then continue ; fi vgremove -ff $vg vgcreate $vg "$dev1" "$dev2" "$dev3" # exit 1 lvcreate -l1 -n $lv1 $vg "$dev1" aux disable_dev "$i" "$j" vgreduce --removemissing --force $vg # check if reduced device was removed test "$i" = "$dev1" && dm_table | not egrep "$vg-$lv1: *[^ ]+" lvcreate -l1 -n $lv2 $vg test "$i" != "$dev1" && check lv_exists $vg $lv1 check lv_exists $vg $lv2 aux enable_dev "$i" "$j" vgscan test "$i" != "$dev1" && check lv_exists $vg $lv1 check lv_exists $vg $lv2 done done vgremove -ff $vg vgcreate $vg "$dev1" "$dev2" "$dev3" # use tricky 'dd' for i in "$dev1" "$dev2" "$dev3" ; do for j in "$dev2" "$dev3" ; do if test "$i" = "$j" ; then continue ; fi dd if="$i" of=backup_i bs=256K count=1 dd if="$j" of=backup_j bs=256K count=1 lvcreate -l1 -n $lv1 $vg "$dev1" dd if=backup_j of="$j" bs=256K count=1 dd if=backup_i of="$i" bs=256K count=1 check lv_exists $vg $lv1 # mda should be now consistent lvremove -f $vg/$lv1 done done # confuse lvm with active LV left behind dd if="$dev1" of=backup_i bs=256K count=1 dd if="$dev2" of=backup_j bs=256K count=1 lvcreate -l1 $vg "$dev1" dd if=backup_j of="$dev2" bs=256K count=1 dd if=backup_i of="$dev1" bs=256K count=1 # CHECKME: following command writes here: # vgreduce --removemissing --force $vg # # WARNING: Inconsistent metadata found for VG LVMTESTvg - updating to use version 2 # Volume group "LVMTESTvg" is already consistent # dirty game dd if=/dev/zero of="$dev3" bs=256K count=1 aux notify_lvmetad "$dev3" # udev be watching you vgreduce --removemissing --force $vg # FIXME: here is LV1 left active - but metadata does not know about it # and lvcreate does not check whether such device exists in the table # so it ends with: # # device-mapper: create ioctl failed: Device or resource busy # Failed to activate new LV. should lvcreate -l1 $vg "$dev1" lvm2-2.02.98/test/shell/lvchange-partial.sh0000640000175000017500000000263412037016272017360 0ustar blankblank#!/bin/bash # Copyright (C) 2012 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 . lib/test aux target_at_least dm-raid 1 1 0 || skip aux prepare_vg 2 lvcreate --type raid1 -m 1 -l 2 -n $lv1 $vg lvchange -an $vg/$lv1 aux disable_dev "$dev1" # # Test for allowable metadata changes # # contiguous_ARG lvchange -C y $vg/$lv1 lvchange -C n $vg/$lv1 # permission_ARG lvchange -p r $vg/$lv1 lvchange -p rw $vg/$lv1 # readahead_ARG lvchange -r none $vg/$lv1 lvchange -r auto $vg/$lv1 # persistent_ARG lvchange -M y --minor 56 --major 253 $vg/$lv1 lvchange -M n $vg/$lv1 # addtag_ARG # deltag_ARG lvchange --addtag foo $vg/$lv1 lvchange --deltag foo $vg/$lv1 # # Test for disallowed metadata changes # # resync_ARG not lvchange --resync $vg/$lv1 # alloc_ARG not lvchange --alloc anywhere $vg/$lv1 # discards_ARG not lvchange --discards ignore $vg/$lv1 # zero_ARG not lvchange --zero y $vg/$lv1 # # Ensure that allowed args don't cause disallowed args to get through # not lvchange --resync -ay $vg/$lv1 not lvchange --resync --addtag foo $vg/$lv1 lvm2-2.02.98/test/shell/pvremove-usage.sh0000640000175000017500000000407212037016273017103 0ustar blankblank#!/bin/sh # Copyright (C) 2008 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 . lib/test aux prepare_devs 3 pvcreate "$dev1" pvcreate --metadatacopies 0 "$dev2" pvcreate --metadatacopies 2 "$dev3" pvremove "$dev2" # failing, but still removing everything what can be removed # is somewhat odd as default, what do we have -f for? pvs | not grep "$dev2" pvcreate --metadatacopies 0 "$dev2" # check pvremove refuses to remove pv in a vg vgcreate -c n $vg "$dev1" "$dev2" not pvremove "$dev2" "$dev3" for mdacp in 0 1 2; do # check pvremove truly wipes the label (pvscan wont find) (---metadatacopies $mdacp) pvcreate --metadatacopies $mdacp "$dev3" pvremove "$dev3" # try to remove agail - should fail cleanly not pvremove "$dev3" pvscan | not grep "$dev3" # bz179473 refuse to wipe non-PV device without -f not pvremove "$dev3" pvremove -f "$dev3" # reset setup vgremove -ff $vg pvcreate --metadatacopies $mdacp "$dev1" pvcreate "$dev2" vgcreate $vg "$dev1" "$dev2" # pvremove -f fails when pv in a vg (---metadatacopies $mdacp) not pvremove -f "$dev1" pvs "$dev1" # pvremove -ff fails without confirmation when pv in a vg (---metadatacopies $mdacp) echo n | not pvremove -ff "$dev1" # pvremove -ff succeds with confirmation when pv in a vg (---metadatacopies $mdacp) pvremove -ffy "$dev1" not pvs "$dev1" vgreduce --removemissing $vg pvcreate --metadatacopies $mdacp "$dev1" vgextend $vg "$dev1" # pvremove -ff -y is sufficient when pv in a vg (---metadatacopies $mdacp)" ' pvremove -ff -y "$dev1" vgreduce --removemissing $vg pvcreate --metadatacopies $mdacp "$dev1" vgextend $vg "$dev1" done lvm2-2.02.98/test/shell/vgrename-usage.sh0000640000175000017500000000222712037016273017044 0ustar blankblank#!/bin/sh # Copyright (C) 2008 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 . lib/test aux prepare_devs 4 pvcreate "$dev1" "$dev2" pvcreate --metadatacopies 0 "$dev3" "$dev4" # vgrename normal operation - rename vg1 to vg2 # vgrename normal operation - rename vg2 to vg1 # ensure name ordering does not matter vgcreate $vg1 "$dev1" "$dev2" vgrename $vg1 $vg2 check vg_field $vg2 vg_name $vg2 vgrename $vg2 $vg1 check vg_field $vg1 vg_name $vg1 vgremove $vg1 # vgrename by uuid (bz231187) vgcreate $vg1 "$dev1" "$dev3" UUID=$(vgs --noheading -o vg_uuid $vg1) check vg_field $vg1 vg_uuid $UUID vgrename $UUID $vg2 check vg_field $vg2 vg_name $vg2 vgremove $vg2 # vgrename fails - new vg already exists vgcreate $vg1 "$dev1" vgcreate $vg2 "$dev2" not vgrename $vg1 $vg2 vgremove $vg1 $vg2 lvm2-2.02.98/test/shell/lvconvert-repair-transient.sh0000640000175000017500000000146612037016272021450 0ustar blankblank#!/bin/sh # Copyright (C) 2008 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 . lib/test aux prepare_vg 5 lvcreate -m 3 --ig -L 1 -n 4way $vg aux disable_dev "$dev2" "$dev4" mkfs.ext3 $DM_DEV_DIR/$vg/4way & sleep 1 aux enable_dev "$dev2" "$dev4" echo n | lvconvert --repair $vg/4way 2>&1 | tee 4way.out lvs -a -o +devices | not grep unknown vgreduce --removemissing $vg check mirror $vg 4way lvchange -a n $vg/4way wait vgremove -f $vg lvm2-2.02.98/test/shell/vgmerge-operation.sh0000640000175000017500000000436312037016273017573 0ustar blankblank#!/bin/sh # Copyright (C) 2007-2012 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 test_description='Test vgmerge operation' . lib/test aux prepare_pvs 4 64 # 'vgmerge succeeds with single linear LV in source VG' vgcreate -c n $vg1 "$dev1" "$dev2" vgcreate -c n $vg2 "$dev3" "$dev4" lvcreate -l 4 -n $lv1 $vg1 "$dev1" vgchange -an $vg1 check pvlv_counts $vg1 2 1 0 check pvlv_counts $vg2 2 0 0 vgmerge $vg2 $vg1 check pvlv_counts $vg2 4 1 0 vgremove -f $vg2 # 'vgmerge succeeds with single linear LV in source and destination VG' vgcreate -c n $vg1 "$dev1" "$dev2" vgcreate -c n $vg2 "$dev3" "$dev4" lvcreate -l 4 -n $lv1 $vg1 lvcreate -l 4 -n $lv2 $vg2 vgchange -an $vg1 vgchange -an $vg2 check pvlv_counts $vg1 2 1 0 check pvlv_counts $vg2 2 1 0 vgmerge $vg2 $vg1 check pvlv_counts $vg2 4 2 0 vgremove -f $vg2 # 'vgmerge succeeds with linear LV + snapshots in source VG' vgcreate -c n $vg1 "$dev1" "$dev2" vgcreate -c n $vg2 "$dev3" "$dev4" lvcreate -l 16 -n $lv1 $vg1 lvcreate -l 4 -s -n $lv2 $vg1/$lv1 vgchange -an $vg1 check pvlv_counts $vg1 2 2 1 check pvlv_counts $vg2 2 0 0 vgmerge $vg2 $vg1 check pvlv_counts $vg2 4 2 1 lvremove -f $vg2/$lv2 vgremove -f $vg2 # 'vgmerge succeeds with mirrored LV in source VG' vgcreate -c n $vg1 "$dev1" "$dev2" "$dev3" vgcreate -c n $vg2 "$dev4" lvcreate -l 4 -n $lv1 -m1 $vg1 vgchange -an $vg1 check pvlv_counts $vg1 3 1 0 check pvlv_counts $vg2 1 0 0 vgmerge $vg2 $vg1 check pvlv_counts $vg2 4 1 0 lvremove -f $vg2/$lv1 vgremove -f $vg2 # 'vgmerge rejects LV name collision' vgcreate -c n $vg1 "$dev1" "$dev2" vgcreate -c n $vg2 "$dev3" "$dev4" lvcreate -l 4 -n $lv1 $vg1 lvcreate -l 4 -n $lv1 $vg2 vgchange -an $vg1 check pvlv_counts $vg1 2 1 0 check pvlv_counts $vg2 2 1 0 not vgmerge $vg2 $vg1 2>err grep "Duplicate logical volume name \"$lv1\" in \"$vg2\" and \"$vg1" err check pvlv_counts $vg1 2 1 0 check pvlv_counts $vg2 2 1 0 vgremove -f $vg1 $vg2 lvm2-2.02.98/test/shell/lvcreate-striped-mirror.sh0000640000175000017500000000377212037016273020731 0ustar blankblank#!/bin/sh # 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 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 . lib/test aux prepare_vg 9 lvcreate -i2 -l2 -m1 --mirrorlog core -n $lv1 $vg 2>&1 | tee log not grep "Rounding" log check mirror_images_redundant $vg $lv1 lvremove -ff $vg lvcreate -i2 -l4 -m1 --mirrorlog core -n $lv1 $vg 2>&1 | tee log not grep "Rounding" log check mirror_images_redundant $vg $lv1 lvremove -ff $vg lvcreate -i3 -l3 -m1 --mirrorlog core -n $lv1 $vg 2>&1 | tee log not grep "Rounding" log check mirror_images_redundant $vg $lv1 lvremove -ff $vg lvcreate -i4 -l4 -m1 --mirrorlog core -n $lv1 $vg 2>&1 | tee log not grep "Rounding" log check mirror_images_redundant $vg $lv1 lvremove -ff $vg lvcreate -i2 -l2 -m2 --mirrorlog core -n $lv1 $vg 2>&1 | tee log not grep "Rounding" log check mirror_images_redundant $vg $lv1 lvremove -ff $vg lvcreate -i3 -l3 -m2 --mirrorlog core -n $lv1 $vg 2>&1 | tee log not grep "Rounding" log check mirror_images_redundant $vg $lv1 lvremove -ff $vg lvcreate -i2 -l2 -m3 --mirrorlog core -n $lv1 $vg 2>&1 | tee log not grep "Rounding" log check mirror_images_redundant $vg $lv1 lvremove -ff $vg lvcreate -i3 -l2 -m2 --mirrorlog core -n $lv1 $vg 2>&1 | tee log grep "Rounding size (2 extents) up to .* (3 extents)" log lvremove -ff $vg lvcreate -i3 -l4 -m2 --mirrorlog core -n $lv1 $vg 2>&1 | tee log grep "Rounding size (4 extents) up to .* (6 extents)" log lvremove -ff $vg lvcreate -i3 -l4 -m1 --mirrorlog core -n $lv1 $vg 2>&1 | tee log grep "Rounding size (4 extents) up to .* (6 extents)" log lvremove -ff $vg lvcreate -i4 -l4 -m1 --mirrorlog core -n $lv1 $vg 2>&1 | tee log not grep "Rounding" log lvremove -ff $vg lvm2-2.02.98/test/shell/lvconvert-repair-dmeventd.sh0000640000175000017500000000146712037016272021250 0ustar blankblank#!/bin/sh # Copyright (C) 2008 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 . lib/test which mkfs.ext2 || skip aux prepare_vg 5 aux prepare_dmeventd lvcreate -m 3 --ig -L 1 -n 4way $vg lvchange --monitor y $vg/4way aux disable_dev "$dev2" "$dev4" mkfs.ext2 $DM_DEV_DIR/$vg/4way sleep 10 # FIXME: need a "poll" utility, akin to "check" aux enable_dev "$dev2" "$dev4" check mirror $vg 4way check mirror_legs $vg 4way 2 vgremove -ff $vg lvm2-2.02.98/test/shell/vgsplit-usage.sh0000640000175000017500000001314312037016273016727 0ustar blankblank#!/bin/sh # Copyright (C) 2007-2011 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 # Test vgsplit command options for validity . lib/test aux prepare_devs 5 for mdatype in 1 2 do pvcreate -M$mdatype $(cat DEVICES) # ensure name order does not matter # NOTE: if we're using lvm1, we must use -M on vgsplit vgcreate -M$mdatype $vg1 $(cat DEVICES) vgsplit -M$mdatype $vg1 $vg2 "$dev1" vgremove $vg1 $vg2 vgcreate -M$mdatype $vg2 $(cat DEVICES) vgsplit -M$mdatype $vg2 $vg1 "$dev1" vgremove $vg1 $vg2 # vgsplit accepts new vg as destination of split # lvm1 -- bz244792 vgcreate -M$mdatype $vg1 $(cat DEVICES) vgsplit $vg1 $vg2 "$dev1" 1>err grep "New volume group \"$vg2\" successfully split from \"$vg1\"" err vgremove $vg1 $vg2 # vgsplit accepts existing vg as destination of split vgcreate -M$mdatype $vg1 "$dev1" "$dev2" vgcreate -M$mdatype $vg2 "$dev3" "$dev4" vgsplit $vg1 $vg2 "$dev1" 1>err grep "Existing volume group \"$vg2\" successfully split from \"$vg1\"" err vgremove $vg1 $vg2 # vgsplit accepts --maxphysicalvolumes 128 on new VG vgcreate -M$mdatype $vg1 "$dev1" "$dev2" vgsplit --maxphysicalvolumes 128 $vg1 $vg2 "$dev1" check vg_field $vg2 max_pv 128 vgremove $vg1 $vg2 # vgsplit accepts --maxlogicalvolumes 128 on new VG vgcreate -M$mdatype $vg1 "$dev1" "$dev2" vgsplit --maxlogicalvolumes 128 $vg1 $vg2 "$dev1" check vg_field $vg2 max_lv 128 vgremove $vg1 $vg2 # vgsplit rejects split because max_pv of destination would be exceeded vgcreate -M$mdatype --maxphysicalvolumes 2 $vg1 "$dev1" "$dev2" vgcreate -M$mdatype --maxphysicalvolumes 2 $vg2 "$dev3" "$dev4" not vgsplit $vg1 $vg2 "$dev1" 2>err; grep "Maximum number of physical volumes (2) exceeded" err vgremove $vg1 $vg2 # vgsplit rejects split because maxphysicalvolumes given with existing vg vgcreate -M$mdatype --maxphysicalvolumes 2 $vg1 "$dev1" "$dev2" vgcreate -M$mdatype --maxphysicalvolumes 2 $vg2 "$dev3" "$dev4" not vgsplit --maxphysicalvolumes 2 $vg1 $vg2 "$dev1" 2>err; grep "Volume group \"$vg2\" exists, but new VG option specified" err vgremove $vg1 $vg2 # vgsplit rejects split because maxlogicalvolumes given with existing vg vgcreate -M$mdatype --maxlogicalvolumes 2 $vg1 "$dev1" "$dev2" vgcreate -M$mdatype --maxlogicalvolumes 2 $vg2 "$dev3" "$dev4" not vgsplit --maxlogicalvolumes 2 $vg1 $vg2 "$dev1" 2>err grep "Volume group \"$vg2\" exists, but new VG option specified" err vgremove $vg1 $vg2 # vgsplit rejects split because alloc given with existing vg vgcreate -M$mdatype --alloc cling $vg1 "$dev1" "$dev2" vgcreate -M$mdatype --alloc cling $vg2 "$dev3" "$dev4" not vgsplit --alloc cling $vg1 $vg2 "$dev1" 2>err; grep "Volume group \"$vg2\" exists, but new VG option specified" err vgremove $vg1 $vg2 # vgsplit rejects split because clustered given with existing vg vgcreate -M$mdatype --clustered n $vg1 "$dev1" "$dev2" vgcreate -M$mdatype --clustered n $vg2 "$dev3" "$dev4" not vgsplit --clustered n $vg1 $vg2 "$dev1" 2>err grep "Volume group \"$vg2\" exists, but new VG option specified" err vgremove $vg1 $vg2 # vgsplit rejects vg with active lv pvcreate -M$mdatype -ff "$dev3" "$dev4" vgcreate -M$mdatype $vg1 "$dev1" "$dev2" vgcreate -M$mdatype $vg2 "$dev3" "$dev4" lvcreate -l 4 -n $lv1 $vg1 not vgsplit $vg1 $vg2 "$dev1" 2>err; grep "Logical volumes in \"$vg1\" must be inactive\$" err vgremove -f $vg1 $vg2 # vgsplit rejects split because max_lv is exceeded vgcreate -M$mdatype --maxlogicalvolumes 2 $vg1 "$dev1" "$dev2" vgcreate -M$mdatype --maxlogicalvolumes 2 $vg2 "$dev3" "$dev4" lvcreate -l 4 -n $lv1 $vg1 lvcreate -l 4 -n $lv2 $vg1 lvcreate -l 4 -n $lv3 $vg2 vgchange -an $vg1 $vg2 not vgsplit $vg1 $vg2 "$dev1" 2>err; grep "Maximum number of logical volumes (2) exceeded" err vgremove -f $vg1 $vg2 # vgsplit verify default - max_lv attribute from new VG is same as source VG" \ vgcreate -M$mdatype $vg1 "$dev1" "$dev2" lvcreate -l 4 -n $lv1 $vg1 vgchange -an $vg1 vgsplit $vg1 $vg2 "$dev1" check compare_vg_field $vg1 $vg2 max_lv vgremove -f $vg1 $vg2 # vgsplit verify default - max_pv attribute from new VG is same as source VG" \ vgcreate -M$mdatype $vg1 "$dev1" "$dev2" lvcreate -l 4 -n $lv1 $vg1 vgchange -an $vg1 vgsplit $vg1 $vg2 "$dev1" check compare_vg_field $vg1 $vg2 max_pv vgremove -f $vg1 $vg2 # vgsplit verify default - vg_fmt attribute from new VG is same as source VG" \ vgcreate -M$mdatype $vg1 "$dev1" "$dev2" lvcreate -l 4 -n $lv1 $vg1 vgchange -an $vg1 vgsplit $vg1 $vg2 "$dev1" check compare_vg_field $vg1 $vg2 vg_fmt vgremove -f $vg2 $vg1 # vgsplit rejects split because PV not in VG vgcreate -M$mdatype $vg1 "$dev1" "$dev2" vgcreate -M$mdatype $vg2 "$dev3" "$dev4" lvcreate -l 4 -n $lv1 $vg1 lvcreate -l 4 -n $lv2 $vg1 vgchange -an $vg1 not vgsplit $vg1 $vg2 "$dev3" 2>err; vgremove -f $vg2 $vg1 done # ONLY LVM2 metadata # setup PVs" ' pvcreate --metadatacopies 0 "$dev5" # vgsplit rejects to give away pv with the last mda copy vgcreate $vg1 "$dev5" "$dev2" lvcreate -l 10 -n $lv1 $vg1 lvchange -an $vg1/$lv1 check pvlv_counts $vg1 2 1 0 not vgsplit $vg1 $vg2 "$dev5"; check pvlv_counts $vg1 2 1 0 vgremove -f $vg1 # vgsplit rejects split because metadata types differ pvcreate -ff -M1 "$dev3" "$dev4" pvcreate -ff "$dev1" "$dev2" vgcreate -M1 $vg1 "$dev3" "$dev4" vgcreate $vg2 "$dev1" "$dev2" not vgsplit $vg1 $vg2 "$dev3" 2>err; grep "Metadata types differ" err vgremove -f $vg1 $vg2 lvm2-2.02.98/test/shell/lvconvert-thin.sh0000640000175000017500000000211012037016273017107 0ustar blankblank#!/bin/sh # Copyright (C) 2012 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 . lib/test # # Main # aux have_thin 1 0 0 || skip aux prepare_pvs 4 64 vgcreate $vg -s 64K $(cat DEVICES) # create mirrored LVs for data and metadata volumes lvcreate -aey -l8 -m1 --mirrorlog core -n $lv1 $vg lvcreate -aey -l4 -m1 --mirrorlog core -n $lv2 $vg lvconvert -c 64K --thinpool $vg/$lv1 --poolmetadata $vg/$lv2 lvcreate -V10M -T $vg/$lv1 --name $lv3 # check lvrename work properly lvrename $vg/$lv1 $vg/pool check lv_field $vg/pool name "pool" lvrename $vg/$lv3 $vg/$lv4 check lv_field $vg/$lv4 name "$lv4" # not yet supported conversions not lvconvert -m 1 $vg/pool not lvconvert -m 1 $vg/$lv3 vgremove -ff $vg lvm2-2.02.98/test/shell/pvcreate-metadata0.sh0000640000175000017500000000157112037016273017606 0ustar blankblank#!/bin/sh # Copyright (C) 2008 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 # # Testcase for bugzilla #450651 # also checks that vgremove properly removes all lv devices in the right order # # 'Test pvcreate without metadata on all pvs' . lib/test aux prepare_devs 2 128 #lv_snap=$lv2 pvcreate "$dev1" pvcreate --metadatacopies 0 "$dev2" # "check lv snapshot" vgcreate -c n $vg "$dev1" "$dev2" lvcreate -n $lv -l 60%FREE $vg lvcreate -s -n $lv2 -l 10%FREE $vg/$lv pvdisplay lvdisplay vgremove -f $vg lvm2-2.02.98/test/shell/pvmove-basic.sh0000640000175000017500000002503412037016273016532 0ustar blankblank#!/bin/sh # Copyright (C) 2008-2012 Red Hat, Inc. All rights reserved. # Copyright (C) 2007 NEC Corporation # # 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 test_description="ensure that pvmove works with basic options" . lib/test which mkfs.ext2 || skip which md5sum || skip # --------------------------------------------------------------------- # Utilities lvdev_() { echo "$DM_DEV_DIR/$1/$2" } lv_is_on_() { local lv=$1 #allready vg/lv shift 1 lvs -a -odevices --noheadings $lv | sed 's/,/\n/g' > out #is on all specified devs for d in $*; do grep "$d(" out; done #isn't on any other dev (we are set -e remember) for d in $*; do ! grep -v "$d(" out; done return 0 } save_dev_sum_() { mkfs.ext2 $1 > /dev/null && md5sum $1 > md5.$(basename $1) } check_dev_sum_() { md5sum -c md5.$(basename $1) } create_vg_() { vgcreate -c n -s 128k $vg $(cat DEVICES) } # --------------------------------------------------------------------- # Initialize PVs and VGs #aux prepare_vg 5 30 aux prepare_pvs 5 5 create_vg_ # --------------------------------------------------------------------- # Common environment setup/cleanup for each sub testcases FIRST="" prepare_lvs_() { lvcreate -l2 -n $lv1 $vg "$dev1" test -z "$FIRST" && lv_is_on_ $vg/$lv1 "$dev1" lvcreate -l9 -i3 -n $lv2 $vg "$dev2" "$dev3" "$dev4" test -z "$FIRST" && lv_is_on_ $vg/$lv2 "$dev2" "$dev3" "$dev4" lvextend -l+2 $vg/$lv1 "$dev2" test -z "$FIRST" && lv_is_on_ $vg/$lv1 "$dev1" "$dev2" lvextend -l+2 $vg/$lv1 "$dev3" test -z "$FIRST" && lv_is_on_ $vg/$lv1 "$dev1" "$dev2" "$dev3" lvextend -l+2 $vg/$lv1 "$dev1" test -z "$FIRST" && lv_is_on_ $vg/$lv1 "$dev1" "$dev2" "$dev3" "$dev1" lvcreate -l1 -n $lv3 $vg "$dev2" test -z "$FIRST" && lv_is_on_ $vg/$lv3 "$dev2" save_dev_sum_ $(lvdev_ $vg $lv1) save_dev_sum_ $(lvdev_ $vg $lv2) save_dev_sum_ $(lvdev_ $vg $lv3) if test -z "$FIRST" ; then get lv_field $vg/$lv1 devices > ${lv1}_devs get lv_field $vg/$lv2 devices > ${lv2}_devs get lv_field $vg/$lv3 devices > ${lv3}_devs fi FIRST=done } lv_not_changed_() { get lv_field $1 devices > out diff $(basename $1)_devs out } check_and_cleanup_lvs_() { lvs -a -o+devices $vg check_dev_sum_ $(lvdev_ $vg $lv1) check_dev_sum_ $(lvdev_ $vg $lv2) check_dev_sum_ $(lvdev_ $vg $lv3) lvs -a -o name $vg > out && ! grep ^pvmove out lvremove -ff $vg (dm_table | not grep $vg) || \ die "ERROR: lvremove did leave some some mappings in DM behind!" } #COMM "check environment setup/cleanup" prepare_lvs_ check_and_cleanup_lvs_ # --------------------------------------------------------------------- # pvmove tests # --- # filter by LV #COMM "only specified LV is moved: from pv2 to pv5 only for lv1" prepare_lvs_ pvmove -i1 -n $vg/$lv1 "$dev2" "$dev5" lv_is_on_ $vg/$lv1 "$dev1" "$dev5" "$dev3" "$dev1" lv_not_changed_ $vg/$lv2 lv_not_changed_ $vg/$lv3 check_and_cleanup_lvs_ # --- # segments in a LV #COMM "the 1st seg of 3-segs LV is moved: from pv1 of lv1 to pv4" prepare_lvs_ pvmove -i0 -n $vg/$lv1 "$dev1" "$dev4" lv_is_on_ $vg/$lv1 "$dev4" "$dev2" "$dev3" "$dev4" lv_not_changed_ $vg/$lv2 lv_not_changed_ $vg/$lv3 check_and_cleanup_lvs_ #COMM "the 2nd seg of 3-segs LV is moved: from pv2 of lv1 to pv4" prepare_lvs_ pvmove -i0 -n $vg/$lv1 "$dev2" "$dev4" lv_is_on_ $vg/$lv1 "$dev1" "$dev4" "$dev3" "$dev1" lv_not_changed_ $vg/$lv2 lv_not_changed_ $vg/$lv3 check_and_cleanup_lvs_ #COMM "the 3rd seg of 3-segs LV is moved: from pv3 of lv1 to pv4" prepare_lvs_ pvmove -i0 -n $vg/$lv1 "$dev3" "$dev4" lv_is_on_ $vg/$lv1 "$dev1" "$dev2" "$dev4" "$dev1" lv_not_changed_ $vg/$lv2 lv_not_changed_ $vg/$lv3 check_and_cleanup_lvs_ # --- # multiple LVs matching #COMM "1 out of 3 LVs is moved: from pv4 to pv5" prepare_lvs_ pvmove -i0 "$dev4" "$dev5" lv_not_changed_ $vg/$lv1 lv_is_on_ $vg/$lv2 "$dev2" "$dev3" "$dev5" lv_not_changed_ $vg/$lv3 check_and_cleanup_lvs_ #COMM "2 out of 3 LVs are moved: from pv3 to pv5" prepare_lvs_ pvmove -i0 "$dev3" "$dev5" lv_is_on_ $vg/$lv1 "$dev1" "$dev2" "$dev5" "$dev1" lv_is_on_ $vg/$lv2 "$dev2" "$dev5" "$dev4" lv_not_changed_ $vg/$lv3 check_and_cleanup_lvs_ #COMM "3 out of 3 LVs are moved: from pv2 to pv5" prepare_lvs_ pvmove -i0 "$dev2" "$dev5" lv_is_on_ $vg/$lv1 "$dev1" "$dev5" "$dev3" "$dev1" lv_is_on_ $vg/$lv2 "$dev5" "$dev3" "$dev4" lv_is_on_ $vg/$lv3 "$dev5" check_and_cleanup_lvs_ # --- # areas of striping #COMM "move the 1st stripe: from pv2 of lv2 to pv1" prepare_lvs_ pvmove -i0 -n $vg/$lv2 "$dev2" "$dev1" lv_not_changed_ $vg/$lv1 lv_is_on_ $vg/$lv2 "$dev1" "$dev3" "$dev4" lv_not_changed_ $vg/$lv3 check_and_cleanup_lvs_ #COMM "move the 2nd stripe: from pv3 of lv2 to pv1" prepare_lvs_ pvmove -i0 -n $vg/$lv2 "$dev3" "$dev1" lv_not_changed_ $vg/$lv1 lv_is_on_ $vg/$lv2 "$dev2" "$dev1" "$dev4" lv_not_changed_ $vg/$lv3 check_and_cleanup_lvs_ #COMM "move the 3rd stripe: from pv4 of lv2 to pv1" prepare_lvs_ pvmove -i0 -n $vg/$lv2 "$dev4" "$dev1" lv_not_changed_ $vg/$lv1 lv_is_on_ $vg/$lv2 "$dev2" "$dev3" "$dev1" lv_not_changed_ $vg/$lv3 check_and_cleanup_lvs_ # --- # partial segment match (source segment splitted) #COMM "match to the start of segment:from pv2:0-0 to pv5" prepare_lvs_ pvmove -i0 "$dev2":0-0 "$dev5" lv_not_changed_ $vg/$lv1 lv_is_on_ $vg/$lv2 "$dev5" "$dev2" "$dev3" "$dev4" lv_not_changed_ $vg/$lv3 check_and_cleanup_lvs_ #COMM "match to the middle of segment: from pv2:1-1 to pv5" prepare_lvs_ pvmove -i0 "$dev2":1-1 "$dev5" lv_not_changed_ $vg/$lv1 lv_is_on_ $vg/$lv2 "$dev2" "$dev5" "$dev2" "$dev3" "$dev4" lv_not_changed_ $vg/$lv3 check_and_cleanup_lvs_ #COMM "match to the end of segment: from pv2:2-2 to pv5" prepare_lvs_ pvmove -i0 "$dev2":2-2 "$dev5" lv_not_changed_ $vg/$lv1 lv_is_on_ $vg/$lv2 "$dev2" "$dev5" "$dev3" "$dev4" lv_not_changed_ $vg/$lv3 check_and_cleanup_lvs_ # --- # destination segment splitted #COMM "no destination split: from pv2:0-2 to pv5" prepare_lvs_ pvmove -i0 "$dev2":0-2 "$dev5" lv_not_changed_ $vg/$lv1 lv_is_on_ $vg/$lv2 "$dev5" "$dev3" "$dev4" lv_not_changed_ $vg/$lv3 check_and_cleanup_lvs_ #COMM "destination split into 2: from pv2:0-2 to pv5:5-5 and pv4:5-6" prepare_lvs_ pvmove -i0 --alloc anywhere "$dev2":0-2 "$dev5":5-5 "$dev4":5-6 lv_not_changed_ $vg/$lv1 lv_is_on_ $vg/$lv2 "$dev5" "$dev4" "$dev3" "$dev4" lv_not_changed_ $vg/$lv3 check_and_cleanup_lvs_ #COMM "destination split into 3: from pv2:0-2 to {pv3,4,5}:5-5" prepare_lvs_ pvmove -i0 --alloc anywhere "$dev2":0-2 "$dev3":5-5 "$dev4":5-5 "$dev5":5-5 lv_not_changed_ $vg/$lv1 lv_is_on_ $vg/$lv2 "$dev3" "$dev4" "$dev5" "$dev3" "$dev4" lv_not_changed_ $vg/$lv3 check_and_cleanup_lvs_ # --- # alloc policy (anywhere, contiguous) with both success and failure cases #COMM "alloc normal on same PV for source and destination: from pv3:0-2 to pv3:5-7" prepare_lvs_ not pvmove -i0 "$dev3":0-2 "$dev3":5-7 # "(cleanup previous test)" lv_not_changed_ $vg/$lv1 lv_not_changed_ $vg/$lv2 lv_not_changed_ $vg/$lv3 check_and_cleanup_lvs_ #COMM "alloc anywhere on same PV for source and destination: from pv3:0-2 to pv3:5-7" prepare_lvs_ pvmove -i0 --alloc anywhere "$dev3":0-2 "$dev3":5-7 lv_not_changed_ $vg/$lv1 lv_is_on_ $vg/$lv2 "$dev2" "$dev3" "$dev4" lv_not_changed_ $vg/$lv3 check_and_cleanup_lvs_ #COMM "alloc anywhere but better area available: from pv3:0-2 to pv3:5-7 or pv5:5-6,pv4:5-5" prepare_lvs_ pvmove -i0 --alloc anywhere "$dev3":0-2 "$dev3":5-7 "$dev5":5-6 "$dev4":5-5 lv_not_changed_ $vg/$lv1 #lv_is_on_ $vg/$lv2 "$dev2" "$dev5" "$dev4" "$dev4" lv_not_changed_ $vg/$lv3 check_and_cleanup_lvs_ #COMM "alloc contiguous but area not available: from pv2:0-2 to pv5:5-5 and pv4:5-6" prepare_lvs_ not pvmove -i0 --alloc contiguous "$dev2":0-2 "$dev5":5-5 "$dev4":5-6 # "(cleanup previous test)" lv_not_changed_ $vg/$lv1 lv_not_changed_ $vg/$lv2 lv_not_changed_ $vg/$lv3 check_and_cleanup_lvs_ #COMM "alloc contiguous and contiguous area available: from pv2:0-2 to pv5:0-0,pv5:3-5 and pv4:5-6" prepare_lvs_ pvmove -i0 --alloc contiguous "$dev2":0-2 "$dev5":0-0 "$dev5":3-5 "$dev4":5-6 lv_not_changed_ $vg/$lv1 lv_is_on_ $vg/$lv2 "$dev5" "$dev3" "$dev4" lv_not_changed_ $vg/$lv3 check_and_cleanup_lvs_ # --- # multiple segments in a LV #COMM "multiple source LVs: from pv3 to pv5" prepare_lvs_ pvmove -i0 "$dev3" "$dev5" lv_is_on_ $vg/$lv1 "$dev1" "$dev2" "$dev5" lv_is_on_ $vg/$lv2 "$dev2" "$dev5" "$dev4" lv_not_changed_ $vg/$lv3 check_and_cleanup_lvs_ # --- # move inactive LV #COMM "move inactive LV: from pv2 to pv5" prepare_lvs_ lvchange -an $vg/$lv1 lvchange -an $vg/$lv3 pvmove -i0 "$dev2" "$dev5" lv_is_on_ $vg/$lv1 "$dev1" "$dev5" "$dev3" lv_is_on_ $vg/$lv2 "$dev5" "$dev3" "$dev4" lv_is_on_ $vg/$lv3 "$dev5" check_and_cleanup_lvs_ # --- # other failure cases #COMM "no PEs to move: from pv3 to pv1" prepare_lvs_ pvmove -i0 "$dev3" "$dev1" not pvmove -i0 "$dev3" "$dev1" # "(cleanup previous test)" lv_is_on_ $vg/$lv1 "$dev1" "$dev2" "$dev1" lv_is_on_ $vg/$lv2 "$dev2" "$dev1" "$dev4" lv_not_changed_ $vg/$lv3 check_and_cleanup_lvs_ #COMM "no space available: from pv2:0-0 to pv1:0-0" prepare_lvs_ not pvmove -i0 "$dev2":0-0 "$dev1":0-0 # "(cleanup previous test)" lv_not_changed_ $vg/$lv1 lv_not_changed_ $vg/$lv2 lv_not_changed_ $vg/$lv3 check_and_cleanup_lvs_ #COMM 'same source and destination: from pv1 to pv1' prepare_lvs_ not pvmove -i0 "$dev1" "$dev1" #"(cleanup previous test)" lv_not_changed_ $vg/$lv1 lv_not_changed_ $vg/$lv2 lv_not_changed_ $vg/$lv3 check_and_cleanup_lvs_ #COMM "sum of specified destination PEs is large enough, but it includes source PEs and the free PEs are not enough" prepare_lvs_ not pvmove --alloc anywhere "$dev1":0-2 "$dev1":0-2 "$dev5":0-0 2> err #"(cleanup previous test)" grep "Insufficient free space" err lv_not_changed_ $vg/$lv1 lv_not_changed_ $vg/$lv2 lv_not_changed_ $vg/$lv3 check_and_cleanup_lvs_ # --------------------------------------------------------------------- #COMM "pvmove abort" prepare_lvs_ pvmove -i100 -b "$dev1" "$dev3" pvmove --abort check_and_cleanup_lvs_ #COMM "pvmove out of --metadatacopies 0 PV (bz252150)" vgremove -ff $vg pvcreate $(cat DEVICES) pvcreate --metadatacopies 0 "$dev1" "$dev2" create_vg_ lvcreate -l4 -n $lv1 $vg "$dev1" pvmove "$dev1" #COMM "pvmove fails activating mirror, properly restores state before pvmove" dmsetup create $vg-pvmove0 --notable not pvmove -i 1 "$dev2" test $(dmsetup info --noheadings -c -o suspended $vg-$lv1) = "Active" dmsetup remove $vg-pvmove0 lvm2-2.02.98/test/shell/lvconvert-repair.sh0000640000175000017500000000747012037016273017445 0ustar blankblank#!/bin/sh # Copyright (C) 2008 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 . lib/test recreate_vg_() { vgremove -ff $vg vgcreate -c n $vg $(cat DEVICES) } aux lvmconf 'allocation/maximise_cling = 0' aux lvmconf 'allocation/mirror_logs_require_separate_pvs = 1' # fail multiple devices # 4-way, disk log => 2-way, disk log aux prepare_vg 8 lvcreate -m 3 --ig -L 1 -n 4way $vg "$dev1" "$dev2" "$dev3" "$dev4" "$dev5":0 aux disable_dev "$dev2" "$dev4" echo n | lvconvert --repair $vg/4way 2>&1 | tee 4way.out lvs -a -o +devices $vg | not grep unknown vgreduce --removemissing $vg aux enable_dev "$dev2" "$dev4" check mirror $vg 4way "$dev5" # 3-way, disk log => linear recreate_vg_ lvcreate -m 2 --ig -L 1 -n 3way $vg aux disable_dev "$dev1" "$dev2" echo n | lvconvert --repair $vg/3way check linear $vg 3way lvs -a -o +devices $vg | not grep unknown lvs -a -o +devices $vg | not grep mlog dmsetup ls | grep $PREFIX | not grep mlog vgreduce --removemissing $vg aux enable_dev "$dev1" "$dev2" check linear $vg 3way # fail just log and get it removed # 3-way, disk log => 3-way, core log recreate_vg_ lvcreate -m 2 --ig -L 1 -n 3way $vg "$dev1" "$dev2" "$dev3" "$dev4":0 aux disable_dev "$dev4" echo n | lvconvert --repair $vg/3way check mirror $vg 3way core lvs -a -o +devices $vg | not grep unknown lvs -a -o +devices $vg | not grep mlog dmsetup ls | grep $PREFIX | not grep mlog vgreduce --removemissing $vg aux enable_dev "$dev4" # 3-way, mirrored log => 3-way, core log recreate_vg_ lvcreate -m 2 --mirrorlog mirrored --ig -L 1 -n 3way $vg \ "$dev1" "$dev2" "$dev3" "$dev4":0 "$dev5":0 aux disable_dev "$dev4" "$dev5" echo n | lvconvert --repair $vg/3way check mirror $vg 3way core lvs -a -o +devices $vg | not grep unknown lvs -a -o +devices $vg | not grep mlog dmsetup ls | grep $PREFIX | not grep mlog vgreduce --removemissing $vg aux enable_dev "$dev4" "$dev5" # 2-way, disk log => 2-way, core log recreate_vg_ lvcreate -m 1 --ig -L 1 -n 2way $vg "$dev1" "$dev2" "$dev3":0 aux disable_dev "$dev3" echo n | lvconvert --repair $vg/2way check mirror $vg 2way core lvs -a -o +devices $vg | not grep unknown lvs -a -o +devices $vg | not grep mlog vgreduce --removemissing $vg aux enable_dev "$dev3" # fail single devices recreate_vg_ vgreduce $vg "$dev4" lvcreate -m 1 --ig -L 1 -n mirror $vg lvchange -a n $vg/mirror vgextend $vg "$dev4" aux disable_dev "$dev1" lvchange --partial -a y $vg/mirror not vgreduce -v --removemissing $vg lvconvert -y --repair $vg/mirror vgreduce --removemissing $vg aux enable_dev "$dev1" vgextend $vg "$dev1" aux disable_dev "$dev2" lvconvert -y --repair $vg/mirror vgreduce --removemissing $vg aux enable_dev "$dev2" vgextend $vg "$dev2" aux disable_dev "$dev3" lvconvert -y --repair $vg/mirror vgreduce --removemissing $vg aux enable_dev "$dev3" vgextend $vg "$dev3" lvremove -ff $vg if aux target_at_least dm-raid 1 1 0; then # RAID5 single replace lvcreate --type raid5 -i 2 -l 2 -n $lv1 $vg "$dev1" "$dev2" "$dev3" aux wait_for_sync $vg $lv1 aux disable_dev "$dev3" lvconvert -y --repair $vg/$lv1 vgreduce --removemissing $vg aux enable_dev "$dev3" vgextend $vg "$dev3" lvremove -ff $vg # RAID6 double replace lvcreate --type raid5 -i 3 -l 2 -n $lv1 $vg \ "$dev1" "$dev2" "$dev3" "$dev4" "$dev5" aux wait_for_sync $vg $lv1 aux disable_dev "$dev4" "$dev5" lvconvert -y --repair $vg/$lv1 vgreduce --removemissing $vg aux enable_dev "$dev4" aux enable_dev "$dev5" vgextend $vg "$dev4" "$dev5" lvremove -ff $vg fi vgremove -ff $vg lvm2-2.02.98/test/shell/pvcreate-operation.sh0000640000175000017500000001020612037016273017741 0ustar blankblank# Copyright (C) 2008 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 . lib/test aux lvmconf 'devices/md_component_detection = 1' aux prepare_devs 4 for mdatype in 1 2 do # pvcreate (lvm$mdatype) refuses to overwrite an mounted filesystem (bz168330) test ! -d mnt && mkdir mnt if mke2fs "$dev1"; then mount "$dev1" mnt not pvcreate -M$mdatype "$dev1" 2>err grep "Can't open "$dev1" exclusively. Mounted filesystem?" err umount "$dev1" fi # pvcreate (lvm$mdatype) succeeds when run repeatedly (pv not in a vg) (bz178216) pvcreate -M$mdatype "$dev1" pvcreate -M$mdatype "$dev1" pvremove -f "$dev1" # pvcreate (lvm$mdatype) fails when PV belongs to VG # pvcreate -M$mdatype "$dev1" vgcreate -M$mdatype $vg1 "$dev1" not pvcreate -M$mdatype "$dev1" vgremove -f $vg1 pvremove -f "$dev1" # pvcreate (lvm$mdatype) fails when PV1 does and PV2 does not belong to VG pvcreate -M$mdatype "$dev1" pvcreate -M$mdatype "$dev2" vgcreate -M$mdatype $vg1 "$dev1" # pvcreate a second time on $dev2 and $dev1 not pvcreate -M$mdatype "$dev2" "$dev1" vgremove -f $vg1 pvremove -f "$dev2" "$dev1" # NOTE: Force pvcreate after test completion to ensure clean device #test_expect_success # "pvcreate (lvm$mdatype) fails on md component device" # 'mdadm -C -l raid0 -n 2 /dev/md0 "$dev1" "$dev2" && # pvcreate -M$mdatype "$dev1"; # status=$?; echo status=$status; test $status != 0 && # mdadm --stop /dev/md0 && # pvcreate -ff -y -M$mdatype "$dev1" "$dev2" && # pvremove -f "$dev1" "$dev2"' done # pvcreate (lvm2) fails without -ff when PV with metadatacopies=0 belongs to VG pvcreate --metadatacopies 0 "$dev1" pvcreate --metadatacopies 1 "$dev2" vgcreate $vg1 "$dev1" "$dev2" not pvcreate "$dev1" vgremove -f $vg1 pvremove -f "$dev2" "$dev1" # pvcreate (lvm2) succeeds with -ff when PV with metadatacopies=0 belongs to VG pvcreate --metadatacopies 0 "$dev1" pvcreate --metadatacopies 1 "$dev2" vgcreate $vg1 "$dev1" "$dev2" pvcreate -ff -y "$dev1" vgreduce --removemissing $vg1 vgremove -ff $vg1 pvremove -f "$dev2" "$dev1" for i in 0 1 2 3 do # pvcreate (lvm2) succeeds writing LVM label at sector $i pvcreate --labelsector $i "$dev1" dd if="$dev1" bs=512 skip=$i count=1 2>/dev/null | strings | grep LABELONE >/dev/null pvremove -f "$dev1" done # pvcreate (lvm2) fails writing LVM label at sector 4 not pvcreate --labelsector 4 "$dev1" backupfile=$PREFIX.mybackupfile uuid1=freddy-fred-fred-fred-fred-fred-freddy uuid2=freddy-fred-fred-fred-fred-fred-fredie bogusuuid=fred # pvcreate rejects uuid option with less than 32 characters not pvcreate --norestorefile --uuid $bogusuuid "$dev1" # pvcreate rejects uuid option without restorefile not pvcreate --uuid $uuid1 "$dev1" # pvcreate rejects uuid already in use pvcreate --norestorefile --uuid $uuid1 "$dev1" not pvcreate --norestorefile --uuid $uuid1 "$dev2" # pvcreate rejects non-existent file given with restorefile not pvcreate --uuid $uuid1 --restorefile $backupfile "$dev1" # pvcreate rejects restorefile with uuid not found in file pvcreate --norestorefile --uuid $uuid1 "$dev1" vgcfgbackup -f $backupfile not pvcreate --uuid $uuid2 --restorefile $backupfile "$dev2" # vgcfgrestore of a VG containing a PV with zero PEs (bz #820116) # (use case: one PV in a VG used solely to keep metadata) size_mb=$(($(blockdev --getsz $dev1) / 2048)) pvcreate --metadatasize $size_mb $dev1 vgcreate $vg1 $dev1 vgcfgbackup -f $backupfile vgcfgrestore -f $backupfile $vg1 vgremove -f $vg1 pvremove -f $dev1 # pvcreate wipes swap signature when forced dd if=/dev/zero of="$dev1" bs=1024 count=64 mkswap "$dev1" blkid -c /dev/null "$dev1" | grep "swap" pvcreate -f "$dev1" # blkid cannot make up its mind whether not finding anything it knows is a failure or not (blkid -c /dev/null "$dev1" || true) | not grep "swap" lvm2-2.02.98/test/shell/lvmetad-pvs.sh0000640000175000017500000000117012037016273016374 0ustar blankblank#!/bin/sh # Copyright (C) 2012 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 . lib/test aux prepare_pvs 1 20000 pvs $(cat DEVICES) | grep "$dev1" # check for PV size overflows pvs $(cat DEVICES) | grep 19.53g pvs $(cat DEVICES) | not grep 16.00e lvm2-2.02.98/test/shell/lvcreate-thin-snap.sh0000640000175000017500000000256312037016273017645 0ustar blankblank#!/bin/sh # Copyright (C) 2012 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 . lib/test check_lv_field_modules_() { mod=$1 shift for d in $*; do check lv_field $vg/$d modules $mod done } # # Main # aux have_thin 1 0 0 || skip aux prepare_pvs 2 64 vgcreate $vg -s 64K $(cat DEVICES) lvcreate -L10M -V10M -T $vg/pool --name $lv1 mkfs.ext4 $DM_DEV_DIR/$vg/$lv1 # create thin snapshot of thin LV lvcreate -s $vg/$lv1 # check snapshot filesystem was properly frozen before snapping fsck -p $DM_DEV_DIR/$vg/lvol0 lvcreate -s $vg/$lv1 --name $lv2 lvcreate -s $vg/$lv1 --name $vg/$lv3 lvcreate --type snapshot $vg/$lv1 lvcreate --type snapshot $vg/$lv1 --name $lv4 lvcreate --type snapshot $vg/$lv1 --name $vg/$lv5 # create old-style snapshot lvcreate -s -L10M --name oldsnap1 $vg/$lv2 lvcreate -s -L10M --name oldsnap2 $vg/$lv2 # thin snap of snap of snap... lvcreate -s --name sn1 $vg/$lv2 lvcreate -s --name sn2 $vg/sn1 lvcreate -s --name sn3 $vg/sn2 lvcreate -s --name sn4 $vg/sn3 vgremove -ff $vg lvm2-2.02.98/test/shell/lvextend-snapshot-dmeventd.sh0000640000175000017500000000266312037016273021434 0ustar blankblank#!/bin/sh # Copyright (C) 2010-2012 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 . lib/test extend() { lvextend --use-policies --config "activation { snapshot_autoextend_threshold = $1 }" $vg/snap } write_() { dd if=/dev/zero of="$DM_DEV_DIR/$vg/snap" bs=1k count=$2 seek=$1 } percent_() { get lv_field $vg/snap snap_percent | cut -d. -f1 } wait_for_change_() { # dmeventd only checks every 10 seconds :( for i in $(seq 1 15) ; do test "$(percent_)" != "$1" && return sleep 1 done return 1 # timeout } aux prepare_dmeventd aux prepare_vg 2 lvcreate -L16M -n base $vg lvcreate -s -L4M -n snap $vg/base write_ 0 1000 test 24 -eq $(percent_) lvchange --monitor y $vg/snap write_ 1000 1700 pre=$(percent_) wait_for_change_ $pre test $pre -gt $(percent_) # check that a second extension happens; we used to fail to extend when the # utilisation ended up between THRESH and (THRESH + 10)... see RHBZ 754198 # (the utilisation after the write should be 57 %) write_ 2700 2000 pre=$(percent_) wait_for_change_ $pre test $pre -gt $(percent_) vgremove -f $vg lvm2-2.02.98/test/shell/lock-blocking.sh0000640000175000017500000000275212037016272016656 0ustar blankblank#!/bin/sh # Copyright (C) 2008 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 test_description='test some blocking / non-blocking multi-vg operations' . lib/test aux prepare_devs 3 test -e LOCAL_CLVMD && skip pvcreate "$dev1" "$dev2" vgcreate $vg "$dev1" "$dev2" # if wait_for_locks set, vgremove should wait for orphan lock # flock process should have exited by the time first vgremove completes flock -w 5 $TESTDIR/var/lock/lvm/P_orphans -c "sleep 10" & while ! test -f $TESTDIR/var/lock/lvm/P_orphans ; do sleep .1 ; done vgremove --config 'global { wait_for_locks = 1 }' $vg not vgremove --config 'global { wait_for_locks = 1 }' $vg test ! -f $TESTDIR/var/lock/lvm/P_orphans # if wait_for_locks not set, vgremove should fail on non-blocking lock # we must wait for flock process at the end - vgremove won't wait vgcreate $vg "$dev1" "$dev2" flock -w 5 $TESTDIR/var/lock/lvm/P_orphans -c "sleep 10" & while ! test -f $TESTDIR/var/lock/lvm/P_orphans ; do sleep .1 ; done flock_pid=`jobs -p` not vgremove --config 'global { wait_for_locks = 0 }' $vg test -f $TESTDIR/var/lock/lvm/P_orphans # still running kill $flock_pid lvm2-2.02.98/test/shell/lvresize-raid.sh0000640000175000017500000000311612037016273016714 0ustar blankblank#!/bin/sh # Copyright (C) 2012 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 . lib/test aux target_at_least dm-raid 1 1 0 || skip aux prepare_vg 5 80 # Extend a 2-way RAID1 for deactivate in true false; do lvcreate --type raid1 -m 1 -l 2 -n $lv1 $vg if $deactivate; then lvchange -an $vg/$lv1 fi lvresize -l +2 $vg/$lv1 #check raid_images_contiguous $vg $lv1 lvremove -ff $vg done # Reduce 2-way RAID1 for deactivate in true false; do lvcreate --type raid1 -m 1 -l 4 -n $lv1 $vg if $deactivate; then lvchange -an $vg/$lv1 fi should lvresize -y -l -2 $vg/$lv1 #check raid_images_contiguous $vg $lv1 lvremove -ff $vg done # Extend 3-striped RAID 4/5/6 for i in 4 5 6 ; do for deactivate in true false; do lvcreate --type raid$i -i 3 -l 3 -n $lv1 $vg if $deactivate; then lvchange -an $vg/$lv1 fi lvresize -l +3 $vg/$lv1 #check raid_images_contiguous $vg $lv1 lvremove -ff $vg done done # Reduce 3-striped RAID 4/5/6 for i in 4 5 6 ; do for deactivate in true false; do lvcreate --type raid$i -i 3 -l 6 -n $lv1 $vg if $deactivate; then lvchange -an $vg/$lv1 fi should lvresize -y -l -3 $vg/$lv1 #check raid_images_contiguous $vg $lv1 lvremove -ff $vg done done lvm2-2.02.98/test/shell/name-mangling.sh0000640000175000017500000001521112037016273016645 0ustar blankblank#!/bin/sh # Copyright (C) 2012 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 . lib/test name_prefix=$RANDOM CHARACTER_WHITELIST="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789#+-.:=@_" FAIL_MIXED_STR="contains mixed mangled and unmangled characters" FAIL_MULTI_STR="seems to be mangled more than once" FAIL_BLACK_STR="should be mangled but it contains blacklisted characters" CORRECT_FORM_STR="name already in correct form" RENAMING_STR="renaming to" function create_dm_dev() { local mode=$1 local name=$2; if [ $mode = "none" ]; then # there's no mangling done - we must use --verifyudev here in # case we're testing with udev so we have the nodes in place, # udev would not create them - it can't handle unmangled names verify_udev="--verifyudev" else verify_udev="" fi dmsetup create "${name_prefix}$name" $verify_udev --manglename $mode --table "0 1 zero" } function remove_dm_dev() { local mode=$1 local name=$2 if [ $mode = "none" ]; then verify_udev="--verifyudev" else verify_udev="" fi dmsetup remove $verify_udev --manglename $mode "${name_prefix}$name" } function check_create_and_remove() { local mode=$1 local input_name=$2 local dm_name=$3 local r=0 if [ $mode = "none" ]; then verify_udev="--verifyudev" else verify_udev="" fi dmsetup create "${name_prefix}$input_name" $verify_udev --manglename $mode --table "0 1 zero" 2>err && \ test -b "$DM_DEV_DIR/mapper/${name_prefix}$dm_name" && \ dmsetup remove "${name_prefix}$input_name" $verify_udev --manglename $mode || r=1 if [ $dm_name = "FAIL_MIXED" ]; then r=0 grep "$FAILED_MIXED_STR" err || r=1 elif [ $dm_name = "FAIL_MULTI" ]; then r=0 grep "$FAILED_MULTI_STR" err || r=1 elif [ $dm_name = "FAIL_BLACK" ]; then r=0 grep "$FAILED_BLACK_STR" err || r=1 fi return $r } function check_dm_field() { local mode=$1 local dm_name="$2" local field=$3 local expected="$4" value=$(dmsetup info --rows --noheadings --manglename $mode -c -o $field "${DM_DEV_DIR}/mapper/${name_prefix}$dm_name" 2> err || true) if [ "$expected" = "FAIL_MIXED" ]; then grep "$FAIL_MIXED_STR" err elif [ "$expected" = "FAIL_MULTI" ]; then grep "$FAIL_MULTI_STR" err elif [ "$expected" = "FAIL_BLACK" ]; then grep "$FAIL_BLACK_STR" err else test "$value" = "${name_prefix}$expected" fi } function check_expected_names() { local mode=$1 local dm_name="$2" local r=0 create_dm_dev none "$dm_name" test -b "$DM_DEV_DIR/mapper/${name_prefix}$dm_name" && \ check_dm_field none "$dm_name" name "$dm_name" && \ check_dm_field $mode "$dm_name" name "$3" && \ check_dm_field $mode "$dm_name" mangled_name "$4" && \ check_dm_field $mode "$dm_name" unmangled_name "$5" || r=1 remove_dm_dev none "$dm_name" return $r } function check_mangle_cmd() { local mode=$1 local dm_name="$2" local expected="$3" local rename_expected=0 local r=0 create_dm_dev none "$dm_name" dmsetup mangle --manglename $mode "${name_prefix}$dm_name" 1>out 2>err || true; if [ "$expected" = "OK" ]; then grep "$CORRECT_FORM_STR" out || r=1 elif [ "$expected" = "FAIL_MIXED" ]; then grep "$FAIL_MIXED_STR" err || r=1 elif [ "$expected" = "FAIL_MULTI" ]; then grep "$FAIL_MULTI_STR" err || r=1 else rename_expected=1 grep -F "$RENAMING_STR ${name_prefix}$expected" out || r=1 fi if [ $r = 0 -a $rename_expected = 1 ]; then # successfuly renamed to expected name remove_dm_dev none "$expected" elif [ $r = 1 ]; then # failed to rename to expected or renamed when it should not - find the new name new_name=$(sed -e "s/.*: $RENAMING_STR //g" out) # try to remove any of the form - falling back to less probable error scenario dmsetup remove --verifyudev --manglename none "$new_name" || \ remove_dm_dev none "$dm_name" || remove_dm_dev none "$expected" else # successfuly done nothing remove_dm_dev none "$dm_name" fi return $r } # check dmsetup can process path where the last component is not equal dm name (rhbz #797322) r=0 create_dm_dev auto "abc" ln -s ${DM_DEV_DIR}/mapper/${name_prefix}abc ${DM_DEV_DIR}/${name_prefix}xyz dmsetup status ${DM_DEV_DIR}/${name_prefix}xyz || r=1 remove_dm_dev auto "abc" if [ r = 1 ]; then exit 1 fi ### ALL WHITELISTED CHARACTERS ### # none of these should be mangled in any mode name="$CHARACTER_WHITELIST" for mode in auto hex none; do check_expected_names $mode "$name" "$name" "$name" "$name" check_mangle_cmd $mode "$name" "OK" done #### NONE MANGLING MODE ### check_create_and_remove none 'a b' 'a b' check_create_and_remove none 'a\x20b' 'a\x20b' check_create_and_remove none 'a b\x20c' 'a b\x20c' check_create_and_remove none 'a\x5cx20b' 'a\x5cx20b' check_expected_names none 'a b' 'a b' 'a\x20b' 'a b' check_expected_names none 'a\x20b' 'a\x20b' 'a\x20b' 'a b' check_expected_names none 'a b\x20c' 'a b\x20c' 'FAIL_MIXED' 'a b c' check_expected_names none 'a\x5cx20b' 'a\x5cx20b' 'a\x5cx20b' 'a\x20b' check_mangle_cmd none 'a b' 'OK' check_mangle_cmd none 'a\x20b' 'a b' check_mangle_cmd none 'a b\x20c' 'a b c' check_mangle_cmd none 'a\x5cx20b' 'a\x20b' ### AUTO MANGLING MODE ### check_create_and_remove auto 'a b' 'a\x20b' check_create_and_remove auto 'a\x20b' 'a\x20b' check_create_and_remove auto 'a b\x20c' 'FAIL_MIXED' check_create_and_remove auto 'a\x5cx20b' 'FAIL_MULTI' check_expected_names auto 'a b' 'FAIL_BLACK' 'FAIL_BLACK' 'FAIL_BLACK' check_expected_names auto 'a\x20b' 'a b' 'a\x20b' 'a b' check_expected_names auto 'a b\x20c' 'FAIL_BLACK' 'FAIL_BLACK' 'FAIL_BLACK' check_expected_names auto 'a\x5cx20b' 'FAIL_MULTI' 'FAIL_MULTI' 'FAIL_MULTI' check_mangle_cmd auto 'a b' 'a\x20b' check_mangle_cmd auto 'a\x20b' 'OK' check_mangle_cmd auto 'a b\x20c' 'FAIL_MIXED' check_mangle_cmd auto 'a\x5cx20b' 'FAIL_MULTI' ### HEX MANGLING MODE ### check_create_and_remove hex 'a b' 'a\x20b' check_create_and_remove hex 'a\x20b' 'a\x5cx20b' check_create_and_remove hex 'a b\x20c' 'a\x20b\x5cx20c' check_create_and_remove hex 'a\x5cx20b' 'a\x5cx5cx20b' check_expected_names hex 'a b' 'FAIL_BLACK' 'FAIL_BLACK' 'FAIL_BLACK' check_expected_names hex 'a\x20b' 'a b' 'a\x20b' 'a b' check_expected_names hex 'a b\x20c' 'FAIL_BLACK' 'FAIL_BLACK' 'FAIL_BLACK' check_expected_names hex 'a\x5cx20b' 'a\x20b' 'a\x5cx20b' 'a\x20b' check_mangle_cmd hex 'a b' 'a\x20b' check_mangle_cmd hex 'a\x20b' 'OK' check_mangle_cmd hex 'a b\x20c' 'FAIL_MIXED' check_mangle_cmd hex 'a\x5cx20b' 'OK' lvm2-2.02.98/test/shell/activate-missing-segment.sh0000640000175000017500000000166112037016272021045 0ustar blankblank#!/bin/sh # 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 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 # Test activation behaviour with devices missing. # - snapshots and their origins are only activated together; if one fails, both # fail # - partial mirrors are not activated (but maybe they should? maybe we should # instead lvconvert --repair them?) # - linear LVs with bits missing are not activated . lib/test aux prepare_vg 2 lvcreate -l100%FREE -n span $vg vgchange -a n $vg aux disable_dev "$dev1" not vgchange -a y $vg vgchange -a y --partial $vg check active $vg span lvm2-2.02.98/test/shell/vgimportclone.sh0000640000175000017500000000244312037016273017026 0ustar blankblank#!/bin/sh # Copyright (C) 2010-2011 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 . lib/test aux prepare_devs 2 vgcreate -c n --metadatasize 128k $vg1 "$dev1" lvcreate -l100%FREE -n $lv1 $vg1 # Clone the LUN dd if="$dev1" of="$dev2" bs=256K count=1 aux notify_lvmetad "$dev2" # Verify pvs works on each device to give us vgname check pv_field "$dev1" vg_name $vg1 check pv_field "$dev2" vg_name $vg1 # Import the cloned PV to a new VG vgimportclone --basevgname $vg2 "$dev2" # We need to re-scan *both* $dev1 and $dev2 since a PV, as far as lvmetad is # concerned, can only live on a single device. With the last pvscan, we told it # that PV from $dev1 now lives on $dev2, but in fact this is not true anymore, # since we wrote a different PV over $dev2. aux notify_lvmetad "$dev2" aux notify_lvmetad "$dev1" # Verify we can activate / deactivate the LV from both VGs lvchange -ay $vg1/$lv1 $vg2/$lv1 vgchange -an $vg1 $vg2 lvm2-2.02.98/test/shell/activate-missing.sh0000640000175000017500000000433212037016272017403 0ustar blankblank#!/bin/sh # 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 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 # Test activation behaviour with devices missing. # - snapshots and their origins are only activated together; if one fails, both # fail # - partial mirrors are not activated (but maybe they should? maybe we should # instead lvconvert --repair them?) # - linear LVs with bits missing are not activated . lib/test aux prepare_vg 4 lvcreate -l1 -n linear1 $vg "$dev1" lvcreate -l1 -n linear2 $vg "$dev2" lvcreate -l2 -n linear12 $vg "$dev1":4 "$dev2":4 lvcreate -l1 -n origin1 $vg "$dev1" lvcreate -s $vg/origin1 -l1 -n s_napshot2 "$dev2" lvcreate -l1 -m1 -n mirror12 --mirrorlog core $vg "$dev1" "$dev2" lvcreate -l1 -m1 -n mirror123 $vg "$dev1" "$dev2" "$dev3" vgchange -a n $vg aux disable_dev "$dev1" not vgchange -a y $vg not vgck $vg check inactive $vg linear1 check active $vg linear2 check inactive $vg origin1 check inactive $vg s_napshot2 check inactive $vg linear12 check inactive $vg mirror12 check inactive $vg mirror123 vgchange -a n $vg aux enable_dev "$dev1" aux disable_dev "$dev2" not vgchange -a y $vg not vgck $vg check active $vg linear1 check inactive $vg linear2 check inactive $vg linear12 check inactive $vg origin1 check inactive $vg s_napshot2 check inactive $vg mirror12 check inactive $vg mirror123 vgchange -a n $vg aux enable_dev "$dev2" aux disable_dev "$dev3" not vgchange -a y $vg not vgck $vg check active $vg origin1 check active $vg s_napshot2 check active $vg linear1 check active $vg linear2 check active $vg linear12 check inactive $vg mirror123 check active $vg mirror12 vgchange -a n $vg aux enable_dev "$dev3" aux disable_dev "$dev4" vgchange -a y $vg not vgck $vg check active $vg origin1 check active $vg s_napshot2 check active $vg linear1 check active $vg linear2 check active $vg linear12 check active $vg mirror12 check active $vg mirror123 lvm2-2.02.98/test/shell/lvcreate-pvtags.sh0000640000175000017500000000247312037016273017250 0ustar blankblank#!/bin/sh # Copyright (C) 2008 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 . lib/test aux prepare_pvs 3 aux lvmconf 'allocation/maximise_cling = 0' aux lvmconf 'allocation/mirror_logs_require_separate_pvs = 1' # not required, just testing aux pvcreate --metadatacopies 0 "$dev1" vgcreate -c n $vg $(cat DEVICES) pvchange --addtag fast $(cat DEVICES) # 3 stripes with 3 PVs (selected by tag, @fast) is fine lvcreate -l3 -i3 $vg @fast # too many stripes(4) for 3 PVs not lvcreate -l4 -i4 $vg @fast # 2 stripes is too many with just one PV not lvcreate -l2 -i2 $vg $DM_DEV_DIR/mapper/pv1 # lvcreate mirror lvcreate -l1 -m1 $vg @fast # lvcreate mirror w/corelog lvcreate -l1 -m2 --corelog $vg @fast # lvcreate mirror w/no free PVs not lvcreate -l1 -m2 $vg @fast # lvcreate mirror (corelog, w/no free PVs) not lvcreate -l1 -m3 --corelog $vg @fast # lvcreate mirror with a single PV arg not lvcreate -l1 -m1 --corelog $vg "$dev1" vgremove -ff $vg lvm2-2.02.98/test/shell/lvconvert-raid10.sh0000640000175000017500000000336212037016272017236 0ustar blankblank#!/bin/sh # Copyright (C) 2012 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 . lib/test get_image_pvs() { local d local images images=`dmsetup ls | grep ${1}-${2}_.image_.* | cut -f1 | sed -e s:-:/:` lvs --noheadings -a -o devices $images | sed s/\(.\)// } ######################################################## # MAIN ######################################################## # RAID10: Can replace 'copies - 1' devices from each stripe # Tests are run on 2-way mirror, 3-way stripe RAID10 aux target_at_least dm-raid 1 3 1 || skip # 9 PVs needed for RAID10 testing (3-stripes/2-mirror - replacing 3 devs) aux prepare_pvs 9 80 vgcreate -c n -s 256k $vg $(cat DEVICES) lvcreate --type raid10 -m 1 -i 3 -l 3 -n $lv1 $vg aux wait_for_sync $vg $lv1 # Can replace any single device for i in $(get_image_pvs $vg $lv1); do lvconvert --replace $i $vg/$lv1 aux wait_for_sync $vg $lv1 done # Can't replace adjacent devices devices=( $(get_image_pvs $vg $lv1) ) not lvconvert --replace ${devices[0]} --replace ${devices[1]} $vg/$lv1 not lvconvert --replace ${devices[2]} --replace ${devices[3]} $vg/$lv1 not lvconvert --replace ${devices[4]} --replace ${devices[5]} $vg/$lv1 # Can replace non-adjacent devices for i in 0 1; do lvconvert \ --replace ${devices[$i]} \ --replace ${devices[$(($i + 2))]} \ --replace ${devices[$(($i + 4))]} \ $vg/$lv1 aux wait_for_sync $vg $lv1 done lvm2-2.02.98/test/shell/vgreduce-usage.sh0000640000175000017500000000570012037016273017043 0ustar blankblank#!/bin/sh # Copyright (C) 2008 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 . lib/test aux prepare_devs 4 for mdatype in 1 2 do # setup PVs pvcreate -M$mdatype "$dev1" "$dev2" # (lvm$mdatype) vgreduce removes only the specified pv from vg (bz427382)" ' vgcreate -c n -M$mdatype $vg1 "$dev1" "$dev2" vgreduce $vg1 "$dev1" check pv_field "$dev2" vg_name $vg1 vgremove -f $vg1 # (lvm$mdatype) vgreduce rejects removing the last pv (--all) vgcreate -c n -M$mdatype $vg1 "$dev1" "$dev2" not vgreduce --all $vg1 vgremove -f $vg1 # (lvm$mdatype) vgreduce rejects removing the last pv vgcreate -c n -M$mdatype $vg1 "$dev1" "$dev2" not vgreduce $vg1 "$dev1" "$dev2" vgremove -f $vg1 pvremove -ff "$dev1" "$dev2" done mdatype=2 # we only expect the following to work for lvm2 metadata # (lvm$mdatype) setup PVs (--metadatacopies 0) pvcreate -M$mdatype "$dev1" "$dev2" pvcreate --metadatacopies 0 -M$mdatype "$dev3" "$dev4" # (lvm$mdatype) vgreduce rejects removing pv with the last mda copy (bz247448) vgcreate -c n -M$mdatype $vg1 "$dev1" "$dev3" not vgreduce $vg1 "$dev1" vgremove -f $vg1 #COMM "(lvm$mdatype) vgreduce --removemissing --force repares to linear (bz221921)" # (lvm$mdatype) setup: create mirror & damage one pv vgcreate -c n -M$mdatype $vg1 "$dev1" "$dev2" "$dev3" lvcreate -n $lv1 -m1 -l 4 $vg1 lvcreate -n $lv2 -l 4 $vg1 "$dev2" lvcreate -n $lv3 -l 4 $vg1 "$dev3" vgchange -an $vg1 aux disable_dev "$dev1" # (lvm$mdatype) vgreduce --removemissing --force repares to linear vgreduce --removemissing --force $vg1 check lv_field $vg1/$lv1 segtype linear check pvlv_counts $vg1 2 3 0 # cleanup aux enable_dev "$dev1" pvscan vgremove -f $vg1 not vgs $vg1 # just double-check it's really gone #COMM "vgreduce rejects --removemissing --mirrorsonly --force when nonmirror lv lost too" # (lvm$mdatype) setup: create mirror + linear lvs vgcreate -c n -M$mdatype $vg1 $(cat DEVICES) lvcreate -n $lv2 -l 4 $vg1 lvcreate -m1 -n $lv1 -l 4 $vg1 "$dev1" "$dev2" "$dev3" lvcreate -n $lv3 -l 4 $vg1 "$dev3" pvs --segments -o +lv_name $(cat DEVICES) # for record only # (lvm$mdatype) setup: damage one pv vgchange -an $vg1 aux disable_dev "$dev1" #pvcreate -ff -y "$dev1" # vgreduce rejects --removemissing --mirrorsonly --force when nonmirror lv lost too #not vgreduce -c n --removemissing --mirrorsonly --force $vg1 # CHECKME - command above was rejected becuase of '-c n' vgreduce --removemissing --mirrorsonly --force $vg1 aux enable_dev "$dev1" pvs -P $(cat DEVICES) # for record lvs -P $vg1 # for record vgs -P $vg1 # for record lvm2-2.02.98/test/shell/unlost-pv.sh0000640000175000017500000000244712037016273016111 0ustar blankblank#!/bin/sh # Copyright (C) 2008 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 . lib/test check_() { # vgscan needs --cache option for direct scan if lvmetad is used test -e LOCAL_LVMETAD && cache="--cache" vgscan $cache 2>&1 | tee vgscan.out $1 grep "Inconsistent metadata found for VG $vg" vgscan.out } aux prepare_vg 3 lvcreate -m 1 -l 1 -n mirror $vg lvchange -a n $vg # try orphaning a missing PV (bz45867) aux disable_dev "$dev1" vgreduce --removemissing --force $vg aux enable_dev "$dev1" check_ test -e LOCAL_LVMETAD && pvcreate -f "$dev1" check_ not # try to just change metadata; we expect the new version (with MISSING_PV set # on the reappeared volume) to be written out to the previously missing PV vgextend $vg "$dev1" lvcreate -l 1 -n boo -a n --zero n $vg aux disable_dev "$dev1" lvremove $vg/mirror aux enable_dev "$dev1" check_ test -e LOCAL_LVMETAD && lvremove $vg/boo # FIXME trigger a write :-( check_ not lvm2-2.02.98/test/shell/lvresize-rounding.sh0000640000175000017500000000367012037016273017627 0ustar blankblank#!/bin/sh # Copyright (C) 2007-2012 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 . lib/test aux prepare_pvs 3 22 vgcreate -s 32K $vg "$dev1" "$dev2" "$dev3" lvcreate -l4 -i3 -I64 $vg lvcreate -l8 -i2 -I64 $vg lvcreate -l16 $vg lvcreate -l32 -i3 -I64 -n $lv1 $vg lvresize -l+64 -i3 -I64 $vg/$lv1 lvresize -l+64 -i3 -I128 $vg/$lv1 #lvcreate -l100%FREE -i3 -I64 --alloc anywhere $vg dmsetup table vgcfgbackup -f /tmp/vg $vg vgremove -f $vg # 15 extents aux prepare_vg 3 22 # Block some extents lvcreate -l4 -i3 $vg lvcreate -l1 $vg lvcreate -l100%FREE -n $lv1 -i3 $vg check vg_field $vg vg_free_count 2 lvremove -f $vg/$lv1 lvcreate -l1 -n $lv1 -i3 $vg lvextend -l+100%FREE -i3 $vg/$lv1 check vg_field $vg vg_free_count 2 lvreduce -f -l50%LV $vg/$lv1 vgremove -f $vg vgcreate -s 4M $vg "$dev1" "$dev2" "$dev3" # Expect to play with 15 extents check vg_field $vg vg_free_count 15 # Should be rounded to 12 extents lvcreate -l10 -n lv -i3 $vg check vg_field $vg vg_free_count 3 # Should want 16 extents not lvextend -l+4 $vg/lv # Round up to whole free space lvextend -l+100%FREE $vg/lv check vg_field $vg vg_free_count 0 # Rounds up and should reduce just by 3 extents lvreduce -f -l-4 $vg/lv check vg_field $vg vg_free_count 3 # Should round up to 15 extents lvextend -f -l+1 $vg/lv check vg_field $vg vg_free_count 0 lvreduce -f -l-4 $vg/lv check vg_field $vg vg_free_count 3 lvextend -l90%VG $vg/lv check vg_field $vg vg_free_count 0 not lvreduce -f -l-10%LV $vg/lv check vg_field $vg vg_free_count 0 lvreduce -f -l-20%LV $vg/lv check vg_field $vg vg_free_count 3 lvm2-2.02.98/test/shell/lvconvert-repair-policy.sh0000640000175000017500000000557612037016272020746 0ustar blankblank#!/bin/sh # Copyright (C) 2008 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 . lib/test aux prepare_vg 4 aux lvmconf 'allocation/maximise_cling = 0' aux lvmconf 'allocation/mirror_logs_require_separate_pvs = 1' # Clean-up and create a 2-way mirror, where the the # leg devices are always on $dev[12] and the log # is always on $dev3. ($dev4 behaves as a spare) cleanup() { vgreduce --removemissing $vg for d in "$@"; do aux enable_dev "$d"; done for d in "$@"; do vgextend $vg "$d"; done lvremove -ff $vg/mirror lvcreate -m 1 --ig -l 2 -n mirror $vg "$dev1" "$dev2" "$dev3":0 } repair() { lvconvert --repair --use-policies --config "$1" $vg/mirror } lvcreate -m 1 -L 1 -n mirror $vg lvchange -a n $vg/mirror # Fail a leg of a mirror. aux disable_dev "$dev1" lvchange --partial -a y $vg/mirror repair 'activation { mirror_image_fault_policy = "remove" }' check linear $vg mirror cleanup "$dev1" # Fail a leg of a mirror. # Expected result: Mirror (leg replaced, should retain log) aux disable_dev "$dev1" repair 'activation { mirror_image_fault_policy = "replace" mirror_log_fault_policy = "remove" }' check mirror $vg mirror check active $vg mirror_mlog cleanup "$dev1" # Fail a leg of a mirror. # Expected result: Mirror (leg replaced) aux disable_dev "$dev1" repair 'activation { mirror_image_fault_policy = "replace" }' check mirror $vg mirror check active $vg mirror_mlog cleanup "$dev1" # Fail a leg of a mirror (use old name for policy specification) # Expected result: Mirror (leg replaced) aux disable_dev "$dev1" repair 'activation { mirror_image_fault_policy = "replace" }' check mirror $vg mirror check active $vg mirror_mlog cleanup "$dev1" # Fail a leg of a mirror w/ no available spare # Expected result: linear # (or 2-way with leg/log overlap if alloc anywhere) aux disable_dev "$dev2" "$dev4" repair 'activation { mirror_image_fault_policy = "replace" }' check mirror $vg mirror not check lv_exists $vg mirror_mlog cleanup "$dev2" "$dev4" # Fail the log device of a mirror w/ no available spare # Expected result: mirror w/ corelog aux disable_dev "$dev3" "$dev4" repair 'activation { mirror_image_fault_policy = "replace" }' $vg/mirror check mirror $vg mirror not check lv_exists $vg mirror_mlog cleanup "$dev3" "$dev4" # Fail the log device with a remove policy # Expected result: mirror w/ corelog lvchange -a y $vg/mirror aux disable_dev "$dev3" "$dev4" repair 'activation { mirror_log_fault_policy = "remove" }' check mirror $vg mirror core not check lv_exists $vg mirror_mlog cleanup "$dev3" "$dev4" lvm2-2.02.98/test/shell/lvcreate-large-raid.sh0000640000175000017500000000377112037016273017755 0ustar blankblank#!/bin/sh # Copyright (C) 2012 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 # 'Exercise some lvcreate diagnostics' . lib/test aux target_at_least dm-raid 1 1 0 || skip aux prepare_vg 5 lvcreate -s -l 20%FREE -n $lv1 $vg --virtualsize 256T lvcreate -s -l 20%FREE -n $lv2 $vg --virtualsize 256T lvcreate -s -l 20%FREE -n $lv3 $vg --virtualsize 256T lvcreate -s -l 20%FREE -n $lv4 $vg --virtualsize 256T lvcreate -s -l 20%FREE -n $lv5 $vg --virtualsize 256T #FIXME this should be 1024T #check lv_field $vg/$lv size "128.00m" aux lvmconf 'devices/filter = [ "a/dev\/mapper\/.*$/", "a/dev\/LVMTEST/", "r/.*/" ]' pvcreate $DM_DEV_DIR/$vg/$lv[12345] vgcreate -c n $vg1 $DM_DEV_DIR/$vg/$lv[12345] # bz837927 START # # Create large RAID LVs # # We need '--nosync' or our virtual devices won't work lvcreate --type raid1 -m 1 -L 200T -n $lv1 $vg1 --nosync check lv_field $vg1/$lv1 size "200.00t" lvremove -ff $vg1 for segtype in raid4 raid5 raid6; do lvcreate --type $segtype -i 3 -L 750T -n $lv1 $vg1 --nosync check lv_field $vg1/$lv1 size "750.00t" lvremove -ff $vg1 done # # Convert large linear to RAID1 (belong in different test script?) # lvcreate -L 200T -n $lv1 $vg1 # Need to deactivate or the up-convert will start sync'ing lvchange -an $vg1/$lv1 lvconvert --type raid1 -m 1 $vg1/$lv1 check lv_field $vg1/$lv1 size "200.00t" lvremove -ff $vg1 # # Extending large RAID LV (belong in different script?) # lvcreate --type raid1 -m 1 -L 200T -n $lv1 $vg1 --nosync check lv_field $vg1/$lv1 size "200.00t" lvextend -L +200T $vg1/$lv1 check lv_field $vg1/$lv1 size "400.00t" lvremove -ff $vg1 # bz837927 END lvremove -ff $vg lvm2-2.02.98/test/shell/000-basic.sh0000640000175000017500000000160612037016272015513 0ustar blankblank#!/bin/sh # Copyright (C) 2009-2011 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 . lib/test lvm version v=$abs_top_builddir/lib/misc/lvm-version.h sed -n "/#define LVM_VERSION ./s///p" "$v" | sed "s/ .*//" > expected lvm pvmove --version|sed -n "1s/.*: *\([0-9][^ ]*\) .*/\1/p" > actual # ensure they are the same diff -u actual expected # ensure we can create devices (uses dmsetup, etc) aux prepare_devs 5 # ensure we do not crash on a bug in config file aux lvmconf 'log/prefix = 1""' not lvs $(cat DEVICES) lvm2-2.02.98/test/shell/vgchange-usage.sh0000640000175000017500000000241612037016273017022 0ustar blankblank#!/bin/sh # Copyright (C) 2008 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 test_description='Exercise some vgchange diagnostics' . lib/test aux prepare_pvs 3 pvcreate --metadatacopies 0 "$dev1" vgcreate $vg $(cat DEVICES) vgdisplay $vg # vgchange -p MaxPhysicalVolumes (bz202232) aux check vg_field $vg max_pv 0 vgchange -p 128 $vg aux check vg_field $vg max_pv 128 pv_count=$(get vg_field $vg pv_count) not vgchange -p 2 $vg 2>err grep "MaxPhysicalVolumes is less than the current number $pv_count of PVs for" err aux check vg_field $vg max_pv 128 # vgchange -l MaxLogicalVolumes aux check vg_field $vg max_lv 0 vgchange -l 128 $vg aux check vg_field $vg max_lv 128 lvcreate -l4 -n $lv1 $vg lvcreate -l4 -n $lv2 $vg lv_count=$(get vg_field $vg lv_count) not vgchange -l 1 $vg 2>err grep "MaxLogicalVolume is less than the current number $lv_count of LVs for" err aux check vg_field $vg max_lv 128 lvm2-2.02.98/test/shell/vgextend-restoremissing.sh0000640000175000017500000000200712037016273021031 0ustar blankblank#!/bin/sh # 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 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 . lib/test aux prepare_vg 3 lvcreate -m 1 -l 1 -n mirror $vg lvchange -a n $vg/mirror lvcreate -l 1 -n lv1 $vg "$dev1" # try to just change metadata; we expect the new version (with MISSING_PV set # on the reappeared volume) to be written out to the previously missing PV aux disable_dev "$dev1" lvremove $vg/mirror aux enable_dev "$dev1" not vgck $vg 2>&1 | tee log grep "missing 1 physical volume" log not lvcreate -m 1 -l 1 -n mirror $vg # write operations fail vgextend --restore $vg "$dev1" # restore the missing device vgck $vg lvcreate -m 1 -l 1 -n mirror $vg lvm2-2.02.98/test/shell/lvmetad-test.sh0000640000175000017500000000150512037016273016545 0ustar blankblank#!/bin/sh # Copyright (C) 2012 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 . lib/test aux prepare_pvs 2 vgcreate $vg1 $dev1 $dev2 --test vgs | not grep $vg1 vgcreate $vg1 $dev1 $dev2 vgs | grep $vg1 lvcreate -n bar -l 1 $vg1 --test lvs | not grep bar lvcreate -n bar -l 1 $vg1 lvs | grep bar lvremove $vg1/bar -f --test lvs | grep bar lvremove $vg1/bar -f lvs | not grep bar vgremove $vg1 --test vgs | grep $vg1 vgremove $vg1 vgs | not grep $vg1 lvm2-2.02.98/test/shell/lvresize-raid10.sh0000640000175000017500000000206412037016273017056 0ustar blankblank#!/bin/sh # Copyright (C) 2012 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 . lib/test aux target_at_least dm-raid 1 3 0 || skip aux prepare_vg 5 80 # Extend RAID10 (2-stripes, 2-mirror) for deactivate in true false; do lvcreate --type raid10 -m 1 -i 2 -l 2 -n $lv1 $vg if $deactivate; then lvchange -an $vg/$lv1 fi lvresize -l +2 $vg/$lv1 #check raid_images_contiguous $vg $lv1 lvremove -ff $vg done # Reduce RAID10 (2-stripes, 2-mirror) for deactivate in true false; do lvcreate --type raid10 -m 1 -i 2 -l 4 -n $lv1 $vg if $deactivate; then lvchange -an $vg/$lv1 fi should lvresize -y -l -2 $vg/$lv1 #check raid_images_contiguous $vg $lv1 lvremove -ff $vg done lvm2-2.02.98/test/shell/lvconvert-mirror-basic-2.sh0000640000175000017500000000077512037016272020713 0ustar blankblank#!/bin/sh # 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 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 . ./shell/lvconvert-mirror-basic.sh test_many 2 lvm2-2.02.98/test/shell/pv-min-size.sh0000640000175000017500000000163612037016273016317 0ustar blankblank#!/bin/sh # Copyright (C) 2011 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 . lib/test # use small default size - 512KB aux lvmconf 'devices/pv_min_size = 512' aux prepare_pvs 1 8 check pv_field "$dev1" pv_name "$dev1" # increase min size beyond created PV size 10MB aux lvmconf 'devices/pv_min_size = 10240' # and test device is not visible not check pv_field "$dev1" pv_name "$dev1" # set too low value errornous value aux lvmconf 'devices/pv_min_size = -100' # check the incorrect value is printed pvs "$dev1" 2>&1 | grep -- -100 lvm2-2.02.98/test/shell/metadata-balance.sh0000640000175000017500000002277512037016273017313 0ustar blankblank#!/bin/sh # Copyright (C) 2008 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 . lib/test aux prepare_devs 6 echo Make sure we can ignore / un-ignore mdas on a per-PV basis for pv_in_vg in 1 0; do for mdacp in 1 2; do pvcreate --metadatacopies $mdacp "$dev1" "$dev2" pvcreate --metadatacopies 0 "$dev3" if [ $pv_in_vg = 1 ]; then vgcreate -c n $vg "$dev1" "$dev2" "$dev3" fi pvchange --metadataignore y "$dev1" check pv_field "$dev1" pv_mda_count $mdacp check pv_field "$dev1" pv_mda_used_count 0 check pv_field "$dev2" pv_mda_count $mdacp check pv_field "$dev2" pv_mda_used_count $mdacp if [ $pv_in_vg = 1 ]; then check vg_field $vg vg_mda_count $(($mdacp * 2)) check vg_field $vg vg_mda_used_count $mdacp check vg_field $vg vg_mda_copies unmanaged fi pvchange --metadataignore n "$dev1" check pv_field "$dev1" pv_mda_count $mdacp check pv_field "$dev1" pv_mda_used_count $mdacp if [ $pv_in_vg = 1 ]; then check vg_field $vg vg_mda_count $(($mdacp * 2)) check vg_field $vg vg_mda_used_count $(($mdacp * 2)) check vg_field $vg vg_mda_copies unmanaged vgremove -f $vg fi done done # Check if a PV has unignored (used) mdas, and if so, ignore pvignore_ () { pv_mda_used_count=$(get pv_field "$1" pv_mda_used_count) if [ $pv_mda_used_count -ne 0 ]; then pvchange --metadataignore y $1 fi } # Check if a PV has ignored mdas, and if so, unignore (make used) pvunignore_ () { pv_mda_count=$(get pv_field "$1" pv_mda_count) pv_mda_used_count=$(get pv_field "$1" pv_mda_used_count) if [ $pv_mda_count -gt $pv_mda_used_count ]; then pvchange --metadataignore n $1 fi } echo Test of vgmetadatacopies with vgcreate and vgchange for mdacp in 1 2; do pvcreate --metadatacopies $mdacp "$dev1" "$dev2" "$dev4" "$dev5" check pv_field "$dev1" pv_mda_used_count $mdacp check pv_field "$dev2" pv_mda_used_count $mdacp check pv_field "$dev4" pv_mda_used_count $mdacp check pv_field "$dev5" pv_mda_used_count $mdacp pvcreate --metadatacopies 0 "$dev3" vgcreate -c n $vg "$dev1" "$dev2" "$dev3" check vg_field $vg vg_mda_copies unmanaged echo ensure both --vgmetadatacopies and --metadatacopies accepted vgchange --metadatacopies $(($mdacp * 1)) $vg echo --vgmetadatacopies is persistent on disk echo --vgmetadatacopies affects underlying pv mda ignore check vg_field $vg vg_mda_copies $(($mdacp * 1)) check vg_field $vg vg_mda_used_count $(($mdacp * 1)) vgchange --vgmetadatacopies $(($mdacp * 2)) $vg check vg_field $vg vg_mda_copies $(($mdacp * 2)) check vg_field $vg vg_mda_used_count $(($mdacp * 2)) echo allow setting metadatacopies larger than number of PVs vgchange --vgmetadatacopies $(($mdacp * 5)) $vg check vg_field $vg vg_mda_copies $(($mdacp * 5)) check vg_field $vg vg_mda_used_count $(($mdacp * 2)) echo setting to 0 disables automatic balancing vgchange --vgmetadatacopies unmanaged $vg check vg_field $vg vg_mda_copies unmanaged vgremove -f $vg echo vgcreate succeeds even when creating a VG w/all ignored mdas pvchange --metadataignore y "$dev1" "$dev2" check pv_field "$dev1" pv_mda_count $mdacp check pv_field "$dev2" pv_mda_used_count 0 vgcreate -c n $vg "$dev1" "$dev2" check vg_field $vg vg_mda_copies unmanaged vgremove -f $vg echo vgcreate succeeds with a specific number of metadata copies vgcreate -c n --vgmetadatacopies $(($mdacp * 2)) $vg "$dev1" "$dev2" check vg_field $vg vg_mda_copies $(($mdacp * 2)) vgremove -f $vg vgcreate -c n --vgmetadatacopies $(($mdacp * 1)) $vg "$dev1" "$dev2" check vg_field $vg vg_mda_copies $(($mdacp * 1)) vgremove -f $vg echo vgcreate succeeds with a larger value than total metadatacopies vgcreate -c n --vgmetadatacopies $(($mdacp * 5)) $vg "$dev1" "$dev2" check vg_field $vg vg_mda_copies $(($mdacp * 5)) vgremove -f $vg echo vgcreate succeeds with --vgmetadatacopies unmanaged vgcreate -c n --vgmetadatacopies unmanaged $vg "$dev1" "$dev2" check vg_field $vg vg_mda_copies unmanaged vgremove -f $vg pvunignore_ "$dev1" pvunignore_ "$dev2" pvunignore_ "$dev4" pvunignore_ "$dev5" echo vgcreate succeds with small value of --metadatacopies, ignores mdas vgcreate -c n --vgmetadatacopies 1 $vg "$dev1" "$dev2" "$dev4" "$dev5" check vg_field $vg vg_mda_copies 1 check vg_field $vg vg_mda_count $(($mdacp * 4)) check vg_field $vg vg_mda_used_count 1 echo Setting a larger value should trigger non-ignore of mdas vgchange --metadatacopies 3 $vg check vg_field $vg vg_mda_copies 3 check vg_field $vg vg_mda_used_count 3 echo Setting all should trigger unignore of all mdas vgchange --vgmetadatacopies all $vg check vg_field $vg vg_mda_count $(($mdacp * 4)) check vg_field $vg vg_mda_copies unmanaged check vg_field $vg vg_mda_used_count $(($mdacp * 4)) echo --vgmetadatacopies 0 should be unmanaged for vgchange and vgcreate vgchange --vgmetadatacopies 0 $vg check vg_field $vg vg_mda_copies unmanaged vgremove -f $vg vgcreate -c n --vgmetadatacopies 0 $vg "$dev1" "$dev2" "$dev4" "$dev5" check vg_field $vg vg_mda_copies unmanaged vgremove -f $vg done echo Test vgextend / vgreduce with vgmetadatacopies for mdacp in 1 2; do pvcreate --metadatacopies $mdacp "$dev1" "$dev2" "$dev4" "$dev5" pvcreate --metadatacopies 0 "$dev3" echo Set a large value of vgmetadatacopies vgcreate -c n --vgmetadatacopies $(($mdacp * 5)) $vg "$dev1" "$dev2" "$dev3" check vg_field $vg vg_mda_copies $(($mdacp * 5)) echo Ignore mdas on devices to be used for vgextend echo Large value of vgetadatacopies should automatically un-ignore mdas pvchange --metadataignore y "$dev4" "$dev5" check pv_field "$dev4" pv_mda_used_count 0 vgextend $vg "$dev4" "$dev5" check pv_field "$dev4" pv_mda_used_count $mdacp check pv_field "$dev5" pv_mda_used_count $mdacp vgremove -f $vg echo Set a small value of vgmetadatacopies vgcreate -c n --vgmetadatacopies $(($mdacp * 1)) $vg "$dev1" "$dev2" "$dev3" check vg_field $vg vg_mda_copies $(($mdacp * 1)) echo Ignore mdas on devices to be used for vgextend echo Small value of vgetadatacopies should leave mdas as ignored pvchange --metadataignore y "$dev4" "$dev5" check pv_field "$dev4" pv_mda_used_count 0 vgextend $vg "$dev4" "$dev5" check pv_field "$dev4" pv_mda_used_count 0 check pv_field "$dev5" pv_mda_used_count 0 echo vgreduce of ignored pv w/mda should not trigger any change to ignore bits vgreduce $vg "$dev4" check pv_field "$dev4" pv_mda_used_count 0 check pv_field "$dev5" pv_mda_used_count 0 echo vgreduce of un-ignored pv w/mda should trigger un-ignore on an mda vgreduce $vg "$dev1" "$dev2" "$dev3" check pv_field "$dev5" pv_mda_used_count $mdacp check vg_field $vg vg_mda_copies $(($mdacp * 1)) pvunignore_ "$dev1" pvunignore_ "$dev2" echo setting vgmetadatacopies to unmanaged should allow vgextend to add w/out balancing vgchange --vgmetadatacopies unmanaged $vg vgextend $vg "$dev1" "$dev2" check vg_field $vg vg_mda_copies unmanaged check vg_field $vg vg_mda_count $(($mdacp * 3)) check vg_field $vg vg_mda_used_count $((mdacp * 3)) check pv_field "$dev1" pv_mda_used_count $mdacp check pv_field "$dev2" pv_mda_used_count $mdacp vgremove -f $vg done echo Test special situations, vgsplit, vgmerge, etc for mdacp in 1 2; do pvcreate --metadatacopies $mdacp "$dev1" "$dev2" "$dev3" "$dev4" "$dev5" vgcreate -c n --vgmetadatacopies 2 $vg1 "$dev1" "$dev2" "$dev3" vgcreate -c n --vgmetadatacopies $(($mdacp * 1)) $vg2 "$dev4" "$dev5" echo vgsplit/vgmerge preserves value of metadata copies check vg_field $vg1 vg_mda_copies 2 check vg_field $vg2 vg_mda_copies $(($mdacp * 1)) vgsplit $vg1 $vg2 "$dev1" check vg_field $vg2 vg_mda_copies $(($mdacp * 1)) vgmerge $vg1 $vg2 check vg_field $vg1 vg_mda_copies 2 check vg_field $vg1 vg_mda_count $(($mdacp * 5)) echo vgsplit into new vg sets proper value of vgmetadatacopies vgsplit --vgmetadatacopies $(($mdacp * 2)) $vg1 $vg2 "$dev1" "$dev2" check vg_field $vg2 vg_mda_copies $(($mdacp * 2)) echo vgchange fails if given both vgmetadatacopies and metadatacopies not vgchange --vgmetadatacopies 5 --metadatacopies 7 $vg2 vgremove -f $vg1 $vg2 done echo Test combination of --vgmetadatacopies and pvchange --metadataignore for mdacp in 1 2; do pvcreate --metadatacopies $mdacp "$dev1" "$dev2" "$dev3" "$dev4" "$dev5" vgcreate -c n --vgmetadatacopies $(($mdacp * 1)) $vg1 "$dev1" "$dev2" check vg_field $vg1 vg_mda_copies $(($mdacp * 1)) check vg_field $vg1 vg_mda_used_count $(($mdacp * 1)) pvignore_ "$dev3" echo Ensure vgextend of PVs with ignored MDAs does not add to vg_mda_used_count vgextend $vg1 "$dev3" check vg_field $vg1 vg_mda_used_count $(($mdacp * 1)) echo Using pvchange to unignore should update vg_mda_used_count pvchange -f --metadataignore n "$dev3" check pv_field "$dev3" pv_mda_used_count $mdacp check vg_field $vg1 vg_mda_used_count $(($mdacp * 2)) echo Set unmanaged on the vg should keep ignore bits the same during vgextend vgchange --vgmetadatacopies unmanaged $vg1 check vg_field $vg1 vg_mda_used_count $(($mdacp * 2)) pvunignore_ "$dev4" vgextend $vg1 "$dev4" check pv_field "$dev4" pv_mda_used_count $mdacp check vg_field $vg1 vg_mda_used_count $(($mdacp * 3)) echo Using pvchange to ignore should update vg_mda_used_count pvchange -f --metadataignore y "$dev4" check pv_field "$dev4" pv_mda_used_count 0 check vg_field $vg1 vg_mda_used_count $(($mdacp * 2)) vgremove -f $vg1 done lvm2-2.02.98/test/shell/mirror-names.sh0000640000175000017500000000714412037016273016554 0ustar blankblank#!/bin/sh # Copyright (C) 2007-2012 Red Hat, Inc. All rights reserved. # Copyright (C) 2007-2008 NEC Corporation # # 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 test_description="check namings of mirrored LV" . lib/test # --------------------------------------------------------------------- # Utilities lv_devices_() { local d local lv=$1 shift local devices=$@ local devs=$(get lv_field $lv devices -a | sed 's/([0-9]*)//g; s/ //g; s/,/ /g') for d in $devs; do (echo $devices | grep $d) || return 1 devices=$(echo $devices | sed "s/$d//") done test -z "$(echo $devices | sed 's/ //g')" } lv_mirror_log_() { test $(get lv_field $1 mirror_log) = $2 } lv_convert_lv_() { get lv_field $1 convert_lv } # --------------------------------------------------------------------- # Common environment setup/cleanup for each sub testcases check_and_cleanup_lvs_() { lvs -a -o+devices $vg lvremove -ff $vg (dm_table | not grep $vg) || \ die "ERROR: lvremove did leave some some mappings in DM behind!" } # --------------------------------------------------------------------- # Initialize PVs and VGs aux prepare_vg 5 80 check_and_cleanup_lvs_ # --------------------------------------------------------------------- # basic #COMM "init: lvcreate" #COMM "mirror images are ${lv1}_mimage_x" lvcreate -l2 -m1 -n $lv1 $vg lv_devices_ $vg/$lv1 ${lv1}_mimage_0 ${lv1}_mimage_1 #COMM "mirror log is ${lv1}_mlog" lv_mirror_log_ $vg/$lv1 ${lv1}_mlog # "cleanup" check_and_cleanup_lvs_ #COMM "mirror with name longer than 22 characters (bz221322)" name="LVwithanamelogerthan22characters_butidontwonttocounthem" lvcreate -m1 -l2 -n $name $vg lvs $vg/$name check_and_cleanup_lvs_ # --------------------------------------------------------------------- # lvrename #COMM "init: lvrename" #COMM "renamed mirror names: $lv1 to $lv2" lvcreate -l2 -m1 -n $lv1 $vg lvrename $vg/$lv1 $vg/$lv2 lv_devices_ $vg/$lv2 ${lv2}_mimage_0 ${lv2}_mimage_1 lv_mirror_log_ $vg/$lv2 ${lv2}_mlog #COMM "cleanup" check_and_cleanup_lvs_ # --------------------------------------------------------------------- # lvconvert #COMM "init: lvconvert" #COMM "converting mirror names is ${lv1}_mimagetmp_2" lvcreate -l2 -m1 -n $lv1 $vg lvconvert -m+1 -i+40 -b $vg/$lv1 convlv=$(lv_convert_lv_ $vg/$lv1) test $convlv = ${lv1}_mimagetmp_2 lv_devices_ $vg/$lv1 $convlv ${lv1}_mimage_2 lv_devices_ $vg/$convlv ${lv1}_mimage_0 ${lv1}_mimage_1 lv_mirror_log_ $vg/$convlv ${lv1}_mlog #COMM "mirror log name after re-adding is ${lv1}_mlog" \ lvconvert --mirrorlog core $vg/$lv1 lvconvert --mirrorlog disk $vg/$lv1 convlv=$(lv_convert_lv_ $vg/$lv1) lv_devices_ $vg/$lv1 $convlv ${lv1}_mimage_2 lv_devices_ $vg/$convlv ${lv1}_mimage_0 ${lv1}_mimage_1 lv_mirror_log_ $vg/$convlv ${lv1}_mlog #COMM "renamed converting mirror names: $lv1 to $lv2" \ lvrename $vg/$lv1 $vg/$lv2 convlv=$(lv_convert_lv_ $vg/$lv2) lv_devices_ $vg/$lv2 $convlv ${lv2}_mimage_2 lv_devices_ $vg/$convlv ${lv2}_mimage_0 ${lv2}_mimage_1 lv_mirror_log_ $vg/$convlv ${lv2}_mlog #COMM "cleanup" check_and_cleanup_lvs_ # Temporary mirror log should have "_mlogtmp_" suffix # but currently lvconvert doesn't have an option to add the log. # If such feature is added in future, a test for that should # be added. # --------------------------------------------------------------------- lvm2-2.02.98/test/shell/mirror-vgreduce-removemissing.sh0000640000175000017500000002612612037016273022143 0ustar blankblank#!/bin/sh # Copyright (C) 2008-2012 Red Hat, Inc. All rights reserved. # Copyright (C) 2007 NEC Corporation # # 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 test_description="ensure that 'vgreduce --removemissing' works on mirrored LV" . lib/test lv_is_on_ () { local lv=$vg/$1 shift local pvs=$@ echo "Check if $lv is exactly on PVs $pvs" rm -f out1 out2 echo $pvs | sed 's/ /\n/g' | sort | uniq > out1 lvs -a -o+devices $lv get lv_devices $lv | sed 's/ /\n/g' | sort | uniq > out2 || true diff --ignore-blank-lines out1 out2 } mimages_are_on_ () { local lv=$1 shift local pvs=$@ local mimages local i echo "Check if mirror images of $lv are on PVs $pvs" rm -f out1 out2 echo $pvs | sed 's/ /\n/g' | sort | uniq > out1 lvs --noheadings -a -o lv_name $vg > lvs_log mimages=$(grep "${lv}_mimage_" lvs_log | \ sed 's/\[//g; s/\]//g' || true) for i in $mimages; do echo "Checking $vg/$i" lvs -a -o+devices $vg/$i lvs -a -odevices --noheadings $vg/$i > lvs_log sed 's/([^)]*)//g; s/ //g; s/,/ /g' lvs_log | sort | uniq >> out2 || true done diff --ignore-blank-lines out1 out2 } mirrorlog_is_on_() { local lv=${1}_mlog shift lv_is_on_ $lv "$@" } lv_is_linear_() { echo "Check if $1 is linear LV (i.e. not a mirror)" get lv_field $vg/$1 "stripes,attr" | grep "^1 -" >/dev/null } rest_pvs_() { local index=$1 local num=$2 local rem= local n for n in $(seq 1 $(($index - 1))) $(seq $(($index + 1)) $num); do eval local dev=$\dev$n rem="$rem $dev" done echo "$rem" } # --------------------------------------------------------------------- # Initialize PVs and VGs aux prepare_vg 5 # --------------------------------------------------------------------- # Common environment setup/cleanup for each sub testcases prepare_lvs_() { lvremove -ff $vg (dm_table | not grep $vg) || \ die "ERROR: lvremove did leave some some mappings in DM behind!" } check_and_cleanup_lvs_() { lvs -a -o+devices $vg prepare_lvs_ } recover_vg_() { aux enable_dev "$@" pvcreate -ff "$@" vgextend $vg "$@" check_and_cleanup_lvs_ } #COMM "check environment setup/cleanup" prepare_lvs_ check_and_cleanup_lvs_ # --------------------------------------------------------------------- # one of mirror images has failed #COMM "basic: fail the 2nd mirror image of 2-way mirrored LV" prepare_lvs_ lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3":0 lvchange -an $vg/$lv1 mimages_are_on_ $lv1 $dev1 $dev2 mirrorlog_is_on_ $lv1 $dev3 aux disable_dev "$dev2" vgreduce --removemissing --force $vg lv_is_linear_ $lv1 lv_is_on_ $lv1 "$dev1" # "cleanup" recover_vg_ "$dev2" # --------------------------------------------------------------------- # LV has 3 images in flat, # 1 out of 3 images fails #COMM test_3way_mirror_fail_1_ test_3way_mirror_fail_1_() { local index=$1 lvcreate -l2 -m2 -n $lv1 $vg "$dev1" "$dev2" "$dev3" "$dev4":0 lvchange -an $vg/$lv1 mimages_are_on_ $lv1 "$dev1" "$dev2" "$dev3" mirrorlog_is_on_ $lv1 "$dev4" eval aux disable_dev \$dev$index vgreduce --removemissing --force $vg lvs -a -o+devices $vg mimages_are_on_ $lv1 $(rest_pvs_ $index 3) mirrorlog_is_on_ $lv1 "$dev4" } for n in $(seq 1 3); do #COMM fail mirror image $(($n - 1)) of 3-way mirrored LV" prepare_lvs_ test_3way_mirror_fail_1_ $n eval recover_vg_ \$dev$n done # --------------------------------------------------------------------- # LV has 3 images in flat, # 2 out of 3 images fail #COMM test_3way_mirror_fail_2_ test_3way_mirror_fail_2_() { local index=$1 lvcreate -l2 -m2 -n $lv1 $vg "$dev1" "$dev2" "$dev3" "$dev4":0 lvchange -an $vg/$lv1 mimages_are_on_ $lv1 "$dev1" "$dev2" "$dev3" mirrorlog_is_on_ $lv1 "$dev4" rest_pvs_ $index 3 aux disable_dev $(rest_pvs_ $index 3) vgreduce --force --removemissing $vg lvs -a -o+devices $vg lv_is_linear_ $lv1 eval lv_is_on_ $lv1 \$dev$n } for n in $(seq 1 3); do #COMM fail mirror images other than mirror image $(($n - 1)) of 3-way mirrored LV prepare_lvs_ test_3way_mirror_fail_2_ $n recover_vg_ $(rest_pvs_ $n 3) done # --------------------------------------------------------------------- # LV has 4 images, 1 of them is in the temporary mirror for syncing. # 1 out of 4 images fails #COMM test_3way_mirror_plus_1_fail_1_ test_3way_mirror_plus_1_fail_1_() { local index=$1 lvcreate -l2 -m2 -n $lv1 $vg "$dev1" "$dev2" "$dev3" "$dev5":0 lvchange -an $vg/$lv1 lvconvert -m+1 $vg/$lv1 "$dev4" check mirror_images_on $vg $lv1 "$dev1" "$dev2" "$dev3" "$dev4" check mirror_log_on $vg $lv1 "$dev5" eval aux disable_dev \$dev$index lvs -a -o +devices vgreduce --removemissing --force $vg lvs -a -o+devices # $vg check mirror_images_on $vg $lv1 "$dev5" # $(rest_pvs_ $index 4) check mirror_log_on $vg $lv1 "$dev5" } for n in $(seq 1 4); do #COMM "fail mirror image $(($n - 1)) of 4-way (1 converting) mirrored LV" prepare_lvs_ test_3way_mirror_plus_1_fail_1_ $n eval recover_vg_ \$dev$n done # --------------------------------------------------------------------- # LV has 4 images, 1 of them is in the temporary mirror for syncing. # 3 out of 4 images fail #COMM test_3way_mirror_plus_1_fail_3_ test_3way_mirror_plus_1_fail_3_() { local index=$1 lvcreate -l2 -m2 -n $lv1 $vg "$dev1" "$dev2" "$dev3" "$dev5":0 lvchange -an $vg/$lv1 lvconvert -m+1 $vg/$lv1 "$dev4" check mirror_images_on $vg $lv1 "$dev1" "$dev2" "$dev3" "$dev4" check mirror_log_on $vg $lv1 "$dev5" lvs -a -o+devices $vg aux disable_dev $(rest_pvs_ $index 4) vgreduce --removemissing --force $vg lvs -a -o+devices $vg eval local dev=\$dev$n check linear $vg $lv1 check lv_on $vg $lv1 $dev } for n in $(seq 1 4); do #COMM "fail mirror images other than mirror image $(($n - 1)) of 4-way (1 converting) mirrored LV" prepare_lvs_ test_3way_mirror_plus_1_fail_3_ $n recover_vg_ $(rest_pvs_ $n 4) done # --------------------------------------------------------------------- # LV has 4 images, 2 of them are in the temporary mirror for syncing. # 1 out of 4 images fail # test_2way_mirror_plus_2_fail_1_ test_2way_mirror_plus_2_fail_1_() { local index=$1 lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev5":0 lvchange -an $vg/$lv1 lvconvert -m+2 $vg/$lv1 "$dev3" "$dev4" mimages_are_on_ $lv1 "$dev1" "$dev2" "$dev3" "$dev4" mirrorlog_is_on_ $lv1 "$dev5" eval aux disable_dev \$dev$n vgreduce --removemissing --force $vg lvs -a -o+devices $vg mimages_are_on_ $lv1 $(rest_pvs_ $index 4) mirrorlog_is_on_ $lv1 "$dev5" } for n in $(seq 1 4); do #COMM "fail mirror image $(($n - 1)) of 4-way (2 converting) mirrored LV" prepare_lvs_ test_2way_mirror_plus_2_fail_1_ $n eval recover_vg_ \$dev$n done # --------------------------------------------------------------------- # LV has 4 images, 2 of them are in the temporary mirror for syncing. # 3 out of 4 images fail # test_2way_mirror_plus_2_fail_3_ test_2way_mirror_plus_2_fail_3_() { local index=$1 lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev5":0 lvchange -an $vg/$lv1 lvconvert -m+2 $vg/$lv1 "$dev3" "$dev4" mimages_are_on_ $lv1 "$dev1" "$dev2" "$dev3" "$dev4" mirrorlog_is_on_ $lv1 "$dev5" aux disable_dev $(rest_pvs_ $index 4) vgreduce --removemissing --force $vg lvs -a -o+devices $vg eval local dev=\$dev$n mimages_are_on_ $lv1 $dev || lv_is_on_ $lv1 $dev not mirrorlog_is_on_ $lv1 "$dev5" } for n in $(seq 1 4); do #COMM "fail mirror images other than mirror image $(($n - 1)) of 4-way (2 converting) mirrored LV" prepare_lvs_ test_2way_mirror_plus_2_fail_3_ $n recover_vg_ $(rest_pvs_ $n 4) done # --------------------------------------------------------------------- # log device is gone (flat mirror and stacked mirror) #COMM "fail mirror log of 2-way mirrored LV" prepare_lvs_ lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev5":0 lvchange -an $vg/$lv1 mimages_are_on_ $lv1 "$dev1" "$dev2" mirrorlog_is_on_ $lv1 "$dev5" aux disable_dev "$dev5" vgreduce --removemissing --force $vg mimages_are_on_ $lv1 "$dev1" "$dev2" not mirrorlog_is_on_ $lv1 "$dev5" recover_vg_ "$dev5" #COMM "fail mirror log of 3-way (1 converting) mirrored LV" prepare_lvs_ lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev5":0 lvchange -an $vg/$lv1 lvconvert -m+1 $vg/$lv1 "$dev3" mimages_are_on_ $lv1 "$dev1" "$dev2" "$dev3" mirrorlog_is_on_ $lv1 "$dev5" aux disable_dev "$dev5" vgreduce --removemissing --force $vg mimages_are_on_ $lv1 "$dev1" "$dev2" "$dev3" not mirrorlog_is_on_ $lv1 "$dev5" recover_vg_ "$dev5" # --------------------------------------------------------------------- # all images are gone (flat mirror and stacked mirror) #COMM "fail all mirror images of 2-way mirrored LV" prepare_lvs_ lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev5":0 lvchange -an $vg/$lv1 mimages_are_on_ $lv1 "$dev1" "$dev2" mirrorlog_is_on_ $lv1 "$dev5" aux disable_dev "$dev1" "$dev2" vgreduce --removemissing --force $vg not lvs $vg/$lv1 recover_vg_ "$dev1" "$dev2" #COMM "fail all mirror images of 3-way (1 converting) mirrored LV" prepare_lvs_ lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev5":0 lvchange -an $vg/$lv1 lvconvert -m+1 $vg/$lv1 "$dev3" mimages_are_on_ $lv1 "$dev1" "$dev2" "$dev3" mirrorlog_is_on_ $lv1 "$dev5" aux disable_dev "$dev1" "$dev2" "$dev3" vgreduce --removemissing --force $vg not lvs $vg/$lv1 recover_vg_ "$dev1" "$dev2" "$dev3" # --------------------------------------------------------------------- # Multiple LVs #COMM "fail a mirror image of one of mirrored LV" prepare_lvs_ lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev5":0 lvchange -an $vg/$lv1 lvcreate -l2 -m1 -n $lv2 $vg "$dev3" "$dev4" "$dev5":1 lvchange -an $vg/$lv2 mimages_are_on_ $lv1 "$dev1" "$dev2" mimages_are_on_ $lv2 "$dev3" "$dev4" mirrorlog_is_on_ $lv1 "$dev5" mirrorlog_is_on_ $lv2 "$dev5" aux disable_dev "$dev2" vgreduce --removemissing --force $vg mimages_are_on_ $lv2 "$dev3" "$dev4" mirrorlog_is_on_ $lv2 "$dev5" lv_is_linear_ $lv1 lv_is_on_ $lv1 "$dev1" recover_vg_ "$dev2" #COMM "fail mirror images, one for each mirrored LV" prepare_lvs_ lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev5":0 lvchange -an $vg/$lv1 lvcreate -l2 -m1 -n $lv2 $vg "$dev3" "$dev4" "$dev5":1 lvchange -an $vg/$lv2 mimages_are_on_ $lv1 "$dev1" "$dev2" mimages_are_on_ $lv2 "$dev3" "$dev4" mirrorlog_is_on_ $lv1 "$dev5" mirrorlog_is_on_ $lv2 "$dev5" aux disable_dev "$dev2" aux disable_dev "$dev4" vgreduce --removemissing --force $vg lv_is_linear_ $lv1 lv_is_on_ $lv1 "$dev1" lv_is_linear_ $lv2 lv_is_on_ $lv2 "$dev3" recover_vg_ "$dev2" "$dev4" # --------------------------------------------------------------------- # no failure #COMM "no failures" prepare_lvs_ lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev5":0 lvchange -an $vg/$lv1 mimages_are_on_ $lv1 "$dev1" "$dev2" mirrorlog_is_on_ $lv1 "$dev5" vgreduce --removemissing --force $vg mimages_are_on_ $lv1 "$dev1" "$dev2" mirrorlog_is_on_ $lv1 "$dev5" check_and_cleanup_lvs_ # --------------------------------------------------------------------- lvm2-2.02.98/test/shell/lvmetad-pvscan-cache.sh0000640000175000017500000000112612037016273020120 0ustar blankblank#!/bin/sh # Copyright (C) 2012 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 . lib/test test -e LOCAL_LVMETAD || skip aux prepare_pvs 2 vgcreate $vg1 $dev1 $dev2 vgs | grep $vg1 pvscan --cache vgs | grep $vg1 lvm2-2.02.98/test/shell/vgchange-sysinit.sh0000640000175000017500000000232612037016273017420 0ustar blankblank#!/bin/sh # Copyright (C) 2011 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 . lib/test which mkfs.ext3 || skip aux prepare_pvs 2 8 test -e LOCAL_CLVMD && skip var_lock="$DM_DEV_DIR/$vg1/$lv1" # keep in sync with aux configured lockingdir mount_dir="var/lock/lvm" cleanup_mounted_and_teardown() { umount "$mount_dir" || true aux teardown } vgcreate -c n $vg1 "$dev1" vgcreate -c n $vg2 "$dev2" lvcreate -l 1 -n $lv2 $vg2 vgchange -an $vg2 lvcreate -n $lv1 -l 100%FREE $vg1 mkfs.ext3 -b4096 -j "$var_lock" trap 'cleanup_mounted_and_teardown' EXIT mount -n -r "$var_lock" "$mount_dir" # locking must fail on read-only filesystem not vgchange -ay $vg2 # no-locking with --sysinit vgchange --sysinit -ay $vg2 test -b "$DM_DEV_DIR/$vg2/$lv2" vgchange --sysinit -an $vg2 test ! -b "$DM_DEV_DIR/$vg2/$lv2" vgchange --ignorelockingfailure -ay $vg2 lvm2-2.02.98/test/shell/vgextend-usage.sh0000640000175000017500000000726412037016273017072 0ustar blankblank#!/bin/sh # Copyright (C) 2008 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 # # Exercise various vgextend commands # . lib/test aux prepare_devs 5 for mdatype in 1 2 do # Explicit pvcreate pvcreate -M$mdatype "$dev1" "$dev2" "$dev3" "$dev4" "$dev5" vgcreate -M$mdatype $vg1 "$dev1" "$dev2" vgextend $vg1 "$dev3" "$dev4" "$dev5" vgremove -ff $vg1 # Implicit pvcreate pvremove "$dev1" "$dev2" "$dev3" "$dev4" "$dev5" vgcreate -M$mdatype $vg1 "$dev1" "$dev2" vgextend -M$mdatype $vg1 "$dev3" "$dev4" "$dev5" vgremove -ff $vg1 pvremove "$dev1" "$dev2" "$dev3" "$dev4" "$dev5" done # Implicit pvcreate tests, test pvcreate options on vgcreate # --force, --yes, --metadata{size|copies|type}, --zero # --dataalignment[offset] vgcreate $vg "$dev2" vgextend --force --yes --zero y $vg "$dev1" vgreduce $vg "$dev1" pvremove -f "$dev1" for i in 0 1 2 3 do # vgcreate (lvm2) succeeds writing LVM label at sector $i vgextend --labelsector $i $vg "$dev1" dd if="$dev1" bs=512 skip=$i count=1 2>/dev/null | strings | grep LABELONE >/dev/null vgreduce $vg "$dev1" pvremove -f "$dev1" done # pvmetadatacopies for i in 0 1 2 do vgextend --pvmetadatacopies $i $vg "$dev1" check pv_field "$dev1" pv_mda_count $i vgreduce $vg "$dev1" pvremove -f "$dev1" done # metadatasize, dataalignment, dataalignmentoffset #COMM 'pvcreate sets data offset next to mda area' vgextend --metadatasize 100k --dataalignment 100k $vg "$dev1" check pv_field "$dev1" pe_start 200.00k vgreduce $vg "$dev1" pvremove -f "$dev1" # data area is aligned to 1M by default, # data area start is shifted by the specified alignment_offset pv_align=1052160B # 1048576 + (7*512) vgextend --metadatasize 128k --dataalignmentoffset 7s $vg "$dev1" check pv_field "$dev1" pe_start $pv_align --units b vgremove -f $vg pvremove -f "$dev1" # vgextend fails if pv belongs to existing vg vgcreate $vg1 "$dev1" "$dev3" vgcreate $vg2 "$dev2" not vgextend $vg2 "$dev3" vgremove -f $vg1 vgremove -f $vg2 pvremove -f "$dev1" "$dev2" "$dev3" #vgextend fails if vg is not resizeable vgcreate $vg1 "$dev1" "$dev2" vgchange --resizeable n $vg1 not vgextend $vg1 "$dev3" vgremove -f $vg1 pvremove -f "$dev1" "$dev2" # all PVs exist in the VG after extended pvcreate "$dev1" vgcreate $vg1 "$dev2" vgextend $vg1 "$dev1" "$dev3" check pv_field "$dev1" vg_name $vg1 check pv_field "$dev2" vg_name $vg1 check pv_field "$dev3" vg_name $vg1 vgremove -f $vg1 pvremove -f "$dev1" "$dev2" "$dev3" echo test vgextend --metadataignore for mdacp in 1 2; do for ignore in y n; do echo vgextend --metadataignore has proper mda_count and mda_used_count vgcreate $vg "$dev3" vgextend --metadataignore $ignore --pvmetadatacopies $mdacp $vg "$dev1" "$dev2" check pv_field "$dev1" pv_mda_count $mdacp check pv_field "$dev2" pv_mda_count $mdacp if [ $ignore = y ]; then check pv_field "$dev1" pv_mda_used_count 0 check pv_field "$dev2" pv_mda_used_count 0 else check pv_field "$dev1" pv_mda_used_count $mdacp check pv_field "$dev2" pv_mda_used_count $mdacp fi echo vg has proper vg_mda_count and vg_mda_used_count check vg_field $vg vg_mda_count $(($mdacp * 2 + 1)) if [ $ignore = y ]; then check vg_field $vg vg_mda_used_count 1 else check vg_field $vg vg_mda_used_count $(($mdacp * 2 + 1)) fi check vg_field $vg vg_mda_copies unmanaged vgremove $vg pvremove -ff "$dev1" "$dev2" "$dev3" done done lvm2-2.02.98/test/shell/dumpconfig.sh0000640000175000017500000000307012037016272016265 0ustar blankblank#!/bin/sh # Copyright (C) 2011 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 . lib/test flatten() { cat > flatten.config for s in `egrep '^[a-z]+ {$' flatten.config | sed -e s,{$,,`; do sed -e "/^$s/,/^}/p;d" flatten.config | sed -e '1d;$d' | sed -e "s,^[ \t]*,$s/,"; done } # clvmd might not be started fast enough and # lvm still activates locking for all commands. # FIXME: Either make longer start delay, # or even better do not initialize # locking for commands like 'dumpconfig' #aux lvmconf "global/locking_type=0" lvm dumpconfig -f lvmdumpconfig flatten < lvmdumpconfig | sort > config.dump flatten < etc/lvm.conf | sort > config.input # check that dumpconfig output corresponds to the lvm.conf input diff -wu config.input config.dump # and that merging multiple config files (through tags) works lvm dumpconfig -f lvmdumpconfig flatten < lvmdumpconfig | not grep 'log/verbose=1' lvm dumpconfig -f lvmdumpconfig flatten < lvmdumpconfig | grep 'log/indent=1' aux lvmconf 'tags/@foo {}' echo 'log { verbose = 1 }' > etc/lvm_foo.conf lvm dumpconfig -f lvmdumpconfig flatten < lvmdumpconfig | grep 'log/verbose=1' lvm dumpconfig -f lvmdumpconfig flatten < lvmdumpconfig | grep 'log/indent=1' lvm2-2.02.98/test/shell/pool-labels.sh0000640000175000017500000000305412037016273016346 0ustar blankblank#!/bin/sh # Copyright (C) 2007 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 . lib/test env printf "" || skip # skip if printf is not available # create the old GFS pool labeled linear devices create_pool_label_() { # FIXME # echo -e is bashism, dash builtin sh doesn't do \xNN in printf either # printf comes from coreutils, and is probably not posix either env printf "\x01\x16\x70\x06\x5f\xcf\xff\xb9\xf8\x24\x8apool1" | dd of="$2" bs=5 seek=1 conv=notrunc env printf "\x04\x01\x03\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x0$1\x68\x01\x16\x70\x00\x00\x00\x00\x00\x06\x5f\xd0" | dd of=$2 bs=273 seek=1 conv=notrunc aux notify_lvmetad "$2" } aux prepare_devs 2 create_pool_label_ 0 "$dev1" create_pool_label_ 1 "$dev2" # check that pvcreate fails without -ff on the pool device not pvcreate "$dev1" # check that vgdisplay and pvcreate -ff works with the pool device vgdisplay --config 'global { locking_type = 0 }' aux disable_dev "$dev2" # FIXME! since pool1 cannot be opened, vgdisplay gives error... should we say # "not" there instead, checking that it indeed does fail? vgdisplay --config 'global { locking_type = 0 }' || true pvcreate -ff -y "$dev1" lvm2-2.02.98/test/shell/discards-thin.sh0000640000175000017500000000250312037016272016666 0ustar blankblank#!/bin/sh # Copyright (C) 2012 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 # # test support of thin discards # . lib/test # # Main # aux have_thin 1 1 0 || skip aux prepare_pvs 2 64 vgcreate $vg -s 64K $(cat DEVICES) # Create named pool only lvcreate -l1 --discards ignore -T $vg/pool check lv_field $vg/pool discards "ignore" lvcreate -l1 --discards nopassdown -T $vg/pool1 check lv_field $vg/pool1 discards "nopassdown" lvcreate -l1 --discards passdown -T $vg/pool2 check lv_field $vg/pool2 discards "passdown" lvchange --discards nopassdown $vg/pool2 # cannot convert active ignore -> passdown not lvchange --discards passdown $vg/pool # cannot convert active nopassdown -> ignore not lvchange --discards ignore $vg/pool1 # deactivate lvchange -an $vg/pool $vg/pool1 lvchange --discards passdown $vg/pool check lv_field $vg/pool discards "passdown" lvchange --discards ignore $vg/pool1 check lv_field $vg/pool1 discards "ignore" vgremove -ff $vg lvm2-2.02.98/test/shell/fsadm.sh0000640000175000017500000000730412037016272015230 0ustar blankblank#!/bin/sh # Copyright (C) 2008-2012 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 test_description='Exercise fsadm filesystem resize' . lib/test aux prepare_vg 1 100 # set to "skip" to avoid testing given fs and test warning result # i.e. check_reiserfs=skip check_ext3= check_xfs= check_reiserfs= which mkfs.ext3 || check_ext3=${check_ext3:-mkfs.ext3} which fsck.ext3 || check_ext3=${check_ext3:-fsck.ext3} which mkfs.xfs || check_xfs=${check_xfs:-mkfs.xfs} which xfs_check || check_xfs=${check_xfs:-xfs_check} which mkfs.reiserfs || check_reiserfs=${check_reiserfs:-mkfs.reiserfs} which reiserfsck || check_reiserfs=${check_reiserfs:-reiserfsck} vg_lv=$vg/$lv1 vg_lv2=$vg/${lv1}bar dev_vg_lv="$DM_DEV_DIR/$vg_lv" dev_vg_lv2="$DM_DEV_DIR/$vg_lv2" mount_dir="mnt" mount_space_dir="mnt space dir" # for recursive call export LVM_BINARY=$(which lvm) test ! -d "$mount_dir" && mkdir "$mount_dir" test ! -d "$mount_space_dir" && mkdir "$mount_space_dir" cleanup_mounted_and_teardown() { umount "$mount_dir" || true umount "$mount_space_dir" || true aux teardown } fscheck_ext3() { fsck.ext3 -p -F -f "$dev_vg_lv" } fscheck_xfs() { xfs_check "$dev_vg_lv" } fscheck_reiserfs() { reiserfsck --check -p -f "$dev_vg_lv" out pvdisplay --maps $(cat DEVICES) >out2 not diff out out2 lvm2-2.02.98/test/shell/metadata.sh0000640000175000017500000000424312037016273015716 0ustar blankblank#!/bin/sh # Copyright (C) 2008 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 . lib/test aux prepare_devs 5 pvcreate "$dev1" pvcreate --metadatacopies 0 "$dev2" pvcreate --metadatacopies 0 "$dev3" pvcreate "$dev4" pvcreate --metadatacopies 0 "$dev5" vgcreate -c n $vg $(cat DEVICES) lvcreate -n $lv -l 1 -i5 -I256 $vg pvchange -x n "$dev1" pvchange -x y "$dev1" vgchange -a n $vg pvchange --uuid "$dev1" pvchange --uuid "$dev2" vgremove -f $vg # check that PVs without metadata don't cause too many full device rescans (bz452606) for mdacp in 1 0; do pvcreate --metadatacopies $mdacp $(cat DEVICES) pvcreate "$dev1" vgcreate -c n $vg $(cat DEVICES) lvcreate -n $lv1 -l 2 -i5 -I256 $vg lvcreate -n $lv2 -m2 -l 2 $vg lvchange -an $vg/$lv1 $vg/$lv2 vgchange -ay $vg lvchange -an $vg/$lv1 $vg/$lv2 vgremove -f $vg done not grep "Cached VG .* incorrect PV list" out0 # some M1 metadata tests pvcreate -M1 "$dev1" "$dev2" "$dev3" pv3_uuid=$(get pv_field "$dev3" pv_uuid) vgcreate -M1 -c n $vg "$dev1" "$dev2" "$dev3" pvchange --uuid "$dev1" # verify pe_start of all M1 PVs pv_align="128.00k" check pv_field "$dev1" pe_start $pv_align check pv_field "$dev2" pe_start $pv_align check pv_field "$dev3" pe_start $pv_align pvs --units k -o name,pe_start,vg_mda_size,vg_name $(cat DEVICES) # upgrade from v1 to v2 metadata vgconvert -M2 $vg # verify pe_start of all M2 PVs check pv_field "$dev1" pe_start $pv_align check pv_field "$dev2" pe_start $pv_align check pv_field "$dev3" pe_start $pv_align pvs --units k -o name,pe_start,vg_mda_size,vg_name $(cat DEVICES) # create backup and then restore $dev3 vgcfgbackup -f $TESTDIR/bak-%s $vg pvcreate -ff -y --restorefile $TESTDIR/bak-$vg --uuid $pv3_uuid "$dev3" vgcfgrestore -f $TESTDIR/bak-$vg $vg # verify pe_start of $dev3 check pv_field "$dev3" pe_start $pv_align lvm2-2.02.98/test/shell/lvconvert-repair-snapshot.sh0000640000175000017500000000167412037016272021301 0ustar blankblank#!/bin/sh # Copyright (C) 2011 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 . lib/test aux prepare_vg 5 aux lvmconf 'allocation/maximise_cling = 0' aux lvmconf 'allocation/mirror_logs_require_separate_pvs = 1' lvcreate -m 3 --ig -L 2M -n 4way $vg "$dev1" "$dev2" "$dev3" "$dev4" "$dev5":0 lvcreate -s $vg/4way -L 2M -n snap aux disable_dev "$dev2" "$dev4" echo n | lvconvert --repair $vg/4way 2>&1 | tee 4way.out lvs -a -o +devices $vg | not grep unknown vgreduce --removemissing $vg aux enable_dev "$dev2" "$dev4" lvs -a -o +devices $vg check mirror $vg 4way "$dev5" lvm2-2.02.98/test/shell/snapshot-merge.sh0000640000175000017500000000730212037016273017071 0ustar blankblank#!/bin/sh # Copyright (C) 2010-2012 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 . lib/test which mkfs.ext3 || skip lvdev_() { echo "$DM_DEV_DIR/$1/$2" } snap_lv_name_() { echo ${1}_snap } setup_merge_() { local VG_NAME=$1 local LV_NAME=$2 local NUM_EXTRA_SNAPS=${3:-0} local BASE_SNAP_LV_NAME=$(snap_lv_name_ $LV_NAME) lvcreate -n $LV_NAME -l 50%FREE $VG_NAME lvcreate -s -n $BASE_SNAP_LV_NAME -l 20%FREE ${VG_NAME}/${LV_NAME} mkfs.ext3 "$(lvdev_ $VG_NAME $LV_NAME)" if [ $NUM_EXTRA_SNAPS -gt 0 ]; then for i in `seq 1 $NUM_EXTRA_SNAPS`; do lvcreate -s -n ${BASE_SNAP_LV_NAME}_${i} -l 20%FREE ${VG_NAME}/${LV_NAME} done fi } aux prepare_vg 1 100 mkdir test_mnt # test full merge of a single LV setup_merge_ $vg $lv1 # now that snapshot LV is created: test if snapshot-merge target is available aux target_at_least snapshot-merge 1 0 0 || skip # make sure lvconvert --merge requires explicit LV listing not lvconvert --merge 2>err lvconvert --merge $vg/$(snap_lv_name_ $lv1) lvremove -f $vg/$lv1 # test that an actively merging snapshot may not be removed setup_merge_ $vg $lv1 lvconvert -i+100 --merge --background $vg/$(snap_lv_name_ $lv1) not lvremove -f $vg/$(snap_lv_name_ $lv1) lvremove -f $vg/$lv1 # "onactivate merge" test setup_merge_ $vg $lv1 mount "$(lvdev_ $vg $lv1)" test_mnt lvconvert --merge $vg/$(snap_lv_name_ $lv1) # -- refresh LV while FS is still mounted (merge must not start), # verify 'snapshot-origin' target is still being used lvchange --refresh $vg/$lv1 umount test_mnt dm_table $vg-$lv1 | grep " snapshot-origin " # -- refresh LV to start merge (now that FS is unmounted), # an active merge uses the 'snapshot-merge' target lvchange --refresh $vg/$lv1 # check whether it's still merging - or maybe got already merged (slow test) dm_table $vg-$lv1 | grep " snapshot-merge " || dm_table $vg-$lv1 | grep " linear " # -- don't care if merge is still active; lvremove at this point # may test stopping an active merge lvremove -f $vg/$lv1 # "onactivate merge" test # -- deactivate/remove after disallowed merge attempt, tests # to make sure preload of origin's metadata is _not_ performed setup_merge_ $vg $lv1 mount "$(lvdev_ $vg $lv1)" test_mnt lvconvert --merge $vg/$(snap_lv_name_ $lv1) # -- refresh LV while FS is still mounted (merge must not start), # verify 'snapshot-origin' target is still being used lvchange --refresh $vg/$lv1 umount test_mnt dm_table $vg-$lv1 | grep " snapshot-origin " >/dev/null lvremove -f $vg/$lv1 # test multiple snapshot merge; tests copy out that is driven by merge setup_merge_ $vg $lv1 1 lvconvert --merge $vg/$(snap_lv_name_ $lv1) lvremove -f $vg/$lv1 # test merging multiple snapshots that share the same tag setup_merge_ $vg $lv1 setup_merge_ $vg $lv2 lvchange --addtag this_is_a_test $vg/$(snap_lv_name_ $lv1) lvchange --addtag this_is_a_test $vg/$(snap_lv_name_ $lv2) lvconvert --merge @this_is_a_test lvs $vg >out not grep $(snap_lv_name_ $lv1) out not grep $(snap_lv_name_ $lv2) out lvremove -f $vg/$lv1 $vg/$lv2 # FIXME following tests would need to poll merge progress, via periodic lvs? # Background processes don't lend themselves to lvm testsuite... # test: onactivate merge of a single lv # test: do onactivate, deactivate the origin LV, reactivate the LV, merge should resume # test: multiple onactivate merge vgremove -f $vg lvm2-2.02.98/test/shell/vgsplit-stacked.sh0000640000175000017500000000151612037016273017242 0ustar blankblank#!/bin/sh # 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 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 . lib/test aux lvmconf 'devices/filter = [ "a/dev\/mirror/", "a/dev\/mapper\/.*$/", "a/dev\/LVMTEST/", "r/.*/" ]' aux prepare_pvs 3 vgcreate $vg1 "$dev1" "$dev2" lvcreate -n $lv1 -l 100%FREE $vg1 #top VG pvcreate $DM_DEV_DIR/$vg1/$lv1 vgcreate $vg $DM_DEV_DIR/$vg1/$lv1 "$dev3" vgchange -a n $vg $vg1 # this should fail but not segfault, RHBZ 481793. not vgsplit $vg $vg1 "$dev3" lvm2-2.02.98/test/shell/vgreduce-removemissing-snapshot.sh0000640000175000017500000000216012037016273022460 0ustar blankblank#!/bin/sh # Copyright (C) 2011 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 . lib/test exit 0 # # Snapshots of 'mirrors' are not supported. They can no longer be created. # This file could be used to test some aspect of vgreduce, snapshot, and # RAID at some point though... # aux prepare_vg 5 lvcreate -m 3 --ig -L 2M -n 4way $vg "$dev1" "$dev2" "$dev3" "$dev4" "$dev5":0 lvcreate -s $vg/4way -L 2M -n snap lvcreate -i 2 -L 2M $vg "$dev1" "$dev2" -n stripe aux disable_dev "$dev2" "$dev4" echo n | lvconvert --repair $vg/4way aux enable_dev "$dev2" "$dev4" #not vgreduce --removemissing $vg vgreduce -v --removemissing --force $vg # "$dev2" "$dev4" lvs -a -o +devices $vg | not grep unknown lvs -a -o +devices $vg check mirror $vg 4way "$dev5" lvm2-2.02.98/test/shell/clvmd-restart.sh0000640000175000017500000000260012037016272016717 0ustar blankblank#!/bin/sh # Copyright (C) 2011 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 # set before test's clvmd is started, so it's passed in environ export LVM_CLVMD_BINARY=clvmd export LVM_BINARY=lvm . lib/test # only clvmd based test, skip otherwise test -e LOCAL_CLVMD || skip read LOCAL_CLVMD < LOCAL_CLVMD aux prepare_pvs 1 vgcreate --clustered y $vg $(cat DEVICES) lvcreate -an --zero n -n $lv1 -l1 $vg lvcreate -an --zero n -n $lv2 -l1 $vg lvcreate -l1 $vg lvchange -aey $vg/$lv1 lvchange -aey $vg/$lv2 "$LVM_CLVMD_BINARY" -S sleep .2 # restarted clvmd has the same PID (no fork, only execvp) NEW_LOCAL_CLVMD=$(pgrep clvmd) test "$LOCAL_CLVMD" -eq "$NEW_LOCAL_CLVMD" # try restart once more "$LVM_CLVMD_BINARY" -S sleep .2 # restarted clvmd has the same PID (no fork, only execvp) NEW_LOCAL_CLVMD=$(pgrep clvmd) test "$LOCAL_CLVMD" -eq "$NEW_LOCAL_CLVMD" # FIXME: Hmm - how could we test exclusivity is preserved in singlenode ? lvchange -an $vg/$lv1 lvchange -ay $vg/$lv1 "$LVM_CLVMD_BINARY" -R vgremove -ff $vg lvm2-2.02.98/test/shell/inconsistent-metadata.sh0000640000175000017500000000447512037016272020442 0ustar blankblank#!/bin/sh # Copyright (C) 2008 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 . lib/test aux prepare_vg 3 12 lvcreate -m 1 -l 1 -n mirror $vg lvcreate -l 1 -n resized $vg lvchange -a n $vg/mirror aux backup_dev $(cat DEVICES) init() { aux restore_dev $(cat DEVICES) lvs -o lv_name,lv_size --units k $vg | tee lvs.out grep resized lvs.out | not grep 8192 lvresize -L 8192K $vg/resized aux restore_dev "$dev1" } check() { lvs -o lv_name,lv_size --units k $vg | tee lvs.out grep resized lvs.out | grep 8192 } # vgscan fixes up metadata (needs --cache option for direct scan if lvmetad is used) test -e LOCAL_LVMETAD && cache="--cache" init vgscan $cache 2>&1 | tee cmd.out grep "Inconsistent metadata found for VG $vg" cmd.out test -e LOCAL_LVMETAD && vgrename $vg foo && vgrename foo $vg # trigger a write vgscan $cache 2>&1 | tee cmd.out not grep "Inconsistent metadata found for VG $vg" cmd.out check # only vgscan would have noticed metadata inconsistencies when lvmetad is active if !test -e LOCAL_LVMETAD; then # vgdisplay fixes init vgdisplay $vg 2>&1 | tee cmd.out grep "Inconsistent metadata found for VG $vg" cmd.out vgdisplay $vg 2>&1 | tee cmd.out not grep "Inconsistent metadata found for VG $vg" cmd.out check # lvs fixes up init lvs $vg 2>&1 | tee cmd.out grep "Inconsistent metadata found for VG $vg" cmd.out vgdisplay $vg 2>&1 | tee cmd.out not grep "Inconsistent metadata found for VG $vg" cmd.out check # vgs fixes up as well init vgs $vg 2>&1 | tee cmd.out grep "Inconsistent metadata found for VG $vg" cmd.out vgs $vg 2>&1 | tee cmd.out not grep "Inconsistent metadata found for VG $vg" cmd.out check fi echo Check auto-repair of failed vgextend - metadata written to original pv but not new pv vgremove -f $vg pvremove -ff $(cat DEVICES) pvcreate $(cat DEVICES) aux backup_dev "$dev2" vgcreate $vg "$dev1" vgextend $vg "$dev2" aux restore_dev "$dev2" should check compare_fields vgs $vg vg_mda_count pvs "$dev2" vg_mda_count lvm2-2.02.98/test/shell/test-partition.sh0000640000175000017500000000135512037016273017125 0ustar blankblank#!/bin/sh # 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 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 # # Testcase for bugzilla #621173 # excercises partition table scanning code path # LVM_TEST_CONFIG_DEVICES="types = [\"device-mapper\", 142]" . lib/test which sfdisk || skip aux prepare_pvs 1 30 pvs "$dev1" # create small partition table echo "1 2" | sfdisk "$dev1" pvs "$dev1" lvm2-2.02.98/test/shell/read-ahead.sh0000640000175000017500000000315312037016273016110 0ustar blankblank#!/bin/sh # Copyright (C) 2008 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 # # tests basic functionality of read-ahead and ra regressions # test_description='Test read-ahead functionality' . lib/test aux prepare_vg 5 #COMM "test various read ahead settings (bz450922)" lvcreate -l 100%FREE -i5 -I256 -n $lv $vg ra=$(get lv_field $vg/$lv lv_kernel_read_ahead --units s --nosuffix) test $(( ( $ra / 5 ) * 5 )) -eq $ra not lvchange -r auto $vg/$lv 2>&1 | grep auto check lv_field $vg/$lv lv_read_ahead auto check lv_field $vg/$lv lv_kernel_read_ahead 5120 --units s --nosuffix lvchange -r 640 $vg/$lv check lv_field $vg/$lv lv_read_ahead 640 --units s --nosuffix lvremove -ff $vg #COMM "read ahead is properly inherited from underlying PV" blockdev --setra 768 "$dev1" vgscan lvcreate -n $lv -L4m $vg "$dev1" test $(blockdev --getra $DM_DEV_DIR/$vg/$lv) -eq 768 lvremove -ff $vg # Check default, active/inactive values for read_ahead / kernel_read_ahead lvcreate -n $lv -l 50%FREE $vg lvchange -an $vg/$lv check lv_field $vg/$lv lv_read_ahead auto check lv_field $vg/$lv lv_kernel_read_ahead -1 lvchange -r 512 $vg/$lv lvchange -ay $vg/$lv check lv_field $vg/$lv lv_read_ahead 256.00k check lv_field $vg/$lv lv_kernel_read_ahead 256.00k lvremove -ff $vg lvm2-2.02.98/test/shell/lvchange-mirror.sh0000640000175000017500000000165212037016272017235 0ustar blankblank#!/bin/sh # 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 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 . lib/test aux prepare_dmeventd aux prepare_vg 3 # force resync 2-way active mirror lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3":0-1 check mirror $vg $lv1 "$dev3" echo y | lvchange --resync $vg/$lv1 check mirror $vg $lv1 "$dev3" lvremove -ff $vg # force resync 2-way inactive mirror lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3":0-1 lvchange -an $vg/$lv1 check mirror $vg $lv1 "$dev3" lvchange --resync $vg/$lv1 check mirror $vg $lv1 "$dev3" lvremove -ff $vg lvm2-2.02.98/test/shell/topology-support.sh0000640000175000017500000000607312037016273017527 0ustar blankblank#!/bin/sh # 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 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 . lib/test which mkfs.ext3 || skip check_logical_block_size() { local DEV_=$(cat SCSI_DEBUG_DEV) # Verify logical_block_size - requires Linux >= 2.6.31 SYSFS_LOGICAL_BLOCK_SIZE=$(echo /sys/block/$(basename $DEV_)/queue/logical_block_size) if [ -f "$SYSFS_LOGICAL_BLOCK_SIZE" ] ; then ACTUAL_LOGICAL_BLOCK_SIZE=$(cat $SYSFS_LOGICAL_BLOCK_SIZE) test $ACTUAL_LOGICAL_BLOCK_SIZE = $1 fi } lvdev_() { echo "$DM_DEV_DIR/$1/$2" } test_snapshot_mount() { lvcreate -L 16M -n $lv1 $vg "$dev1" mkfs.ext3 $(lvdev_ $vg $lv1) mkdir test_mnt mount "$(lvdev_ $vg $lv1)" test_mnt lvcreate -L 16M -n $lv2 -s $vg/$lv1 umount test_mnt # mount the origin mount "$(lvdev_ $vg $lv1)" test_mnt umount test_mnt # mount the snapshot mount "$(lvdev_ $vg $lv2)" test_mnt umount test_mnt rm -r test_mnt vgchange -an $vg lvremove -f $vg/$lv2 lvremove -f $vg/$lv1 } # FIXME add more topology-specific tests and validation (striped LVs, etc) NUM_DEVS=1 PER_DEV_SIZE=34 DEV_SIZE=$(($NUM_DEVS*$PER_DEV_SIZE)) # Test that kernel supports topology aux prepare_scsi_debug_dev $DEV_SIZE || skip if [ ! -e /sys/block/$(basename $(cat SCSI_DEBUG_DEV))/alignment_offset ] ; then aux cleanup_scsi_debug_dev skip fi aux cleanup_scsi_debug_dev # --------------------------------------------- # Create "desktop-class" 4K drive # (logical_block_size=512, physical_block_size=4096, alignment_offset=0): LOGICAL_BLOCK_SIZE=512 aux prepare_scsi_debug_dev $DEV_SIZE \ sector_size=$LOGICAL_BLOCK_SIZE physblk_exp=3 check_logical_block_size $LOGICAL_BLOCK_SIZE aux prepare_pvs $NUM_DEVS $PER_DEV_SIZE vgcreate -c n $vg $(cat DEVICES) test_snapshot_mount vgremove $vg aux cleanup_scsi_debug_dev # --------------------------------------------- # Create "desktop-class" 4K drive w/ 63-sector DOS partition compensation # (logical_block_size=512, physical_block_size=4096, alignment_offset=3584): LOGICAL_BLOCK_SIZE=512 aux prepare_scsi_debug_dev $DEV_SIZE \ sector_size=$LOGICAL_BLOCK_SIZE physblk_exp=3 lowest_aligned=7 check_logical_block_size $LOGICAL_BLOCK_SIZE aux prepare_pvs $NUM_DEVS $PER_DEV_SIZE vgcreate -c n $vg $(cat DEVICES) test_snapshot_mount vgremove $vg aux cleanup_scsi_debug_dev # --------------------------------------------- # Create "enterprise-class" 4K drive # (logical_block_size=4096, physical_block_size=4096, alignment_offset=0): LOGICAL_BLOCK_SIZE=4096 aux prepare_scsi_debug_dev $DEV_SIZE \ sector_size=$LOGICAL_BLOCK_SIZE check_logical_block_size $LOGICAL_BLOCK_SIZE aux prepare_pvs $NUM_DEVS $PER_DEV_SIZE vgcreate -c n $vg $(cat DEVICES) test_snapshot_mount vgremove $vg lvm2-2.02.98/test/shell/lvconvert-repair-replace.sh0000640000175000017500000000623412037016272021052 0ustar blankblank#!/bin/sh # Copyright (C) 2008 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 . lib/test aux prepare_vg 6 aux lvmconf 'allocation/maximise_cling = 0' aux lvmconf 'allocation/mirror_logs_require_separate_pvs = 1' # 3-way, disk log # multiple failures, full replace lvcreate --mirrorlog disk -m 2 --ig -L 1 -n 3way $vg "$dev1" "$dev2" "$dev3" "$dev4":0-1 aux disable_dev "$dev1" "$dev2" echo y | lvconvert --repair $vg/3way 2>&1 | tee 3way.out lvs -a -o +devices $vg | not grep unknown not grep "WARNING: Failed" 3way.out vgreduce --removemissing $vg check mirror $vg 3way aux enable_dev "$dev1" "$dev2" vgremove -ff $vg; vgcreate -c n $vg "$dev1" "$dev2" "$dev3" "$dev4" "$dev5" "$dev6" # 2-way, mirrored log # Double log failure, full replace lvcreate --mirrorlog mirrored -m 1 --ig -L 1 -n 2way $vg \ "$dev1" "$dev2" "$dev3":0 "$dev4":0 aux disable_dev "$dev3" "$dev4" echo y | lvconvert --repair $vg/2way 2>&1 | tee 2way.out lvs -a -o +devices $vg | not grep unknown not grep "WARNING: Failed" 2way.out vgreduce --removemissing $vg check mirror $vg 2way aux enable_dev "$dev3" "$dev4" vgremove -ff $vg; vgcreate -c n $vg "$dev1" "$dev2" "$dev3" "$dev4" "$dev5" "$dev6" # 3-way, mirrored log # Single log failure, replace lvcreate --mirrorlog mirrored -m 2 --ig -L 1 -n 3way $vg \ "$dev1" "$dev2" "$dev3" "$dev4":0 "$dev5":0 aux disable_dev "$dev4" echo y | lvconvert --repair $vg/3way 2>&1 | tee 3way.out lvs -a -o +devices $vg | not grep unknown not grep "WARNING: Failed" 3way.out vgreduce --removemissing $vg check mirror $vg 3way aux enable_dev "$dev4" vgremove -ff $vg; vgcreate -c n $vg "$dev1" "$dev2" "$dev3" "$dev4" "$dev5" # 3-way, disk log # multiple failures, partial replace lvcreate --mirrorlog disk -m 2 --ig -L 1 -n 3way $vg "$dev1" "$dev2" "$dev3" "$dev4" aux disable_dev "$dev1" "$dev2" echo y | lvconvert --repair $vg/3way 2>&1 | tee 3way.out grep "WARNING: Failed" 3way.out lvs -a -o +devices $vg | not grep unknown vgreduce --removemissing $vg check mirror $vg 3way aux enable_dev "$dev1" "$dev2" lvchange -a n $vg/3way vgremove -ff $vg; vgcreate -c n $vg "$dev1" "$dev2" "$dev3" lvcreate --mirrorlog disk -m 1 --ig -L 1 -n 2way $vg "$dev1" "$dev2" "$dev3" aux disable_dev "$dev1" echo y | lvconvert --repair $vg/2way 2>&1 | tee 2way.out grep "WARNING: Failed" 2way.out lvs -a -o +devices $vg | not grep unknown vgreduce --removemissing $vg check mirror $vg 2way aux enable_dev "$dev1" "$dev2" lvchange -a n $vg/2way vgremove -ff $vg; vgcreate -c n $vg "$dev1" "$dev2" "$dev3" "$dev4" # Test repair of inactive mirror with log failure # Replacement should fail, but covert should succeed (switch to corelog) lvcreate -m 2 --ig -l 2 -n mirror2 $vg "$dev1" "$dev2" "$dev3" "$dev4":0 vgchange -a n $vg pvremove -ff -y "$dev4" echo 'y' | lvconvert -y --repair $vg/mirror2 check mirror $vg mirror2 vgs $vg lvm2-2.02.98/test/shell/lvconvert-mirror-basic-1.sh0000640000175000017500000000077512037016272020712 0ustar blankblank#!/bin/sh # 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 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 . ./shell/lvconvert-mirror-basic.sh test_many 1 lvm2-2.02.98/test/shell/lvextend-percent-extents.sh0000640000175000017500000000727312037016273021123 0ustar blankblank#!/bin/sh # Copyright (C) 2008-2011 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 # 'Check extents percentage arguments' . lib/test aux prepare_vg 2 128 lvcreate -L 64m -n $lv $vg # 'lvextend rejects both size and extents without PVs' not lvextend -l 10 -L 64m $vg/$lv 2>err grep "Please specify either size or extents but not both." err # 'lvextend rejects both size and extents with PVs' not lvextend -l 10 -L 64m $vg/$lv "$dev1" 2>err grep "Please specify either size or extents but not both." err # 'lvextend accepts no size or extents but one PV - bz154691' lvextend $vg/$lv "$dev1" >out grep "Logical volume $lv successfully resized" out check pv_field "$dev1" pv_free "0" lvremove -f $vg/$lv # 'lvextend computes necessary free space correctly - bz213552' vgsize=$(get vg_field $vg vg_extent_count) lvcreate -l $vgsize -n $lv $vg lvreduce -f -l $(( $vgsize / 2 )) $vg/$lv lvextend -l $vgsize $vg/$lv # 'Reset LV to original size' lvremove -f $vg/$lv lvcreate -L 64m -n $lv $vg # 'lvextend accepts no size but extents 100%PVS and two PVs - bz154691' lvextend -l +100%PVS $vg/$lv "$dev1" "$dev2" >out grep "Logical volume $lv successfully resized" out check pv_field "$dev1" pv_free "0" check pv_field "$dev2" pv_free "0" # Exercise the range overlap code. Allocate every 2 extents. # # Physical Extents # 1 2 #012345678901234567890123 # #aaXXaaXXaaXXaaXXaaXXaaXX - (a)llocated #rrrXXXrrrXXXrrrXXXrrrXXX - (r)ange on cmdline #ooXXXXXXoXXXooXXXXXXoXXX - (o)verlap of range and allocated # # Key: a - allocated # F - free # r - part of a range on the cmdline # N - not on cmdline # # Create the LV with 12 extents, allocated every other 2 extents. # Then extend it, with a range of PVs on the cmdline of every other 3 extents. # Total number of extents should be 12 + overlap = 12 + 6 = 18. # Thus, total size for the LV should be 18 * 4M = 72M # # 'Reset LV to 12 extents, allocate every other 2 extents' create_pvs=$(for i in $(seq 0 4 20); do echo -n "$dev1:$i-$(($i + 1)) "; done) lvremove -f $vg/$lv lvcreate -l 12 -n $lv $vg $create_pvs check lv_field $vg/$lv lv_size "48.00m" # 'lvextend with partially allocated PVs and extents 100%PVS with PE ranges' extend_pvs=$(for i in $(seq 0 6 18); do echo -n "$dev1:$i-$(($i + 2)) "; done) lvextend -l +100%PVS $vg/$lv $extend_pvs >out grep "Logical volume $lv successfully resized" out check lv_field $vg/$lv lv_size "72.00m" # Simple seg_count validation; initially create the LV with half the # of # extents (should be 1 lv segment), extend it (should go to 2 segments), # then reduce (should be back to 1) # FIXME: test other segment fields such as seg_size, pvseg_start, pvseg_size lvremove -f $vg/$lv pe_count=$(get pv_field "$dev1" pv_pe_count) pe1=$(( $pe_count / 2 )) lvcreate -l $pe1 -n $lv $vg pesize=$(get lv_field $vg/$lv vg_extent_size --units b --nosuffix) segsize=$(( $pe1 * $pesize / 1024 / 1024 ))m check lv_field $vg/$lv seg_count "1" check lv_field $vg/$lv seg_start "0" check lv_field $vg/$lv seg_start_pe "0" #check lv_field $vg/$lv seg_size $segsize lvextend -l +$(( $pe_count * 1 )) $vg/$lv check lv_field $vg/$lv seg_count "2" lvreduce -f -l -$(( $pe_count * 1 )) $vg/$lv check lv_field $vg/$lv seg_count "1" # do not reduce to 0 extents lvremove -f $vg/$lv lvcreate -i2 -I 64k -l10 -n $lv $vg lvreduce -f -l1 $vg/$lv check lv_field $vg/$lv lv_size "8.00m" lvm2-2.02.98/test/shell/vgmerge-usage.sh0000640000175000017500000000410212037016273016666 0ustar blankblank#!/bin/sh # Copyright (C) 2008-2011 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 # 'Test vgmerge command options for validity' . lib/test aux prepare_pvs 4 # 'vgmerge normal operation' # ensure ordering does not matter vgcreate $vg1 "$dev1" "$dev2" vgcreate $vg2 "$dev3" "$dev4" vgmerge $vg1 $vg2 vgremove $vg1 vgcreate -c n $vg2 "$dev1" "$dev2" vgcreate -c n $vg1 "$dev3" "$dev4" vgmerge $vg2 $vg1 vgremove $vg2 # 'vgmerge rejects duplicate vg name' vgcreate $vg1 "$dev1" "$dev2" vgcreate $vg2 "$dev3" "$dev4" not vgmerge $vg1 $vg1 2>err grep "Duplicate volume group name \"$vg1\"\$" err vgremove $vg1 $vg2 # 'vgmerge rejects vgs with incompatible extent_size' vgcreate --physicalextentsize 4M $vg1 "$dev1" "$dev2" vgcreate --physicalextentsize 8M $vg2 "$dev3" "$dev4" not vgmerge $vg1 $vg2 2>err grep "Extent sizes differ" err vgremove $vg1 $vg2 # 'vgmerge rejects vgmerge because max_pv is exceeded' vgcreate --maxphysicalvolumes 2 $vg1 "$dev1" "$dev2" vgcreate --maxphysicalvolumes 2 $vg2 "$dev3" "$dev4" not vgmerge $vg1 $vg2 2>err grep "Maximum number of physical volumes (2) exceeded" err vgremove $vg1 $vg2 # 'vgmerge rejects vg with active lv' vgcreate $vg1 "$dev1" "$dev2" vgcreate $vg2 "$dev3" "$dev4" lvcreate -l 4 -n lv1 $vg2 not vgmerge $vg1 $vg2 2>err grep "Logical volumes in \"$vg2\" must be inactive" err vgremove -f $vg1 $vg2 # 'vgmerge rejects vgmerge because max_lv is exceeded' vgcreate --maxlogicalvolumes 2 $vg1 "$dev1" "$dev2" vgcreate --maxlogicalvolumes 2 $vg2 "$dev3" "$dev4" lvcreate -l 4 -n lv1 $vg1 lvcreate -l 4 -n lv2 $vg1 lvcreate -l 4 -n lv3 $vg2 vgchange -an $vg1 $vg2 not vgmerge $vg1 $vg2 2>err grep "Maximum number of logical volumes (2) exceeded" err vgremove -f $vg1 $vg2 lvm2-2.02.98/test/shell/lvcreate-thin-power2.sh0000640000175000017500000000166112037016273020120 0ustar blankblank#!/bin/sh # Copyright (C) 2012 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 # # test support for non-power-of-2 thin chunk size # . lib/test # # Main # aux have_thin 1 4 0 || skip aux prepare_pvs 2 64 vgcreate $vg -s 64K $(cat DEVICES) # create non-power-of-2 pool lvcreate -l100 -c 192 -T $vg/pool check lv_field $vg/pool discards "ignore" # check we cannot change discards settings not lvchange --discard passdown $vg/pool not lvchange --discard nopassdown $vg/pool # must be multiple of 64KB not lvcreate -l100 -c 168 -T $vg/pool1 vgremove -ff $vg lvm2-2.02.98/test/shell/lvconvert-mirror-basic.sh0000640000175000017500000000736012037016272020551 0ustar blankblank#!/bin/sh # Copyright (C) 2010-2012 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 . lib/test log_name_to_count() { case "$1" in mirrored) echo 2 ;; disk) echo 1 ;; *) echo 0 ;; esac } # FIXME: For test_[up|down]convert, I'd still like to be able # to specifiy devices - especially if I can do partial PV # specification for down-converts. It may even be wise to # do one round through these tests without specifying the PVs # to use and one round where we do. # test_lvconvert # start_mirror_count: The '-m' argument to create with # start_log_type: core|disk|mirrored # final_mirror_count: The '-m' argument to convert to # final_log_type: core|disk|mirrored # active: Whether the LV should be active when the convert happens # # Exmaple: Convert 3-way disk-log mirror to # 2-way disk-log mirror while not active # -> test_lvconvert 2 disk 3 disk 0 test_lvconvert() { local start_count=$1 local start_count_p1=$(($start_count + 1)) local start_log_type=$2 local finish_count=$3 local finish_count_p1=$(($finish_count + 1)) local finish_log_type=$4 local dev_array=("$dev1" "$dev2" "$dev3" "$dev4" "$dev5") local start_log_count local finish_log_count local max_log_count local alloc="" local active=true local i test "$5" = "active" && active=false #test $finish_count -gt $start_count && up=true # Do we have enough devices for the mirror images? test $start_count_p1 -gt ${#dev_array[@]} && \ die "Action requires too many devices" # Do we have enough devices for the mirror images? test $finish_count_p1 -gt ${#dev_array[@]} && \ die "Action requires too many devices" start_log_count=$(log_name_to_count $start_log_type) finish_log_count=$(log_name_to_count $finish_log_type) if [ $finish_log_count -gt $start_log_count ]; then max_log_count=$finish_log_count else max_log_count=$start_log_count fi if [ $start_count -gt 0 ]; then # Are there extra devices for the log or do we overlap if [ $(($start_count_p1 + $start_log_count)) -gt ${#dev_array[@]} ]; then alloc="--alloc anywhere" fi lvcreate -l2 -m $start_count --mirrorlog $start_log_type \ -n $lv1 $vg $alloc check mirror_legs $vg $lv1 $start_count_p1 # FIXME: check mirror log else lvcreate -l2 -n $lv1 $vg fi lvs -a -o name,copy_percent,devices $vg test $active || lvchange -an $vg/$lv1 # Are there extra devices for the log or do we overlap if [ $(($finish_count_p1 + $finish_log_count)) -gt ${#dev_array[@]} ]; then alloc="--alloc anywhere" fi lvconvert -m $finish_count --mirrorlog $finish_log_type \ $vg/$lv1 $alloc test $active || lvchange -ay $vg/$lv1 check mirror_no_temporaries $vg $lv1 if [ "$finish_count_p1" -eq 1 ]; then check linear $vg $lv1 else if test -n "$alloc"; then check mirror_nonredundant $vg $lv1 else check mirror $vg $lv1 fi check mirror_legs $vg $lv1 $finish_count_p1 fi } aux prepare_pvs 5 5 vgcreate -c n -s 128k $vg $(cat DEVICES) test_many() { i=$1 for j in $(seq 0 3); do for k in core disk mirrored; do for l in core disk mirrored; do if test "$i" -eq "$j" && test "$k" = "$l"; then continue; fi : ---------------------------------------------------- : "Testing mirror conversion -m$i/$k -> -m$j/$l" : ---------------------------------------------------- test_lvconvert $i $k $j $l 0 lvremove -ff $vg test_lvconvert $i $k $j $l 1 lvremove -ff $vg done done done } lvm2-2.02.98/test/shell/lvcreate-raid10.sh0000640000175000017500000000223612037016273017021 0ustar blankblank#!/bin/sh # Copyright (C) 2012 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 . lib/test ######################################################## # MAIN ######################################################## aux target_at_least dm-raid 1 3 0 || skip aux prepare_pvs 6 20 # 6 devices for RAID10 (2-mirror,3-stripe) test vgcreate -c n -s 512k $vg $(cat DEVICES) # # Create RAID10: # # Should not allow more than 2-way mirror not lvcreate --type raid10 -m 2 -i 2 -l 2 -n $lv1 $vg # 2-way mirror, 2-stripes lvcreate --type raid10 -m 1 -i 2 -l 2 -n $lv1 $vg aux wait_for_sync $vg $lv1 lvremove -ff $vg # 2-way mirror, 3-stripes lvcreate --type raid10 -m 1 -i 3 -l 3 -n $lv1 $vg aux wait_for_sync $vg $lv1 lvremove -ff $vg # # FIXME: Add tests that specify particular PVs to use for creation # lvm2-2.02.98/test/shell/pvchange-usage.sh0000640000175000017500000000330412037016273017030 0ustar blankblank#!/bin/sh # Copyright (C) 2008 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 # 'Test pvchange option values' . lib/test aux prepare_devs 4 for mda in 0 1 2 do # "setup pv with metadatacopies = $mda" pvcreate "$dev4" pvcreate --metadatacopies $mda "$dev1" vgcreate $vg1 "$dev1" "$dev4" # "pvchange adds/dels tag to pvs with metadatacopies = $mda " pvchange "$dev1" --addtag test$mda check pv_field "$dev1" pv_tags test$mda pvchange "$dev1" --deltag test$mda check pv_field "$dev1" pv_tags "" # "vgchange disable/enable allocation for pvs with metadatacopies = $mda (bz452982)" pvchange "$dev1" -x n check pv_field "$dev1" pv_attr --- pvchange "$dev1" -x y check pv_field "$dev1" pv_attr a-- # 'remove pv' vgremove $vg1 pvremove "$dev1" "$dev4" done # "pvchange uuid" pvcreate --metadatacopies 0 "$dev1" pvcreate --metadatacopies 2 "$dev2" vgcreate $vg1 "$dev1" "$dev2" pvchange -u "$dev1" pvchange -u "$dev2" check pvlv_counts $vg1 2 0 0 pvchange -u --all check pvlv_counts $vg1 2 0 0 # "pvchange rejects uuid change under an active lv" lvcreate -l 16 -i 2 -n $lv --alloc anywhere $vg1 check pvlv_counts $vg1 2 1 0 not pvchange -u "$dev1" lvchange -an $vg1/$lv pvchange -u "$dev1" # "cleanup" lvremove -f $vg1/$lv vgremove $vg1 # "pvchange reject --addtag to lvm1 pv" pvcreate -M1 "$dev1" not pvchange "$dev1" --addtag test lvm2-2.02.98/test/shell/lvm-init.sh0000640000175000017500000000116512037016273015675 0ustar blankblank#!/bin/sh # Copyright (C) 2008 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 # # tests lvm initialization, and especially negative tests of error paths # . lib/test aux prepare_devs 5 # invalid units not pvs --config 'global { units = "<" }' lvm2-2.02.98/test/shell/pvcreate-operation-md.sh0000640000175000017500000001242212037016273020341 0ustar blankblank#!/bin/sh # Copyright (C) 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 . lib/test # skip this test if mdadm or sfdisk (or others) aren't available which mdadm || skip which sfdisk || skip which perl || skip which awk || skip which cut || skip test -f /proc/mdstat && grep -q raid0 /proc/mdstat || \ modprobe raid0 || skip aux lvmconf 'devices/md_component_detection = 1' aux lvmconf 'devices/filter = [ "a|/dev/md.*|", "a/dev\/mapper\/.*$/", "r/.*/" ]' aux prepare_devs 2 # Have MD use a non-standard name to avoid colliding with an existing MD device # - mdadm >= 3.0 requires that non-standard device names be in /dev/md/ # - newer mdadm _completely_ defers to udev to create the associated device node mdadm_maj=$(mdadm --version 2>&1 | perl -pi -e 's|.* v(\d+).*|\1|') [ $mdadm_maj -ge 3 ] && \ mddev=/dev/md/md_lvm_test0 || \ mddev=/dev/md_lvm_test0 cleanup_md() { # sleeps offer hack to defeat: 'md: md127 still in use' # see: https://bugzilla.redhat.com/show_bug.cgi?id=509908#c25 aux udev_wait mdadm --stop "$mddev" || true aux udev_wait if [ -b "$mddev" ]; then # mdadm doesn't always cleanup the device node sleep 2 rm -f "$mddev" fi } cleanup_md_and_teardown() { cleanup_md aux teardown } # create 2 disk MD raid0 array (stripe_width=128K) test -b "$mddev" && skip mdadm --create --metadata=1.0 "$mddev" --auto=md --level 0 --raid-devices=2 --chunk 64 "$dev1" "$dev2" trap 'cleanup_md_and_teardown' EXIT # cleanup this MD device at the end of the test test -b "$mddev" || skip # Test alignment of PV on MD without any MD-aware or topology-aware detection # - should treat $mddev just like any other block device pv_align="1.00m" pvcreate --metadatasize 128k \ --config 'devices {md_chunk_alignment=0 data_alignment_detection=0 data_alignment_offset_detection=0}' \ "$mddev" check pv_field "$mddev" pe_start $pv_align # Test md_chunk_alignment independent of topology-aware detection pv_align="1.00m" pvcreate --metadatasize 128k \ --config 'devices {data_alignment_detection=0 data_alignment_offset_detection=0}' \ "$mddev" check pv_field "$mddev" pe_start $pv_align # Test newer topology-aware alignment detection # - first added to 2.6.31 but not "reliable" until 2.6.33 if kernel_at_least 2 6 33 ; then pv_align="1.00m" # optimal_io_size=131072, minimum_io_size=65536 pvcreate --metadatasize 128k \ --config 'devices { md_chunk_alignment=0 }' "$mddev" check pv_field "$mddev" pe_start $pv_align fi # partition MD array directly, depends on blkext in Linux >= 2.6.28 if kernel_at_least 2 6 28 ; then # create one partition sfdisk "$mddev" < parent lookup via sysfs paths not pvcreate --metadatasize 128k "$mddev" # verify alignment_offset is accounted for in pe_start # - topology infrastructure is available in Linux >= 2.6.31 # - also tests partition -> parent lookup via sysfs paths # Oh joy: need to lookup /sys/block/md127 rather than /sys/block/md_lvm_test0 mddev_maj_min=$(ls -lL "$mddev" | awk '{ print $5 $6 }' | perl -pi -e 's|,|:|') mddev_p_sysfs_name=$(echo /sys/dev/block/${mddev_maj_min}/*p1) base_mddev_p=`basename $mddev_p_sysfs_name` mddev_p=/dev/${base_mddev_p} # in case the system is running without devtmpfs /dev # wait here for created device node on tmpfs aux udev_wait "$mddev_p" test -b "$mddev_p" || skip # Checking for 'alignment_offset' in sysfs implies Linux >= 2.6.31 # but reliable alignment_offset support requires kernel.org Linux >= 2.6.33 sysfs_alignment_offset=/sys/dev/block/${mddev_maj_min}/${base_mddev_p}/alignment_offset [ -f $sysfs_alignment_offset ] && kernel_at_least 2 6 33 && \ alignment_offset=`cat $sysfs_alignment_offset` || \ alignment_offset=0 if [ $alignment_offset -gt 0 ]; then # default alignment is 1M, add alignment_offset pv_align=$((1048576+$alignment_offset))B pvcreate --metadatasize 128k "$mddev_p" check pv_field "$mddev_p" pe_start $pv_align --units b pvremove "$mddev_p" fi fi # Test newer topology-aware alignment detection w/ --dataalignment override if kernel_at_least 2 6 33 ; then cleanup_md pvcreate -f "$dev1" pvcreate -f "$dev2" # create 2 disk MD raid0 array (stripe_width=2M) test -b "$mddev" && skip mdadm --create --metadata=1.0 "$mddev" --auto=md --level 0 --raid-devices=2 --chunk 1024 "$dev1" "$dev2" test -b "$mddev" || skip # optimal_io_size=2097152, minimum_io_size=1048576 pv_align="2.00m" pvcreate --metadatasize 128k \ --config 'devices { md_chunk_alignment=0 }' "$mddev" check pv_field "$mddev" pe_start $pv_align # now verify pe_start alignment override using --dataalignment pv_align="192.00k" pvcreate --dataalignment 64k --metadatasize 128k \ --config 'devices { md_chunk_alignment=0 }' "$mddev" check pv_field "$mddev" pe_start $pv_align fi lvm2-2.02.98/test/shell/lvmetad-disabled.sh0000640000175000017500000000143712037016273017341 0ustar blankblank#!/bin/sh # Copyright (C) 2012 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 . lib/test test -e LOCAL_LVMETAD || skip kill $(cat LOCAL_LVMETAD) test -e $LVMETAD_PIDFILE && skip lvmetad test -e $LVMETAD_PIDFILE cp $LVMETAD_PIDFILE LOCAL_LVMETAD pvs 2>&1 | not grep "lvmetad is running" aux lvmconf "global/use_lvmetad = 0" pvs 2>&1 | grep "lvmetad is running" kill $(cat $LVMETAD_PIDFILE) not ls $LVMETAD_PIDFILE lvm2-2.02.98/test/shell/covercmd.sh0000640000175000017500000000435012037016272015736 0ustar blankblank#!/bin/sh # Copyright (C) 2008-2012 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 # # tests basic functionality of read-ahead and ra regressions # . lib/test aux prepare_devs 5 TEST_UUID="aaaaaa-aaaa-aaaa-aaaa-aaaa-aaaa-aaaaaa" pvcreate "$dev1" pvcreate --metadatacopies 0 "$dev2" pvcreate --metadatacopies 0 "$dev3" pvcreate "$dev4" pvcreate --norestorefile -u $TEST_UUID --metadatacopies 0 "$dev5" vgcreate -c n $vg $(cat DEVICES) lvcreate -l 5 -i5 -I256 -n $lv $vg if aux have_readline; then # test *scan and *display tools cat <& /dev/null; then socat "unix-connect:$1" - elif echo | nc -U "$1"; then nc -U "$1" else echo "WARNING: Neither socat nor nc -U seems to be available." 1>&2 echo "# DUMP FAILED" return 1 fi } lvmetad_dump() { (echo 'request="dump"'; echo '##') | lvmetad_talk "$@" } (echo | lvmetad_talk ./lvmetad.socket) || skip lvmetad_dump ./lvmetad.socket | tee lvmetad.txt grep $vg1 lvmetad.txt lvm2-2.02.98/test/shell/tags.sh0000640000175000017500000000540412037016273015074 0ustar blankblank#!/bin/sh # Copyright (C) 2008-2012 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 . lib/test aux prepare_pvs 4 # vgcreate with --addtag vgcreate -c n --addtag firstvg $vg1 "$dev1" "$dev2" vgcreate -c n --addtag secondvg $vg2 "$dev3" "$dev4" check vg_field $vg1 tags "firstvg" check vg_field $vg2 tags "secondvg" vgremove -f $vg1 $vg2 # vgchange with --addtag and --deltag vgcreate -c n $vg1 "$dev1" "$dev2" vgcreate -c n $vg2 "$dev3" "$dev4" vgchange --addtag firstvgtag1 $vg1 # adding a tag multiple times is not an error vgchange --addtag firstvgtag2 $vg1 vgchange --addtag firstvgtag2 $vg1 vgchange --addtag firstvgtag3 $vg1 vgchange --addtag secondvgtag1 $vg2 vgchange --addtag secondvgtag2 $vg2 vgchange --addtag secondvgtag3 $vg2 check vg_field @firstvgtag2 tags "firstvgtag1,firstvgtag2,firstvgtag3" check vg_field @secondvgtag1 tags "secondvgtag1,secondvgtag2,secondvgtag3" vgchange --deltag firstvgtag2 $vg1 check vg_field @firstvgtag1 tags "firstvgtag1,firstvgtag3" # deleting a tag multiple times is not an error vgchange --deltag firstvgtag2 $vg1 vgchange --deltag firstvgtag1 $vg2 vgremove -f $vg1 $vg2 # lvcreate with --addtag vgcreate -c n $vg1 "$dev1" "$dev2" lvcreate --addtag firstlvtag1 -l 4 -n $lv1 $vg1 lvcreate --addtag secondlvtag1 -l 4 -n $lv2 $vg1 check lv_field @firstlvtag1 tags "firstlvtag1" not check lv_field @secondlvtag1 tags "firstlvtag1" check lv_field $vg1/$lv2 tags "secondlvtag1" not check lv_field $vg1/$lv1 tags "secondlvtag1" vgremove -f $vg1 # lvchange with --addtag and --deltag vgcreate -c n $vg1 "$dev1" "$dev2" lvcreate -l 4 -n $lv1 $vg1 lvcreate -l 4 -n $lv2 $vg1 lvchange --addtag firstlvtag1 $vg1/$lv1 # adding a tag multiple times is not an error lvchange --addtag firstlvtag2 $vg1/$lv1 lvchange --addtag firstlvtag2 $vg1/$lv1 lvchange --addtag firstlvtag3 $vg1/$lv1 lvchange --addtag secondlvtag1 $vg1/$lv2 lvchange --addtag secondlvtag2 $vg1/$lv2 lvchange --addtag secondlvtag3 $vg1/$lv2 check lv_field $vg1/$lv1 tags "firstlvtag1,firstlvtag2,firstlvtag3" not check lv_field $vg1/$lv1 tags "secondlvtag1" check lv_field $vg1/$lv2 tags "secondlvtag1,secondlvtag2,secondlvtag3" not check lv_field $vg1/$lv1 tags "secondlvtag1" # deleting a tag multiple times is not an error lvchange --deltag firstlvtag2 $vg1/$lv1 lvchange --deltag firstlvtag2 $vg1/$lv1 check lv_field $vg1/$lv1 tags "firstlvtag1,firstlvtag3" check lv_field $vg1/$lv2 tags "secondlvtag1,secondlvtag2,secondlvtag3" lvm2-2.02.98/test/shell/vgcreate-usage.sh0000640000175000017500000001260612037016273017042 0ustar blankblank#!/bin/sh # Copyright (C) 2008-2012 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 test_description='Exercise some vgcreate diagnostics' . lib/test aux prepare_devs 3 pvcreate "$dev1" "$dev2" pvcreate --metadatacopies 0 "$dev3" vg=${PREFIX}vg #COMM 'vgcreate accepts 8.00m physicalextentsize for VG' vgcreate -c n $vg --physicalextentsize 8.00m "$dev1" "$dev2" check vg_field $vg vg_extent_size 8.00m vgremove $vg # try vgck and to remove it again - should fail (but not segfault) not vgremove $vg not vgck $vg #COMM 'vgcreate accepts smaller (128) maxlogicalvolumes for VG' vgcreate -c n $vg --maxlogicalvolumes 128 "$dev1" "$dev2" check vg_field $vg max_lv 128 vgremove $vg #COMM 'vgcreate accepts smaller (128) maxphysicalvolumes for VG' vgcreate -c n $vg --maxphysicalvolumes 128 "$dev1" "$dev2" check vg_field $vg max_pv 128 vgremove $vg #COMM 'vgcreate rejects a zero physical extent size' not vgcreate -c n --physicalextentsize 0 $vg "$dev1" "$dev2" 2>err grep "Physical extent size may not be zero" err #COMM 'vgcreate rejects "inherit" allocation policy' not vgcreate -c n --alloc inherit $vg "$dev1" "$dev2" 2>err grep "Volume Group allocation policy cannot inherit from anything" err #COMM 'vgcreate rejects vgname "."' vginvalid=.; not vgcreate -c n $vginvalid "$dev1" "$dev2" 2>err grep "New volume group name \"$vginvalid\" is invalid" err #COMM 'vgcreate rejects vgname greater than 128 characters' vginvalid=thisnameisridiculouslylongtotestvalidationcodecheckingmaximumsizethisiswhathappenswhenprogrammersgetboredandorarenotcreativedonttrythisathome not vgcreate -c n $vginvalid "$dev1" "$dev2" 2>err grep "New volume group name \"$vginvalid\" is invalid" err #COMM 'vgcreate rejects already existing vgname "/tmp/$vg"' #touch /tmp/$vg #not vgcreate $vg "$dev1" "$dev2" 2>err #grep "New volume group name \"$vg\" is invalid\$" err #COMM "vgcreate rejects repeated invocation (run 2 times) (bz178216)" vgcreate -c n $vg "$dev1" "$dev2" not vgcreate -c n $vg "$dev1" "$dev2" vgremove -ff $vg #COMM 'vgcreate rejects MaxLogicalVolumes > 255' not vgcreate -c n --metadatatype 1 --maxlogicalvolumes 1024 $vg "$dev1" "$dev2" 2>err grep "Number of volumes may not exceed 255" err #COMM "vgcreate fails when the only pv has --metadatacopies 0" not vgcreate -c n $vg "$dev3" # Test default (4MB) vg_extent_size as well as limits of extent_size not vgcreate -c n --physicalextentsize 0k $vg "$dev1" "$dev2" vgcreate -c n --physicalextentsize 1k $vg "$dev1" "$dev2" check vg_field $vg vg_extent_size 1.00k vgremove -ff $vg not vgcreate -c n --physicalextentsize 3K $vg "$dev1" "$dev2" not vgcreate -c n --physicalextentsize 1024t $vg "$dev1" "$dev2" #not vgcreate --physicalextentsize 1T $vg "$dev1" "$dev2" # FIXME: vgcreate allows physicalextentsize larger than pv size! # Test default max_lv, max_pv, extent_size, alloc_policy, clustered vgcreate -c n $vg "$dev1" "$dev2" check vg_field $vg vg_extent_size 4.00m check vg_field $vg max_lv 0 check vg_field $vg max_pv 0 check vg_field $vg vg_attr "wz--n-" vgremove -ff $vg # Implicit pvcreate tests, test pvcreate options on vgcreate # --force, --yes, --metadata{size|copies|type}, --zero # --dataalignment[offset] pvremove "$dev1" "$dev2" vgcreate -c n --force --yes --zero y $vg "$dev1" "$dev2" vgremove -f $vg pvremove -f "$dev1" for i in 0 1 2 3 do # vgcreate (lvm2) succeeds writing LVM label at sector $i vgcreate -c n --labelsector $i $vg "$dev1" dd if="$dev1" bs=512 skip=$i count=1 2>/dev/null | strings | grep LABELONE >/dev/null vgremove -f $vg pvremove -f "$dev1" done # pvmetadatacopies for i in 1 2 do vgcreate -c n --pvmetadatacopies $i $vg "$dev1" check pv_field "$dev1" pv_mda_count $i vgremove -f $vg pvremove -f "$dev1" done not vgcreate -c n --pvmetadatacopies 0 $vg "$dev1" pvcreate --metadatacopies 1 "$dev2" vgcreate -c n --pvmetadatacopies 0 $vg "$dev1" "$dev2" check pv_field "$dev1" pv_mda_count 0 check pv_field "$dev2" pv_mda_count 1 vgremove -f $vg pvremove -f "$dev1" # metadatasize, dataalignment, dataalignmentoffset #COMM 'pvcreate sets data offset next to mda area' vgcreate -c n --metadatasize 100k --dataalignment 100k $vg "$dev1" check pv_field "$dev1" pe_start 200.00k vgremove -f $vg pvremove -f "$dev1" # data area is aligned to 1M by default, # data area start is shifted by the specified alignment_offset pv_align=1052160 # 1048576 + (7*512) vgcreate -c n --metadatasize 128k --dataalignmentoffset 7s $vg "$dev1" check pv_field "$dev1" pe_start ${pv_align}B --units b vgremove -f $vg pvremove -f "$dev1" # metadatatype for i in 1 2 do vgcreate -c n -M $i $vg "$dev1" check vg_field $vg vg_fmt lvm$i vgremove -f $vg pvremove -f "$dev1" done # vgcreate fails if pv belongs to existing vg vgcreate -c n $vg1 "$dev1" "$dev2" not vgcreate $vg2 "$dev2" vgremove -f $vg1 pvremove -f "$dev1" "$dev2" # all PVs exist in the VG after created pvcreate "$dev1" vgcreate -c n $vg1 "$dev1" "$dev2" "$dev3" check pv_field "$dev1" vg_name $vg1 check pv_field "$dev2" vg_name $vg1 check pv_field "$dev3" vg_name $vg1 vgremove -f $vg1 pvremove -f "$dev1" "$dev2" "$dev3" lvm2-2.02.98/test/shell/mdata-strings.sh0000640000175000017500000000236612037016273016717 0ustar blankblank#!/bin/sh # Copyright (C) 2008-2011 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 # 'Test for proper escaping of strings in metadata (bz431474)' . lib/test aux prepare_devs 2 aux lvmconf 'devices/global_filter = [ "a|.*LVMTEST.*dev/mapper/.*pv[0-9_]*$|", "r|.*|" ]' # for udev impossible to create pv_ugly="__\"!@#\$%^&*,()|@||'\\\"__pv1" # 'set up temp files, loopback devices' name=$(basename "$dev1") dmsetup rename "$name" "$PREFIX$pv_ugly" dev1=$(dirname "$dev1")/"$PREFIX$pv_ugly" dm_table | grep -F "$pv_ugly" # 'pvcreate, vgcreate on filename with backslashed chars' created="$dev1" # when used with real udev without fallback, it will fail here pvcreate "$dev1" || created="$dev2" pvdisplay | should grep -F "$pv_ugly" should check pv_field "$dev1" pv_name "$dev1" vgcreate $vg "$created" # 'no parse errors and VG really exists' vgs $vg 2>err not grep "Parse error" err lvm2-2.02.98/test/shell/lvmcache-exercise.sh0000640000175000017500000000115112037016273017520 0ustar blankblank#!/bin/sh # Copyright (C) 2008 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 . lib/test aux prepare_pvs 5 vgcreate $vg1 "$dev1" vgcreate $vg2 "$dev3" aux disable_dev "$dev1" pvscan vgcreate $vg1 "$dev2" aux enable_dev "$dev1" pvs lvm2-2.02.98/test/shell/vgchange-maxlv.sh0000640000175000017500000000161112037016273017041 0ustar blankblank#!/bin/sh # 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 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 . lib/test aux prepare_dmeventd aux prepare_pvs 3 vgcreate -c n -l 2 $vg $(cat DEVICES) lvcreate -n one -l 1 $vg lvcreate -n two -l 1 $vg not lvcreate -n three -l 1 $vg vgremove -ff $vg vgcreate -c n -l 3 $vg $(cat DEVICES) lvcreate -n one -l 1 $vg lvcreate -n snap -s -l 1 $vg/one lvcreate -n two -l 1 $vg not lvcreate -n three -l 1 $vg vgchange --monitor y $vg vgchange -an $vg 2>&1 | tee vgchange.out not grep "event server" vgchange.out lvm2-2.02.98/test/shell/activate-partial.sh0000640000175000017500000000156112037016272017367 0ustar blankblank#!/bin/sh # 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 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 . lib/test aux prepare_vg 3 lvcreate -m 1 -l 1 -n mirror $vg lvchange -a n $vg/mirror aux disable_dev "$dev1" not vgreduce --removemissing $vg not lvchange -v -a y $vg/mirror lvchange -v --partial -a y $vg/mirror not lvchange -v --refresh $vg/mirror lvchange -v --refresh --partial $vg/mirror # also check that vgchange works vgchange -a n --partial $vg vgchange -a y --partial $vg # check vgremove vgremove -f $vg lvm2-2.02.98/test/shell/lvcreate-raid.sh0000640000175000017500000000271712037016273016664 0ustar blankblank#!/bin/sh # Copyright (C) 2011-2012 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 . lib/test ######################################################## # MAIN ######################################################## aux target_at_least dm-raid 1 1 0 || skip aux prepare_pvs 6 20 # 6 devices for RAID10 (2-mirror,3-stripe) test vgcreate -c n -s 512k $vg $(cat DEVICES) ########################################### # Create, wait for sync, remove tests ########################################### # Create RAID1 (implicit 2-way) lvcreate --type raid1 -l 2 -n $lv1 $vg aux wait_for_sync $vg $lv1 lvremove -ff $vg # Create RAID1 (explicit 2-way) lvcreate --type raid1 -m 1 -l 2 -n $lv1 $vg aux wait_for_sync $vg $lv1 lvremove -ff $vg # Create RAID1 (explicit 3-way) lvcreate --type raid1 -m 2 -l 2 -n $lv1 $vg aux wait_for_sync $vg $lv1 lvremove -ff $vg # Create RAID 4/5/6 (explicit 3-stripe + parity devs) for i in raid4 \ raid5 raid5_ls raid5_la raid5_rs raid5_ra \ raid6 raid6_zr raid6_nr raid6_nc; do lvcreate --type $i -l 3 -i 3 -n $lv1 $vg aux wait_for_sync $vg $lv1 lvremove -ff $vg done lvm2-2.02.98/test/shell/lvconvert-raid.sh0000640000175000017500000001272012037016272017073 0ustar blankblank#!/bin/sh # Copyright (C) 2011-2012 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 . lib/test get_image_pvs() { local d local images images=`dmsetup ls | grep ${1}-${2}_.image_.* | cut -f1 | sed -e s:-:/:` lvs --noheadings -a -o devices $images | sed s/\(.\)// } ######################################################## # MAIN ######################################################## aux target_at_least dm-raid 1 1 0 || skip aux kernel_at_least 3 2 0 || skip # 9 PVs needed for RAID10 testing (3-stripes/2-mirror - replacing 3 devs) aux prepare_pvs 9 80 vgcreate -c n -s 256k $vg $(cat DEVICES) ########################################### # RAID1 convert tests ########################################### for under_snap in false true; do for i in 1 2 3 4; do for j in 1 2 3 4; do if [ $i -eq 1 ]; then from="linear" else from="$i-way" fi if [ $j -eq 1 ]; then to="linear" else to="$j-way" fi echo -n "Converting from $from to $to" if $under_snap; then echo -n " (while under a snapshot)" fi echo if [ $i -eq 1 ]; then # Shouldn't be able to create with just 1 image not lvcreate --type raid1 -m 0 -l 2 -n $lv1 $vg lvcreate -l 2 -n $lv1 $vg else lvcreate --type raid1 -m $(($i - 1)) -l 2 -n $lv1 $vg aux wait_for_sync $vg $lv1 fi if $under_snap; then lvcreate -s $vg/$lv1 -n snap -l 2 fi lvconvert -m $((j - 1)) $vg/$lv1 # FIXME: ensure no residual devices if [ $j -eq 1 ]; then check linear $vg $lv1 fi lvremove -ff $vg done done done ############################################## # RAID1 - shouldn't be able to add image # if created '--nosync', but should # be able to after 'lvchange --resync' ############################################## lvcreate --type raid1 -m 1 -l 2 -n $lv1 $vg --nosync not lvconvert -m +1 $vg/$lv1 lvchange --resync -y $vg/$lv1 aux wait_for_sync $vg $lv1 lvconvert -m +1 $vg/$lv1 lvremove -ff $vg # 3-way to 2-way convert while specifying devices lvcreate --type raid1 -m 2 -l 2 -n $lv1 $vg $dev1 $dev2 $dev3 aux wait_for_sync $vg $lv1 lvconvert -m1 $vg/$lv1 $dev2 lvremove -ff $vg # # FIXME: Add tests that specify particular devices to be removed # ########################################### # RAID1 split tests ########################################### # 3-way to 2-way/linear lvcreate --type raid1 -m 2 -l 2 -n $lv1 $vg aux wait_for_sync $vg $lv1 lvconvert --splitmirrors 1 -n $lv2 $vg/$lv1 check lv_exists $vg $lv1 check linear $vg $lv2 # FIXME: ensure no residual devices lvremove -ff $vg # 2-way to linear/linear lvcreate --type raid1 -m 1 -l 2 -n $lv1 $vg aux wait_for_sync $vg $lv1 lvconvert --splitmirrors 1 -n $lv2 $vg/$lv1 check linear $vg $lv1 check linear $vg $lv2 # FIXME: ensure no residual devices lvremove -ff $vg # 3-way to linear/2-way lvcreate --type raid1 -m 2 -l 2 -n $lv1 $vg aux wait_for_sync $vg $lv1 # FIXME: Can't split off a RAID1 from a RAID1 yet # 'should' results in "warnings" should lvconvert --splitmirrors 2 -n $lv2 $vg/$lv1 #check linear $vg $lv1 #check lv_exists $vg $lv2 # FIXME: ensure no residual devices lvremove -ff $vg ########################################### # RAID1 split + trackchanges / merge ########################################### # 3-way to 2-way/linear lvcreate --type raid1 -m 2 -l 2 -n $lv1 $vg aux wait_for_sync $vg $lv1 lvconvert --splitmirrors 1 --trackchanges $vg/$lv1 check lv_exists $vg $lv1 check linear $vg ${lv1}_rimage_2 lvconvert --merge $vg/${lv1}_rimage_2 # FIXME: ensure no residual devices lvremove -ff $vg ########################################### # Mirror to RAID1 conversion ########################################### for i in 1 2 3 ; do lvcreate --type mirror -m $i -l 2 -n $lv1 $vg aux wait_for_sync $vg $lv1 lvconvert --type raid1 $vg/$lv1 lvremove -ff $vg done ########################################### # Device Replacement Testing ########################################### # RAID1: Replace up to n-1 devices - trying different combinations # Test for 2-way to 4-way RAID1 LVs for i in {1..3}; do lvcreate --type raid1 -m $i -l 2 -n $lv1 $vg for j in $(seq $(($i + 1))); do # The number of devs to replace at once for o in $(seq 0 $i); do # The offset into the device list replace="" devices=( $(get_image_pvs $vg $lv1) ) for k in $(seq $j); do index=$((($k + $o) % ($i + 1))) replace="$replace --replace ${devices[$index]}" done aux wait_for_sync $vg $lv1 if [ $j -ge $((i + 1)) ]; then # Can't replace all at once. not lvconvert $replace $vg/$lv1 else lvconvert $replace $vg/$lv1 fi done done lvremove -ff $vg done # RAID 4/5/6 (can replace up to 'parity' devices) for i in 4 5 6; do lvcreate --type raid$i -i 3 -l 3 -n $lv1 $vg if [ $i -eq 6 ]; then dev_cnt=5 limit=2 else dev_cnt=4 limit=1 fi for j in {1..3}; do for o in $(seq 0 $i); do replace="" devices=( $(get_image_pvs $vg $lv1) ) for k in $(seq $j); do index=$((($k + $o) % $dev_cnt)) replace="$replace --replace ${devices[$index]}" done aux wait_for_sync $vg $lv1 if [ $j -gt $limit ]; then not lvconvert $replace $vg/$lv1 else lvconvert $replace $vg/$lv1 fi done done lvremove -ff $vg done lvm2-2.02.98/test/shell/vgcfgbackup-usage.sh0000640000175000017500000000346712037016273017531 0ustar blankblank#!/bin/sh # Copyright (C) 2008 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 . lib/test aux prepare_pvs 4 # vgcfgbackup handles similar VG names (bz458941) vg1=${PREFIX}vg00 vg2=${PREFIX}vg01 vgcreate $vg1 "$dev1" vgcreate $vg2 "$dev2" vgcfgbackup -f $TESTDIR/bak-%s >out grep "Volume group \"$vg1\" successfully backed up." out grep "Volume group \"$vg2\" successfully backed up." out vgremove -ff $vg1 $vg2 # vgcfgbackup correctly stores metadata with missing PVs # and vgcfgrestore able to restore them when device reappears pv1_uuid=$(get pv_field "$dev1" pv_uuid) pv2_uuid=$(get pv_field "$dev2" pv_uuid) vgcreate $vg $(cat DEVICES) lvcreate -l1 -n $lv1 $vg "$dev1" lvcreate -l1 -n $lv2 $vg "$dev2" lvcreate -l1 -n $lv3 $vg "$dev3" vgchange -a n $vg pvcreate -ff -y "$dev1" pvcreate -ff -y "$dev2" vgcfgbackup -f "$(pwd)/backup.$$" $vg sed 's/flags = \[\"MISSING\"\]/flags = \[\]/' "$(pwd)/backup.$$" > "$(pwd)/backup.$$1" pvcreate -ff -y --norestorefile -u $pv1_uuid "$dev1" pvcreate -ff -y --norestorefile -u $pv2_uuid "$dev2" vgcfgrestore -f "$(pwd)/backup.$$1" $vg vgremove -ff $vg # vgcfgbackup correctly stores metadata LVM1 with missing PVs # FIXME: clvmd seems to have problem with metadata format change here # fix it and remove this vgscan vgscan pvcreate -M1 $(cat DEVICES) vgcreate -M1 -c n $vg $(cat DEVICES) lvcreate -l1 -n $lv1 $vg "$dev1" pvremove -ff -y "$dev2" not lvcreate -l1 -n $lv1 $vg "$dev3" vgcfgbackup -f "$(pwd)/backup.$$" $vg lvm2-2.02.98/test/shell/lvcreate-large-raid10.sh0000640000175000017500000000232512037016273020110 0ustar blankblank#!/bin/sh # Copyright (C) 2012 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 # 'Exercise some lvcreate diagnostics' . lib/test aux target_at_least dm-raid 1 3 0 || skip aux prepare_vg 5 lvcreate -s -l 20%FREE -n $lv1 $vg --virtualsize 256T lvcreate -s -l 20%FREE -n $lv2 $vg --virtualsize 256T lvcreate -s -l 20%FREE -n $lv3 $vg --virtualsize 256T lvcreate -s -l 20%FREE -n $lv4 $vg --virtualsize 256T lvcreate -s -l 20%FREE -n $lv5 $vg --virtualsize 256T aux lvmconf 'devices/filter = [ "a/dev\/mapper\/.*$/", "a/dev\/LVMTEST/", "r/.*/" ]' pvcreate $DM_DEV_DIR/$vg/$lv[12345] vgcreate -c n $vg1 $DM_DEV_DIR/$vg/$lv[12345] # # Create large RAID LVs # # We need '--nosync' or our virtual devices won't work lvcreate --type raid10 -m 1 -i 2 -L 200T -n $lv1 $vg1 --nosync check lv_field $vg1/$lv1 size "200.00t" lvremove -ff $vg1 lvremove -ff $vg lvm2-2.02.98/test/shell/nomda-missing.sh0000640000175000017500000000404112037016273016677 0ustar blankblank#!/bin/sh # 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 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 . lib/test aux prepare_devs 4 pvcreate "$dev1" "$dev2" pvcreate --metadatacopies 0 "$dev3" "$dev4" vgcreate -c n $vg "$dev1" "$dev2" "$dev3" "$dev4" lvcreate -l1 -n linear1 $vg "$dev1" lvcreate -l1 -n linear2 $vg "$dev2" lvcreate -l2 -n linear12 $vg "$dev1":4 "$dev2":4 lvcreate -l1 -n origin1 $vg "$dev1" lvcreate -s $vg/origin1 -l1 -n s_napshot2 "$dev2" lvcreate -l1 -m1 -n mirror12 --mirrorlog core $vg "$dev1" "$dev2" lvcreate -l1 -m1 -n mirror123 $vg "$dev1" "$dev2" "$dev3" vgchange -a n $vg aux disable_dev "$dev1" not vgchange -a y $vg not vgck $vg check inactive $vg linear1 check active $vg linear2 check inactive $vg origin1 check inactive $vg s_napshot2 check inactive $vg linear12 check inactive $vg mirror12 check inactive $vg mirror123 vgchange -a n $vg aux enable_dev "$dev1" aux disable_dev "$dev2" not vgchange -a y $vg not vgck $vg check active $vg linear1 check inactive $vg linear2 check inactive $vg linear12 check inactive $vg origin1 check inactive $vg s_napshot2 check inactive $vg mirror12 check inactive $vg mirror123 vgchange -a n $vg aux enable_dev "$dev2" aux disable_dev "$dev3" not vgchange -a y $vg not vgck $vg check active $vg origin1 check active $vg s_napshot2 check active $vg linear1 check active $vg linear2 check active $vg linear12 check inactive $vg mirror123 check active $vg mirror12 vgchange -a n $vg aux enable_dev "$dev3" aux disable_dev "$dev4" vgchange -a y $vg not vgck $vg check active $vg origin1 check active $vg s_napshot2 check active $vg linear1 check active $vg linear2 check active $vg linear12 check active $vg mirror12 check active $vg mirror123 lvm2-2.02.98/test/shell/lvcreate-usage.sh0000640000175000017500000001134412037016273017045 0ustar blankblank#!/bin/sh # Copyright (C) 2008-2011 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 # 'Exercise some lvcreate diagnostics' . lib/test aux prepare_pvs 4 aux pvcreate --metadatacopies 0 "$dev1" vgcreate -cn $vg $(cat DEVICES) # "lvcreate rejects repeated invocation (run 2 times) (bz178216)" lvcreate -n $lv -l 4 $vg not lvcreate -n $lv -l 4 $vg lvremove -ff $vg/$lv # try to remove it again - should fail (but not segfault) not lvremove -ff $vg/$lv # "lvcreate rejects a negative stripe_size" not lvcreate -L 64m -n $lv -i2 --stripesize -4 $vg 2>err; grep "Negative stripesize is invalid" err # 'lvcreate rejects a too-large stripesize' not lvcreate -L 64m -n $lv -i2 --stripesize 4294967291 $vg 2>err grep "Stripe size cannot be larger than" err # 'lvcreate w/single stripe succeeds with diagnostics to stdout' lvcreate -L 64m -n $lv -i1 --stripesize 4 $vg 2> err | tee out grep "Ignoring stripesize argument with single stripe" out lvdisplay $vg lvremove -ff $vg # 'lvcreate w/default (64KB) stripe size succeeds with diagnostics to stdout' lvcreate -L 64m -n $lv -i2 $vg > out grep "Using default stripesize" out lvdisplay $vg check lv_field $vg/$lv stripesize "64.00k" lvremove -ff $vg # 'lvcreate rejects an invalid number of stripes' not lvcreate -L 64m -n $lv -i129 $vg 2>err grep "Number of stripes (129) must be between 1 and 128" err # The case on lvdisplay output is to verify that the LV was not created. # 'lvcreate rejects an invalid stripe size' not lvcreate -L 64m -n $lv -i2 --stripesize 3 $vg 2>err grep "Invalid stripe size" err test -z "$(lvdisplay $vg)" # Setting max_lv works. (bz490298) lvremove -ff $vg vgchange -l 3 $vg lvcreate -l1 -n $lv1 $vg lvcreate -l1 -s -n $lv2 $vg/$lv1 lvcreate -l1 -n $lv3 $vg not lvcreate -l1 -n $lv4 $vg lvremove -ff $vg/$lv3 lvcreate -l1 -s -n $lv3 $vg/$lv1 not lvcreate -l1 -n $lv4 $vg not lvcreate -l1 -m1 -n $lv4 $vg lvremove -ff $vg/$lv3 lvcreate -l1 -m1 -n $lv3 $vg vgs -o +max_lv $vg not lvcreate -l1 -n $lv4 $vg not lvcreate -l1 -m1 -n $lv4 $vg lvconvert -m0 $vg/$lv3 lvconvert -m2 -i 1 $vg/$lv3 lvconvert -m1 $vg/$lv3 not vgchange -l 2 vgchange -l 4 vgs $vg lvremove -ff $vg vgchange -l 0 $vg # lvcreate rejects invalid chunksize, accepts between 4K and 512K # validate origin_size vgremove -ff $vg vgcreate -cn $vg $(cat DEVICES) lvcreate -L 32m -n $lv1 $vg not lvcreate -L 8m -n $lv2 -s --chunksize 3k $vg/$lv1 not lvcreate -L 8m -n $lv2 -s --chunksize 1024k $vg/$lv1 lvcreate -L 8m -n $lv2 -s --chunksize 4k $vg/$lv1 check lv_field $vg/$lv2 chunk_size "4.00k" check lv_field $vg/$lv2 origin_size "32.00m" lvcreate -L 8m -n $lv3 -s --chunksize 512k $vg/$lv1 check lv_field $vg/$lv3 chunk_size "512.00k" check lv_field $vg/$lv3 origin_size "32.00m" lvremove -ff $vg vgchange -l 0 $vg # regionsize must be # - nonzero (bz186013) # - a power of 2 and a multiple of page size # - <= size of LV not lvcreate -L 32m -n $lv -R0 $vg 2>err grep "Non-zero region size must be supplied." err not lvcreate -L 32m -n $lv -R 11k $vg not lvcreate -L 32m -n $lv -R 1k $vg lvcreate -L 32m -n $lv --regionsize 128m -m 1 $vg check lv_field $vg/$lv regionsize "32.00m" lvremove -ff $vg lvcreate -L 32m -n $lv --regionsize 4m -m 1 $vg check lv_field $vg/$lv regionsize "4.00m" lvremove -ff $vg # snapshot with virtual origin works lvcreate -s --virtualoriginsize 64m -L 32m -n $lv1 $vg lvrename $vg/$lv1 $vg/$lv2 lvcreate -s --virtualoriginsize 64m -L 32m -n $lv1 $vg lvchange -a n $vg/$lv1 lvremove -ff $vg/$lv1 lvremove -ff $vg # readahead default (auto), none, #, auto lvcreate -L 32m -n $lv $vg check lv_field $vg/$lv lv_read_ahead "auto" lvremove -ff $vg lvcreate -L 32m -n $lv --readahead none $vg check lv_field $vg/$lv lv_read_ahead "0" check lv_field $vg/$lv lv_kernel_read_ahead "0" lvremove -ff $vg lvcreate -L 32m -n $lv --readahead 8k $vg check lv_field $vg/$lv lv_read_ahead "8.00k" check lv_field $vg/$lv lv_kernel_read_ahead "8.00k" lvremove -ff $vg lvcreate -L 32m -n $lv --readahead auto $vg check lv_field $vg/$lv lv_read_ahead "auto" check lv_field $vg/$lv lv_kernel_read_ahead "128.00k" lvremove -ff $vg lvcreate -L 32m -n $lv -i2 --stripesize 16k --readahead auto $vg check lv_field $vg/$lv lv_read_ahead "auto" check lv_field $vg/$lv lv_kernel_read_ahead "128.00k" lvremove -ff $vg lvcreate -L 32m -n $lv -i2 --stripesize 128k --readahead auto $vg check lv_field $vg/$lv lv_read_ahead "auto" check lv_field $vg/$lv lv_kernel_read_ahead "512.00k" lvremove -ff $vg lvm2-2.02.98/test/shell/lvmetad-warning.sh0000640000175000017500000000201312037016273017226 0ustar blankblank#!/bin/sh # Copyright (C) 2012 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 . lib/test test -e LOCAL_LVMETAD || skip aux prepare_pvs 2 vgcreate $vg1 $dev1 $dev2 lvchange -ay $vg1 2>&1 | not grep "Failed to connect" kill $(cat LOCAL_LVMETAD) lvchange -ay $vg1 2>&1 | grep "Failed to connect" lvchange -ay $vg1 --sysinit 2>&1 | not grep "Failed to connect" aux lvmconf 'global/use_lvmetad = 0' lvchange -ay $vg1 2>&1 | not grep "Failed to connect" lvchange -ay $vg1 --sysinit 2>&1 | not grep "Failed to connect" aux prepare_lvmetad lvchange -ay $vg1 2>&1 | not grep "Failed to connect" lvchange -ay $vg1 --sysinit 2>&1 | not grep "Failed to connect" lvm2-2.02.98/test/shell/lvcreate-thin.sh0000640000175000017500000001443612037016273016710 0ustar blankblank#!/bin/sh # Copyright (C) 2011-2012 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 # test currently needs to drop # 'return NULL' in _lv_create_an_lv after log_error("Can't create %s without using " . lib/test check_lv_field_modules_() { mod=$1 shift for d in $*; do check lv_field $vg/$d modules $mod done } # # Main # aux have_thin 1 0 0 || skip aux prepare_pvs 2 64 vgcreate $vg -s 64K $(cat DEVICES) # Create named pool only lvcreate -l1 -T $vg/pool1 lvcreate -l1 -T --thinpool $vg/pool2 lvcreate -l1 -T --thinpool pool3 $vg lvcreate -l1 --type thin $vg/pool4 lvcreate -l1 --type thin --thinpool $vg/pool5 lvcreate -l1 --type thin --thinpool pool6 $vg lvcreate -l1 --type thin-pool $vg/pool7 lvcreate -l1 --type thin-pool --thinpool $vg/pool8 lvcreate -l1 --type thin-pool --thinpool pool9 $vg lvremove -ff $vg/pool1 $vg/pool2 $vg/pool3 $vg/pool4 $vg/pool5 $vg/pool6 $vg/pool7 $vg/pool8 $vg/pool9 check vg_field $vg lv_count 0 # Create default pool name lvcreate -l1 -T $vg lvcreate -l1 --type thin $vg lvcreate -l1 --type thin-pool $vg lvremove -ff $vg/lvol0 $vg/lvol1 $vg/lvol2 check vg_field $vg lv_count 0 # Create default pool and default thin LV lvcreate -l1 -V2G -T $vg lvcreate -l1 -V2G --type thin $vg lvremove -ff $vg # Create named pool and default thin LV lvcreate -L4M -V2G -T $vg/pool1 lvcreate -L4M -V2G -T --thinpool $vg/pool2 lvcreate -L4M -V2G -T --thinpool pool3 $vg lvcreate -L4M -V2G --type thin $vg/pool4 lvcreate -L4M -V2G --type thin --thinpool $vg/pool5 lvcreate -L4M -V2G --type thin --thinpool pool6 $vg check lv_exists $vg lvol0 lvol1 lvol2 lvol3 lvol4 lvol5 lvremove -ff $vg # Create named pool and named thin LV lvcreate -L4M -V2G -T $vg/pool1 --name lv1 lvcreate -L4M -V2G -T $vg/pool2 --name $vg/lv2 lvcreate -L4M -V2G -T --thinpool $vg/pool3 --name lv3 lvcreate -L4M -V2G -T --thinpool $vg/pool4 --name $vg/lv4 lvcreate -L4M -V2G -T --thinpool pool5 --name lv5 $vg lvcreate -L4M -V2G -T --thinpool pool6 --name $vg/lv6 $vg check lv_exists $vg lv1 lv2 lv3 lv4 lv5 lv6 lvremove -ff $vg lvcreate -L4M -V2G --type thin $vg/pool1 --name lv1 lvcreate -L4M -V2G --type thin $vg/pool2 --name $vg/lv2 lvcreate -L4M -V2G --type thin --thinpool $vg/pool3 --name lv3 lvcreate -L4M -V2G --type thin --thinpool $vg/pool4 --name $vg/lv4 lvcreate -L4M -V2G --type thin --thinpool pool5 --name lv5 $vg lvcreate -L4M -V2G --type thin --thinpool pool6 --name $vg/lv6 $vg check lv_exists $vg lv1 lv2 lv3 lv4 lv5 lv6 lvremove -ff $vg # Create default thin LV in existing pool lvcreate -L4M -T $vg/pool lvcreate -V2G -T $vg/pool lvcreate -V2G -T --thinpool $vg/pool lvcreate -V2G -T --thinpool pool $vg lvcreate -V2G --type thin $vg/pool lvcreate -V2G --type thin --thinpool $vg/pool lvcreate -V2G --type thin --thinpool pool $vg check lv_exists $vg lvol0 lvol1 lvol2 lvol3 lvol4 lvol5 # Create named thin LV in existing pool lvcreate -V2G -T $vg/pool --name lv1 lvcreate -V2G -T $vg/pool --name $vg/lv2 lvcreate -V2G -T --thinpool $vg/pool --name lv3 lvcreate -V2G -T --thinpool $vg/pool --name $vg/lv4 lvcreate -V2G -T --thinpool pool --name lv5 $vg lvcreate -V2G -T --thinpool pool --name $vg/lv6 $vg lvcreate -V2G --type thin $vg/pool --name lv7 lvcreate -V2G --type thin $vg/pool --name $vg/lv8 lvcreate -V2G --type thin --thinpool $vg/pool --name lv9 lvcreate -V2G --type thin --thinpool $vg/pool --name $vg/lv10 lvcreate -V2G --type thin --thinpool pool --name lv11 $vg lvcreate -V2G --type thin --thinpool pool --name $vg/lv12 $vg check lv_exists $vg lv1 lv2 lv3 lv4 lv5 lv6 lv7 lv8 lv9 lv10 lv11 lv12 check vg_field $vg lv_count 19 lvremove -ff $vg check vg_field $vg lv_count 0 # Create thin snapshot of thinLV lvcreate -L10M -V10M -T $vg/pool --name lv1 mkfs.ext4 $DM_DEV_DIR/$vg/lv1 lvcreate -s $vg/lv1 fsck -p $DM_DEV_DIR/$vg/lvol0 lvcreate -s $vg/lv1 --name lv2 lvcreate -s $vg/lv1 --name $vg/lv3 lvcreate --type snapshot $vg/lv1 lvcreate --type snapshot $vg/lv1 --name lv4 lvcreate --type snapshot $vg/lv1 --name $vg/lv5 check_lv_field_modules_ thin-pool lv1 lvol0 lv2 lv3 lvol1 lv4 lv5 check vg_field $vg lv_count 8 lvremove -ff $vg # Normal Snapshots of thinLV lvcreate -L4M -V2G -T $vg/pool --name lv1 lvcreate -s $vg/lv1 -l1 lvcreate -s $vg/lv1 -l1 --name lv2 lvcreate -s $vg/lv1 -l1 --name $vg/lv3 lvcreate -s lv1 -L4M --name $vg/lv4 check_lv_field_modules_ snapshot lvol0 lv2 lv3 lv4 check vg_field $vg lv_count 6 lvremove -ff $vg check vg_field $vg lv_count 0 lvdisplay $vg # Fail cases # Too small pool size (1 extent 64KB) for given chunk size not lvcreate --chunksize 256 -l1 -T $vg/pool1 # Too small chunk size (min is 64KB - 128 sectors) not lvcreate --chunksize 32 -l1 -T $vg/pool1 # Too large chunk size (max is 1GB) not lvcreate -L4M --chunksize 2G -T $vg/pool1 lvcreate -L4M -V2G --name lv1 -T $vg/pool1 # Origin name is not accepted not lvcreate -s $vg/lv1 -L4M -V2G --name $vg/lv4 # Check we cannot create mirror and thin or thinpool together not lvcreate -T mirpool -L4M --alloc anywhere -m1 $vg not lvcreate --thinpool mirpool -L4M --alloc anywhere -m1 $vg vgremove -ff $vg # Test --poolmetadatasize range # allocating large devices for testing aux teardown_devs aux prepare_pvs 10 16500 vgcreate $vg -s 64K $(cat DEVICES) lvcreate -L4M --chunksize 128 --poolmetadatasize 0 -T $vg/pool1 2>out grep "WARNING: Minimum" out # FIXME: metadata allocation fails, if PV doesn't have at least 16GB # i.e. pool metadata device cannot be multisegment lvcreate -L4M --chunksize 64k --poolmetadatasize 17G -T $vg/pool2 2>out grep "WARNING: Maximum" out check lv_field $vg/pool1_tmeta size "2.00m" check lv_field $vg/pool2_tmeta size "16.00g" lvremove -ff $vg # Test automatic calculation of pool metadata size lvcreate -L160G -T $vg/pool check lv_field $vg/pool lv_metadata_size "80.00m" check lv_field $vg/pool chunksize "128.00k" lvremove -ff $vg/pool lvcreate -L10G --chunksize 256 -T $vg/pool1 lvcreate -L60G --chunksize 1024 -T $vg/pool2 check lv_field $vg/pool1_tmeta size "2.50m" check lv_field $vg/pool2_tmeta size "3.75m" vgremove -ff $vg lvm2-2.02.98/test/shell/activate-minor.sh0000640000175000017500000000123712037016272017057 0ustar blankblank#!/bin/bash # Copyright (C) 2012 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 . lib/test aux prepare_vg 2 lvcreate -a n --zero n -l 1 -n foo $vg lvchange $vg/foo -My --major=255 --minor=123 lvchange $vg/foo -a y dmsetup info $vg-foo | tee info egrep "^Major, minor: *[0-9]+, 123" info lvm2-2.02.98/aclocal.m40000640000175000017500000001363112037016272013354 0ustar blankblank# 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 . # # 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 .]) ]) else $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS $1[]_LIBS=$pkg_cv_[]$1[]_LIBS AC_MSG_RESULT([yes]) $3 fi[]dnl ])# PKG_CHECK_MODULES lvm2-2.02.98/Makefile.in0000640000175000017500000001142212037016272013555 0ustar blankblank# # 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 ifeq ("@UDEV_RULES@", "yes") SUBDIRS += udev endif ifeq ("@INTL@", "yes") SUBDIRS += po endif SUBDIRS += lib tools daemons libdm libdaemon ifeq ("@APPLIB@", "yes") SUBDIRS += liblvm endif ifeq ("@PYTHON_BINDINGS@", "yes") SUBDIRS += python endif SUBDIRS += scripts # FIXME Should use intermediate Makefiles here! ifeq ($(MAKECMDGOALS),distclean) SUBDIRS = doc include man test scripts \ libdaemon lib tools daemons libdm \ udev po liblvm python \ unit-tests/datastruct unit-tests/mm unit-tests/regex tools.distclean: test.distclean endif DISTCLEAN_DIRS += lcov_reports* DISTCLEAN_TARGETS += config.cache config.log config.status make.tmpl include make.tmpl libdm: include lib: libdm libdaemon liblvm: lib daemons: lib libdaemon tools tools: lib libdaemon device-mapper po: tools daemons scripts: liblvm libdm lib.device-mapper: include.device-mapper libdm.device-mapper: include.device-mapper liblvm.device-mapper: include.device-mapper daemons.device-mapper: libdm.device-mapper tools.device-mapper: libdm.device-mapper 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 ifeq ("@PYTHON_BINDINGS@", "yes") python: liblvm endif ifneq ("$(CFLOW_CMD)", "") tools.cflow: libdm.cflow lib.cflow daemons.cflow: tools.cflow cflow: include.cflow endif ifneq ("@CSCOPE_CMD@", "") cscope.out: @CSCOPE_CMD@ -b -R -s$(top_srcdir) all: cscope.out endif DISTCLEAN_TARGETS += cscope.out check check_cluster check_local check_lvmetad unit: all $(MAKE) -C test $(@) install_system_dirs: $(INSTALL_DIR) $(DESTDIR)$(DEFAULT_SYS_DIR) $(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_ARCHIVE_DIR) $(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_BACKUP_DIR) $(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_CACHE_DIR) $(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_LOCK_DIR) $(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_RUN_DIR) $(INSTALL_ROOT_DATA) /dev/null $(DESTDIR)$(DEFAULT_CACHE_DIR)/.cache install_initscripts: $(MAKE) -C scripts install_initscripts install_systemd_generators: $(MAKE) -C scripts install_systemd_generators install_systemd_units: $(MAKE) -C scripts install_systemd_units ifeq ("@PYTHON_BINDINGS@", "yes") install_python_bindings: $(MAKE) -C liblvm/python install_python_bindings endif install_tmpfiles_configuration: $(MAKE) -C scripts install_tmpfiles_configuration LCOV_TRACES = libdm.info lib.info tools.info \ daemons/dmeventd.info daemons/clvmd.info CLEAN_TARGETS += $(LCOV_TRACES) ifneq ("$(LCOV)", "") .PHONY: lcov-reset lcov lcov-dated $(LCOV_TRACES) ifeq ($(MAKECMDGOALS),lcov-dated) LCOV_REPORTS_DIR := lcov_reports-$(shell date +%Y%m%d%k%M%S) lcov-dated: lcov else LCOV_REPORTS_DIR := lcov_reports endif lcov-reset: $(LCOV) --zerocounters $(addprefix -d , $(basename $(LCOV_TRACES))) # maybe use subdirs processing to create tracefiles... $(LCOV_TRACES): $(LCOV) -b $(basename $@) -d $(basename $@) \ --ignore-errors source -c -o - | $(SED) \ -e "s/\(dmeventd_lvm.[ch]\)/plugins\/lvm2\/\1/" \ -e "s/dmeventd_\(mirror\|snapshot\|thin\|raid\)\.c/plugins\/\1\/dmeventd_\1\.c/" \ >$@ ifneq ("$(GENHTML)", "") lcov: $(LCOV_TRACES) $(RM) -r $(LCOV_REPORTS_DIR) $(MKDIR_P) $(LCOV_REPORTS_DIR) for i in $(LCOV_TRACES); do \ test -s $$i && lc="$$lc $$i"; \ done; \ test -z "$$lc" || $(GENHTML) -p @abs_top_builddir@ \ -o $(LCOV_REPORTS_DIR) $$lc endif endif ifeq ("$(TESTING)", "yes") # testing and report generation RUBY=ruby1.9 -Ireport-generators/lib -Ireport-generators/test .PHONY: unit-test ruby-test test-programs # FIXME: put dependencies on libdm and liblvm # FIXME: Should be handled by Makefiles in subdirs, not here at top level. test-programs: cd unit-tests/regex && $(MAKE) cd unit-tests/datastruct && $(MAKE) cd unit-tests/mm && $(MAKE) unit-test: test-programs $(RUBY) report-generators/unit_test.rb $(shell find . -name TESTS) $(RUBY) report-generators/title_page.rb memcheck: test-programs $(RUBY) report-generators/memcheck.rb $(shell find . -name TESTS) $(RUBY) report-generators/title_page.rb ruby-test: $(RUBY) report-generators/test/ts.rb endif lvm2-2.02.98/INSTALL0000640000175000017500000000167112037016272012546 0ustar blankblankInstallation ============ 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. lvm2-2.02.98/make.tmpl.in0000640000175000017500000002775112037016272013744 0ustar blankblank# @configure_input@ # # 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 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 SHELL = /bin/sh @SET_MAKE@ CC ?= @CC@ RANLIB = @RANLIB@ INSTALL = @INSTALL@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ LCOV = @LCOV@ GENHTML = @GENHTML@ LN_S = @LN_S@ SED = @SED@ CFLOW_CMD = @CFLOW_CMD@ AWK = @AWK@ PYTHON = @PYTHON@ LIBS = @LIBS@ # Extra libraries always linked with static binaries STATIC_LIBS = $(SELINUX_LIBS) $(UDEV_LIBS) DEFS += @DEFS@ CFLAGS += @CFLAGS@ CLDFLAGS += @CLDFLAGS@ ELDFLAGS += @ELDFLAGS@ LDDEPS += @LDDEPS@ LDFLAGS += @LDFLAGS@ LIB_SUFFIX = @LIB_SUFFIX@ LVMINTERNAL_LIBS = -llvm-internal $(DAEMON_LIBS) $(UDEV_LIBS) $(DL_LIBS) DL_LIBS = @DL_LIBS@ PTHREAD_LIBS = @PTHREAD_LIBS@ READLINE_LIBS = @READLINE_LIBS@ SELINUX_LIBS = @SELINUX_LIBS@ UDEV_LIBS = @UDEV_LIBS@ TESTING = @TESTING@ # Setup directory variables prefix = @prefix@ exec_prefix = @exec_prefix@ udev_prefix = @udev_prefix@ sysconfdir = @sysconfdir@ rootdir = $(DESTDIR)/ bindir = $(DESTDIR)@bindir@ confdir = $(DESTDIR)@CONFDIR@/lvm includedir = $(DESTDIR)@includedir@ libdir = $(DESTDIR)@libdir@ usrlibdir = $(DESTDIR)@usrlibdir@ sbindir = $(DESTDIR)@sbindir@ usrsbindir = $(DESTDIR)@usrsbindir@ datarootdir = @datarootdir@ infodir = $(DESTDIR)@infodir@ mandir = $(DESTDIR)@mandir@ localedir = $(DESTDIR)@LOCALEDIR@ staticdir = $(DESTDIR)@STATICDIR@ udevdir = $(DESTDIR)@udevdir@ pkgconfigdir = $(usrlibdir)/pkgconfig initdir = $(DESTDIR)$(sysconfdir)/rc.d/init.d systemd_unit_dir = $(DESTDIR)@systemdsystemunitdir@ systemd_generator_dir = $(DESTDIR)@systemdutildir@/system-generators tmpfiles_dir = $(DESTDIR)@tmpfilesdir@ ocf_scriptdir = $(DESTDIR)@OCFDIR@ USRLIB_RELPATH = $(shell echo $(abspath $(usrlibdir) $(libdir)) | \ $(AWK) -f $(top_srcdir)/scripts/relpath.awk) DEFAULT_SYS_DIR = @DEFAULT_SYS_DIR@ DEFAULT_ARCHIVE_DIR = $(DEFAULT_SYS_DIR)/@DEFAULT_ARCHIVE_SUBDIR@ DEFAULT_BACKUP_DIR = $(DEFAULT_SYS_DIR)/@DEFAULT_BACKUP_SUBDIR@ DEFAULT_CACHE_DIR = $(DEFAULT_SYS_DIR)/@DEFAULT_CACHE_SUBDIR@ DEFAULT_LOCK_DIR = @DEFAULT_LOCK_DIR@ DEFAULT_RUN_DIR = @DEFAULT_RUN_DIR@ # Setup vpath search paths for some suffixes vpath %.c $(srcdir) vpath %.in $(srcdir) vpath %.po $(srcdir) vpath %.exported_symbols $(srcdir) interface = @interface@ interfacebuilddir = $(top_builddir)/libdm/$(interface) # The number of jobs to run, if blank, defaults to the make standard ifndef MAKEFLAGS MAKEFLAGS = @JOBS@ endif # Handle installation of files ifeq ("@WRITE_INSTALL@", "yes") # leaving defaults M_INSTALL_SCRIPT = M_INSTALL_DATA = -m 644 else M_INSTALL_PROGRAM = -m 555 M_INSTALL_DATA = -m 444 endif INSTALL_PROGRAM = $(INSTALL) $(M_INSTALL_PROGRAM) $(STRIP) INSTALL_DATA = $(INSTALL) -p $(M_INSTALL_DATA) INSTALL_WDATA = $(INSTALL) -p -m 644 INSTALL_DIR = $(INSTALL) -m 755 -d INSTALL_ROOT_DIR = $(INSTALL) -m 700 -d INSTALL_ROOT_DATA = $(INSTALL) -m 600 INSTALL_SCRIPT = $(INSTALL) -p $(M_INSTALL_PROGRAM) .SUFFIXES: .c .d .o .so .a .po .pot .mo .dylib WFLAGS += -Wall -Wundef -Wshadow -Wcast-align -Wwrite-strings \ -Wmissing-prototypes -Wmissing-declarations -Wnested-externs \ -Winline -Wmissing-noreturn -Wformat-security -Wredundant-decls \ -Wpointer-arith #WFLAGS += -W -Wconversion -Wbad-function-cast -Wcast-qual #WFLAGS += -pedantic -std=gnu99 #DEFS += -DDEBUG_CRC32 CFLAGS += -fPIC @COPTIMISE_FLAG@ LDFLAGS += @COPTIMISE_FLAG@ ifeq ("@DEBUG@", "yes") CFLAGS += -g -fno-omit-frame-pointer DEFS += -DDEBUG # memory debugging is not thread-safe yet ifneq ("@DMEVENTD@", "yes") DEFS += -DDEBUG_MEM endif endif ifeq ("@INTL@", "yes") DEFS += -DINTL_PACKAGE=\"@INTL_PACKAGE@\" -DLOCALEDIR=\"@LOCALEDIR@\" endif LDFLAGS += -L$(top_builddir)/libdm -L$(top_builddir)/lib CLDFLAGS += -L$(top_builddir)/libdm -L$(top_builddir)/lib DAEMON_LIBS = -ldaemonclient LDFLAGS += -L$(top_builddir)/libdaemon/client CLDFLAGS += -L$(top_builddir)/libdaemon/client ifeq ("@DMEVENTD@", "yes") LDFLAGS += -L$(top_builddir)/daemons/dmeventd CLDFLAGS += -L$(top_builddir)/daemons/dmeventd endif ifeq ("@DM_COMPAT@", "yes") DEFS += -DDM_COMPAT endif ifeq ("@DM_IOCTLS@", "yes") DEFS += -DDM_IOCTLS endif # Combination of DEBUG_POOL and DEBUG_ENFORCE_POOL_LOCKING is not suppored. #DEFS += -DDEBUG_POOL # Default pool locking is using the crc checksum. With mprotect memory # enforcing compilation faulty memory write could be easily found. #DEFS += -DDEBUG_ENFORCE_POOL_LOCKING #DEFS += -DBOUNDS_CHECK #CFLAGS += -pg #LDFLAGS += -pg STRIP= #STRIP = -s LVM_VERSION := $(shell cat $(top_srcdir)/VERSION) LIB_VERSION_LVM := $(shell $(AWK) -F '.' '{printf "%s.%s",$$1,$$2}' $(top_srcdir)/VERSION) LIB_VERSION_DM := $(shell $(AWK) -F '.' '{printf "%s.%s",$$1,$$2}' $(top_srcdir)/VERSION_DM) LIB_VERSION_APP := $(shell $(AWK) -F '[(). ]' '{printf "%s.%s",$$1,$$4}' $(top_srcdir)/VERSION) INCLUDES += -I. -I$(top_builddir)/include INC_LNS = $(top_builddir)/include/.symlinks_created DEPS = $(top_builddir)/make.tmpl $(top_srcdir)/VERSION \ $(top_builddir)/Makefile $(INC_LNS) OBJECTS = $(SOURCES:%.c=%.o) POTFILES = $(SOURCES:%.c=%.pot) .PHONY: all pofile distclean clean cleandir cflow device-mapper .PHONY: install install_cluster install_device-mapper install_lvm2 .PHONY: install_lib_shared install_dm_plugin install_lvm2_plugin .PHONY: install_ocf help .PHONY: python_bindings install_python_bindings .PHONY: $(SUBDIRS) $(SUBDIRS.install) $(SUBDIRS.clean) $(SUBDIRS.distclean) .PHONY: $(SUBDIRS.pofile) $(SUBDIRS.install_cluster) $(SUBDIRS.cflow) .PHONY: $(SUBDIRS.device-mapper) $(SUBDIRS.install-device-mapper) SUBDIRS.device-mapper := $(SUBDIRS:=.device-mapper) SUBDIRS.install := $(SUBDIRS:=.install) SUBDIRS.install_cluster := $(SUBDIRS:=.install_cluster) SUBDIRS.install_device-mapper := $(SUBDIRS:=.install_device-mapper) SUBDIRS.install_lvm2 := $(SUBDIRS:=.install_lvm2) SUBDIRS.install_ocf := $(SUBDIRS:=.install_ocf) SUBDIRS.pofile := $(SUBDIRS:=.pofile) SUBDIRS.cflow := $(SUBDIRS:=.cflow) SUBDIRS.clean := $(SUBDIRS:=.clean) SUBDIRS.distclean := $(SUBDIRS:=.distclean) TARGETS += $(LIB_SHARED) $(LIB_STATIC) all: $(SUBDIRS) $(TARGETS) install: all $(SUBDIRS.install) install_cluster: all $(SUBDIRS.install_cluster) install_device-mapper: $(SUBDIRS.install_device-mapper) install_lvm2: $(SUBDIRS.install_lvm2) install_ocf: $(SUBDIRS.install_ocf) cflow: $(SUBDIRS.cflow) $(SUBDIRS): $(SUBDIRS.device-mapper) $(MAKE) -C $@ $(SUBDIRS.device-mapper): $(MAKE) -C $(@:.device-mapper=) device-mapper $(SUBDIRS.install): $(SUBDIRS) $(MAKE) -C $(@:.install=) install $(SUBDIRS.install_cluster): $(SUBDIRS) $(MAKE) -C $(@:.install_cluster=) install_cluster $(SUBDIRS.install_device-mapper): device-mapper $(MAKE) -C $(@:.install_device-mapper=) install_device-mapper $(SUBDIRS.install_lvm2): $(SUBDIRS) $(MAKE) -C $(@:.install_lvm2=) install_lvm2 $(SUBDIRS.install_ocf): $(MAKE) -C $(@:.install_ocf=) install_ocf $(SUBDIRS.clean): -$(MAKE) -C $(@:.clean=) clean $(SUBDIRS.distclean): -$(MAKE) -C $(@:.distclean=) distclean $(SUBDIRS.cflow): $(MAKE) -C $(@:.cflow=) cflow ifeq ("@INTL@", "yes") pofile: $(SUBDIRS.pofile) $(POTFILES) $(SUBDIRS.pofile): $(MAKE) -C $(@:.pofile=) pofile endif ifneq ("$(CFLOW_LIST_TARGET)", "") CLEAN_CFLOW += $(CFLOW_LIST_TARGET) $(CFLOW_LIST_TARGET): $(CFLOW_LIST) echo "CFLOW_SOURCES += $(addprefix \ \$$(top_srcdir)$(subst $(top_srcdir),,$(srcdir))/, $(CFLOW_LIST))" > $@ cflow: $(CFLOW_LIST_TARGET) endif ifneq ("$(CFLOW_TARGET)", "") CLEAN_CFLOW += \ $(CFLOW_TARGET).cflow \ $(CFLOW_TARGET).xref \ $(CFLOW_TARGET).tree \ $(CFLOW_TARGET).rtree \ $(CFLOW_TARGET).rxref ifneq ("$(CFLOW_CMD)", "") CFLOW_FLAGS +=\ --cpp="$(CC) -E" \ --symbol _ISbit:wrapper \ --symbol __attribute__:wrapper \ --symbol __const__:wrapper \ --symbol __const:type \ --symbol __restrict:type \ --symbol __extension__:wrapper \ --symbol __nonnull:wrapper \ --symbol __nothrow__:wrapper \ --symbol __pure__:wrapper \ --symbol __REDIRECT:wrapper \ --symbol __REDIRECT_NTH:wrapper \ --symbol __wur:wrapper \ -I$(top_srcdir)/libdm \ -I$(top_srcdir)/libdm/ioctl \ -I$(top_srcdir)/daemons/dmeventd/plugins/lvm2/ \ $(INCLUDES) $(DEFS) $(CFLOW_TARGET).cflow: $(CFLOW_SOURCES) $(CFLOW_CMD) -o$@ $(CFLOW_FLAGS) $(CFLOW_SOURCES) $(CFLOW_TARGET).rxref: $(CFLOW_SOURCES) $(CFLOW_CMD) -o$@ $(CFLOW_FLAGS) -r --omit-arguments $(CFLOW_SOURCES) $(CFLOW_TARGET).tree: $(CFLOW_SOURCES) $(CFLOW_CMD) -o$@ $(CFLOW_FLAGS) --omit-arguments -T -b $(CFLOW_SOURCES) $(CFLOW_TARGET).xref: $(CFLOW_SOURCES) $(CFLOW_CMD) -o$@ $(CFLOW_FLAGS) --omit-arguments -x $(CFLOW_SOURCES) #$(CFLOW_TARGET).rtree: $(CFLOW_SOURCES) # $(CFLOW_CMD) -o$@ $(CFLOW_FLAGS) -r --omit-arguments -T -b $(CFLOW_SOURCES) cflow: $(CFLOW_TARGET).cflow $(CFLOW_TARGET).tree $(CFLOW_TARGET).rxref $(CFLOW_TARGET).xref #$(CFLOW_TARGET).rtree endif endif $(TARGETS): $(OBJECTS) %.o: %.c $(CC) -c $(INCLUDES) $(DEFS) $(WFLAGS) $(CFLAGS) $< -o $@ %.pot: %.c Makefile $(CC) -E $(INCLUDES) -include $(top_srcdir)/include/pogen.h \ $(DEFS) $(WFLAGS) $(CFLAGS) $< > $@ %.so: %.o $(CC) -c $(CFLAGS) $(CLDFLAGS) $< $(LIBS) -o $@ ifneq (,$(LIB_SHARED)) TARGETS += $(LIB_SHARED).$(LIB_VERSION) $(LIB_SHARED).$(LIB_VERSION): $(OBJECTS) $(LDDEPS) ifeq ("@LIB_SUFFIX@","so") $(CC) -shared -Wl,-soname,$(notdir $@) \ $(CFLAGS) $(CLDFLAGS) $(OBJECTS) $(LIBS) -o $@ endif ifeq ("@LIB_SUFFIX@","dylib") $(CC) -dynamiclib -dylib_current_version,$(LIB_VERSION) \ $(CFLAGS) $(CLDFLAGS) $(OBJECTS) $(LIBS) -o $@ endif $(LIB_SHARED): $(LIB_SHARED).$(LIB_VERSION) $(LN_S) -f $( $@ .export.sym: .exported_symbols_generated set -e; (echo "Base {"; echo " global:"; \ sed "s/^/ /;s/$$/;/" < $<; \ echo " local:"; echo " *;"; echo "};") > $@ ifeq (,$(findstring $(MAKECMDGOALS),cscope.out cflow clean distclean lcov \ help check check_local check_cluster check_lvmetad)) ifdef SOURCES -include $(SOURCES:.c=.d) endif ifdef SOURCES2 -include $(SOURCES2:.c=.d) endif endif lvm2-2.02.98/daemons/0000750000175000017500000000000012037016272013135 5ustar blankblanklvm2-2.02.98/daemons/dmeventd/0000750000175000017500000000000012037016272014743 5ustar blankblanklvm2-2.02.98/daemons/dmeventd/.exported_symbols0000640000175000017500000000006712037016272020352 0ustar blankblankinit_fifos fini_fifos daemon_talk dm_event_get_version lvm2-2.02.98/daemons/dmeventd/plugins/0000750000175000017500000000000012037016272016424 5ustar blankblanklvm2-2.02.98/daemons/dmeventd/plugins/snapshot/0000750000175000017500000000000012037016272020263 5ustar blankblanklvm2-2.02.98/daemons/dmeventd/plugins/snapshot/.exported_symbols0000640000175000017500000000006012037016272023663 0ustar blankblankprocess_event register_device unregister_device lvm2-2.02.98/daemons/dmeventd/plugins/snapshot/Makefile.in0000640000175000017500000000206412037016272022333 0ustar blankblank# # 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 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 $(DAEMON_LIBS) install_lvm2: install_dm_plugin install: install_lvm2 lvm2-2.02.98/daemons/dmeventd/plugins/snapshot/dmeventd_snapshot.c0000640000175000017500000001624412037016272024164 0ustar blankblank/* * Copyright (C) 2007-2011 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU Lesser General Public License v.2.1. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "lib.h" #include "lvm2cmd.h" #include "errors.h" #include "libdevmapper-event.h" #include "dmeventd_lvm.h" #include #include /* 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; }; struct dso_state { int percent_check; int known_size; char cmd_str[1024]; }; /* 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 *cmd) { return dmeventd_lvm2_run(cmd) == 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 */ if (dm_split_words(buffer, 3, 0, words) < 2) continue; /* find the major/minor of the device */ if (stat(words[0], &st)) continue; /* can't stat, skip this one */ if (S_ISBLK(st.st_mode) && major(st.st_rdev) == major && minor(st.st_rdev) == minor) { syslog(LOG_ERR, "Unmounting invalid snapshot %s from %s.\n", device, words[1]); if (!_run(UMOUNT_COMMAND, "-fl", words[1], NULL)) syslog(LOG_ERR, "Failed to umount snapshot %s from %s: %s.\n", device, words[1], strerror(errno)); } } if (fclose(mounts)) syslog(LOG_ERR, "Failed to close /proc/mounts.\n"); } void process_event(struct dm_task *dmt, enum dm_event_mask event __attribute__((unused)), void **private) { void *next = NULL; uint64_t start, length; char *target_type = NULL; char *params; struct snap_status status = { 0 }; const char *device = dm_task_get_name(dmt); int percent; struct dso_state *state = *private; /* No longer monitoring, waiting for remove */ if (!state->percent_check) return; dmeventd_lvm2_lock(); dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms); if (!target_type) goto out; _parse_snapshot_params(params, &status); if (status.invalid) { struct dm_info info; if (dm_task_get_info(dmt, &info)) { dmeventd_lvm2_unlock(); _umount(device, info.major, info.minor); return; } /* else; too bad, but this is best-effort thing... */ } /* Snapshot size had changed. Clear the threshold. */ if (state->known_size != status.max) { state->percent_check = CHECK_MINIMUM; state->known_size = status.max; } /* * 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); state->percent_check = 0; goto out; } percent = 100 * status.used / status.max; if (percent >= state->percent_check) { /* Usage has raised more than CHECK_STEP since the last time. Run actions. */ state->percent_check = (percent / CHECK_STEP) * CHECK_STEP + CHECK_STEP; if (percent >= WARNING_THRESH) /* Print a warning to syslog. */ syslog(LOG_WARNING, "Snapshot %s is now %i%% full.\n", device, percent); /* Try to extend the snapshot, in accord with user-set policies */ if (!_extend(state->cmd_str)) syslog(LOG_ERR, "Failed to extend snapshot %s.\n", device); } out: dmeventd_lvm2_unlock(); } int register_device(const char *device, const char *uuid __attribute__((unused)), int major __attribute__((unused)), int minor __attribute__((unused)), void **private) { struct dso_state *state; if (!dmeventd_lvm2_init()) goto out; if (!(state = dm_zalloc(sizeof(*state)))) goto bad; if (!dmeventd_lvm2_command(dmeventd_lvm2_pool(), state->cmd_str, sizeof(state->cmd_str), "lvextend --use-policies", device)) goto bad; state->percent_check = CHECK_MINIMUM; state->known_size = 0; *private = state; syslog(LOG_INFO, "Monitoring snapshot %s\n", device); return 1; bad: dm_free(state); dmeventd_lvm2_exit(); out: syslog(LOG_ERR, "Failed to monitor snapshot %s.\n", device); return 0; } int unregister_device(const char *device, const char *uuid __attribute__((unused)), int major __attribute__((unused)), int minor __attribute__((unused)), void **private) { struct dso_state *state = *private; syslog(LOG_INFO, "No longer monitoring snapshot %s\n", device); dm_free(state); dmeventd_lvm2_exit(); return 1; } lvm2-2.02.98/daemons/dmeventd/plugins/mirror/0000750000175000017500000000000012037016272017736 5ustar blankblanklvm2-2.02.98/daemons/dmeventd/plugins/mirror/.exported_symbols0000640000175000017500000000006012037016272023336 0ustar blankblankprocess_event register_device unregister_device lvm2-2.02.98/daemons/dmeventd/plugins/mirror/Makefile.in0000640000175000017500000000221512037016272022004 0ustar blankblank# # Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. # Copyright (C) 2004-2005, 2008-2011 Red Hat, Inc. All rights reserved. # # This file is part of LVM2. # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions # of the GNU General Public License v.2. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation, # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA srcdir = @srcdir@ top_srcdir = @top_srcdir@ top_builddir = @top_builddir@ 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 $(DAEMON_LIBS) install_lvm2: install_dm_plugin install: install_lvm2 lvm2-2.02.98/daemons/dmeventd/plugins/mirror/dmeventd_mirror.c0000640000175000017500000001434512037016272023312 0ustar blankblank/* * Copyright (C) 2005-2012 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU Lesser General Public License v.2.1. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "lib.h" #include "lvm2cmd.h" #include "errors.h" #include "libdevmapper-event.h" #include "dmeventd_lvm.h" #include "defaults.h" #include /* FIXME Replace syslog with multilog */ /* FIXME Missing openlog? */ /* FIXME Replace most syslogs with log_error() style messages and add complete context. */ /* FIXME Reformat to 80 char lines. */ #define ME_IGNORE 0 #define ME_INSYNC 1 #define ME_FAILURE 2 static int _process_status_code(const char status_code, const char *dev_name, const char *dev_type, int r) { /* * A => Alive - No failures * D => Dead - A write failure occurred leaving mirror out-of-sync * F => Flush failed. * S => Sync - A sychronization failure occurred, mirror out-of-sync * R => Read - A read failure occurred, mirror data unaffected * U => Unclassified failure (bug) */ if (status_code == 'F') { syslog(LOG_ERR, "%s device %s flush failed.", dev_type, dev_name); r = ME_FAILURE; } else if (status_code == 'S') syslog(LOG_ERR, "%s device %s sync failed.", dev_type, dev_name); else if (status_code == 'R') syslog(LOG_ERR, "%s device %s read failed.", dev_type, dev_name); else if (status_code != 'A') { syslog(LOG_ERR, "%s device %s has failed (%c).", dev_type, dev_name, status_code); r = ME_FAILURE; } return r; } static int _get_mirror_event(char *params) { int i, r = ME_INSYNC; char **args = NULL; char *dev_status_str; char *log_status_str; char *sync_str; char *p = NULL; int log_argc, num_devs; /* * dm core parms: 0 409600 mirror * Mirror core parms: 2 253:4 253:5 400/400 * New-style failure params: 1 AA * New-style log params: 3 cluster 253:3 A * or 3 disk 253:3 A * or 1 core */ /* number of devices */ if (!dm_split_words(params, 1, 0, &p)) goto out_parse; if (!(num_devs = atoi(p)) || (num_devs > DEFAULT_MIRROR_MAX_IMAGES) || (num_devs < 0)) goto out_parse; p += strlen(p) + 1; /* devices names + "400/400" + "1 AA" + 1 or 3 log parms + NULL */ args = dm_malloc((num_devs + 7) * sizeof(char *)); if (!args || dm_split_words(p, num_devs + 7, 0, args) < num_devs + 5) goto out_parse; /* FIXME: Code differs from lib/mirror/mirrored.c */ dev_status_str = args[2 + num_devs]; log_argc = atoi(args[3 + num_devs]); log_status_str = args[3 + num_devs + log_argc]; sync_str = args[num_devs]; /* Check for bad mirror devices */ for (i = 0; i < num_devs; i++) r = _process_status_code(dev_status_str[i], args[i], i ? "Secondary mirror" : "Primary mirror", r); /* Check for bad disk log device */ if (log_argc > 1) r = _process_status_code(log_status_str[0], args[2 + num_devs + log_argc], "Log", r); if (r == ME_FAILURE) goto out; p = strstr(sync_str, "/"); if (p) { p[0] = '\0'; if (strcmp(sync_str, p+1)) r = ME_IGNORE; p[0] = '/'; } else goto out_parse; out: dm_free(args); return r; out_parse: dm_free(args); syslog(LOG_ERR, "Unable to parse mirror status string."); return ME_IGNORE; } static int _remove_failed_devices(const char *device) { int r; #define CMD_SIZE 256 /* FIXME Use system restriction */ char cmd_str[CMD_SIZE]; if (!dmeventd_lvm2_command(dmeventd_lvm2_pool(), cmd_str, sizeof(cmd_str), "lvconvert --config devices{ignore_suspended_devices=1} " "--repair --use-policies", device)) return -ENAMETOOLONG; /* FIXME Replace with generic error return - reason for failure has already got logged */ r = dmeventd_lvm2_run(cmd_str); syslog(LOG_INFO, "Repair of mirrored device %s %s.", device, (r == 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))) { if (!dmeventd_lvm2_init()) return 0; syslog(LOG_INFO, "Monitoring mirror device %s for events.", device); return 1; } int unregister_device(const char *device, const char *uuid __attribute__((unused)), int major __attribute__((unused)), int minor __attribute__((unused)), void **unused __attribute__((unused))) { syslog(LOG_INFO, "No longer monitoring mirror device %s for events.", device); dmeventd_lvm2_exit(); return 1; } lvm2-2.02.98/daemons/dmeventd/plugins/lvm2/0000750000175000017500000000000012037016272017304 5ustar blankblanklvm2-2.02.98/daemons/dmeventd/plugins/lvm2/.exported_symbols0000640000175000017500000000021112037016272022702 0ustar blankblankdmeventd_lvm2_init dmeventd_lvm2_exit dmeventd_lvm2_lock dmeventd_lvm2_unlock dmeventd_lvm2_pool dmeventd_lvm2_run dmeventd_lvm2_command lvm2-2.02.98/daemons/dmeventd/plugins/lvm2/dmeventd_lvm.h0000640000175000017500000000242512037016272022145 0ustar blankblank/* * 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); int dmeventd_lvm2_command(struct dm_pool *mem, char *buffer, size_t size, const char *cmd, const char *device); #endif /* _DMEVENTD_LVMWRAP_H */ lvm2-2.02.98/daemons/dmeventd/plugins/lvm2/Makefile.in0000640000175000017500000000154512037016272021357 0ustar blankblank# # Copyright (C) 2010-2011 Red Hat, Inc. All rights reserved. # # This file is part of LVM2. # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions # of the GNU General Public License v.2. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation, # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA srcdir = @srcdir@ top_srcdir = @top_srcdir@ top_builddir = @top_builddir@ 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) $(DAEMON_LIBS) install_lvm2: install_lib_shared install: install_lvm2 lvm2-2.02.98/daemons/dmeventd/plugins/lvm2/dmeventd_lvm.c0000640000175000017500000000761212037016272022143 0ustar blankblank/* * Copyright (C) 2010 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU Lesser General Public License v.2.1. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "lib.h" #include "log.h" #include "lvm2cmd.h" #include "dmeventd_lvm.h" #include #include extern int dmeventd_debug; /* * register_device() is called first and performs initialisation. * Only one device may be registered or unregistered at a time. */ static pthread_mutex_t _register_mutex = PTHREAD_MUTEX_INITIALIZER; /* * Number of active registrations. */ static int _register_count = 0; static struct dm_pool *_mem_pool = NULL; static void *_lvm_handle = NULL; /* * Currently only one event can be processed at a time. */ static pthread_mutex_t _event_mutex = PTHREAD_MUTEX_INITIALIZER; /* * FIXME Do not pass things directly to syslog, rather use the existing logging * facilities to sort logging ... however that mechanism needs to be somehow * configurable and we don't have that option yet */ static void _temporary_log_fn(int level, const char *file __attribute__((unused)), int line __attribute__((unused)), int dm_errno __attribute__((unused)), const char *message) { level &= ~(_LOG_STDERR | _LOG_ONCE); switch (level) { case _LOG_DEBUG: if (dmeventd_debug >= 3) syslog(LOG_DEBUG, "%s", message); break; case _LOG_INFO: if (dmeventd_debug >= 2) syslog(LOG_INFO, "%s", message); break; case _LOG_NOTICE: if (dmeventd_debug >= 1) syslog(LOG_NOTICE, "%s", message); break; case _LOG_WARN: syslog(LOG_WARNING, "%s", message); break; case _LOG_ERR: syslog(LOG_ERR, "%s", message); break; default: syslog(LOG_CRIT, "%s", message); } } void dmeventd_lvm2_lock(void) { pthread_mutex_lock(&_event_mutex); } void dmeventd_lvm2_unlock(void) { pthread_mutex_unlock(&_event_mutex); } int dmeventd_lvm2_init(void) { int r = 0; pthread_mutex_lock(&_register_mutex); /* * Need some space for allocations. 1024 should be more * than enough for what we need (device mapper name splitting) */ if (!_mem_pool && !(_mem_pool = dm_pool_create("mirror_dso", 1024))) goto out; if (!_lvm_handle) { lvm2_log_fn(_temporary_log_fn); if (!(_lvm_handle = lvm2_init())) { dm_pool_destroy(_mem_pool); _mem_pool = NULL; goto out; } lvm2_disable_dmeventd_monitoring(_lvm_handle); /* FIXME Temporary: move to dmeventd core */ lvm2_run(_lvm_handle, "_memlock_inc"); } _register_count++; r = 1; out: pthread_mutex_unlock(&_register_mutex); return r; } void dmeventd_lvm2_exit(void) { pthread_mutex_lock(&_register_mutex); if (!--_register_count) { lvm2_run(_lvm_handle, "_memlock_dec"); dm_pool_destroy(_mem_pool); _mem_pool = NULL; lvm2_exit(_lvm_handle); _lvm_handle = NULL; } pthread_mutex_unlock(&_register_mutex); } struct dm_pool *dmeventd_lvm2_pool(void) { return _mem_pool; } int dmeventd_lvm2_run(const char *cmdline) { return lvm2_run(_lvm_handle, cmdline); } int dmeventd_lvm2_command(struct dm_pool *mem, char *buffer, size_t size, const char *cmd, const char *device) { char *vg = NULL, *lv = NULL, *layer; int r; if (!dm_split_lvm_name(mem, device, &vg, &lv, &layer)) { syslog(LOG_ERR, "Unable to determine VG name from %s.\n", device); return 0; } /* strip off the mirror component designations */ layer = strstr(lv, "_mlog"); if (layer) *layer = '\0'; r = dm_snprintf(buffer, size, "%s %s/%s", cmd, vg, lv); dm_pool_free(mem, vg); if (r < 0) { syslog(LOG_ERR, "Unable to form LVM command. (too long).\n"); return 0; } return 1; } lvm2-2.02.98/daemons/dmeventd/plugins/thin/0000750000175000017500000000000012037016272017366 5ustar blankblanklvm2-2.02.98/daemons/dmeventd/plugins/thin/.exported_symbols0000640000175000017500000000006012037016272022766 0ustar blankblankprocess_event register_device unregister_device lvm2-2.02.98/daemons/dmeventd/plugins/thin/dmeventd_thin.c0000640000175000017500000002553312037016272022373 0ustar blankblank/* * Copyright (C) 2011-2012 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU Lesser General Public License v.2.1. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "lib.h" #include "lvm2cmd.h" #include "errors.h" #include "libdevmapper-event.h" #include "dmeventd_lvm.h" #include #include /* FIXME Replace syslog with multilog */ /* FIXME Missing openlog? */ /* First warning when thin is 80% full. */ #define WARNING_THRESH 80 /* Run a check every 5%. */ #define CHECK_STEP 5 /* Do not bother checking thins less than 50% full. */ #define CHECK_MINIMUM 50 #define UMOUNT_COMMAND "/bin/umount" #define THIN_DEBUG 0 struct dso_state { struct dm_pool *mem; int metadata_percent_check; int data_percent_check; uint64_t known_metadata_size; uint64_t known_data_size; char cmd_str[1024]; }; /* TODO - move this mountinfo code into library to be reusable */ #ifdef linux # include "kdev_t.h" #else # define MAJOR(x) major((x)) # define MINOR(x) minor((x)) # define MKDEV(x,y) makedev((x),(y)) #endif /* Macros to make string defines */ #define TO_STRING_EXP(A) #A #define TO_STRING(A) TO_STRING_EXP(A) static int _is_octal(int a) { return (((a) & ~7) == '0'); } /* Convert mangled mountinfo into normal ASCII string */ static void _unmangle_mountinfo_string(const char *src, char *buf) { if (!src) return; while (*src) { if ((*src == '\\') && _is_octal(src[1]) && _is_octal(src[2]) && _is_octal(src[3])) { *buf++ = 64 * (src[1] & 7) + 8 * (src[2] & 7) + (src[3] & 7); src += 4; } else *buf++ = *src++; } *buf = '\0'; } /* Parse one line of mountinfo */ static int _parse_mountinfo_line(const char *line, unsigned *maj, unsigned *min, char *buf) { char root[PATH_MAX + 1]; char target[PATH_MAX + 1]; /* TODO: maybe detect availability of %ms glib support ? */ if (sscanf(line, "%*u %*u %u:%u %" TO_STRING(PATH_MAX) "s %" TO_STRING(PATH_MAX) "s", maj, min, root, target) < 4) return 0; _unmangle_mountinfo_string(target, buf); #if THIN_DEBUG syslog(LOG_DEBUG, "Mounted %u:%u %s", *maj, *min, buf); #endif return 1; } /* Get dependencies for device, and try to find matching device */ static int _has_deps(const char *name, int tp_major, int tp_minor, int *dev_minor) { struct dm_task *dmt; const struct dm_deps *deps; struct dm_info info; int major, minor; int r = 0; if (!(dmt = dm_task_create(DM_DEVICE_DEPS))) return 0; if (!dm_task_set_name(dmt, name)) goto out; if (!dm_task_no_open_count(dmt)) goto out; if (!dm_task_run(dmt)) goto out; if (!dm_task_get_info(dmt, &info)) goto out; if (!(deps = dm_task_get_deps(dmt))) goto out; if (!info.exists || deps->count != 1) goto out; major = (int) MAJOR(deps->device[0]); minor = (int) MINOR(deps->device[0]); if ((major != tp_major) || (minor != tp_minor)) goto out; *dev_minor = info.minor; #if THIN_DEBUG { char dev_name[PATH_MAX]; if (dm_device_get_name(major, minor, 0, dev_name, sizeof(dev_name))) syslog(LOG_DEBUG, "Found %s (%u:%u) depends on %s", name, major, *dev_minor, dev_name); } #endif r = 1; out: dm_task_destroy(dmt); return r; } /* Get all active devices */ static int _find_all_devs(dm_bitset_t bs, int tp_major, int tp_minor) { struct dm_task *dmt; struct dm_names *names; unsigned next = 0; int minor, r = 1; if (!(dmt = dm_task_create(DM_DEVICE_LIST))) return 0; if (!dm_task_run(dmt)) { r = 0; goto out; } if (!(names = dm_task_get_names(dmt))) { r = 0; goto out; } if (!names->dev) goto out; do { names = (struct dm_names *)((char *) names + next); if (_has_deps(names->name, tp_major, tp_minor, &minor)) dm_bit_set(bs, minor); next = names->next; } while (next); out: dm_task_destroy(dmt); return r; } static int _extend(struct dso_state *state) { #if THIN_DEBUG syslog(LOG_INFO, "dmeventd executes: %s.\n", state->cmd_str); #endif return (dmeventd_lvm2_run(state->cmd_str) == ECMD_PROCESSED); } 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 */ } /* * Find all thin pool users and try to umount them. * TODO: work with read-only thin pool support */ static void _umount(struct dm_task *dmt, const char *device) { static const char mountinfo[] = "/proc/self/mountinfo"; static const size_t MINORS = 4096; FILE *minfo; char buffer[4096]; char target[PATH_MAX]; struct dm_info info; unsigned maj, min; dm_bitset_t minors; /* Bitset for active thin pool minors */ if (!dm_task_get_info(dmt, &info)) return; dmeventd_lvm2_unlock(); if (!(minors = dm_bitset_create(NULL, MINORS))) { syslog(LOG_ERR, "Failed to allocate bitset. Not unmounting %s.\n", device); goto out; } if (!(minfo = fopen(mountinfo, "r"))) { syslog(LOG_ERR, "Could not read %s. Not umounting %s.\n", mountinfo, device); goto out; } if (!_find_all_devs(minors, info.major, info.minor)) { syslog(LOG_ERR, "Failed to detect mounted volumes for %s.\n", device); goto out; } while (!feof(minfo)) { /* read mountinfo line */ if (!fgets(buffer, sizeof(buffer), minfo)) break; /* eof, likely */ if (_parse_mountinfo_line(buffer, &maj, &min, target) && (maj == info.major) && dm_bit(minors, min)) { syslog(LOG_INFO, "Unmounting thin volume %s from %s.\n", device, target); if (!_run(UMOUNT_COMMAND, "-fl", target, NULL)) syslog(LOG_ERR, "Failed to umount thin %s from %s: %s.\n", device, target, strerror(errno)); } } if (fclose(minfo)) syslog(LOG_ERR, "Failed to close %s\n", mountinfo); dm_bitset_destroy(minors); out: dmeventd_lvm2_lock(); } void process_event(struct dm_task *dmt, enum dm_event_mask event __attribute__((unused)), void **private) { const char *device = dm_task_get_name(dmt); int percent; struct dso_state *state = *private; struct dm_status_thin_pool *tps = NULL; void *next = NULL; uint64_t start, length; char *target_type = NULL; char *params; #if 0 /* No longer monitoring, waiting for remove */ if (!state->meta_percent_check && !state->data_percent_check) return; #endif dmeventd_lvm2_lock(); dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms); if (!target_type || (strcmp(target_type, "thin-pool") != 0)) { syslog(LOG_ERR, "Invalid target type.\n"); goto out; } if (!dm_get_status_thin_pool(state->mem, params, &tps)) { syslog(LOG_ERR, "Failed to parse status.\n"); _umount(dmt, device); goto out; } #if THIN_DEBUG syslog(LOG_INFO, "%p: Got status %" PRIu64 " / %" PRIu64 " %" PRIu64 " / %" PRIu64 ".\n", state, tps->used_metadata_blocks, tps->total_metadata_blocks, tps->used_data_blocks, tps->total_data_blocks); #endif /* Thin pool size had changed. Clear the threshold. */ if (state->known_metadata_size != tps->total_metadata_blocks) { state->metadata_percent_check = CHECK_MINIMUM; state->known_metadata_size = tps->total_metadata_blocks; } if (state->known_data_size != tps->total_data_blocks) { state->data_percent_check = CHECK_MINIMUM; state->known_data_size = tps->total_data_blocks; } percent = 100 * tps->used_metadata_blocks / tps->total_metadata_blocks; if (percent >= state->metadata_percent_check) { /* * Usage has raised more than CHECK_STEP since the last * time. Run actions. */ state->metadata_percent_check = (percent / CHECK_STEP) * CHECK_STEP + CHECK_STEP; /* FIXME: extension of metadata needs to be written! */ if (percent >= WARNING_THRESH) /* Print a warning to syslog. */ syslog(LOG_WARNING, "Thin metadata %s is now %i%% full.\n", device, percent); /* Try to extend the metadata, in accord with user-set policies */ if (!_extend(state)) { syslog(LOG_ERR, "Failed to extend thin metadata %s.\n", device); _umount(dmt, device); } /* FIXME: hmm READ-ONLY switch should happen in error path */ } percent = 100 * tps->used_data_blocks / tps->total_data_blocks; if (percent >= state->data_percent_check) { /* * Usage has raised more than CHECK_STEP since * the last time. Run actions. */ state->data_percent_check = (percent / CHECK_STEP) * CHECK_STEP + CHECK_STEP; if (percent >= WARNING_THRESH) /* Print a warning to syslog. */ syslog(LOG_WARNING, "Thin %s is now %i%% full.\n", device, percent); /* Try to extend the thin data, in accord with user-set policies */ if (!_extend(state)) { syslog(LOG_ERR, "Failed to extend thin %s.\n", device); state->data_percent_check = 0; _umount(dmt, device); } /* FIXME: hmm READ-ONLY switch should happen in error path */ } out: if (tps) dm_pool_free(state->mem, tps); dmeventd_lvm2_unlock(); } int register_device(const char *device, const char *uuid __attribute__((unused)), int major __attribute__((unused)), int minor __attribute__((unused)), void **private) { struct dm_pool *statemem = NULL; struct dso_state *state; if (!dmeventd_lvm2_init()) goto bad; if (!(statemem = dm_pool_create("thin_pool_state", 2048)) || !(state = dm_pool_zalloc(statemem, sizeof(*state))) || !dmeventd_lvm2_command(statemem, state->cmd_str, sizeof(state->cmd_str), "lvextend --use-policies", device)) { if (statemem) dm_pool_destroy(statemem); dmeventd_lvm2_exit(); goto bad; } state->mem = statemem; state->metadata_percent_check = CHECK_MINIMUM; state->data_percent_check = CHECK_MINIMUM; *private = state; syslog(LOG_INFO, "Monitoring thin %s.\n", device); return 1; bad: syslog(LOG_ERR, "Failed to monitor thin %s.\n", device); return 0; } int unregister_device(const char *device, const char *uuid __attribute__((unused)), int major __attribute__((unused)), int minor __attribute__((unused)), void **private) { struct dso_state *state = *private; syslog(LOG_INFO, "No longer monitoring thin %s.\n", device); dm_pool_destroy(state->mem); dmeventd_lvm2_exit(); return 1; } lvm2-2.02.98/daemons/dmeventd/plugins/thin/Makefile.in0000640000175000017500000000204412037016272021434 0ustar blankblank# # Copyright (C) 2011 Red Hat, Inc. All rights reserved. # # This file is part of LVM2. # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions # of the GNU General Public License v.2. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation, # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA srcdir = @srcdir@ top_srcdir = @top_srcdir@ top_builddir = @top_builddir@ 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_thin.c LIB_NAME = libdevmapper-event-lvm2thin LIB_SHARED = $(LIB_NAME).$(LIB_SUFFIX) LIB_VERSION = $(LIB_VERSION_LVM) CFLOW_LIST = $(SOURCES) CFLOW_LIST_TARGET = $(LIB_NAME).cflow include $(top_builddir)/make.tmpl LIBS += -ldevmapper-event-lvm2 -ldevmapper install_lvm2: install_dm_plugin install: install_lvm2 lvm2-2.02.98/daemons/dmeventd/plugins/Makefile.in0000640000175000017500000000201712037016272020472 0ustar blankblank# # Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. # Copyright (C) 2004-2005, 2011 Red Hat, Inc. All rights reserved. # # This file is part of LVM2. # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions # of the GNU General Public License v.2. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation, # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA srcdir = @srcdir@ top_srcdir = @top_srcdir@ top_builddir = @top_builddir@ SUBDIRS += lvm2 ifneq ("@MIRRORS@", "none") SUBDIRS += mirror endif ifneq ("@SNAPSHOTS@", "none") SUBDIRS += snapshot endif ifneq ("@RAID@", "none") SUBDIRS += raid endif ifneq ("@THIN@", "none") SUBDIRS += thin endif ifeq ($(MAKECMDGOALS),distclean) SUBDIRS = lvm2 mirror snapshot raid thin endif include $(top_builddir)/make.tmpl snapshot: lvm2 mirror: lvm2 raid: lvm2 thin: lvm2 lvm2-2.02.98/daemons/dmeventd/plugins/raid/0000750000175000017500000000000012037016272017343 5ustar blankblanklvm2-2.02.98/daemons/dmeventd/plugins/raid/.exported_symbols0000640000175000017500000000006012037016272022743 0ustar blankblankprocess_event register_device unregister_device lvm2-2.02.98/daemons/dmeventd/plugins/raid/dmeventd_raid.c0000640000175000017500000001034312037016272022316 0ustar blankblank/* * Copyright (C) 2005-2011 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU Lesser General Public License v.2.1. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "lib.h" #include "lvm2cmd.h" #include "errors.h" #include "libdevmapper-event.h" #include "dmeventd_lvm.h" #include /* FIXME Replace syslog with multilog */ /* FIXME Missing openlog? */ /* FIXME Replace most syslogs with log_error() style messages and add complete context. */ /* FIXME Reformat to 80 char lines. */ /* * run_repair is a close copy to * plugins/mirror/dmeventd_mirror.c:_remove_failed_devices() */ static int run_repair(const char *device) { int r; #define CMD_SIZE 256 /* FIXME Use system restriction */ char cmd_str[CMD_SIZE]; if (!dmeventd_lvm2_command(dmeventd_lvm2_pool(), cmd_str, sizeof(cmd_str), "lvconvert --config devices{ignore_suspended_devices=1} " "--repair --use-policies", device)) return -1; r = dmeventd_lvm2_run(cmd_str); if (r != ECMD_PROCESSED) syslog(LOG_INFO, "Repair of RAID device %s failed.", device); return (r == ECMD_PROCESSED) ? 0 : -1; } static int _process_raid_event(char *params, const char *device) { int i, n, failure = 0; char *p, *a[4]; char *raid_type; char *num_devices; char *health_chars; char *resync_ratio; /* * RAID parms: <#raid_disks> \ * */ if (!dm_split_words(params, 4, 0, a)) { syslog(LOG_ERR, "Failed to process status line for %s\n", device); return -EINVAL; } raid_type = a[0]; num_devices = a[1]; health_chars = a[2]; resync_ratio = a[3]; if (!(n = atoi(num_devices))) { syslog(LOG_ERR, "Failed to parse number of devices for %s: %s", device, num_devices); return -EINVAL; } for (i = 0; i < n; i++) { switch (health_chars[i]) { case 'A': /* Device is 'A'live and well */ case 'a': /* Device is 'a'live, but not yet in-sync */ break; case 'D': syslog(LOG_ERR, "Device #%d of %s array, %s, has failed.", i, raid_type, device); failure++; break; default: /* Unhandled character returned from kernel */ break; } if (failure) return run_repair(device); } p = strstr(resync_ratio, "/"); if (!p) { syslog(LOG_ERR, "Failed to parse resync_ratio for %s: %s", device, resync_ratio); return -EINVAL; } p[0] = '\0'; syslog(LOG_INFO, "%s array, %s, is %s in-sync.", raid_type, device, strcmp(resync_ratio, p+1) ? "not" : "now"); return 0; } void process_event(struct dm_task *dmt, enum dm_event_mask event __attribute__((unused)), void **unused __attribute__((unused))) { void *next = NULL; uint64_t start, length; char *target_type = NULL; char *params; const char *device = dm_task_get_name(dmt); dmeventd_lvm2_lock(); do { next = dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms); if (!target_type) { syslog(LOG_INFO, "%s mapping lost.", device); continue; } if (strcmp(target_type, "raid")) { syslog(LOG_INFO, "%s has non-raid portion.", device); continue; } if (_process_raid_event(params, device)) syslog(LOG_ERR, "Failed to process event for %s", device); } while (next); dmeventd_lvm2_unlock(); } int register_device(const char *device, const char *uuid __attribute__((unused)), int major __attribute__((unused)), int minor __attribute__((unused)), void **unused __attribute__((unused))) { if (!dmeventd_lvm2_init()) return 0; syslog(LOG_INFO, "Monitoring RAID device %s for events.", device); return 1; } int unregister_device(const char *device, const char *uuid __attribute__((unused)), int major __attribute__((unused)), int minor __attribute__((unused)), void **unused __attribute__((unused))) { syslog(LOG_INFO, "No longer monitoring RAID device %s for events.", device); dmeventd_lvm2_exit(); return 1; } lvm2-2.02.98/daemons/dmeventd/plugins/raid/Makefile.in0000640000175000017500000000204412037016272021411 0ustar blankblank# # Copyright (C) 2011 Red Hat, Inc. All rights reserved. # # This file is part of LVM2. # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions # of the GNU General Public License v.2. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation, # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA srcdir = @srcdir@ top_srcdir = @top_srcdir@ top_builddir = @top_builddir@ 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_raid.c LIB_NAME = libdevmapper-event-lvm2raid LIB_SHARED = $(LIB_NAME).$(LIB_SUFFIX) LIB_VERSION = $(LIB_VERSION_LVM) CFLOW_LIST = $(SOURCES) CFLOW_LIST_TARGET = $(LIB_NAME).cflow include $(top_builddir)/make.tmpl LIBS += -ldevmapper-event-lvm2 -ldevmapper install_lvm2: install_dm_plugin install: install_lvm2 lvm2-2.02.98/daemons/dmeventd/dmeventd.h0000640000175000017500000000454612037016272016734 0ustar blankblank/* * Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved. * * This file is part of the device-mapper userspace tools. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU Lesser General Public License v.2.1. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __DMEVENTD_DOT_H__ #define __DMEVENTD_DOT_H__ /* FIXME This stuff must be configurable. */ #define DM_EVENT_FIFO_CLIENT DEFAULT_DM_RUN_DIR "/dmeventd-client" #define DM_EVENT_FIFO_SERVER DEFAULT_DM_RUN_DIR "/dmeventd-server" #define DM_EVENT_DEFAULT_TIMEOUT 10 /* Commands for the daemon passed in the message below. */ enum dm_event_command { DM_EVENT_CMD_ACTIVE = 1, DM_EVENT_CMD_REGISTER_FOR_EVENT, DM_EVENT_CMD_UNREGISTER_FOR_EVENT, DM_EVENT_CMD_GET_REGISTERED_DEVICE, DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE, DM_EVENT_CMD_SET_TIMEOUT, DM_EVENT_CMD_GET_TIMEOUT, DM_EVENT_CMD_HELLO, DM_EVENT_CMD_DIE, DM_EVENT_CMD_GET_STATUS, }; /* Message passed between client and daemon. */ struct dm_event_daemon_message { uint32_t cmd; uint32_t size; char *data; }; /* FIXME Is this meant to be exported? I can't see where the interface uses it. */ /* Fifos for client/daemon communication. */ struct dm_event_fifos { int client; int server; const char *client_path; const char *server_path; }; /* EXIT_SUCCESS 0 -- stdlib.h */ /* EXIT_FAILURE 1 -- stdlib.h */ /* EXIT_LOCKFILE_INUSE 2 -- obsoleted */ #define EXIT_DESC_CLOSE_FAILURE 3 #define EXIT_DESC_OPEN_FAILURE 4 /* EXIT_OPEN_PID_FAILURE 5 -- obsoleted */ #define EXIT_FIFO_FAILURE 6 #define EXIT_CHDIR_FAILURE 7 /* Implemented in libdevmapper-event.c, but not part of public API. */ // FIXME misuse of bitmask as enum int daemon_talk(struct dm_event_fifos *fifos, struct dm_event_daemon_message *msg, int cmd, const char *dso_name, const char *dev_name, enum dm_event_mask evmask, uint32_t timeout); int init_fifos(struct dm_event_fifos *fifos); void fini_fifos(struct dm_event_fifos *fifos); int dm_event_get_version(struct dm_event_fifos *fifos, int *version); #endif /* __DMEVENTD_DOT_H__ */ lvm2-2.02.98/daemons/dmeventd/libdevmapper-event.h0000640000175000017500000001035212037016272020707 0ustar blankblank/* * 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 /* * Event library interface. */ enum dm_event_mask { DM_EVENT_SETTINGS_MASK = 0x0000FF, DM_EVENT_SINGLE = 0x000001, /* Report multiple errors just once. */ DM_EVENT_MULTI = 0x000002, /* Report all of them. */ DM_EVENT_ERROR_MASK = 0x00FF00, DM_EVENT_SECTOR_ERROR = 0x000100, /* Failure on a particular sector. */ DM_EVENT_DEVICE_ERROR = 0x000200, /* Device failure. */ DM_EVENT_PATH_ERROR = 0x000400, /* Failure on an io path. */ DM_EVENT_ADAPTOR_ERROR = 0x000800, /* Failure of a host adaptor. */ DM_EVENT_STATUS_MASK = 0xFF0000, DM_EVENT_SYNC_STATUS = 0x010000, /* Mirror synchronization completed/failed. */ DM_EVENT_TIMEOUT = 0x020000, /* Timeout has occured */ DM_EVENT_REGISTRATION_PENDING = 0x1000000, /* Monitor thread is setting-up/shutting-down */ }; #define DM_EVENT_ALL_ERRORS DM_EVENT_ERROR_MASK #define DM_EVENT_PROTOCOL_VERSION 1 struct dm_event_handler; struct dm_event_handler *dm_event_handler_create(void); void dm_event_handler_destroy(struct dm_event_handler *dmevh); /* * Path of shared library to handle events. * * All of dmeventd, dso, device_name and uuid strings are duplicated so * you do not need to keep the pointers valid after the call succeeds. * They may return -ENOMEM though. */ int dm_event_handler_set_dso(struct dm_event_handler *dmevh, const char *path); /* * Path of dmeventd binary. */ int dm_event_handler_set_dmeventd_path(struct dm_event_handler *dmevh, const char *dmeventd_path); /* * Identify the device to monitor by exactly one of device_name, uuid or * device number. String arguments are duplicated, see above. */ int dm_event_handler_set_dev_name(struct dm_event_handler *dmevh, const char *device_name); int dm_event_handler_set_uuid(struct dm_event_handler *dmevh, const char *uuid); void dm_event_handler_set_major(struct dm_event_handler *dmevh, int major); void dm_event_handler_set_minor(struct dm_event_handler *dmevh, int minor); void dm_event_handler_set_timeout(struct dm_event_handler *dmevh, int timeout); /* * Specify mask for events to monitor. */ // FIXME misuse of bitmask as enum void dm_event_handler_set_event_mask(struct dm_event_handler *dmevh, enum dm_event_mask evmask); const char *dm_event_handler_get_dso(const struct dm_event_handler *dmevh); const char *dm_event_handler_get_dev_name(const struct dm_event_handler *dmevh); const char *dm_event_handler_get_uuid(const struct dm_event_handler *dmevh); int dm_event_handler_get_major(const struct dm_event_handler *dmevh); int dm_event_handler_get_minor(const struct dm_event_handler *dmevh); int dm_event_handler_get_timeout(const struct dm_event_handler *dmevh); // FIXME misuse of bitmask as enum enum dm_event_mask dm_event_handler_get_event_mask(const struct dm_event_handler *dmevh); /* FIXME Review interface (what about this next thing?) */ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next); /* * Initiate monitoring using dmeventd. */ int dm_event_register_handler(const struct dm_event_handler *dmevh); int dm_event_unregister_handler(const struct dm_event_handler *dmevh); /* Prototypes for DSO interface, see dmeventd.c, struct dso_data for detailed descriptions. */ // FIXME misuse of bitmask as enum void process_event(struct dm_task *dmt, enum dm_event_mask evmask, void **user); int register_device(const char *device_name, const char *uuid, int major, int minor, void **user); int unregister_device(const char *device_name, const char *uuid, int major, int minor, void **user); #endif lvm2-2.02.98/daemons/dmeventd/Makefile.in0000640000175000017500000000622512037016272017016 0ustar blankblank# # Copyright (C) 2005-2011 Red Hat, Inc. All rights reserved. # # This file is part of the device-mapper userspace tools. # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions # of the GNU Lesser General Public License v.2.1. # # You should have received a copy of the GNU Lesser General Public License # along with this program; if not, write to the Free Software Foundation, # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA srcdir = @srcdir@ top_srcdir = @top_srcdir@ top_builddir = @top_builddir@ SOURCES = libdevmapper-event.c SOURCES2 = dmeventd.c TARGETS = dmeventd .PHONY: install_lib_dynamic install_lib_static install_include \ install_pkgconfig install_dmeventd_dynamic install_dmeventd_static \ install_lib install_dmeventd INSTALL_DMEVENTD_TARGETS = install_dmeventd_dynamic INSTALL_LIB_TARGETS = install_lib_dynamic LIB_NAME = libdevmapper-event ifeq ("@STATIC_LINK@", "yes") LIB_STATIC = $(LIB_NAME).a TARGETS += $(LIB_STATIC) dmeventd.static INSTALL_DMEVENTD_TARGETS += install_dmeventd_static INSTALL_LIB_TARGETS += install_lib_static endif LIB_VERSION = $(LIB_VERSION_DM) LIB_SHARED = $(LIB_NAME).$(LIB_SUFFIX) CLEAN_TARGETS = dmeventd.static $(LIB_NAME).a ifneq ($(MAKECMDGOALS),device-mapper) SUBDIRS+=plugins endif CFLOW_LIST = $(SOURCES) CFLOW_LIST_TARGET = $(LIB_NAME).cflow CFLOW_TARGET = dmeventd EXPORTED_HEADER = $(srcdir)/libdevmapper-event.h EXPORTED_FN_PREFIX = dm_event include $(top_builddir)/make.tmpl all: device-mapper device-mapper: $(TARGETS) LIBS += -ldevmapper LVMLIBS += -ldevmapper-event $(PTHREAD_LIBS) dmeventd: $(LIB_SHARED) dmeventd.o $(CC) $(CFLAGS) $(LDFLAGS) $(ELDFLAGS) -L. -o $@ dmeventd.o \ $(DL_LIBS) $(LVMLIBS) $(LIBS) -rdynamic dmeventd.static: $(LIB_STATIC) dmeventd.o $(interfacebuilddir)/libdevmapper.a $(CC) $(CFLAGS) $(LDFLAGS) $(ELDFLAGS) -static -L. -L$(interfacebuilddir) -o $@ \ dmeventd.o $(DL_LIBS) $(LVMLIBS) $(LIBS) $(STATIC_LIBS) ifeq ("@PKGCONFIG@", "yes") INSTALL_LIB_TARGETS += install_pkgconfig endif ifneq ("$(CFLOW_CMD)", "") CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES)) -include $(top_builddir)/libdm/libdevmapper.cflow -include $(top_builddir)/lib/liblvm-internal.cflow -include $(top_builddir)/lib/liblvm2cmd.cflow -include $(top_builddir)/daemons/dmeventd/$(LIB_NAME).cflow -include $(top_builddir)/daemons/dmeventd/plugins/mirror/$(LIB_NAME)-lvm2mirror.cflow endif install_include: $(srcdir)/libdevmapper-event.h $(INSTALL_DATA) -D $< $(includedir)/$( #include #include #include #include #include #include #include #include #include #include #include /* 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_zalloc(sizeof(*dmevh)))) { log_error("Failed to allocate event handler."); return NULL; } return dmevh; } void dm_event_handler_destroy(struct dm_event_handler *dmevh) { _dm_event_handler_clear_dev_info(dmevh); dm_free(dmevh->dso); dm_free(dmevh->dmeventd_path); dm_free(dmevh); } int dm_event_handler_set_dmeventd_path(struct dm_event_handler *dmevh, const char *dmeventd_path) { if (!dmeventd_path) /* noop */ return 0; dm_free(dmevh->dmeventd_path); 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 == 0) && (i > 4) && !bytes) { log_error("No input from event server."); return 0; } } if (ret < 1) { log_error("Unable to read from event server."); return 0; } ret = read(fifos->server, buf + bytes, size); if (ret < 0) { if ((errno == EINTR) || (errno == EAGAIN)) continue; else { log_error("Unable to read from event server."); return 0; } } bytes += ret; if (header && (bytes == 2 * sizeof(uint32_t))) { msg->cmd = ntohl(header[0]); msg->size = ntohl(header[1]); buf = msg->data = dm_malloc(msg->size); size = msg->size; bytes = 0; header = 0; } } if (bytes != size) { dm_free(msg->data); msg->data = NULL; } return bytes == size; } /* Write message to daemon. */ static int _daemon_write(struct dm_event_fifos *fifos, struct dm_event_daemon_message *msg) { 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; ret = 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 */ if (close(fifos->client)) log_sys_error("close", fifos->client_path); return 1; } else if (errno != ENXIO) { /* problem */ log_sys_error("open", fifos->client_path); return 0; } start_server: /* server is not running */ if ((args[0][0] == '/') && stat(args[0], &statbuf)) { log_sys_error("stat", args[0]); return 0; } pid = fork(); if (pid < 0) log_sys_error("fork", ""); else if (!pid) { execvp(args[0], args); log_error("Unable to exec dmeventd: %s", strerror(errno)); _exit(EXIT_FAILURE); } else { if (waitpid(pid, &status, 0) < 0) log_error("Unable to start dmeventd: %s", strerror(errno)); else if (WEXITSTATUS(status)) log_error("Unable to start dmeventd."); else ret = 1; } return ret; } int init_fifos(struct dm_event_fifos *fifos) { /* FIXME? Is fifo the most suitable method? Why not share comms/daemon code with something else e.g. multipath? */ /* 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_sys_error("open", fifos->server_path); return 0; } /* Lock out anyone else trying to do communication with the daemon. */ if (flock(fifos->server, LOCK_EX) < 0) { log_sys_error("flock", fifos->server_path); if (close(fifos->server)) log_sys_error("close", fifos->server_path); 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_sys_error("open", fifos->client_path); if (close(fifos->server)) log_sys_error("close", fifos->server_path); 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); if (close(fifos->client)) log_sys_error("close", fifos->client_path); if (close(fifos->server)) log_sys_error("close", fifos->server_path); } /* Get uuid of a device */ static struct dm_task *_get_device_info(const struct dm_event_handler *dmevh) { struct dm_task *dmt; struct dm_info info; if (!(dmt = dm_task_create(DM_DEVICE_INFO))) { log_error("_get_device_info: dm_task creation for info failed"); return NULL; } if (dmevh->uuid) { if (!dm_task_set_uuid(dmt, dmevh->uuid)) goto_bad; } else if (dmevh->dev_name) { if (!dm_task_set_name(dmt, dmevh->dev_name)) goto_bad; } else if (dmevh->major && dmevh->minor) { if (!dm_task_set_major(dmt, dmevh->major) || !dm_task_set_minor(dmt, dmevh->minor)) goto_bad; } /* FIXME Add name or uuid or devno to messages */ if (!dm_task_run(dmt)) { log_error("_get_device_info: dm_task_run() failed"); goto bad; } if (!dm_task_get_info(dmt, &info)) { log_error("_get_device_info: failed to get info for device"); goto bad; } if (!info.exists) { log_error("_get_device_info: %s%s%s%.0d%s%.0d%s%s: device not found", dmevh->uuid ? : "", (!dmevh->uuid && dmevh->dev_name) ? dmevh->dev_name : "", (!dmevh->uuid && !dmevh->dev_name && dmevh->major > 0) ? "(" : "", (!dmevh->uuid && !dmevh->dev_name && dmevh->major > 0) ? dmevh->major : 0, (!dmevh->uuid && !dmevh->dev_name && dmevh->major > 0) ? ":" : "", (!dmevh->uuid && !dmevh->dev_name && dmevh->minor > 0) ? dmevh->minor : 0, (!dmevh->uuid && !dmevh->dev_name && dmevh->major > 0) && dmevh->minor == 0 ? "0" : "", (!dmevh->uuid && !dmevh->dev_name && dmevh->major > 0) ? ") " : ""); goto bad; } return dmt; bad: dm_task_destroy(dmt); return NULL; } /* Handle the event (de)registration call and return negative error codes. */ static int _do_event(int cmd, char *dmeventd_path, struct dm_event_daemon_message *msg, const char *dso_name, const char *dev_name, enum dm_event_mask evmask, uint32_t timeout) { int ret; struct dm_event_fifos fifos; 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)) { log_debug("%s: device not registered.", dm_task_get_name(dmt)); ret = -ENOENT; goto fail; } /* FIXME this will probably horribly break if we get ill-formatted reply */ ret = _parse_message(&msg, &reply_dso, &reply_uuid, &reply_mask); dm_task_destroy(dmt); dmt = NULL; dm_free(msg.data); msg.data = NULL; _dm_event_handler_clear_dev_info(dmevh); if (!reply_uuid) { ret = -ENXIO; /* dmeventd probably gave us bogus uuid back */ goto fail; } 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; } /* * You can (and have to) call this at the stage of the protocol where * daemon_talk(fifos, &msg, DM_EVENT_CMD_HELLO, NULL, NULL, 0, 0) * * would be normally sent. This call will parse the version reply from * dmeventd, in addition to above call. It is not safe to call this at any * other place in the protocol. * * This is an internal function, not exposed in the public API. */ int dm_event_get_version(struct dm_event_fifos *fifos, int *version) { char *p; struct dm_event_daemon_message msg = { 0, 0, NULL }; if (daemon_talk(fifos, &msg, DM_EVENT_CMD_HELLO, NULL, NULL, 0, 0)) return 0; p = msg.data; *version = 0; p = strchr(p, ' '); /* Message ID */ if (!p) return 0; p = strchr(p + 1, ' '); /* HELLO */ if (!p) return 0; p = strchr(p + 1, ' '); /* HELLO, once more */ if (p) *version = atoi(p); return 1; } #if 0 /* left out for now */ static char *_skip_string(char *src, const int delimiter) { src = srtchr(src, delimiter); if (src && *(src + 1)) return src + 1; return NULL; } int dm_event_set_timeout(const char *device_path, uint32_t timeout) { struct dm_event_daemon_message msg = { 0, 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 lvm2-2.02.98/daemons/dmeventd/libdevmapper-event.pc.in0000640000175000017500000000040712037016272021467 0ustar blankblankprefix=@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 lvm2-2.02.98/daemons/dmeventd/dmeventd.c0000640000175000017500000013673312037016272016733 0ustar blankblank/* * 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 */ /* * dmeventd - dm event daemon to monitor active mapped devices */ #define _GNU_SOURCE #define _FILE_OFFSET_BITS 64 #include "configure.h" #include "libdevmapper.h" #include "libdevmapper-event.h" #include "dmeventd.h" //#include "libmultilog.h" #include "dm-logging.h" #include #include #include #include #include #include #include #include #include #include #include /* for htonl, ntohl */ #ifdef linux /* * Kernel version 2.6.36 and higher has * new OOM killer adjustment interface. */ # define OOM_ADJ_FILE_OLD "/proc/self/oom_adj" # define OOM_ADJ_FILE "/proc/self/oom_score_adj" /* From linux/oom.h */ /* Old interface */ # define OOM_DISABLE (-17) # define OOM_ADJUST_MIN (-16) /* New interface */ # define OOM_SCORE_ADJ_MIN (-1000) /* Systemd on-demand activation support */ # define SD_ACTIVATION_ENV_VAR_NAME "SD_ACTIVATION" # define SD_LISTEN_PID_ENV_VAR_NAME "LISTEN_PID" # define SD_LISTEN_FDS_ENV_VAR_NAME "LISTEN_FDS" # define SD_LISTEN_FDS_START 3 # define SD_FD_FIFO_SERVER SD_LISTEN_FDS_START # define SD_FD_FIFO_CLIENT (SD_LISTEN_FDS_START + 1) #endif /* FIXME We use syslog for now, because multilog is not yet implemented */ #include static volatile sig_atomic_t _exit_now = 0; /* set to '1' when signal is given to exit */ static volatile sig_atomic_t _thread_registries_empty = 1; /* registries are empty initially */ /* List (un)link macros. */ #define LINK(x, head) dm_list_add(head, &(x)->list) #define LINK_DSO(dso) LINK(dso, &_dso_registry) #define LINK_THREAD(thread) LINK(thread, &_thread_registry) #define UNLINK(x) dm_list_del(&(x)->list) #define UNLINK_DSO(x) UNLINK(x) #define UNLINK_THREAD(x) UNLINK(x) #define DAEMON_NAME "dmeventd" /* Global mutex for thread list access. Has to be held when: - iterating thread list - adding or removing elements from thread list - changing or reading thread_status's fields: processing, status, events Use _lock_mutex() and _unlock_mutex() to hold/release it */ static pthread_mutex_t _global_mutex; /* There are three states a thread can attain (see struct thread_status, field int status): - DM_THREAD_RUNNING: thread has started up and is either working or waiting for events... transitions to either SHUTDOWN or DONE - DM_THREAD_SHUTDOWN: thread is still doing something, but it is supposed to terminate (and transition to DONE) as soon as it finishes whatever it was doing at the point of flipping state to SHUTDOWN... the thread is still on the thread list - DM_THREAD_DONE: thread has terminated and has been moved over to unused thread list, cleanup pending */ #define DM_THREAD_RUNNING 0 #define DM_THREAD_SHUTDOWN 1 #define DM_THREAD_DONE 2 #define THREAD_STACK_SIZE (300*1024) int dmeventd_debug = 0; static int _systemd_activation = 0; static int _foreground = 0; static int _restart = 0; static char **_initial_registrations = 0; /* Data kept about a DSO. */ struct dso_data { struct dm_list list; char *dso_name; /* DSO name (eg, "evms", "dmraid", "lvm2"). */ void *dso_handle; /* Opaque handle as returned from dlopen(). */ unsigned int ref_count; /* Library reference count. */ /* * Event processing. * * The DSO can do whatever appropriate steps if an event * happens such as changing the mapping in case a mirror * fails, update the application metadata etc. * * This function gets a dm_task that is a result of * DM_DEVICE_WAITEVENT ioctl (results equivalent to * DM_DEVICE_STATUS). It should not destroy it. * The caller must dispose of the task. */ void (*process_event)(struct dm_task *dmt, enum dm_event_mask event, void **user); /* * Device registration. * * When an application registers a device for an event, the DSO * can carry out appropriate steps so that a later call to * the process_event() function is sane (eg, read metadata * and activate a mapping). */ int (*register_device)(const char *device, const char *uuid, int major, int minor, void **user); /* * Device unregistration. * * In case all devices of a mapping (eg, RAID10) are unregistered * for events, the DSO can recognize this and carry out appropriate * steps (eg, deactivate mapping, metadata update). */ int (*unregister_device)(const char *device, const char *uuid, int major, int minor, void **user); }; static DM_LIST_INIT(_dso_registry); /* Structure to keep parsed register variables from client message. */ struct message_data { char *id; char *dso_name; /* Name of DSO. */ char *device_uuid; /* Mapped device path. */ union { char *str; /* Events string as fetched from message. */ enum dm_event_mask field; /* Events bitfield. */ } events; union { char *str; uint32_t secs; } timeout; struct dm_event_daemon_message *msg; /* Pointer to message buffer. */ }; /* * Housekeeping of thread+device states. * * One thread per mapped device which can block on it until an event * occurs and the event processing function of the DSO gets called. */ struct thread_status { struct dm_list list; pthread_t thread; struct dso_data *dso_data; /* DSO this thread accesses. */ struct { char *uuid; char *name; int major, minor; } device; uint32_t event_nr; /* event number */ int processing; /* Set when event is being processed */ int status; /* see DM_THREAD_{RUNNING,SHUTDOWN,DONE} constants above */ enum dm_event_mask events; /* bitfield for event filter. */ enum dm_event_mask current_events; /* bitfield for occured events. */ struct dm_task *current_task; time_t next_time; uint32_t timeout; struct dm_list timeout_list; void *dso_private; /* dso per-thread status variable */ }; static DM_LIST_INIT(_thread_registry); static DM_LIST_INIT(_thread_registry_unused); static int _timeout_running; static DM_LIST_INIT(_timeout_registry); static pthread_mutex_t _timeout_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t _timeout_cond = PTHREAD_COND_INITIALIZER; /* Allocate/free the status structure for a monitoring thread. */ static struct thread_status *_alloc_thread_status(struct message_data *data, struct dso_data *dso_data) { struct thread_status *ret = (typeof(ret)) dm_zalloc(sizeof(*ret)); if (!ret) return NULL; if (!(ret->device.uuid = dm_strdup(data->device_uuid))) { dm_free(ret); return NULL; } ret->current_task = NULL; ret->device.name = NULL; ret->device.major = ret->device.minor = 0; ret->dso_data = dso_data; ret->events = data->events.field; ret->timeout = data->timeout.secs; dm_list_init(&ret->timeout_list); return ret; } static void _lib_put(struct dso_data *data); static void _free_thread_status(struct thread_status *thread) { _lib_put(thread->dso_data); if (thread->current_task) dm_task_destroy(thread->current_task); dm_free(thread->device.uuid); dm_free(thread->device.name); dm_free(thread); } /* Allocate/free DSO data. */ static struct dso_data *_alloc_dso_data(struct message_data *data) { struct dso_data *ret = (typeof(ret)) dm_zalloc(sizeof(*ret)); if (!ret) return NULL; if (!(ret->dso_name = dm_strdup(data->dso_name))) { dm_free(ret); return NULL; } return ret; } /* Create a device monitoring thread. */ static int _pthread_create_smallstack(pthread_t *t, void *(*fun)(void *), void *arg) { pthread_attr_t attr; pthread_attr_init(&attr); /* * We use a smaller stack since it gets preallocated in its entirety */ pthread_attr_setstacksize(&attr, THREAD_STACK_SIZE); return pthread_create(t, &attr, fun, arg); } static void _free_dso_data(struct dso_data *data) { dm_free(data->dso_name); dm_free(data); } /* * Fetch a string off src and duplicate it into *ptr. * Pay attention to zero-length strings. */ /* FIXME? move to libdevmapper to share with the client lib (need to make delimiter a parameter then) */ static int _fetch_string(char **ptr, char **src, const int delimiter) { int ret = 0; char *p; size_t len; if ((p = strchr(*src, delimiter))) *p = 0; if ((*ptr = dm_strdup(*src))) { if ((len = strlen(*ptr))) *src += len; else { dm_free(*ptr); *ptr = NULL; } (*src)++; ret = 1; } if (p) *p = delimiter; return ret; } /* Free message memory. */ static void _free_message(struct message_data *message_data) { dm_free(message_data->id); dm_free(message_data->dso_name); dm_free(message_data->device_uuid); } /* Parse a register message from the client. */ static int _parse_message(struct message_data *message_data) { int ret = 0; char *p = message_data->msg->data; struct dm_event_daemon_message *msg = message_data->msg; if (!msg->data) return 0; /* * Retrieve application identifier, mapped device * path and events # string from message. */ if (_fetch_string(&message_data->id, &p, ' ') && _fetch_string(&message_data->dso_name, &p, ' ') && _fetch_string(&message_data->device_uuid, &p, ' ') && _fetch_string(&message_data->events.str, &p, ' ') && _fetch_string(&message_data->timeout.str, &p, ' ')) { if (message_data->events.str) { enum dm_event_mask i = atoi(message_data->events.str); /* * Free string representaion of events. * Not needed an more. */ dm_free(message_data->events.str); message_data->events.field = i; } if (message_data->timeout.str) { uint32_t secs = atoi(message_data->timeout.str); dm_free(message_data->timeout.str); message_data->timeout.secs = secs ? secs : DM_EVENT_DEFAULT_TIMEOUT; } ret = 1; } dm_free(msg->data); msg->data = NULL; msg->size = 0; return ret; }; /* Global mutex to lock access to lists et al. See _global_mutex above. */ static int _lock_mutex(void) { return pthread_mutex_lock(&_global_mutex); } static int _unlock_mutex(void) { return pthread_mutex_unlock(&_global_mutex); } /* Check, if a device exists. */ static int _fill_device_data(struct thread_status *ts) { struct dm_task *dmt; struct dm_info dmi; if (!ts->device.uuid) return 0; ts->device.name = NULL; ts->device.major = ts->device.minor = 0; dmt = dm_task_create(DM_DEVICE_INFO); if (!dmt) return 0; if (!dm_task_set_uuid(dmt, ts->device.uuid)) goto fail; if (!dm_task_run(dmt)) goto fail; ts->device.name = dm_strdup(dm_task_get_name(dmt)); if (!ts->device.name) goto fail; if (!dm_task_get_info(dmt, &dmi)) goto fail; ts->device.major = dmi.major; ts->device.minor = dmi.minor; dm_task_destroy(dmt); return 1; fail: dm_task_destroy(dmt); dm_free(ts->device.name); return 0; } /* * Find an existing thread for a device. * * Mutex must be held when calling this. */ static struct thread_status *_lookup_thread_status(struct message_data *data) { struct thread_status *thread; dm_list_iterate_items(thread, &_thread_registry) if (!strcmp(data->device_uuid, thread->device.uuid)) return thread; return NULL; } static int _get_status(struct message_data *message_data) { struct dm_event_daemon_message *msg = message_data->msg; struct thread_status *thread; int i, j; int ret = -1; int count = dm_list_size(&_thread_registry); int size = 0, current = 0; char *buffers[count]; char *message; dm_free(msg->data); for (i = 0; i < count; ++i) buffers[i] = NULL; i = 0; _lock_mutex(); dm_list_iterate_items(thread, &_thread_registry) { if ((current = dm_asprintf(buffers + i, "0:%d %s %s %u %" PRIu32 ";", i, thread->dso_data->dso_name, thread->device.uuid, thread->events, thread->timeout)) < 0) { _unlock_mutex(); goto out; } ++ i; size += current; } _unlock_mutex(); msg->size = size + strlen(message_data->id) + 1; msg->data = dm_malloc(msg->size); if (!msg->data) goto out; *msg->data = 0; message = msg->data; strcpy(message, message_data->id); message += strlen(message_data->id); *message = ' '; message ++; for (j = 0; j < i; ++j) { strcpy(message, buffers[j]); message += strlen(buffers[j]); } ret = 0; out: for (j = 0; j < i; ++j) dm_free(buffers[j]); return ret; } /* Cleanup at exit. */ static void _exit_dm_lib(void) { dm_lib_release(); dm_lib_exit(); } static void _exit_timeout(void *unused __attribute__((unused))) { _timeout_running = 0; pthread_mutex_unlock(&_timeout_mutex); } /* Wake up monitor threads every so often. */ static void *_timeout_thread(void *unused __attribute__((unused))) { struct timespec timeout; time_t curr_time; timeout.tv_nsec = 0; pthread_cleanup_push(_exit_timeout, NULL); pthread_mutex_lock(&_timeout_mutex); while (!dm_list_empty(&_timeout_registry)) { struct thread_status *thread; timeout.tv_sec = 0; curr_time = time(NULL); dm_list_iterate_items_gen(thread, &_timeout_registry, timeout_list) { if (thread->next_time <= curr_time) { thread->next_time = curr_time + thread->timeout; pthread_kill(thread->thread, SIGALRM); } if (thread->next_time < timeout.tv_sec || !timeout.tv_sec) timeout.tv_sec = thread->next_time; } pthread_cond_timedwait(&_timeout_cond, &_timeout_mutex, &timeout); } pthread_cleanup_pop(1); return NULL; } static int _register_for_timeout(struct thread_status *thread) { int ret = 0; pthread_mutex_lock(&_timeout_mutex); thread->next_time = time(NULL) + thread->timeout; if (dm_list_empty(&thread->timeout_list)) { dm_list_add(&_timeout_registry, &thread->timeout_list); if (_timeout_running) pthread_cond_signal(&_timeout_cond); } if (!_timeout_running) { pthread_t timeout_id; if (!(ret = -_pthread_create_smallstack(&timeout_id, _timeout_thread, NULL))) _timeout_running = 1; } pthread_mutex_unlock(&_timeout_mutex); return ret; } static void _unregister_for_timeout(struct thread_status *thread) { pthread_mutex_lock(&_timeout_mutex); if (!dm_list_empty(&thread->timeout_list)) { dm_list_del(&thread->timeout_list); dm_list_init(&thread->timeout_list); } pthread_mutex_unlock(&_timeout_mutex); } __attribute__((format(printf, 4, 5))) static void _no_intr_log(int level, const char *file, int line, const char *f, ...) { va_list ap; if (errno == EINTR) return; if (level > _LOG_WARN) return; va_start(ap, f); if (level < _LOG_WARN) vfprintf(stderr, f, ap); else vprintf(f, ap); va_end(ap); if (level < _LOG_WARN) fprintf(stderr, "\n"); else fprintf(stdout, "\n"); } static sigset_t _unblock_sigalrm(void) { sigset_t set, old; sigemptyset(&set); sigaddset(&set, SIGALRM); pthread_sigmask(SIG_UNBLOCK, &set, &old); return old; } #define DM_WAIT_RETRY 0 #define DM_WAIT_INTR 1 #define DM_WAIT_FATAL 2 /* Wait on a device until an event occurs. */ static int _event_wait(struct thread_status *thread, struct dm_task **task) { sigset_t set; int ret = DM_WAIT_RETRY; struct dm_task *dmt; struct dm_info info; *task = 0; if (!(dmt = dm_task_create(DM_DEVICE_WAITEVENT))) return DM_WAIT_RETRY; thread->current_task = dmt; if (!dm_task_set_uuid(dmt, thread->device.uuid) || !dm_task_set_event_nr(dmt, thread->event_nr)) goto out; /* * This is so that you can break out of waiting on an event, * either for a timeout event, or to cancel the thread. */ set = _unblock_sigalrm(); dm_log_init(_no_intr_log); errno = 0; if (dm_task_run(dmt)) { thread->current_events |= DM_EVENT_DEVICE_ERROR; ret = DM_WAIT_INTR; if ((ret = dm_task_get_info(dmt, &info))) thread->event_nr = info.event_nr; } else if (thread->events & DM_EVENT_TIMEOUT && errno == EINTR) { thread->current_events |= DM_EVENT_TIMEOUT; ret = DM_WAIT_INTR; } else if (thread->status == DM_THREAD_SHUTDOWN && errno == EINTR) { ret = DM_WAIT_FATAL; } else { syslog(LOG_NOTICE, "dm_task_run failed, errno = %d, %s", errno, strerror(errno)); if (errno == ENXIO) { syslog(LOG_ERR, "%s disappeared, detaching", thread->device.name); ret = DM_WAIT_FATAL; } } pthread_sigmask(SIG_SETMASK, &set, NULL); dm_log_init(NULL); out: if (ret == DM_WAIT_FATAL || ret == DM_WAIT_RETRY) { dm_task_destroy(dmt); thread->current_task = NULL; } else *task = dmt; return ret; } /* Register a device with the DSO. */ static int _do_register_device(struct thread_status *thread) { return thread->dso_data->register_device(thread->device.name, thread->device.uuid, thread->device.major, thread->device.minor, &(thread->dso_private)); } /* Unregister a device with the DSO. */ static int _do_unregister_device(struct thread_status *thread) { return thread->dso_data->unregister_device(thread->device.name, thread->device.uuid, thread->device.major, thread->device.minor, &(thread->dso_private)); } /* Process an event in the DSO. */ static void _do_process_event(struct thread_status *thread, struct dm_task *task) { thread->dso_data->process_event(task, thread->current_events, &(thread->dso_private)); } /* Thread cleanup handler to unregister device. */ static void _monitor_unregister(void *arg) { struct thread_status *thread = arg, *thread_iter; if (!_do_unregister_device(thread)) syslog(LOG_ERR, "%s: %s unregister failed\n", __func__, thread->device.name); if (thread->current_task) dm_task_destroy(thread->current_task); thread->current_task = NULL; _lock_mutex(); if (thread->events & DM_EVENT_TIMEOUT) { /* _unregister_for_timeout locks another mutex, we don't want to deadlock so we release our mutex for a bit */ _unlock_mutex(); _unregister_for_timeout(thread); _lock_mutex(); } /* we may have been relinked to unused registry since we were called, so check that */ dm_list_iterate_items(thread_iter, &_thread_registry_unused) if (thread_iter == thread) { thread->status = DM_THREAD_DONE; _unlock_mutex(); return; } thread->status = DM_THREAD_DONE; pthread_mutex_lock(&_timeout_mutex); UNLINK_THREAD(thread); LINK(thread, &_thread_registry_unused); pthread_mutex_unlock(&_timeout_mutex); _unlock_mutex(); } static struct dm_task *_get_device_status(struct thread_status *ts) { struct dm_task *dmt = dm_task_create(DM_DEVICE_STATUS); if (!dmt) return NULL; if (!dm_task_set_uuid(dmt, ts->device.uuid)) { dm_task_destroy(dmt); return NULL; } if (!dm_task_run(dmt)) { dm_task_destroy(dmt); return NULL; } return dmt; } /* Device monitoring thread. */ static void *_monitor_thread(void *arg) { struct thread_status *thread = arg; int wait_error = 0; struct dm_task *task; pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL); pthread_cleanup_push(_monitor_unregister, thread); /* Wait for do_process_request() to finish its task. */ _lock_mutex(); thread->status = DM_THREAD_RUNNING; _unlock_mutex(); /* Loop forever awaiting/analyzing device events. */ while (1) { thread->current_events = 0; wait_error = _event_wait(thread, &task); if (wait_error == DM_WAIT_RETRY) continue; if (wait_error == DM_WAIT_FATAL) break; /* Timeout occurred, task is not filled properly. * We get device status here for processing it in DSO. */ if (wait_error == DM_WAIT_INTR && thread->current_events & DM_EVENT_TIMEOUT) { dm_task_destroy(task); task = _get_device_status(thread); /* FIXME: syslog fail here ? */ if (!(thread->current_task = task)) continue; } /* * We know that wait succeeded and stored a * pointer to dm_task with device status into task. */ /* * Check against filter. * * If there's current events delivered from _event_wait() AND * the device got registered for those events AND * those events haven't been processed yet, call * the DSO's process_event() handler. */ _lock_mutex(); if (thread->status == DM_THREAD_SHUTDOWN) { _unlock_mutex(); break; } _unlock_mutex(); if (thread->events & thread->current_events) { _lock_mutex(); thread->processing = 1; _unlock_mutex(); _do_process_event(thread, task); dm_task_destroy(task); thread->current_task = NULL; _lock_mutex(); thread->processing = 0; _unlock_mutex(); } else { dm_task_destroy(task); thread->current_task = NULL; } } pthread_cleanup_pop(1); return NULL; } /* Create a device monitoring thread. */ static int _create_thread(struct thread_status *thread) { return _pthread_create_smallstack(&thread->thread, _monitor_thread, thread); } static int _terminate_thread(struct thread_status *thread) { return pthread_kill(thread->thread, SIGALRM); } /* DSO reference counting. Call with _global_mutex locked! */ static void _lib_get(struct dso_data *data) { data->ref_count++; } static void _lib_put(struct dso_data *data) { if (!--data->ref_count) { dlclose(data->dso_handle); UNLINK_DSO(data); _free_dso_data(data); } } /* Find DSO data. */ static struct dso_data *_lookup_dso(struct message_data *data) { struct dso_data *dso_data, *ret = NULL; dm_list_iterate_items(dso_data, &_dso_registry) if (!strcmp(data->dso_name, dso_data->dso_name)) { _lib_get(dso_data); ret = dso_data; break; } return ret; } /* Lookup DSO symbols we need. */ static int _lookup_symbol(void *dl, void **symbol, const char *name) { if ((*symbol = dlsym(dl, name))) return 1; return 0; } static int lookup_symbols(void *dl, struct dso_data *data) { return _lookup_symbol(dl, (void *) &data->process_event, "process_event") && _lookup_symbol(dl, (void *) &data->register_device, "register_device") && _lookup_symbol(dl, (void *) &data->unregister_device, "unregister_device"); } /* Load an application specific DSO. */ static struct dso_data *_load_dso(struct message_data *data) { void *dl; struct dso_data *ret = NULL; if (!(dl = dlopen(data->dso_name, RTLD_NOW))) { const char *dlerr = dlerror(); syslog(LOG_ERR, "dmeventd %s dlopen failed: %s", data->dso_name, dlerr); data->msg->size = dm_asprintf(&(data->msg->data), "%s %s dlopen failed: %s", data->id, data->dso_name, dlerr); return NULL; } if (!(ret = _alloc_dso_data(data))) { dlclose(dl); return NULL; } if (!(lookup_symbols(dl, ret))) { _free_dso_data(ret); dlclose(dl); return NULL; } /* * Keep handle to close the library once * we've got no references to it any more. */ ret->dso_handle = dl; _lib_get(ret); _lock_mutex(); LINK_DSO(ret); _unlock_mutex(); return ret; } /* Return success on daemon active check. */ static int _active(struct message_data *message_data) { return 0; } /* * Register for an event. * * Only one caller at a time here, because we use * a FIFO and lock it against multiple accesses. */ static int _register_for_event(struct message_data *message_data) { int ret = 0; struct thread_status *thread, *thread_new = NULL; struct dso_data *dso_data; if (!(dso_data = _lookup_dso(message_data)) && !(dso_data = _load_dso(message_data))) { stack; #ifdef ELIBACC ret = -ELIBACC; #else ret = -ENODEV; #endif goto out; } /* Preallocate thread status struct to avoid deadlock. */ if (!(thread_new = _alloc_thread_status(message_data, dso_data))) { stack; ret = -ENOMEM; goto out; } if (!_fill_device_data(thread_new)) { stack; ret = -ENODEV; goto out; } _lock_mutex(); /* If creation of timeout thread fails (as it may), we fail here completely. The client is responsible for either retrying later or trying to register without timeout events. However, if timeout thread cannot be started, it usually means we are so starved on resources that we are almost as good as dead already... */ if (thread_new->events & DM_EVENT_TIMEOUT) { ret = -_register_for_timeout(thread_new); if (ret) goto outth; } if (!(thread = _lookup_thread_status(message_data))) { _unlock_mutex(); if (!(ret = _do_register_device(thread_new))) goto out; thread = thread_new; thread_new = NULL; /* Try to create the monitoring thread for this device. */ _lock_mutex(); if ((ret = -_create_thread(thread))) { _unlock_mutex(); _do_unregister_device(thread); _free_thread_status(thread); goto out; } else LINK_THREAD(thread); } /* Or event # into events bitfield. */ thread->events |= message_data->events.field; outth: _unlock_mutex(); out: /* * Deallocate thread status after releasing * the lock in case we haven't used it. */ if (thread_new) _free_thread_status(thread_new); return ret; } /* * Unregister for an event. * * Only one caller at a time here as with register_for_event(). */ static int _unregister_for_event(struct message_data *message_data) { int ret = 0; struct thread_status *thread; /* * Clear event in bitfield and deactivate * monitoring thread in case bitfield is 0. */ _lock_mutex(); if (!(thread = _lookup_thread_status(message_data))) { _unlock_mutex(); ret = -ENODEV; goto out; } if (thread->status == DM_THREAD_DONE) { /* the thread has terminated while we were not watching */ _unlock_mutex(); return 0; } thread->events &= ~message_data->events.field; if (!(thread->events & DM_EVENT_TIMEOUT)) _unregister_for_timeout(thread); /* * In case there's no events to monitor on this device -> * unlink and terminate its monitoring thread. */ if (!thread->events) { pthread_mutex_lock(&_timeout_mutex); UNLINK_THREAD(thread); LINK(thread, &_thread_registry_unused); pthread_mutex_unlock(&_timeout_mutex); } _unlock_mutex(); out: return ret; } /* * Get registered device. * * Only one caller at a time here as with register_for_event(). */ static int _registered_device(struct message_data *message_data, struct thread_status *thread) { struct dm_event_daemon_message *msg = message_data->msg; const char *fmt = "%s %s %s %u"; const char *id = message_data->id; const char *dso = thread->dso_data->dso_name; const char *dev = thread->device.uuid; int r; unsigned events = ((thread->status == DM_THREAD_RUNNING) && (thread->events)) ? thread->events : thread-> events | DM_EVENT_REGISTRATION_PENDING; dm_free(msg->data); if ((r = dm_asprintf(&(msg->data), fmt, id, dso, dev, events)) < 0) { msg->size = 0; return -ENOMEM; } msg->size = (uint32_t) r; return 0; } static int _want_registered_device(char *dso_name, char *device_uuid, struct thread_status *thread) { /* If DSO names and device paths are equal. */ if (dso_name && device_uuid) return !strcmp(dso_name, thread->dso_data->dso_name) && !strcmp(device_uuid, thread->device.uuid) && (thread->status == DM_THREAD_RUNNING || (thread->events & DM_EVENT_REGISTRATION_PENDING)); /* If DSO names are equal. */ if (dso_name) return !strcmp(dso_name, thread->dso_data->dso_name) && (thread->status == DM_THREAD_RUNNING || (thread->events & DM_EVENT_REGISTRATION_PENDING)); /* If device paths are equal. */ if (device_uuid) return !strcmp(device_uuid, thread->device.uuid) && (thread->status == DM_THREAD_RUNNING || (thread->events & DM_EVENT_REGISTRATION_PENDING)); return 1; } static int _get_registered_dev(struct message_data *message_data, int next) { struct thread_status *thread, *hit = NULL; int ret = -ENOENT; _lock_mutex(); /* Iterate list of threads checking if we want a particular one. */ dm_list_iterate_items(thread, &_thread_registry) if (_want_registered_device(message_data->dso_name, message_data->device_uuid, thread)) { hit = thread; break; } /* * If we got a registered device and want the next one -> * fetch next conforming element off the list. */ if (hit && !next) goto reg; if (!hit) goto out; while (1) { if (dm_list_end(&_thread_registry, &thread->list)) goto out; thread = dm_list_item(thread->list.n, struct thread_status); if (_want_registered_device(message_data->dso_name, NULL, thread)) { hit = thread; break; } } reg: ret = _registered_device(message_data, hit); out: _unlock_mutex(); return ret; } static int _get_registered_device(struct message_data *message_data) { return _get_registered_dev(message_data, 0); } static int _get_next_registered_device(struct message_data *message_data) { return _get_registered_dev(message_data, 1); } static int _set_timeout(struct message_data *message_data) { struct thread_status *thread; _lock_mutex(); if ((thread = _lookup_thread_status(message_data))) thread->timeout = message_data->timeout.secs; _unlock_mutex(); return thread ? 0 : -ENODEV; } static int _get_timeout(struct message_data *message_data) { struct thread_status *thread; struct dm_event_daemon_message *msg = message_data->msg; dm_free(msg->data); _lock_mutex(); if ((thread = _lookup_thread_status(message_data))) { msg->size = dm_asprintf(&(msg->data), "%s %" PRIu32, message_data->id, thread->timeout); } else { msg->data = NULL; msg->size = 0; } _unlock_mutex(); return thread ? 0 : -ENODEV; } /* Initialize a fifos structure with path names. */ static void _init_fifos(struct dm_event_fifos *fifos) { memset(fifos, 0, sizeof(*fifos)); fifos->client_path = DM_EVENT_FIFO_CLIENT; fifos->server_path = DM_EVENT_FIFO_SERVER; } /* Open fifos used for client communication. */ static int _open_fifos(struct dm_event_fifos *fifos) { struct stat st; /* Create client fifo. */ (void) dm_prepare_selinux_context(fifos->client_path, S_IFIFO); if ((mkfifo(fifos->client_path, 0600) == -1) && errno != EEXIST) { syslog(LOG_ERR, "%s: Failed to create client fifo %s: %m.\n", __func__, fifos->client_path); (void) dm_prepare_selinux_context(NULL, 0); return 0; } /* Create server fifo. */ (void) dm_prepare_selinux_context(fifos->server_path, S_IFIFO); if ((mkfifo(fifos->server_path, 0600) == -1) && errno != EEXIST) { syslog(LOG_ERR, "%s: Failed to create server fifo %s: %m.\n", __func__, fifos->server_path); (void) dm_prepare_selinux_context(NULL, 0); return 0; } (void) dm_prepare_selinux_context(NULL, 0); /* Warn about wrong permissions if applicable */ if ((!stat(fifos->client_path, &st)) && (st.st_mode & 0777) != 0600) syslog(LOG_WARNING, "Fixing wrong permissions on %s: %m.\n", fifos->client_path); if ((!stat(fifos->server_path, &st)) && (st.st_mode & 0777) != 0600) syslog(LOG_WARNING, "Fixing wrong permissions on %s: %m.\n", fifos->server_path); /* If they were already there, make sure permissions are ok. */ if (chmod(fifos->client_path, 0600)) { syslog(LOG_ERR, "Unable to set correct file permissions on %s: %m.\n", fifos->client_path); return 0; } if (chmod(fifos->server_path, 0600)) { syslog(LOG_ERR, "Unable to set correct file permissions on %s: %m.\n", fifos->server_path); return 0; } /* Need to open read+write or we will block or fail */ if ((fifos->server = open(fifos->server_path, O_RDWR)) < 0) { syslog(LOG_ERR, "Failed to open fifo server %s: %m.\n", fifos->server_path); return 0; } /* Need to open read+write for select() to work. */ if ((fifos->client = open(fifos->client_path, O_RDWR)) < 0) { syslog(LOG_ERR, "Failed to open fifo client %s: %m", fifos->client_path); if (close(fifos->server)) syslog(LOG_ERR, "Failed to close fifo server %s: %m", fifos->server_path); return 0; } return 1; } /* * Read message from client making sure that data is available * and a complete message is read. Must not block indefinitely. */ static int _client_read(struct dm_event_fifos *fifos, struct dm_event_daemon_message *msg) { struct timeval t; unsigned bytes = 0; int ret = 0; fd_set fds; size_t size = 2 * sizeof(uint32_t); /* status + size */ uint32_t *header = alloca(size); char *buf = (char *)header; msg->data = NULL; errno = 0; while (bytes < size && errno != EOF) { /* Watch client read FIFO for input. */ FD_ZERO(&fds); FD_SET(fifos->client, &fds); t.tv_sec = 1; t.tv_usec = 0; ret = select(fifos->client + 1, &fds, NULL, NULL, &t); if (!ret && !bytes) /* nothing to read */ return 0; if (!ret) /* trying to finish read */ continue; if (ret < 0) /* error */ return 0; ret = read(fifos->client, buf + bytes, size - bytes); bytes += ret > 0 ? ret : 0; 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; msg->size = 0; } return bytes == size; } /* * Write a message to the client making sure that it is ready to write. */ static int _client_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; header[0] = htonl(msg->cmd); header[1] = htonl(msg->size); if (msg->data) memcpy(buf + 2 * sizeof(uint32_t), msg->data, msg->size); errno = 0; while (bytes < size && errno != EIO) { do { /* Watch client write FIFO to be ready for output. */ FD_ZERO(&fds); FD_SET(fifos->server, &fds); } while (select(fifos->server + 1, NULL, &fds, NULL, NULL) != 1); ret = write(fifos->server, buf + bytes, size - bytes); bytes += ret > 0 ? ret : 0; } return bytes == size; } /* * Handle a client request. * * We put the request handling functions into * a list because of the growing number. */ static int _handle_request(struct dm_event_daemon_message *msg, struct message_data *message_data) { static struct request { unsigned int cmd; int (*f)(struct message_data *); } requests[] = { { DM_EVENT_CMD_REGISTER_FOR_EVENT, _register_for_event}, { DM_EVENT_CMD_UNREGISTER_FOR_EVENT, _unregister_for_event}, { DM_EVENT_CMD_GET_REGISTERED_DEVICE, _get_registered_device}, { DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE, _get_next_registered_device}, { DM_EVENT_CMD_SET_TIMEOUT, _set_timeout}, { DM_EVENT_CMD_GET_TIMEOUT, _get_timeout}, { DM_EVENT_CMD_ACTIVE, _active}, { DM_EVENT_CMD_GET_STATUS, _get_status}, }, *req; for (req = requests; req < requests + sizeof(requests) / sizeof(struct request); req++) if (req->cmd == msg->cmd) return req->f(message_data); return -EINVAL; } /* Process a request passed from the communication thread. */ static int _do_process_request(struct dm_event_daemon_message *msg) { int ret; char *answer; struct message_data message_data = { .msg = msg }; /* Parse the message. */ if (msg->cmd == DM_EVENT_CMD_HELLO || msg->cmd == DM_EVENT_CMD_DIE) { ret = 0; answer = msg->data; if (answer) { msg->size = dm_asprintf(&(msg->data), "%s %s %d", answer, msg->cmd == DM_EVENT_CMD_DIE ? "DYING" : "HELLO", DM_EVENT_PROTOCOL_VERSION); dm_free(answer); } else { msg->size = 0; msg->data = NULL; } } else if (msg->cmd != DM_EVENT_CMD_ACTIVE && !_parse_message(&message_data)) { stack; ret = -EINVAL; } else ret = _handle_request(msg, &message_data); msg->cmd = ret; if (!msg->data) msg->size = dm_asprintf(&(msg->data), "%s %s", message_data.id, strerror(-ret)); _free_message(&message_data); return ret; } /* Only one caller at a time. */ static void _process_request(struct dm_event_fifos *fifos) { int die = 0; struct dm_event_daemon_message msg = { 0 }; /* * Read the request from the client (client_read, client_write * give true on success and false on failure). */ if (!_client_read(fifos, &msg)) return; if (msg.cmd == DM_EVENT_CMD_DIE) die = 1; /* _do_process_request fills in msg (if memory allows for data, otherwise just cmd and size = 0) */ _do_process_request(&msg); if (!_client_write(fifos, &msg)) stack; dm_free(msg.data); if (die) raise(9); } static void _process_initial_registrations(void) { int i = 0; char *reg; struct dm_event_daemon_message msg = { 0, 0, NULL }; while ((reg = _initial_registrations[i])) { msg.cmd = DM_EVENT_CMD_REGISTER_FOR_EVENT; if ((msg.size = strlen(reg))) { msg.data = reg; _do_process_request(&msg); } ++ i; } } static void _cleanup_unused_threads(void) { int ret; struct dm_list *l; struct thread_status *thread; int join_ret = 0; _lock_mutex(); while ((l = dm_list_first(&_thread_registry_unused))) { thread = dm_list_item(l, struct thread_status); if (thread->processing) break; /* cleanup on the next round */ if (thread->status == DM_THREAD_RUNNING) { thread->status = DM_THREAD_SHUTDOWN; break; } if (thread->status == DM_THREAD_SHUTDOWN) { if (!thread->events) { /* turn codes negative -- should we be returning this? */ ret = _terminate_thread(thread); if (ret == ESRCH) { thread->status = DM_THREAD_DONE; } else if (ret) { syslog(LOG_ERR, "Unable to terminate thread: %s\n", strerror(-ret)); stack; } break; } dm_list_del(l); syslog(LOG_ERR, "thread can't be on unused list unless !thread->events"); thread->status = DM_THREAD_RUNNING; LINK_THREAD(thread); continue; } if (thread->status == DM_THREAD_DONE) { dm_list_del(l); join_ret = pthread_join(thread->thread, NULL); _free_thread_status(thread); } } _unlock_mutex(); if (join_ret) syslog(LOG_ERR, "Failed pthread_join: %s\n", strerror(join_ret)); } static void _sig_alarm(int signum __attribute__((unused))) { pthread_testcancel(); } /* Init thread signal handling. */ static void _init_thread_signals(void) { sigset_t my_sigset; struct sigaction act = { .sa_handler = _sig_alarm }; sigaction(SIGALRM, &act, NULL); sigfillset(&my_sigset); /* These are used for exiting */ sigdelset(&my_sigset, SIGTERM); sigdelset(&my_sigset, SIGINT); sigdelset(&my_sigset, SIGHUP); sigdelset(&my_sigset, SIGQUIT); pthread_sigmask(SIG_BLOCK, &my_sigset, NULL); } /* * exit_handler * @sig * * Set the global variable which the process should * be watching to determine when to exit. */ static void _exit_handler(int sig __attribute__((unused))) { /* * We exit when '_exit_now' is set. * That is, when a signal has been received. * * We can not simply set '_exit_now' unless all * threads are done processing. */ if (!_thread_registries_empty) { syslog(LOG_ERR, "There are still devices being monitored."); syslog(LOG_ERR, "Refusing to exit."); } else _exit_now = 1; } #ifdef linux static int _set_oom_adj(const char *oom_adj_path, int val) { FILE *fp; if (!(fp = fopen(oom_adj_path, "w"))) { perror("oom_adj: fopen failed"); return 0; } fprintf(fp, "%i", val); if (dm_fclose(fp)) perror("oom_adj: fclose failed"); return 1; } /* * Protection against OOM killer if kernel supports it */ static int _protect_against_oom_killer(void) { struct stat st; if (stat(OOM_ADJ_FILE, &st) == -1) { if (errno != ENOENT) perror(OOM_ADJ_FILE ": stat failed"); /* Try old oom_adj interface as a fallback */ if (stat(OOM_ADJ_FILE_OLD, &st) == -1) { if (errno == ENOENT) perror(OOM_ADJ_FILE_OLD " not found"); else perror(OOM_ADJ_FILE_OLD ": stat failed"); return 1; } return _set_oom_adj(OOM_ADJ_FILE_OLD, OOM_DISABLE) || _set_oom_adj(OOM_ADJ_FILE_OLD, OOM_ADJUST_MIN); } return _set_oom_adj(OOM_ADJ_FILE, OOM_SCORE_ADJ_MIN); } static int _handle_preloaded_fifo(int fd, const char *path) { struct stat st_fd, st_path; int flags; if ((flags = fcntl(fd, F_GETFD)) < 0) return 0; if (flags & FD_CLOEXEC) return 0; if (fstat(fd, &st_fd) < 0 || !S_ISFIFO(st_fd.st_mode)) return 0; if (stat(path, &st_path) < 0 || st_path.st_dev != st_fd.st_dev || st_path.st_ino != st_fd.st_ino) return 0; if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) return 0; return 1; } static int _systemd_handover(struct dm_event_fifos *fifos) { const char *e; char *p; unsigned long env_pid, env_listen_fds; int r = 0; memset(fifos, 0, sizeof(*fifos)); /* SD_ACTIVATION must be set! */ if (!(e = getenv(SD_ACTIVATION_ENV_VAR_NAME)) || strcmp(e, "1")) goto out; /* LISTEN_PID must be equal to our PID! */ if (!(e = getenv(SD_LISTEN_PID_ENV_VAR_NAME))) goto out; errno = 0; env_pid = strtoul(e, &p, 10); if (errno || !p || *p || env_pid <= 0 || getpid() != (pid_t) env_pid) goto out; /* LISTEN_FDS must be 2 and the fds must be FIFOSs! */ if (!(e = getenv(SD_LISTEN_FDS_ENV_VAR_NAME))) goto out; errno = 0; env_listen_fds = strtoul(e, &p, 10); if (errno || !p || *p || env_listen_fds != 2) goto out; /* Check and handle the FIFOs passed in */ r = (_handle_preloaded_fifo(SD_FD_FIFO_SERVER, DM_EVENT_FIFO_SERVER) && _handle_preloaded_fifo(SD_FD_FIFO_CLIENT, DM_EVENT_FIFO_CLIENT)); if (r) { fifos->server = SD_FD_FIFO_SERVER; fifos->server_path = DM_EVENT_FIFO_SERVER; fifos->client = SD_FD_FIFO_CLIENT; fifos->client_path = DM_EVENT_FIFO_CLIENT; } out: unsetenv(SD_ACTIVATION_ENV_VAR_NAME); unsetenv(SD_LISTEN_PID_ENV_VAR_NAME); unsetenv(SD_LISTEN_FDS_ENV_VAR_NAME); return r; } #endif static void _remove_files_on_exit(void) { if (unlink(DMEVENTD_PIDFILE)) perror(DMEVENTD_PIDFILE ": unlink failed"); if (!_systemd_activation) { if (unlink(DM_EVENT_FIFO_CLIENT)) perror(DM_EVENT_FIFO_CLIENT " : unlink failed"); if (unlink(DM_EVENT_FIFO_SERVER)) perror(DM_EVENT_FIFO_SERVER " : unlink failed"); } } static void _daemonize(void) { int child_status; int fd; pid_t pid; struct rlimit rlim; struct timeval tval; sigset_t my_sigset; sigemptyset(&my_sigset); if (sigprocmask(SIG_SETMASK, &my_sigset, NULL) < 0) { fprintf(stderr, "Unable to restore signals.\n"); exit(EXIT_FAILURE); } signal(SIGTERM, &_exit_handler); switch (pid = fork()) { case -1: perror("fork failed:"); exit(EXIT_FAILURE); case 0: /* Child */ break; default: /* Wait for response from child */ while (!waitpid(pid, &child_status, WNOHANG) && !_exit_now) { tval.tv_sec = 0; tval.tv_usec = 250000; /* .25 sec */ select(0, NULL, NULL, NULL, &tval); } if (_exit_now) /* Child has signaled it is ok - we can exit now */ exit(EXIT_SUCCESS); /* Problem with child. Determine what it is by exit code */ switch (WEXITSTATUS(child_status)) { case EXIT_DESC_CLOSE_FAILURE: case EXIT_DESC_OPEN_FAILURE: case EXIT_FIFO_FAILURE: case EXIT_CHDIR_FAILURE: default: fprintf(stderr, "Child exited with code %d\n", WEXITSTATUS(child_status)); break; } exit(WEXITSTATUS(child_status)); } if (chdir("/")) exit(EXIT_CHDIR_FAILURE); if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) fd = 256; /* just have to guess */ else fd = rlim.rlim_cur; for (--fd; fd >= 0; fd--) { #ifdef linux /* Do not close fds preloaded by systemd! */ if (_systemd_activation && (fd == SD_FD_FIFO_SERVER || fd == SD_FD_FIFO_CLIENT)) continue; #endif (void) close(fd); } if ((open("/dev/null", O_RDONLY) < 0) || (open("/dev/null", O_WRONLY) < 0) || (open("/dev/null", O_WRONLY) < 0)) exit(EXIT_DESC_OPEN_FAILURE); setsid(); } static void restart(void) { struct dm_event_fifos fifos; struct dm_event_daemon_message msg = { 0, 0, NULL }; int i, count = 0; char *message; int length; int version; /* Get the list of registrations from the running daemon. */ if (!init_fifos(&fifos)) { fprintf(stderr, "WARNING: Could not initiate communication with existing dmeventd.\n"); exit(EXIT_FAILURE); } if (!dm_event_get_version(&fifos, &version)) { fprintf(stderr, "WARNING: Could not communicate with existing dmeventd.\n"); fini_fifos(&fifos); exit(EXIT_FAILURE); } if (version < 1) { fprintf(stderr, "WARNING: The running dmeventd instance is too old.\n" "Protocol version %d (required: 1). Action cancelled.\n", version); exit(EXIT_FAILURE); } if (daemon_talk(&fifos, &msg, DM_EVENT_CMD_GET_STATUS, "-", "-", 0, 0)) { exit(EXIT_FAILURE); } message = msg.data; message = strchr(message, ' '); ++ message; length = strlen(msg.data); for (i = 0; i < length; ++i) { if (msg.data[i] == ';') { msg.data[i] = 0; ++count; } } if (!(_initial_registrations = dm_malloc(sizeof(char*) * (count + 1)))) { fprintf(stderr, "Memory allocation registration failed.\n"); exit(EXIT_FAILURE); } for (i = 0; i < count; ++i) { if (!(_initial_registrations[i] = dm_strdup(message))) { fprintf(stderr, "Memory allocation for message failed.\n"); exit(EXIT_FAILURE); } message += strlen(message) + 1; } _initial_registrations[count] = 0; if (daemon_talk(&fifos, &msg, DM_EVENT_CMD_DIE, "-", "-", 0, 0)) { fprintf(stderr, "Old dmeventd refused to die.\n"); exit(EXIT_FAILURE); } /* * Wait for daemon to die, detected by sending further DIE messages * until one fails. */ for (i = 0; i < 10; ++i) { if (daemon_talk(&fifos, &msg, DM_EVENT_CMD_DIE, "-", "-", 0, 0)) break; /* yep, it's dead probably */ usleep(10); } fini_fifos(&fifos); } static void usage(char *prog, FILE *file) { fprintf(file, "Usage:\n" "%s [-d [-d [-d]]] [-f] [-h] [-R] [-V] [-?]\n\n" " -d Log debug messages to syslog (-d, -dd, -ddd)\n" " -f Don't fork, run in the foreground\n" " -h -? Show this help information\n" " -R Restart dmeventd\n" " -V Show version of dmeventd\n\n", prog); } int main(int argc, char *argv[]) { signed char opt; struct dm_event_fifos fifos; //struct sys_log logdata = {DAEMON_NAME, LOG_DAEMON}; opterr = 0; optind = 0; while ((opt = getopt(argc, argv, "?fhVdR")) != EOF) { switch (opt) { case 'h': usage(argv[0], stdout); exit(0); case '?': usage(argv[0], stderr); exit(0); case 'R': _restart++; break; case 'f': _foreground++; break; case 'd': dmeventd_debug++; break; case 'V': printf("dmeventd version: %s\n", DM_LIB_VERSION); exit(1); } } /* * Switch to C locale to avoid reading large locale-archive file * used by some glibc (on some distributions it takes over 100MB). * Daemon currently needs to use mlockall(). */ if (setenv("LANG", "C", 1)) perror("Cannot set LANG to C"); if (_restart) restart(); #ifdef linux _systemd_activation = _systemd_handover(&fifos); #endif if (!_foreground) _daemonize(); openlog("dmeventd", LOG_PID, LOG_DAEMON); (void) dm_prepare_selinux_context(DMEVENTD_PIDFILE, S_IFREG); if (dm_create_lockfile(DMEVENTD_PIDFILE) == 0) exit(EXIT_FAILURE); atexit(_remove_files_on_exit); (void) dm_prepare_selinux_context(NULL, 0); /* Set the rest of the signals to cause '_exit_now' to be set */ signal(SIGTERM, &_exit_handler); signal(SIGINT, &_exit_handler); signal(SIGHUP, &_exit_handler); signal(SIGQUIT, &_exit_handler); #ifdef linux /* Systemd has adjusted oom killer for us already */ if (!_systemd_activation && !_protect_against_oom_killer()) syslog(LOG_ERR, "Failed to protect against OOM killer"); #endif _init_thread_signals(); //multilog_clear_logging(); //multilog_add_type(std_syslog, &logdata); //multilog_init_verbose(std_syslog, _LOG_DEBUG); //multilog_async(1); if (!_systemd_activation) _init_fifos(&fifos); pthread_mutex_init(&_global_mutex, NULL); if (!_systemd_activation && !_open_fifos(&fifos)) exit(EXIT_FIFO_FAILURE); /* Signal parent, letting them know we are ready to go. */ if (!_foreground) kill(getppid(), SIGTERM); syslog(LOG_NOTICE, "dmeventd ready for processing."); if (_initial_registrations) _process_initial_registrations(); while (!_exit_now) { _process_request(&fifos); _cleanup_unused_threads(); _lock_mutex(); if (!dm_list_empty(&_thread_registry) || !dm_list_empty(&_thread_registry_unused)) _thread_registries_empty = 0; else _thread_registries_empty = 1; _unlock_mutex(); } _exit_dm_lib(); pthread_mutex_destroy(&_global_mutex); syslog(LOG_NOTICE, "dmeventd shutting down."); closelog(); exit(EXIT_SUCCESS); } lvm2-2.02.98/daemons/clvmd/0000750000175000017500000000000012037016272014242 5ustar blankblanklvm2-2.02.98/daemons/clvmd/clvm.h0000640000175000017500000000546712037016272015371 0ustar blankblank/* * 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 or FLAG_REMOTE is also set. */ char args[1]; /* Arguments for the command follow the node name, This member is only valid if the node name is empty */ } __attribute__ ((packed)); /* Flags */ #define CLVMD_FLAG_LOCAL 1 /* Only do this on the local node */ #define CLVMD_FLAG_SYSTEMLV 2 /* Data in system LV under my node name */ #define CLVMD_FLAG_NODEERRS 4 /* Reply has errors in node-specific portion */ #define CLVMD_FLAG_REMOTE 8 /* Do this on all nodes except for the local node */ /* Name of the local socket to communicate between lvm and clvmd */ static const char CLVMD_SOCKNAME[]= DEFAULT_RUN_DIR "/clvmd.sock"; /* Internal commands & replies */ #define CLVMD_CMD_REPLY 1 #define CLVMD_CMD_VERSION 2 /* Send version around cluster when we start */ #define CLVMD_CMD_GOAWAY 3 /* Die if received this - we are running an incompatible version */ #define CLVMD_CMD_TEST 4 /* Just for mucking about */ #define CLVMD_CMD_LOCK 30 #define CLVMD_CMD_UNLOCK 31 /* Lock/Unlock commands */ #define CLVMD_CMD_LOCK_LV 50 #define CLVMD_CMD_LOCK_VG 51 #define CLVMD_CMD_LOCK_QUERY 52 /* Misc functions */ #define CLVMD_CMD_REFRESH 40 #define CLVMD_CMD_GET_CLUSTERNAME 41 #define CLVMD_CMD_SET_DEBUG 42 #define CLVMD_CMD_VG_BACKUP 43 #define CLVMD_CMD_RESTART 44 #define CLVMD_CMD_SYNC_NAMES 45 /* Used internally by some callers, but not part of the protocol.*/ #define NODE_ALL "*" #define NODE_LOCAL "." #define NODE_REMOTE "^" #endif lvm2-2.02.98/daemons/clvmd/clvmd-command.c0000640000175000017500000002630612037016272017137 0ustar blankblank/* * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved. * Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU General Public License v.2. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* CLVMD Cluster LVM daemon command processor. To add commands to the daemon simply add a processor in do_command and return and messages back in buf and the length in *retlen. The initial value of buflen is the maximum size of the buffer. if buf is not large enough then it may be reallocated by the functions in here to a suitable size bearing in mind that anything larger than the passed-in size will have to be returned using the system LV and so performance will suffer. The status return will be negated and passed back to the originating node. pre- and post- command routines are called only on the local node. The purpose is primarily to get and release locks, though the pre- routine should also do any other local setups required by the command (if any) and can return a failure code that prevents the command from being distributed around the cluster The pre- and post- routines are run in their own thread so can block as long they like, do_command is run in the main clvmd thread so should not block for too long. If the pre-command returns an error code (!=0) then the command will not be propogated around the cluster but the post-command WILL be called Also note that the pre and post routine are *always* called on the local node, even if the command to be executed was only requested to run on a remote node. It may peek inside the client structure to check the status of the command. The clients of the daemon must, naturally, understand the return messages and codes. Routines in here may only READ the values in the client structure passed in apart from client->private which they are free to do what they like with. */ #include "clvmd-common.h" #include "clvmd-comms.h" #include "clvm.h" #include "clvmd.h" #include "lvm-globals.h" #include "lvm-functions.h" #include "locking.h" #include 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; /* Reset test mode before we start */ init_test(0); /* Do the command */ switch (msg->cmd) { /* Just a test message */ case CLVMD_CMD_TEST: if (arglen > buflen) { char *new_buf; buflen = arglen + 200; new_buf = realloc(*buf, buflen); if (new_buf == NULL) { status = errno; free (*buf); } *buf = new_buf; } if (*buf) { if (uname(&nodeinfo)) memset(&nodeinfo, 0, sizeof(nodeinfo)); *retlen = 1 + dm_snprintf(*buf, buflen, "TEST from %s: %s v%s", nodeinfo.nodename, args, nodeinfo.release); } break; case CLVMD_CMD_LOCK_VG: lock_cmd = args[0]; lock_flags = args[1]; lockname = &args[2]; /* Check to see if the VG is in use by LVM1 */ status = do_check_lvm1(lockname); if (lock_flags & LCK_TEST_MODE) init_test(1); do_lock_vg(lock_cmd, lock_flags, lockname); break; case CLVMD_CMD_LOCK_LV: /* This is the biggie */ lock_cmd = args[0]; lock_flags = args[1]; lockname = &args[2]; if (lock_flags & LCK_TEST_MODE) init_test(1); status = do_lock_lv(lock_cmd, lock_flags, lockname); /* Replace EIO with something less scary */ if (status == EIO) { *retlen = 1 + dm_snprintf(*buf, buflen, "%s", get_last_lvm_error()); return EIO; } break; case CLVMD_CMD_LOCK_QUERY: lockname = &args[2]; if (buflen < 3) return EIO; if ((locktype = do_lock_query(lockname))) *retlen = 1 + dm_snprintf(*buf, buflen, "%s", locktype); break; case CLVMD_CMD_REFRESH: do_refresh_cache(); break; case CLVMD_CMD_SYNC_NAMES: lvm_do_fs_unlock(); break; case CLVMD_CMD_SET_DEBUG: clvmd_set_debug((debug_t) args[0]); break; case CLVMD_CMD_RESTART: status = restart_clvmd(); break; case CLVMD_CMD_GET_CLUSTERNAME: status = clops->get_cluster_name(*buf, buflen); if (!status) *retlen = strlen(*buf)+1; break; case CLVMD_CMD_VG_BACKUP: /* * Do not run backup on local node, caller should do that. */ if (!client) lvm_do_backup(&args[2]); break; default: /* Won't get here because command is validated in pre_command */ break; } /* Check the status of the command and return the error text */ if (status) { *retlen = 1 + ((*buf) ? dm_snprintf(*buf, buflen, "%s", strerror(status)) : -1); } return status; } static int lock_vg(struct local_client *client) { struct dm_hash_table *lock_hash; struct clvm_header *header = (struct clvm_header *) client->bits.localsock.cmd; unsigned char lock_cmd; int lock_mode; char *args = header->node + strlen(header->node) + 1; int lkid; int status = 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; 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 if (!dm_hash_insert(lock_hash, lockname, (void *)(long)lkid)) return ENOMEM; } return status; } /* Pre-command is a good place to get locks that are needed only for the duration of the commands around the cluster (don't forget to free them in post-command), and to sanity check the command arguments */ int do_pre_command(struct local_client *client) { struct clvm_header *header = (struct clvm_header *) client->bits.localsock.cmd; unsigned char lock_cmd; unsigned char lock_flags; char *args = header->node + strlen(header->node) + 1; int lockid = 0; int status = 0; char *lockname; init_test(0); 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]; if (lock_flags & LCK_TEST_MODE) init_test(1); 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; init_test(0); 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_LV: lock_cmd = args[0]; lock_flags = args[1]; lockname = &args[2]; if (lock_flags & LCK_TEST_MODE) init_test(1); status = post_lock_lv(lock_cmd, lock_flags, lockname); break; default: /* Nothing to do here */ break; } return status; } /* Called when the client is about to be deleted */ void cmd_client_cleanup(struct local_client *client) { struct dm_hash_node *v; struct dm_hash_table *lock_hash; int lkid; char *lockname; if (!client->bits.localsock.private) return; lock_hash = (struct dm_hash_table *)client->bits.localsock.private; dm_hash_iterate(v, lock_hash) { lkid = (int)(long)dm_hash_get_data(lock_hash, v); lockname = dm_hash_get_key(lock_hash, v); DEBUGLOG("cleanup: Unlocking lock %s %x\n", lockname, lkid); (void) sync_unlock(lockname, lkid); } dm_hash_destroy(lock_hash); client->bits.localsock.private = 0; } static int restart_clvmd(void) { const char **argv; char *lv_name; int argc = 0, max_locks = 0; struct dm_hash_node *hn = NULL; char debug_arg[16]; const char *clvmd = getenv("LVM_CLVMD_BINARY") ? : CLVMD_PATH; DEBUGLOG("clvmd restart requested\n"); /* Count exclusively-open LVs */ do { hn = get_next_excl_lock(hn, &lv_name); if (lv_name) { max_locks++; if (!*lv_name) break; /* FIXME: Is this error ? */ } } while (hn); /* clvmd + locks (-E uuid) + debug (-d X) + NULL */ if (!(argv = malloc((max_locks * 2 + 5) * sizeof(*argv)))) goto_out; /* * Build the command-line */ argv[argc++] = "clvmd"; /* Propogate debug options */ if (clvmd_get_debug()) { if (dm_snprintf(debug_arg, sizeof(debug_arg), "-d%u", clvmd_get_debug()) < 0) goto_out; argv[argc++] = debug_arg; } argv[argc++] = "-I"; argv[argc++] = clops->name; /* Now add the exclusively-open LVs */ hn = NULL; do { hn = get_next_excl_lock(hn, &lv_name); if (lv_name) { if (!*lv_name) break; /* FIXME: Is this error ? */ argv[argc++] = "-E"; argv[argc++] = lv_name; DEBUGLOG("excl lock: %s\n", lv_name); } } while (hn); argv[argc] = NULL; /* Exec new clvmd */ DEBUGLOG("--- Restarting %s ---\n", clvmd); for (argc = 1; argv[argc]; argc++) DEBUGLOG("--- %d: %s\n", argc, argv[argc]); /* NOTE: This will fail when downgrading! */ execvp(clvmd, (char **)argv); out: /* We failed */ DEBUGLOG("Restart of clvmd failed.\n"); free(argv); return EIO; } lvm2-2.02.98/daemons/clvmd/clvmd-openais.c0000640000175000017500000004002312037016272017147 0ustar blankblank/* * 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 #include #include #include #include #include #include #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 = calloc(1, sizeof(struct local_client)); if (!client) { DEBUGLOG("malloc failed\n"); return -1; } client->fd = fd; client->type = CLUSTER_INTERNAL; client->callback = callback; add_client(client); /* Set Close-on-exec */ fcntl(fd, F_SETFD, 1); return 0; } static void openais_cpg_deliver_callback (cpg_handle_t handle, const struct cpg_name *groupName, uint32_t nodeid, uint32_t pid, void *msg, size_t msg_len) { int target_nodeid; memcpy(&target_nodeid, msg, OPENAIS_CSID_LEN); DEBUGLOG("%u got message from nodeid %d for %d. len %" PRIsize_t "\n", our_nodeid, nodeid, target_nodeid, msg_len-4); if (nodeid != our_nodeid) if (target_nodeid == our_nodeid || target_nodeid == 0) process_message(cluster_client, (char *)msg+OPENAIS_CSID_LEN, msg_len-OPENAIS_CSID_LEN, (char*)&nodeid); } static void openais_cpg_confchg_callback(cpg_handle_t handle, const struct cpg_name *groupName, const struct cpg_address *member_list, size_t member_list_entries, const struct cpg_address *left_list, size_t left_list_entries, const struct cpg_address *joined_list, size_t joined_list_entries) { int i; struct node_info *ninfo; DEBUGLOG("confchg callback. %" PRIsize_t " joined, " "%" PRIsize_t " left, %" PRIsize_t " members\n", joined_list_entries, left_list_entries, member_list_entries); for (i=0; inodeid = joined_list[i].nodeid; dm_hash_insert_binary(node_hash, (char *)&ninfo->nodeid, OPENAIS_CSID_LEN, ninfo); } } ninfo->state = NODE_CLVMD; } for (i=0; istate = NODE_DOWN; } for (i=0; inodeid = 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=%" PRIx64 "\n", err, lock_id); linfo->lock_id = lock_id; linfo->res_handle = res_handle; dm_hash_insert(lock_hash, resource, linfo); return ais_to_errno(err); } static int _unlock_resource(char *resource, int lockid) { SaAisErrorT err; struct lock_info *linfo; DEBUGLOG("unlock_resource %s\n", resource); linfo = dm_hash_lookup(lock_hash, resource); if (!linfo) return 0; DEBUGLOG("unlock_resource: lockid: %" PRIx64 "\n", linfo->lock_id); err = saLckResourceUnlock(linfo->lock_id, SA_TIME_END); if (err != SA_AIS_OK) { DEBUGLOG("Unlock returned %d\n", err); return ais_to_errno(err); } /* Release the resource */ dm_hash_remove(lock_hash, resource); saLckResourceClose(linfo->res_handle); free(linfo); return ais_to_errno(err); } static int _sync_lock(const char *resource, int mode, int flags, int *lockid) { int status; char lock1[strlen(resource)+3]; char lock2[strlen(resource)+3]; snprintf(lock1, sizeof(lock1), "%s-1", resource); snprintf(lock2, sizeof(lock2), "%s-2", resource); switch (mode) { case LCK_EXCL: status = _lock_resource(lock1, SA_LCK_EX_LOCK_MODE, flags, lockid); if (status) goto out; /* If we can't get this lock too then bail out */ status = _lock_resource(lock2, SA_LCK_EX_LOCK_MODE, LCK_NONBLOCK, lockid); if (status == SA_LCK_LOCK_NOT_QUEUED) { _unlock_resource(lock1, *lockid); status = -1; errno = EAGAIN; } break; case LCK_PREAD: case LCK_READ: status = _lock_resource(lock1, SA_LCK_PR_LOCK_MODE, flags, lockid); if (status) goto out; _unlock_resource(lock2, *lockid); break; case LCK_WRITE: status = _lock_resource(lock2, SA_LCK_EX_LOCK_MODE, flags, lockid); if (status) goto out; _unlock_resource(lock1, *lockid); break; default: status = -1; errno = EINVAL; break; } out: *lockid = mode; return status; } static int _sync_unlock(const char *resource, int lockid) { int status = 0; char lock1[strlen(resource)+3]; char lock2[strlen(resource)+3]; snprintf(lock1, sizeof(lock1), "%s-1", resource); snprintf(lock2, sizeof(lock2), "%s-2", resource); _unlock_resource(lock1, lockid); _unlock_resource(lock2, lockid); return status; } /* We are always quorate ! */ static int _is_quorate() { return 1; } static int _get_main_cluster_fd(void) { int select_fd; cpg_fd_get(cpg_handle, &select_fd); return select_fd; } static int _cluster_fd_callback(struct local_client *fd, char *buf, int len, const char *csid, struct local_client **new_client) { cluster_client = fd; *new_client = NULL; cpg_dispatch(cpg_handle, SA_DISPATCH_ONE); return 1; } static int _cluster_send_message(const void *buf, int msglen, const char *csid, const char *errtext) { struct iovec iov[2]; SaAisErrorT err; int target_node; if (csid) memcpy(&target_node, csid, OPENAIS_CSID_LEN); else target_node = 0; iov[0].iov_base = &target_node; iov[0].iov_len = sizeof(int); iov[1].iov_base = (char *)buf; iov[1].iov_len = msglen; err = cpg_mcast_joined(cpg_handle, CPG_TYPE_AGREED, iov, 2); return ais_to_errno(err); } /* We don't have a cluster name to report here */ static int _get_cluster_name(char *buf, int buflen) { strncpy(buf, "OpenAIS", buflen); return 0; } static struct cluster_ops _cluster_openais_ops = { .name = "openais", .cluster_init_completed = NULL, .cluster_send_message = _cluster_send_message, .name_from_csid = _name_from_csid, .csid_from_name = _csid_from_name, .get_num_nodes = _get_num_nodes, .cluster_fd_callback = _cluster_fd_callback, .get_main_cluster_fd = _get_main_cluster_fd, .cluster_do_node_callback = _cluster_do_node_callback, .is_quorate = _is_quorate, .get_our_csid = _get_our_csid, .add_up_node = _add_up_node, .reread_config = NULL, .cluster_closedown = _cluster_closedown, .get_cluster_name = _get_cluster_name, .sync_lock = _sync_lock, .sync_unlock = _sync_unlock, }; struct cluster_ops *init_openais_cluster(void) { if (!_init_cluster()) return &_cluster_openais_ops; else return NULL; } lvm2-2.02.98/daemons/clvmd/clvmd-common.h0000640000175000017500000000146512037016272017015 0ustar blankblank/* * 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 #include #endif lvm2-2.02.98/daemons/clvmd/refresh_clvmd.h0000640000175000017500000000114712037016272017242 0ustar blankblank/* * 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); lvm2-2.02.98/daemons/clvmd/lvm-functions.c0000640000175000017500000005456112037016272017226 0ustar blankblank/* * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved. * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU General Public License v.2. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "clvmd-common.h" #include #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 static struct cmd_context *cmd = NULL; static struct dm_hash_table *lv_hash = NULL; static pthread_mutex_t lv_hash_lock; static pthread_mutex_t lvm_lock; static char last_error[1024]; struct lv_info { int lock_id; int lock_mode; }; static const char *decode_full_locking_cmd(uint32_t cmdl) { static char buf[128]; const char *type; const char *scope; const char *command; switch (cmdl & LCK_TYPE_MASK) { case LCK_NULL: type = "NULL"; break; case LCK_READ: type = "READ"; break; case LCK_PREAD: type = "PREAD"; break; case LCK_WRITE: type = "WRITE"; break; case LCK_EXCL: type = "EXCL"; break; case LCK_UNLOCK: type = "UNLOCK"; break; default: type = "unknown"; break; } switch (cmdl & LCK_SCOPE_MASK) { case LCK_VG: scope = "VG"; command = "LCK_VG"; break; case LCK_LV: scope = "LV"; switch (cmdl & LCK_MASK) { case LCK_LV_EXCLUSIVE & LCK_MASK: command = "LCK_LV_EXCLUSIVE"; break; case LCK_LV_SUSPEND & LCK_MASK: command = "LCK_LV_SUSPEND"; break; case LCK_LV_RESUME & LCK_MASK: command = "LCK_LV_RESUME"; break; case LCK_LV_ACTIVATE & LCK_MASK: command = "LCK_LV_ACTIVATE"; break; case LCK_LV_DEACTIVATE & LCK_MASK: command = "LCK_LV_DEACTIVATE"; break; default: command = "unknown"; break; } break; default: scope = "unknown"; command = "unknown"; break; } sprintf(buf, "0x%x %s (%s|%s%s%s%s%s)", cmdl, command, type, scope, cmdl & LCK_NONBLOCK ? "|NONBLOCK" : "", cmdl & LCK_HOLD ? "|HOLD" : "", cmdl & LCK_CLUSTER_VG ? "|CLUSTER_VG" : "", cmdl & LCK_CACHE ? "|CACHE" : ""); return buf; } /* * Only processes 8 bits: excludes LCK_CACHE. */ static const char *decode_locking_cmd(unsigned char cmdl) { return decode_full_locking_cmd((uint32_t) cmdl); } static const char *decode_flags(unsigned char flags) { static char buf[128]; int len; len = sprintf(buf, "0x%x ( %s%s%s%s%s%s%s)", flags, flags & LCK_PARTIAL_MODE ? "PARTIAL_MODE|" : "", flags & LCK_MIRROR_NOSYNC_MODE ? "MIRROR_NOSYNC|" : "", flags & LCK_DMEVENTD_MONITOR_MODE ? "DMEVENTD_MONITOR|" : "", flags & LCK_ORIGIN_ONLY_MODE ? "ORIGIN_ONLY|" : "", flags & LCK_TEST_MODE ? "TEST|" : "", flags & LCK_CONVERT ? "CONVERT|" : "", flags & LCK_DMEVENTD_MONITOR_IGNORE ? "DMEVENTD_MONITOR_IGNORE|" : ""); if (len > 1) buf[len - 2] = ' '; else buf[0] = '\0'; return buf; } char *get_last_lvm_error(void) { return last_error; } /* * Hash lock info helpers */ static struct lv_info *lookup_info(const char *resource) { struct lv_info *lvi; pthread_mutex_lock(&lv_hash_lock); lvi = dm_hash_lookup(lv_hash, resource); pthread_mutex_unlock(&lv_hash_lock); return lvi; } static int insert_info(const char *resource, struct lv_info *lvi) { int ret; pthread_mutex_lock(&lv_hash_lock); ret = dm_hash_insert(lv_hash, resource, lvi); pthread_mutex_unlock(&lv_hash_lock); return ret; } static void remove_info(const char *resource) { 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(void) { /* Create hash table for keeping LV locks & status */ lv_hash = dm_hash_create(1024); pthread_mutex_init(&lv_hash_lock, NULL); pthread_mutex_init(&lvm_lock, NULL); } /* Called at shutdown to tidy the lockspace */ void destroy_lvhash(void) { struct dm_hash_node *v; struct lv_info *lvi; char *resource; int status; pthread_mutex_lock(&lv_hash_lock); dm_hash_iterate(v, lv_hash) { lvi = dm_hash_get_data(lv_hash, v); resource = dm_hash_get_key(lv_hash, v); if ((status = sync_unlock(resource, lvi->lock_id))) DEBUGLOG("unlock_all. unlock failed(%d): %s\n", status, strerror(errno)); 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; if (test_mode()) return 0; /* Mask off invalid options */ flags &= LCKF_NOQUEUE | LCKF_CONVERT; lvi = lookup_info(resource); if (lvi) { if (lvi->lock_mode == mode) { DEBUGLOG("hold_lock, lock mode %d already held\n", mode); return 0; } if ((lvi->lock_mode == LCK_EXCL) && (mode == LCK_WRITE)) { DEBUGLOG("hold_lock, lock already held LCK_EXCL, " "ignoring LCK_WRITE request"); 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) { errno = ENOMEM; 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 if (!insert_info(resource, lvi)) { errno = ENOMEM; return -1; } errno = saved_errno; } return status; } /* Unlock and remove it from the hash table */ static int hold_unlock(char *resource) { struct lv_info *lvi; int status; int saved_errno; if (test_mode()) return 0; 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 command, unsigned char lock_flags, int mode) { int oldmode; int status; int activate_lv; int exclusive = 0; struct lvinfo lvi; /* Is it already open ? */ oldmode = get_current_lock(resource); if (oldmode == mode && (command & LCK_CLUSTER_VG)) { DEBUGLOG("do_activate_lv, lock already held at %d\n", oldmode); return 0; /* Nothing to do */ } /* Does the config file want us to activate this LV ? */ if (!lv_activation_filter(cmd, resource, &activate_lv)) 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 (command & LCK_CLUSTER_VG) { status = hold_lock(resource, mode, LCKF_NOQUEUE | (lock_flags & LCK_CONVERT ? LCKF_CONVERT:0)); if (status) { /* Return an LVM-sensible error for this. * Forcing EIO makes the upper level return this text * rather than the strerror text for EAGAIN. */ if (errno == EAGAIN) { sprintf(last_error, "Volume is busy on another node"); errno = EIO; } return errno; } } /* If it's suspended then resume it */ if (!lv_info_by_lvid(cmd, resource, 0, &lvi, 0, 0)) goto error; if (lvi.suspended) { critical_section_inc(cmd, "resuming"); if (!lv_resume(cmd, resource, 0)) { critical_section_dec(cmd, "resumed"); 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 command, unsigned char lock_flags) { int oldmode, origin_only, exclusive, revert; /* Is it open ? */ oldmode = get_current_lock(resource); if (oldmode == -1 && (command & LCK_CLUSTER_VG)) { DEBUGLOG("do_resume_lv, lock not already held\n"); return 0; /* We don't need to do anything */ } origin_only = (lock_flags & LCK_ORIGIN_ONLY_MODE) ? 1 : 0; exclusive = (oldmode == LCK_EXCL) ? 1 : 0; revert = (lock_flags & LCK_REVERT_MODE) ? 1 : 0; if (!lv_resume_if_active(cmd, resource, origin_only, exclusive, revert)) return EIO; return 0; } /* Suspend the device if active */ static int do_suspend_lv(char *resource, unsigned char command, unsigned char lock_flags) { int oldmode; struct lvinfo lvi; unsigned origin_only = (lock_flags & LCK_ORIGIN_ONLY_MODE) ? 1 : 0; unsigned exclusive; /* Is it open ? */ oldmode = get_current_lock(resource); if (oldmode == -1 && (command & LCK_CLUSTER_VG)) { DEBUGLOG("do_suspend_lv, lock not already held\n"); return 0; /* Not active, so it's OK */ } exclusive = (oldmode == LCK_EXCL) ? 1 : 0; /* 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, exclusive)) return EIO; return 0; } static int do_deactivate_lv(char *resource, unsigned char command, unsigned char lock_flags) { int oldmode; int status; /* Is it open ? */ oldmode = get_current_lock(resource); if (oldmode == -1 && (command & LCK_CLUSTER_VG)) { DEBUGLOG("do_deactivate_lock, lock not already held\n"); return 0; /* We don't need to do anything */ } if (!lv_deactivate(cmd, resource)) return EIO; if (command & LCK_CLUSTER_VG) { status = hold_unlock(resource); if (status) return errno; } return 0; } const char *do_lock_query(char *resource) { int mode; const char *type = 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, critical_section = %d\n", resource, decode_locking_cmd(command), decode_flags(lock_flags), critical_section()); 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_IGNORE) init_dmeventd_monitor(DMEVENTD_MONITOR_IGNORE); else { if (lock_flags & LCK_DMEVENTD_MONITOR_MODE) init_dmeventd_monitor(1); else init_dmeventd_monitor(0); } cmd->partial_activation = (lock_flags & LCK_PARTIAL_MODE) ? 1 : 0; /* clvmd should never try to read suspended device */ init_ignore_suspended_devices(1); switch (command & LCK_MASK) { case LCK_LV_EXCLUSIVE: status = do_activate_lv(resource, command, lock_flags, LCK_EXCL); break; case LCK_LV_SUSPEND: status = do_suspend_lv(resource, command, lock_flags); break; case LCK_UNLOCK: case LCK_LV_RESUME: /* if active */ status = do_resume_lv(resource, command, lock_flags); break; case LCK_LV_ACTIVATE: status = do_activate_lv(resource, command, lock_flags, LCK_READ); break; case LCK_LV_DEACTIVATE: status = do_deactivate_lv(resource, command, lock_flags); break; default: DEBUGLOG("Invalid LV command 0x%x\n", command); status = EINVAL; break; } if (lock_flags & LCK_MIRROR_NOSYNC_MODE) init_mirror_in_sync(0); cmd->partial_activation = 0; /* clean the pool for another command */ dm_pool_empty(cmd->mem); pthread_mutex_unlock(&lvm_lock); DEBUGLOG("Command return is %d, critical_section is %d\n", status, critical_section()); return status; } /* Functions to do on the local node only BEFORE the cluster-wide stuff above happens */ int pre_lock_lv(unsigned char command, unsigned char lock_flags, char *resource) { /* Nearly all the stuff happens cluster-wide. Apart from SUSPEND. Here we get the lock out on this node (because we are the node modifying the metadata) before suspending cluster-wide. LCKF_CONVERT is used always, local node is going to modify metadata */ if ((command & (LCK_SCOPE_MASK | LCK_TYPE_MASK)) == LCK_LV_SUSPEND && (command & LCK_CLUSTER_VG)) { DEBUGLOG("pre_lock_lv: resource '%s', cmd = %s, flags = %s\n", resource, decode_locking_cmd(command), decode_flags(lock_flags)); if (hold_lock(resource, LCK_WRITE, LCKF_NOQUEUE | LCKF_CONVERT)) return errno; } return 0; } /* Functions to do on the local node only AFTER the cluster-wide stuff above happens */ int post_lock_lv(unsigned char command, unsigned char lock_flags, char *resource) { int status; unsigned origin_only = (lock_flags & LCK_ORIGIN_ONLY_MODE) ? 1 : 0; /* Opposite of above, done on resume after a metadata update */ if ((command & (LCK_SCOPE_MASK | LCK_TYPE_MASK)) == LCK_LV_RESUME && (command & LCK_CLUSTER_VG)) { int oldmode; DEBUGLOG ("post_lock_lv: resource '%s', cmd = %s, flags = %s\n", resource, decode_locking_cmd(command), decode_flags(lock_flags)); /* If the lock state is PW then restore it to what it was */ oldmode = get_current_lock(resource); if (oldmode == LCK_WRITE) { struct lvinfo lvi; pthread_mutex_lock(&lvm_lock); status = lv_info_by_lvid(cmd, resource, origin_only, &lvi, 0, 0); pthread_mutex_unlock(&lvm_lock); if (!status) return EIO; if (lvi.exists) { if (hold_lock(resource, LCK_READ, LCKF_CONVERT)) return errno; } else if (hold_unlock(resource)) return errno; } } return 0; } /* Check if a VG is in use by LVM1 so we don't stomp on it */ int do_check_lvm1(const char *vgname) { int status; status = check_lvm1_vg_inactive(cmd, vgname); return status == 1 ? 0 : EBUSY; } int do_refresh_cache(void) { DEBUGLOG("Refreshing context\n"); log_notice("Refreshing context"); pthread_mutex_lock(&lvm_lock); if (!refresh_toolcontext(cmd)) { pthread_mutex_unlock(&lvm_lock); return -1; } init_full_scan_done(0); init_ignore_suspended_devices(1); lvmcache_label_scan(cmd, 2); dm_pool_empty(cmd->mem); pthread_mutex_unlock(&lvm_lock); return 0; } /* * Handle VG lock - drop metadata or update lvmcache state */ void do_lock_vg(unsigned char command, unsigned char lock_flags, char *resource) { uint32_t lock_cmd = command; char *vgname = resource + 2; lock_cmd &= (LCK_SCOPE_MASK | LCK_TYPE_MASK | LCK_HOLD); /* * Check if LCK_CACHE should be set. All P_ locks except # are cache related. */ if (strncmp(resource, "P_#", 3) && !strncmp(resource, "P_", 2)) lock_cmd |= LCK_CACHE; DEBUGLOG("do_lock_vg: resource '%s', cmd = %s, flags = %s, critical_section = %d\n", resource, decode_full_locking_cmd(lock_cmd), decode_flags(lock_flags), critical_section()); /* P_#global causes a full cache refresh */ if (!strcmp(resource, "P_" VG_GLOBAL)) { do_refresh_cache(); return; } pthread_mutex_lock(&lvm_lock); 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); } /* * Ideally, clvmd should be started before any LVs are active * but this may not be the case... * I suppose this also comes in handy if clvmd crashes, not that it would! */ static int get_initial_state(struct dm_hash_table *excl_uuid) { int lock_mode; char lv[64], vg[64], flags[25], vg_flags[25]; char uuid[65]; char line[255]; char *lvs_cmd; const char *lvm_binary = getenv("LVM_BINARY") ? : LVM_PATH; FILE *lvs; if (dm_asprintf(&lvs_cmd, "%s lvs --config 'log{command_names=0 prefix=\"\"}' " "--nolocking --noheadings -o vg_uuid,lv_uuid,lv_attr,vg_attr", lvm_binary) < 0) return_0; /* FIXME: Maybe link and use liblvm2cmd directly instead of fork */ if (!(lvs = popen(lvs_cmd, "r"))) { dm_free(lvs_cmd); return 0; } while (fgets(line, sizeof(line), lvs)) { if (sscanf(line, "%64s %64s %25s %25s\n", vg, lv, flags, vg_flags) == 4) { /* States: s:suspended a:active S:dropped snapshot I:invalid snapshot */ if (strlen(vg) == 38 && /* is is a valid UUID ? */ (flags[4] == 'a' || flags[4] == 's') && /* is it active or suspended? */ vg_flags[5] == 'c') { /* is it clustered ? */ /* Convert hyphen-separated UUIDs into one */ memcpy(&uuid[0], &vg[0], 6); memcpy(&uuid[6], &vg[7], 4); memcpy(&uuid[10], &vg[12], 4); memcpy(&uuid[14], &vg[17], 4); memcpy(&uuid[18], &vg[22], 4); memcpy(&uuid[22], &vg[27], 4); memcpy(&uuid[26], &vg[32], 6); memcpy(&uuid[32], &lv[0], 6); memcpy(&uuid[38], &lv[7], 4); memcpy(&uuid[42], &lv[12], 4); memcpy(&uuid[46], &lv[17], 4); memcpy(&uuid[50], &lv[22], 4); memcpy(&uuid[54], &lv[27], 4); memcpy(&uuid[58], &lv[32], 6); uuid[64] = '\0'; /* Look for this lock in the list of EX locks we were passed on the command-line */ lock_mode = (dm_hash_lookup(excl_uuid, uuid)) ? LCK_EXCL : LCK_READ; DEBUGLOG("getting initial lock for %s\n", uuid); if (hold_lock(uuid, lock_mode, LCKF_NOQUEUE)) DEBUGLOG("Failed to hold lock %s\n", uuid); } } } if (fclose(lvs)) DEBUGLOG("lvs fclose failed: %s\n", strerror(errno)); dm_free(lvs_cmd); return 1; } static void lvm2_log_fn(int level, const char *file, int line, int dm_errno, const char *message) { /* Send messages to the normal LVM2 logging system too, so we get debug output when it's asked for. We need to NULL the function ptr otherwise it will just call back into here! */ init_log_fn(NULL); print_log(level, file, line, dm_errno, "%s", message); init_log_fn(lvm2_log_fn); /* * Ignore non-error messages, but store the latest one for returning * to the user. */ if (level != _LOG_ERR && level != _LOG_FATAL) return; strncpy(last_error, message, sizeof(last_error)); last_error[sizeof(last_error)-1] = '\0'; } /* This checks some basic cluster-LVM configuration stuff */ static void check_config(void) { int locking_type; locking_type = find_config_tree_int(cmd, "global/locking_type", 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); release_vg(vg); dm_pool_empty(cmd->mem); pthread_mutex_unlock(&lvm_lock); } struct dm_hash_node *get_next_excl_lock(struct dm_hash_node *v, char **name) { struct lv_info *lvi; *name = NULL; if (!v) v = dm_hash_get_first(lv_hash); do { if (v) { lvi = dm_hash_get_data(lv_hash, v); DEBUGLOG("Looking for EX locks. found %x mode %d\n", lvi->lock_id, lvi->lock_mode); if (lvi->lock_mode == LCK_EXCL) { *name = dm_hash_get_key(lv_hash, v); } v = dm_hash_get_next(lv_hash, v); } } while (v && !*name); if (*name) DEBUGLOG("returning EXclusive UUID %s\n", *name); return v; } void lvm_do_fs_unlock(void) { pthread_mutex_lock(&lvm_lock); DEBUGLOG("Syncing device names\n"); fs_unlock(); pthread_mutex_unlock(&lvm_lock); } /* Called to initialise the LVM context of the daemon */ int init_clvm(struct dm_hash_table *excl_uuid) { /* Use LOG_DAEMON for syslog messages instead of LOG_USER */ init_syslog(LOG_DAEMON); openlog("clvmd", LOG_PID, LOG_DAEMON); /* Initialise already held locks */ if (!get_initial_state(excl_uuid)) log_error("Cannot load initial lock states."); if (!(cmd = create_toolcontext(1, NULL, 0, 1))) { log_error("Failed to allocate command context"); return 0; } if (stored_errno()) { destroy_toolcontext(cmd); return 0; } cmd->cmd_line = "clvmd"; /* Check lvm.conf is setup for cluster-LVM */ check_config(); init_ignore_suspended_devices(1); /* Trap log messages so we can pass them back to the user */ init_log_fn(lvm2_log_fn); memlock_inc_daemon(cmd); return 1; } void destroy_lvm(void) { if (cmd) { memlock_dec_daemon(cmd); destroy_toolcontext(cmd); } cmd = NULL; } lvm2-2.02.98/daemons/clvmd/clvmd-cman.c0000640000175000017500000002717112037016272016440 0ustar blankblank/* * 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 #include "clvmd-comms.h" #include "clvm.h" #include "clvmd.h" #include "lvm-functions.h" #include #include #define LOCKSPACE_NAME "clvmd" struct clvmd_node { struct cman_node *node; int clvmd_up; }; static int num_nodes; static struct cman_node *nodes = NULL; static struct cman_node this_node; static int count_nodes; /* size of allocated nodes array */ static struct dm_hash_table *node_updown_hash; static dlm_lshandle_t *lockspace; static cman_handle_t c_handle; static void count_clvmds_running(void); static void get_members(void); static int nodeid_from_csid(const char *csid); static int name_from_nodeid(int nodeid, char *name); static void event_callback(cman_handle_t handle, void *private, int reason, int arg); static void data_callback(cman_handle_t handle, void *private, char *buf, int len, uint8_t port, int nodeid); struct lock_wait { pthread_cond_t cond; pthread_mutex_t mutex; struct dlm_lksb lksb; }; static int _init_cluster(void) { node_updown_hash = dm_hash_create(100); /* Open the cluster communication socket */ c_handle = cman_init(NULL); if (!c_handle) { syslog(LOG_ERR, "Can't open cluster manager socket: %m"); return -1; } DEBUGLOG("Connected to CMAN\n"); if (cman_start_recv_data(c_handle, data_callback, CLUSTER_PORT_CLVMD)) { syslog(LOG_ERR, "Can't bind cluster socket: %m"); return -1; } if (cman_start_notification(c_handle, event_callback)) { syslog(LOG_ERR, "Can't start cluster event listening"); return -1; } /* Get the cluster members list */ get_members(); count_clvmds_running(); DEBUGLOG("CMAN initialisation complete\n"); /* Create a lockspace for LV & VG locks to live in */ lockspace = dlm_open_lockspace(LOCKSPACE_NAME); if (!lockspace) { lockspace = dlm_create_lockspace(LOCKSPACE_NAME, 0600); if (!lockspace) { syslog(LOG_ERR, "Unable to create DLM lockspace for CLVM: %m"); return -1; } DEBUGLOG("Created DLM lockspace for CLVMD.\n"); } else DEBUGLOG("Opened existing DLM lockspace for CLVMD.\n"); dlm_ls_pthread_init(lockspace); DEBUGLOG("DLM initialisation complete\n"); return 0; } static void _cluster_init_completed(void) { clvmd_cluster_init_completed(); } static int _get_main_cluster_fd() { 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= 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 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 = { .name = "cman", .cluster_init_completed = _cluster_init_completed, .cluster_send_message = _cluster_send_message, .name_from_csid = _name_from_csid, .csid_from_name = _csid_from_name, .get_num_nodes = _get_num_nodes, .cluster_fd_callback = _cluster_fd_callback, .get_main_cluster_fd = _get_main_cluster_fd, .cluster_do_node_callback = _cluster_do_node_callback, .is_quorate = _is_quorate, .get_our_csid = _get_our_csid, .add_up_node = _add_up_node, .cluster_closedown = _cluster_closedown, .get_cluster_name = _get_cluster_name, .sync_lock = _sync_lock, .sync_unlock = _sync_unlock, }; struct cluster_ops *init_cman_cluster(void) { if (!_init_cluster()) return &_cluster_cman_ops; else return NULL; } lvm2-2.02.98/daemons/clvmd/refresh_clvmd.c0000640000175000017500000002173212037016272017237 0ustar blankblank/* * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved. * Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU General Public License v.2. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* FIXME Remove duplicated functions from this file. */ /* * Send a command to a running clvmd from the command-line */ #include "clvmd-common.h" #include "clvm.h" #include "refresh_clvmd.h" #include #include #include typedef struct lvm_response { char node[255]; char *response; int status; int len; } lvm_response_t; /* * This gets stuck at the start of memory we allocate so we * can sanity-check it at deallocation time */ #define LVM_SIGNATURE 0x434C564D static int _clvmd_sock = -1; /* Open connection to the clvm daemon */ static int _open_local_sock(void) { int local_socket; struct sockaddr_un sockaddr = { .sun_family = AF_UNIX }; if (!dm_strncpy(sockaddr.sun_path, CLVMD_SOCKNAME, sizeof(sockaddr.sun_path))) { fprintf(stderr, "%s: clvmd socket name too long.", CLVMD_SOCKNAME); return -1; } /* Open local socket */ if ((local_socket = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { fprintf(stderr, "Local socket creation failed: %s", strerror(errno)); return -1; } if (connect(local_socket,(struct sockaddr *) &sockaddr, sizeof(sockaddr))) { int saved_errno = errno; fprintf(stderr, "connect() failed on local socket: %s\n", strerror(errno)); if (close(local_socket)) return -1; errno = saved_errno; return -1; } return local_socket; } /* Send a request and return the status */ static int _send_request(const char *inbuf, int inlen, char **retbuf, int no_response) { char outbuf[PIPE_BUF]; struct clvm_header *outheader = (struct clvm_header *) outbuf; int len; unsigned off; int buflen; int err; /* Send it to CLVMD */ rewrite: if ( (err = write(_clvmd_sock, inbuf, inlen)) != inlen) { if (err == -1 && errno == EINTR) goto rewrite; fprintf(stderr, "Error writing data to clvmd: %s", strerror(errno)); return 0; } if (no_response) return 1; /* Get the response */ reread: if ((len = read(_clvmd_sock, outbuf, sizeof(struct clvm_header))) < 0) { if (errno == EINTR) goto reread; fprintf(stderr, "Error reading data from clvmd: %s", strerror(errno)); return 0; } if (len == 0) { fprintf(stderr, "EOF reading CLVMD"); errno = ENOTCONN; return 0; } /* Allocate buffer */ buflen = len + outheader->arglen; *retbuf = dm_malloc(buflen); if (!*retbuf) { errno = ENOMEM; return 0; } /* Copy the header */ memcpy(*retbuf, outbuf, len); outheader = (struct clvm_header *) *retbuf; /* Read the returned values */ off = 1; /* we've already read the first byte */ while (off <= outheader->arglen && len > 0) { len = read(_clvmd_sock, outheader->args + off, buflen - off - offsetof(struct clvm_header, args)); if (len > 0) off += len; } /* Was it an error ? */ if (outheader->status != 0) { errno = outheader->status; /* Only return an error here if there are no node-specific errors present in the message that might have more detail */ if (!(outheader->flags & CLVMD_FLAG_NODEERRS)) { fprintf(stderr, "cluster request failed: %s\n", strerror(errno)); return 0; } } return 1; } /* Build the structure header and parse-out wildcard node names */ static void _build_header(struct clvm_header *head, int cmd, const char *node, unsigned int len) { head->cmd = cmd; head->status = 0; head->flags = 0; head->xid = 0; head->clientid = 0; if (len) /* 1 byte is used from struct clvm_header.args[1], so -> len - 1 */ head->arglen = len - 1; else { head->arglen = 0; *head->args = '\0'; } /* * Translate special node names. */ if (!node || !strcmp(node, NODE_ALL)) head->node[0] = '\0'; else if (!strcmp(node, NODE_LOCAL)) { head->node[0] = '\0'; head->flags = CLVMD_FLAG_LOCAL; } else strcpy(head->node, node); } /* * Send a message to a(or all) node(s) in the cluster and wait for replies */ static int _cluster_request(char cmd, const char *node, void *data, int len, lvm_response_t ** response, int *num, int no_response) { char outbuf[sizeof(struct clvm_header) + len + strlen(node) + 1]; char *inptr; char *retbuf = NULL; int status; int i; int num_responses = 0; struct clvm_header *head = (struct clvm_header *) outbuf; lvm_response_t *rarray; *num = 0; if (_clvmd_sock == -1) _clvmd_sock = _open_local_sock(); if (_clvmd_sock == -1) return 0; _build_header(head, cmd, node, len); if (len) memcpy(head->node + strlen(head->node) + 1, data, len); status = _send_request(outbuf, sizeof(struct clvm_header) + strlen(head->node) + len, &retbuf, no_response); if (!status || no_response) goto out; /* Count the number of responses we got */ head = (struct clvm_header *) retbuf; inptr = head->args; while (inptr[0]) { num_responses++; inptr += strlen(inptr) + 1; inptr += sizeof(int); inptr += strlen(inptr) + 1; } /* * Allocate response array. * With an extra pair of INTs on the front to sanity * check the pointer when we are given it back to free */ *response = 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 ? NODE_ALL : NODE_LOCAL, args, 0, &response, &num_responses, 0); /* If any nodes were down then display them and return an error */ for (i = 0; i < num_responses; i++) { if (response[i].status == EHOSTDOWN) { fprintf(stderr, "clvmd not running on node %s", response[i].node); status = 0; errno = response[i].status; } else if (response[i].status) { fprintf(stderr, "Error resetting node %s: %s", response[i].node, response[i].response[0] ? response[i].response : strerror(response[i].status)); status = 0; errno = response[i].status; } } saved_errno = errno; _cluster_free_request(response, num_responses); errno = saved_errno; return status; } int restart_clvmd(int all_nodes) { int dummy, status; status = _cluster_request(CLVMD_CMD_RESTART, all_nodes ? NODE_ALL : NODE_LOCAL, NULL, 0, NULL, &dummy, 1); /* * FIXME: we cannot receive response, clvmd re-exec before it. * but also should not close socket too early (the whole rq is dropped then). * FIXME: This should be handled this way: * - client waits for RESTART ack (and socket close) * - server restarts * - client checks that server is ready again (VERSION command?) */ usleep(500000); return status; } int debug_clvmd(int level, int clusterwide) { int num_responses; char args[1]; const char *nodes; lvm_response_t *response = NULL; int saved_errno; int status; int i; args[0] = level; if (clusterwide) nodes = NODE_ALL; else nodes = NODE_LOCAL; status = _cluster_request(CLVMD_CMD_SET_DEBUG, nodes, args, 1, &response, &num_responses, 0); /* If any nodes were down then display them and return an error */ for (i = 0; i < num_responses; i++) { if (response[i].status == EHOSTDOWN) { fprintf(stderr, "clvmd not running on node %s", response[i].node); status = 0; errno = response[i].status; } else if (response[i].status) { fprintf(stderr, "Error setting debug on node %s: %s", response[i].node, response[i].response[0] ? response[i].response : strerror(response[i].status)); status = 0; errno = response[i].status; } } saved_errno = errno; _cluster_free_request(response, num_responses); errno = saved_errno; return status; } lvm2-2.02.98/daemons/clvmd/clvmd-corosync.c0000640000175000017500000003773412037016272017367 0ustar blankblank/* * Copyright (C) 2009-2012 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU Lesser General Public License v.2.1. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * This provides the interface between clvmd and corosync/DLM as the cluster * and lock manager. */ #include "clvmd-common.h" #include #include "clvm.h" #include "clvmd-comms.h" #include "clvmd.h" #include "lvm-functions.h" #include "locking.h" #include #include #ifdef HAVE_COROSYNC_CONFDB_H # include #elif defined HAVE_COROSYNC_CMAP_H # include #else # error "Either HAVE_COROSYNC_CONFDB_H or HAVE_COROSYNC_CMAP_H must be defined." #endif #include #include /* 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; inodeid = joined_list[i].nodeid; dm_hash_insert_binary(node_hash, (char *)&ninfo->nodeid, COROSYNC_CSID_LEN, ninfo); } } ninfo->state = NODE_CLVMD; } for (i=0; istate = NODE_DOWN; } for (i=0; inodeid = 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; #ifdef QUORUM_SET /* corosync/quorum.h */ uint32_t quorum_type; #endif node_hash = dm_hash_create(100); err = cpg_initialize(&cpg_handle, &corosync_cpg_callbacks); if (err != CS_OK) { syslog(LOG_ERR, "Cannot initialise Corosync CPG service: %d", err); DEBUGLOG("Cannot initialise Corosync CPG service: %d", err); return cs_to_errno(err); } #ifdef QUORUM_SET err = quorum_initialize(&quorum_handle, &quorum_callbacks, &quorum_type); if (quorum_type != QUORUM_SET) { syslog(LOG_ERR, "Corosync quorum service is not configured"); DEBUGLOG("Corosync quorum service is not configured"); return EINVAL; } #else err = quorum_initialize(&quorum_handle, &quorum_callbacks); #endif if (err != CS_OK) { syslog(LOG_ERR, "Cannot initialise Corosync quorum service: %d", err); DEBUGLOG("Cannot initialise Corosync quorum service: %d", err); return cs_to_errno(err); } /* Create a lockspace for LV & VG locks to live in */ lockspace = dlm_open_lockspace(LOCKSPACE_NAME); if (!lockspace) { lockspace = dlm_create_lockspace(LOCKSPACE_NAME, 0600); if (!lockspace) { syslog(LOG_ERR, "Unable to create DLM lockspace for CLVM: %m"); return -1; } DEBUGLOG("Created DLM lockspace for CLVMD.\n"); } else DEBUGLOG("Opened existing DLM lockspace for CLVMD.\n"); dlm_ls_pthread_init(lockspace); DEBUGLOG("DLM initialisation complete\n"); /* Connect to the clvmd group */ strcpy((char *)cpg_group_name.value, "clvmd"); cpg_group_name.length = strlen((char *)cpg_group_name.value); err = cpg_join(cpg_handle, &cpg_group_name); if (err != CS_OK) { cpg_finalize(cpg_handle); quorum_finalize(quorum_handle); dlm_release_lockspace(LOCKSPACE_NAME, lockspace, 1); syslog(LOG_ERR, "Cannot join clvmd process group"); DEBUGLOG("Cannot join clvmd process group: %d\n", err); return cs_to_errno(err); } err = cpg_local_get(cpg_handle, &our_nodeid); if (err != CS_OK) { cpg_finalize(cpg_handle); quorum_finalize(quorum_handle); dlm_release_lockspace(LOCKSPACE_NAME, lockspace, 1); syslog(LOG_ERR, "Cannot get local node id\n"); return cs_to_errno(err); } DEBUGLOG("Our local node id is %d\n", our_nodeid); DEBUGLOG("Connected to Corosync\n"); return 0; } static void _cluster_closedown(void) { 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); } #ifdef HAVE_COROSYNC_CONFDB_H /* * We are not necessarily connected to a Red Hat Cluster system, * but if we are, this returns the cluster name from cluster.conf. * I've used confdb rather than ccs to reduce the inter-package * dependancies as well as to allow people to set a cluster name * for themselves even if they are not running on RH cluster. */ static int _get_cluster_name(char *buf, int buflen) { confdb_handle_t handle; int result; size_t namelen = buflen; hdb_handle_t cluster_handle; confdb_callbacks_t callbacks = { .confdb_key_change_notify_fn = NULL, .confdb_object_create_change_notify_fn = NULL, .confdb_object_delete_change_notify_fn = NULL }; /* This is a default in case everything else fails */ strncpy(buf, "Corosync", buflen); /* Look for a cluster name in confdb */ result = confdb_initialize (&handle, &callbacks); if (result != CS_OK) return 0; result = confdb_object_find_start(handle, OBJECT_PARENT_HANDLE); if (result != CS_OK) goto out; result = confdb_object_find(handle, OBJECT_PARENT_HANDLE, (void *)"cluster", strlen("cluster"), &cluster_handle); if (result != CS_OK) goto out; result = confdb_key_get(handle, cluster_handle, (void *)"name", strlen("name"), buf, &namelen); if (result != CS_OK) goto out; buf[namelen] = '\0'; out: confdb_finalize(handle); return 0; } #elif defined HAVE_COROSYNC_CMAP_H static int _get_cluster_name(char *buf, int buflen) { cmap_handle_t cmap_handle = 0; int result; char *name = NULL; /* This is a default in case everything else fails */ strncpy(buf, "Corosync", buflen); /* Look for a cluster name in cmap */ result = cmap_initialize(&cmap_handle); if (result != CS_OK) return 0; result = cmap_get_string(cmap_handle, "totem.cluster_name", &name); if (result != CS_OK) goto out; memset(buf, 0, buflen); strncpy(buf, name, buflen - 1); out: if (name) free(name); cmap_finalize(cmap_handle); return 0; } #endif static struct cluster_ops _cluster_corosync_ops = { .name = "corosync", .cluster_init_completed = NULL, .cluster_send_message = _cluster_send_message, .name_from_csid = _name_from_csid, .csid_from_name = _csid_from_name, .get_num_nodes = _get_num_nodes, .cluster_fd_callback = _cluster_fd_callback, .get_main_cluster_fd = _get_main_cluster_fd, .cluster_do_node_callback = _cluster_do_node_callback, .is_quorate = _is_quorate, .get_our_csid = _get_our_csid, .add_up_node = _add_up_node, .reread_config = NULL, .cluster_closedown = _cluster_closedown, .get_cluster_name = _get_cluster_name, .sync_lock = _lock_resource, .sync_unlock = _unlock_resource, }; struct cluster_ops *init_corosync_cluster(void) { if (!_init_cluster()) return &_cluster_corosync_ops; else return NULL; } lvm2-2.02.98/daemons/clvmd/Makefile.in0000640000175000017500000000507612037016272016320 0ustar blankblank# # Copyright (C) 2004 Red Hat, Inc. All rights reserved. # # This file is part of LVM2. # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions # of the GNU General Public License v.2. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation, # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA srcdir = @srcdir@ top_srcdir = @top_srcdir@ top_builddir = @top_builddir@ CMAN_LIBS = @CMAN_LIBS@ CMAN_CFLAGS = @CMAN_CFLAGS@ CMAP_LIBS = @CMAP_LIBS@ CMAP_CFLAGS = @CMAP_CFLAGS@ CONFDB_LIBS = @CONFDB_LIBS@ CONFDB_CFLAGS = @CONFDB_CFLAGS@ CPG_LIBS = @CPG_LIBS@ CPG_CFLAGS = @CPG_CFLAGS@ DLM_LIBS = @DLM_LIBS@ DLM_CFLAGS = @DLM_CFLAGS@ QUORUM_LIBS = @QUORUM_LIBS@ QUORUM_CFLAGS = @QUORUM_CFLAGS@ SALCK_LIBS = @SALCK_LIBS@ SALCK_CFLAGS = @SALCK_CFLAGS@ SOURCES = \ clvmd-command.c \ clvmd.c \ lvm-functions.c \ refresh_clvmd.c ifeq ("@DEBUG@", "yes") DEFS += -DDEBUG endif ifneq (,$(findstring cman,, "@CLVMD@,")) SOURCES += clvmd-cman.c LMLIBS += $(CMAN_LIBS) $(CONFDB_LIBS) $(DLM_LIBS) CFLAGS += $(CMAN_CFLAGS) $(CONFDB_CFLAGS) $(DLM_CFLAGS) DEFS += -DUSE_CMAN endif ifneq (,$(findstring openais,, "@CLVMD@,")) SOURCES += clvmd-openais.c LMLIBS += $(CONFDB_LIBS) $(CPG_LIBS) $(SALCK_LIBS) CFLAGS += $(CONFDB_CFLAGS) $(CPG_CFLAGS) $(SALCK_CFLAGS) DEFS += -DUSE_OPENAIS endif ifneq (,$(findstring corosync,, "@CLVMD@,")) SOURCES += clvmd-corosync.c LMLIBS += $(CMAP_LIBS) $(CONFDB_LIBS) $(CPG_LIBS) $(DLM_LIBS) $(QUORUM_LIBS) CFLAGS += $(CMAP_CFLAGS) $(CONFDB_CFLAGS) $(CPG_CFLAGS) $(DLM_CFLAGS) $(QUORUM_CFLAGS) DEFS += -DUSE_COROSYNC endif ifneq (,$(findstring singlenode,, "@CLVMD@,")) SOURCES += clvmd-singlenode.c DEFS += -DUSE_SINGLENODE endif ifeq ($(MAKECMDGOALS),distclean) SOURCES += clvmd-cman.c SOURCES += clvmd-openais.c SOURCES += clvmd-corosync.c SOURCES += clvmd-singlenode.c endif TARGETS = \ clvmd LVMLIBS = $(LVMINTERNAL_LIBS) ifeq ("@DMEVENTD@", "yes") LVMLIBS += -ldevmapper-event endif include $(top_builddir)/make.tmpl LVMLIBS += -ldevmapper LIBS += $(PTHREAD_LIBS) 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) lvm2-2.02.98/daemons/clvmd/lvm-functions.h0000640000175000017500000000300412037016272017215 0ustar blankblank/* * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved. * Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU General Public License v.2. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* Functions in lvm-functions.c */ #ifndef _LVM_FUNCTIONS_H #define _LVM_FUNCTIONS_H extern int pre_lock_lv(unsigned char lock_cmd, unsigned char lock_flags, char *resource); extern int do_lock_lv(unsigned char lock_cmd, unsigned char lock_flags, char *resource); extern const char *do_lock_query(char *resource); extern int post_lock_lv(unsigned char lock_cmd, unsigned char lock_flags, char *resource); extern int do_check_lvm1(const char *vgname); extern int do_refresh_cache(void); extern int init_clvm(struct dm_hash_table *excl_uuid); extern void destroy_lvm(void); extern void init_lvhash(void); extern void destroy_lvhash(void); extern void lvm_do_backup(const char *vgname); extern char *get_last_lvm_error(void); extern void do_lock_vg(unsigned char command, unsigned char lock_flags, char *resource); extern struct dm_hash_node *get_next_excl_lock(struct dm_hash_node *v, char **name); void lvm_do_fs_unlock(void); #endif lvm2-2.02.98/daemons/clvmd/clvmd.h0000640000175000017500000000762312037016272015531 0ustar blankblank/* * 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, char *buf, int len, const char *csid); extern void debuglog(const char *fmt, ... ) __attribute__ ((format(printf, 1, 2))); void clvmd_set_debug(debug_t new_de); debug_t clvmd_get_debug(void); int sync_lock(const char *resource, int mode, int flags, int *lockid); int sync_unlock(const char *resource, int lockid); #endif lvm2-2.02.98/daemons/clvmd/clvmd-singlenode.c0000640000175000017500000001661212037016272017647 0ustar blankblank/* * 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 #include "locking.h" #include "clvm.h" #include "clvmd-comms.h" #include "lvm-functions.h" #include "clvmd.h" #include #include #include static const char SINGLENODE_CLVMD_SOCKNAME[] = DEFAULT_RUN_DIR "/clvmd_singlenode.sock"; static int listen_fd = -1; static struct dm_hash_table *_locks; static int _lockid; struct lock { int lockid; int mode; int excl; }; static void close_comms(void) { if (listen_fd != -1 && close(listen_fd)) stack; (void)unlink(SINGLENODE_CLVMD_SOCKNAME); listen_fd = -1; } static int init_comms(void) { mode_t old_mask; struct sockaddr_un addr = { .sun_family = AF_UNIX }; if (!dm_strncpy(addr.sun_path, SINGLENODE_CLVMD_SOCKNAME, sizeof(addr.sun_path))) { DEBUGLOG("%s: singlenode socket name too long.", SINGLENODE_CLVMD_SOCKNAME); return -1; } close_comms(); (void) dm_prepare_selinux_context(SINGLENODE_CLVMD_SOCKNAME, S_IFSOCK); old_mask = umask(0077); listen_fd = socket(PF_UNIX, SOCK_STREAM, 0); if (listen_fd < 0) { DEBUGLOG("Can't create local socket: %s\n", strerror(errno)); goto error; } /* Set Close-on-exec */ if (fcntl(listen_fd, F_SETFD, 1)) { DEBUGLOG("Setting CLOEXEC on client fd failed: %s\n", strerror(errno)); goto error; } if (bind(listen_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { DEBUGLOG("Can't bind local socket: %s\n", strerror(errno)); goto error; } if (listen(listen_fd, 10) < 0) { DEBUGLOG("Can't listen local socket: %s\n", strerror(errno)); goto error; } umask(old_mask); (void) dm_prepare_selinux_context(NULL, 0); return 0; error: umask(old_mask); (void) dm_prepare_selinux_context(NULL, 0); close_comms(); return -1; } static int _init_cluster(void) { int r; if (!(_locks = dm_hash_create(128))) { DEBUGLOG("Failed to allocate single-node hash table.\n"); return 1; } r = init_comms(); if (r) { dm_hash_destroy(_locks); return r; } DEBUGLOG("Single-node cluster initialised.\n"); return 0; } static void _cluster_closedown(void) { close_comms(); DEBUGLOG("cluster_closedown\n"); destroy_lvhash(); dm_hash_destroy(_locks); _locks = NULL; _lockid = 0; } 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 pthread_mutex_t _lock_mutex = PTHREAD_MUTEX_INITIALIZER; /* Using one common condition for all locks for simplicity */ static pthread_cond_t _lock_cond = PTHREAD_COND_INITIALIZER; /* Real locking */ static int _lock_resource(const char *resource, int mode, int flags, int *lockid) { struct lock *lck; DEBUGLOG("Locking resource %s, flags=%d, mode=%d\n", resource, flags, mode); mode &= LCK_TYPE_MASK; pthread_mutex_lock(&_lock_mutex); retry: if (!(lck = dm_hash_lookup(_locks, resource))) { /* Add new locked resource */ if (!(lck = dm_zalloc(sizeof(struct lock))) || !dm_hash_insert(_locks, resource, lck)) goto bad; lck->lockid = ++_lockid; goto out; } /* Update/convert lock */ if (flags == LCKF_CONVERT) { if (lck->excl) mode = LCK_EXCL; } else if ((lck->mode == LCK_WRITE) || (lck->mode == LCK_EXCL)) { DEBUGLOG("Resource %s already %s locked (%d)...\n", resource, (lck->mode == LCK_WRITE) ? "write" : "exclusively", lck->lockid); goto maybe_retry; } else if (lck->mode > mode) { DEBUGLOG("Resource %s already locked and %s lock requested...\n", resource, (mode == LCK_READ) ? "READ" : (mode == LCK_WRITE) ? "WRITE" : "EXCLUSIVE"); goto maybe_retry; } out: *lockid = lck->lockid; lck->mode = mode; lck->excl |= (mode == LCK_EXCL); DEBUGLOG("Locked resource %s, lockid=%d, mode=%d\n", resource, lck->lockid, mode); pthread_cond_broadcast(&_lock_cond); /* wakeup waiters */ pthread_mutex_unlock(&_lock_mutex); return 0; maybe_retry: if (!(flags & LCK_NONBLOCK)) { pthread_cond_wait(&_lock_cond, &_lock_mutex); DEBUGLOG("Resource %s RETRYING lock...\n", resource); goto retry; } bad: DEBUGLOG("Failed to lock resource %s\n", resource); pthread_mutex_unlock(&_lock_mutex); return 1; /* fail */ } static int _unlock_resource(const char *resource, int lockid) { struct lock *lck; if (lockid < 0) { DEBUGLOG("Not tracking unlock of lockid -1: %s, lockid=%d\n", resource, lockid); return 0; } DEBUGLOG("Unlocking resource %s, lockid=%d\n", resource, lockid); pthread_mutex_lock(&_lock_mutex); if (!(lck = dm_hash_lookup(_locks, resource))) { pthread_mutex_unlock(&_lock_mutex); DEBUGLOG("Resource %s, lockid=%d is not locked.\n", resource, lockid); return 1; } if (lck->lockid != lockid) { pthread_mutex_unlock(&_lock_mutex); DEBUGLOG("Resource %s has wrong lockid %d, expected %d.\n", resource, lck->lockid, lockid); return 1; } dm_hash_remove(_locks, resource); dm_free(lck); pthread_cond_broadcast(&_lock_cond); /* wakeup waiters */ pthread_mutex_unlock(&_lock_mutex); 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 = { .name = "singlenode", .cluster_init_completed = NULL, .cluster_send_message = _cluster_send_message, .name_from_csid = _name_from_csid, .csid_from_name = _csid_from_name, .get_num_nodes = _get_num_nodes, .cluster_fd_callback = _cluster_fd_callback, .get_main_cluster_fd = _get_main_cluster_fd, .cluster_do_node_callback = _cluster_do_node_callback, .is_quorate = _is_quorate, .get_our_csid = _get_our_csid, .add_up_node = _add_up_node, .reread_config = NULL, .cluster_closedown = _cluster_closedown, .get_cluster_name = _get_cluster_name, .sync_lock = _lock_resource, .sync_unlock = _unlock_resource, }; struct cluster_ops *init_singlenode_cluster(void) { if (!_init_cluster()) return &_cluster_singlenode_ops; else return NULL; } lvm2-2.02.98/daemons/clvmd/clvmd.c0000640000175000017500000017460312037016272015527 0ustar blankblank/* * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved. * Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU General Public License v.2. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * CLVMD: Cluster LVM daemon */ #include "clvmd-common.h" #include #include #include "clvmd-comms.h" #include "clvm.h" #include "clvmd.h" #include "lvm-functions.h" #include "lvm-version.h" #include "refresh_clvmd.h" #ifdef HAVE_COROSYNC_CONFDB_H #include #endif #include #include #include #include #include #include #include #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif #define MAX_RETRIES 4 #define MAX_MISSING_LEN 8000 /* Max supported clvmd message size ? */ #define ISLOCAL_CSID(c) (memcmp(c, our_csid, max_csid_len) == 0) /* Head of the fd list. Also contains the cluster_socket details */ static struct local_client local_client_head; static unsigned short global_xid = 0; /* Last transaction ID issued */ struct cluster_ops *clops = NULL; static char our_csid[MAX_CSID_LEN]; static unsigned max_csid_len; static unsigned max_cluster_message; static unsigned max_cluster_member_name_len; /* Structure of items on the LVM thread list */ struct lvm_thread_cmd { struct dm_list list; struct local_client *client; struct clvm_header *msg; char csid[MAX_CSID_LEN]; int remote; /* Flag */ int msglen; unsigned short xid; }; struct lvm_startup_params { struct dm_hash_table *excl_uuid; }; static debug_t debug = DEBUG_OFF; static int foreground_mode = 0; static pthread_t lvm_thread; /* Stack size 128KiB for thread, must be bigger then DEFAULT_RESERVED_STACK */ static const size_t STACK_SIZE = 128 * 1024; static pthread_attr_t stack_attr; static pthread_mutex_t lvm_thread_mutex; static pthread_cond_t lvm_thread_cond; static pthread_barrier_t lvm_start_barrier; static struct dm_list lvm_cmd_head; static volatile sig_atomic_t quit = 0; static volatile sig_atomic_t reread_config = 0; static int child_pipe[2]; /* Reasons the daemon failed initialisation */ #define DFAIL_INIT 1 #define DFAIL_LOCAL_SOCK 2 #define DFAIL_CLUSTER_IF 3 #define DFAIL_MALLOC 4 #define DFAIL_TIMEOUT 5 #define SUCCESS 0 typedef enum {IF_AUTO, IF_CMAN, IF_OPENAIS, IF_COROSYNC, IF_SINGLENODE} if_type_t; /* Prototypes for code further down */ static void sigusr2_handler(int sig); static void sighup_handler(int sig); static void sigterm_handler(int sig); static void send_local_reply(struct local_client *client, int status, int clientid); static void free_reply(struct local_client *client); static void send_version_message(void); static void *pre_and_post_thread(void *arg); static int send_message(void *buf, int msglen, const char *csid, int fd, const char *errtext); static int read_from_local_sock(struct local_client *thisfd); static int process_local_command(struct clvm_header *msg, int msglen, struct local_client *client, unsigned short xid); static void process_remote_command(struct clvm_header *msg, int msglen, int fd, const char *csid); static int process_reply(const struct clvm_header *msg, int msglen, const char *csid); static int open_local_sock(void); static void close_local_sock(int local_socket); static int check_local_clvmd(void); static struct local_client *find_client(int clientid); static void main_loop(int local_sock, int cmd_timeout); static void be_daemon(int start_timeout); static int check_all_clvmds_running(struct local_client *client); static int local_rendezvous_callback(struct local_client *thisfd, char *buf, int len, const char *csid, struct local_client **new_client); static void *lvm_thread_fn(void *) __attribute__((noreturn)); static int add_to_lvmqueue(struct local_client *client, struct clvm_header *msg, int msglen, const char *csid); static int distribute_command(struct local_client *thisfd); static void hton_clvm(struct clvm_header *hdr); static void ntoh_clvm(struct clvm_header *hdr); static void add_reply_to_list(struct local_client *client, int status, const char *csid, const char *buf, int len); static if_type_t parse_cluster_interface(char *ifname); static if_type_t get_cluster_type(void); static void usage(const char *prog, FILE *file) { fprintf(file, "Usage: %s [options]\n" " -V Show version of clvmd\n" " -h Show this help information\n" " -d[n] Set debug logging (0:none, 1:stderr (implies -f option), 2:syslog)\n" " -f Don't fork, run in the foreground\n" " -E Take this lock uuid as exclusively locked resource (for restart)\n" " -R Tell all running clvmds in the cluster to reload their device cache\n" " -S Restart clvmd, preserving exclusive locks\n" " -C Sets debug level (from -d) on all clvmd instances clusterwide\n" " -t Command timeout (default 60 seconds)\n" " -T Startup timeout (default none)\n" " -I Cluster manager (default: auto)\n" " Available cluster managers: " #ifdef USE_COROSYNC "corosync " #endif #ifdef USE_CMAN "cman " #endif #ifdef USE_OPENAIS "openais " #endif #ifdef USE_SINGLENODE "singlenode " #endif "\n", prog); } /* Called to signal the parent how well we got on during initialisation */ static void child_init_signal(int status) { if (child_pipe[1]) { /* FIXME Use a proper wrapper around write */ if (write(child_pipe[1], &status, sizeof(status)) < 0) log_sys_error("write", "child_pipe"); if (close(child_pipe[1])) log_sys_error("close", "child_pipe"); } } static __attribute__((noreturn)) void child_init_signal_and_exit(int status) { child_init_signal(status); exit(status); } static void safe_close(int *fd) { if (*fd >= 0) { int to_close = *fd; *fd = -1; if (close(to_close)) log_sys_error("close", ""); /* path */ } } void debuglog(const char *fmt, ...) { time_t P; va_list ap; static int syslog_init = 0; switch (clvmd_get_debug()) { case DEBUG_STDERR: va_start(ap,fmt); time(&P); fprintf(stderr, "CLVMD[%x]: %.15s ", (int)pthread_self(), ctime(&P)+4 ); vfprintf(stderr, fmt, ap); va_end(ap); break; case DEBUG_SYSLOG: if (!syslog_init) { openlog("clvmd", LOG_PID, LOG_DAEMON); syslog_init = 1; } va_start(ap,fmt); vsyslog(LOG_DEBUG, fmt, ap); va_end(ap); break; case DEBUG_OFF: break; } } void clvmd_set_debug(debug_t new_debug) { if (!foreground_mode && new_debug == DEBUG_STDERR) new_debug = DEBUG_SYSLOG; if (new_debug > DEBUG_SYSLOG) new_debug = DEBUG_SYSLOG; debug = new_debug; } debug_t clvmd_get_debug(void) { return debug; } static const char *decode_cmd(unsigned char cmdl) { static char buf[128]; const char *command; switch (cmdl) { case CLVMD_CMD_TEST: command = "TEST"; break; case CLVMD_CMD_LOCK_VG: command = "LOCK_VG"; break; case CLVMD_CMD_LOCK_LV: command = "LOCK_LV"; break; case CLVMD_CMD_REFRESH: command = "REFRESH"; break; case CLVMD_CMD_SET_DEBUG: command = "SET_DEBUG"; break; case CLVMD_CMD_GET_CLUSTERNAME: command = "GET_CLUSTERNAME"; break; case CLVMD_CMD_VG_BACKUP: command = "VG_BACKUP"; break; case CLVMD_CMD_REPLY: command = "REPLY"; break; case CLVMD_CMD_VERSION: command = "VERSION"; break; case CLVMD_CMD_GOAWAY: command = "GOAWAY"; break; case CLVMD_CMD_LOCK: command = "LOCK"; break; case CLVMD_CMD_UNLOCK: command = "UNLOCK"; break; case CLVMD_CMD_LOCK_QUERY: command = "LOCK_QUERY"; break; case CLVMD_CMD_RESTART: command = "RESTART"; break; case CLVMD_CMD_SYNC_NAMES: command = "SYNC_NAMES"; break; default: command = "unknown"; break; } snprintf(buf, sizeof(buf), "%s (0x%x)", command, cmdl); return buf; } static void remove_lockfile(void) { if (unlink(CLVMD_PIDFILE)) log_sys_error("unlink", CLVMD_PIDFILE); } /* * clvmd require dm-ioctl capability for operation */ static void check_permissions(void) { if (getuid() || geteuid()) { log_error("Cannot run as a non-root user."); /* * Fail cleanly here if not run as root, instead of failing * later when attempting a root-only operation * Preferred exit code from an initscript for this. */ exit(4); } } int main(int argc, char *argv[]) { int local_sock; struct local_client *newfd, *delfd; struct lvm_startup_params lvm_params; int opt; int cmd_timeout = DEFAULT_CMD_TIMEOUT; int start_timeout = 0; if_type_t cluster_iface = IF_AUTO; sigset_t ss; debug_t debug_opt = DEBUG_OFF; debug_t debug_arg = DEBUG_OFF; int clusterwide_opt = 0; mode_t old_mask; int ret = 1; struct option longopts[] = { { "help", 0, 0, 'h' }, { NULL, 0, 0, 0 } }; if (!(lvm_params.excl_uuid = dm_hash_create(128))) { fprintf(stderr, "Failed to allocate hash table\n"); return 1; } /* Deal with command-line arguments */ opterr = 0; optind = 0; while ((opt = getopt_long(argc, argv, "vVhfd::t:RST:CI:E:", longopts, NULL)) != -1) { switch (opt) { case 'h': usage(argv[0], stdout); exit(0); case 'R': check_permissions(); ret = (refresh_clvmd(1) == 1) ? 0 : 1; goto out; case 'S': check_permissions(); ret = (restart_clvmd(clusterwide_opt) == 1) ? 0 : 1; goto out; case 'C': clusterwide_opt = 1; break; case 'd': debug_opt = DEBUG_STDERR; debug_arg = optarg ? (debug_t) atoi(optarg) : DEBUG_STDERR; if (debug_arg == DEBUG_STDERR) foreground_mode = 1; break; case 'f': foreground_mode = 1; break; case 't': cmd_timeout = atoi(optarg); if (!cmd_timeout) { fprintf(stderr, "command timeout is invalid\n"); usage(argv[0], stderr); exit(1); } break; case 'I': cluster_iface = parse_cluster_interface(optarg); break; case 'E': if (!dm_hash_insert(lvm_params.excl_uuid, optarg, optarg)) { fprintf(stderr, "Failed to allocate hash entry\n"); goto out; } break; case 'T': start_timeout = atoi(optarg); if (start_timeout <= 0) { fprintf(stderr, "startup timeout is invalid\n"); usage(argv[0], stderr); exit(1); } break; case 'V': printf("Cluster LVM daemon version: %s\n", LVM_VERSION); printf("Protocol version: %d.%d.%d\n", CLVMD_MAJOR_VERSION, CLVMD_MINOR_VERSION, CLVMD_PATCH_VERSION); exit(0); break; default: usage(argv[0], stderr); exit(2); } } check_permissions(); /* * Switch to C locale to avoid reading large locale-archive file * used by some glibc (on some distributions it takes over 100MB). * Daemon currently needs to use mlockall(). */ if (setenv("LANG", "C", 1)) perror("Cannot set LANG to C"); /* Setting debug options on an existing clvmd */ if (debug_opt && !check_local_clvmd()) { dm_hash_destroy(lvm_params.excl_uuid); return debug_clvmd(debug_arg, clusterwide_opt)==1?0:1; } clvmd_set_debug(debug_opt); /* Fork into the background (unless requested not to) */ if (!foreground_mode) be_daemon(start_timeout); (void) dm_prepare_selinux_context(DEFAULT_RUN_DIR, S_IFDIR); old_mask = umask(0077); if (dm_create_dir(DEFAULT_RUN_DIR) == 0) { DEBUGLOG("clvmd: unable to create %s directory\n", DEFAULT_RUN_DIR); umask(old_mask); exit(1); } umask(old_mask); /* Create pidfile */ (void) dm_prepare_selinux_context(CLVMD_PIDFILE, S_IFREG); if (dm_create_lockfile(CLVMD_PIDFILE) == 0) { DEBUGLOG("clvmd: unable to create lockfile\n"); exit(1); } (void) dm_prepare_selinux_context(NULL, 0); atexit(remove_lockfile); DEBUGLOG("CLVMD started\n"); /* Open the Unix socket we listen for commands on. We do this before opening the cluster socket so that potential clients will block rather than error if we are running but the cluster is not ready yet */ local_sock = open_local_sock(); if (local_sock < 0) { child_init_signal_and_exit(DFAIL_LOCAL_SOCK); /* NOTREACHED */ } /* Set up signal handlers, USR1 is for cluster change notifications (in cman) USR2 causes child threads to exit. (HUP used to cause gulm to re-read the nodes list from CCS.) PIPE should be ignored */ signal(SIGUSR2, sigusr2_handler); signal(SIGHUP, sighup_handler); signal(SIGPIPE, SIG_IGN); /* Block SIGUSR2/SIGINT/SIGTERM in process */ sigemptyset(&ss); sigaddset(&ss, SIGUSR2); sigaddset(&ss, SIGINT); sigaddset(&ss, SIGTERM); sigprocmask(SIG_BLOCK, &ss, NULL); /* Initialise the LVM thread variables */ dm_list_init(&lvm_cmd_head); if (pthread_attr_init(&stack_attr) || pthread_attr_setstacksize(&stack_attr, STACK_SIZE)) { log_sys_error("pthread_attr_init", ""); exit(1); } pthread_mutex_init(&lvm_thread_mutex, NULL); pthread_cond_init(&lvm_thread_cond, NULL); pthread_barrier_init(&lvm_start_barrier, NULL, 2); init_lvhash(); /* Start the cluster interface */ if (cluster_iface == IF_AUTO) cluster_iface = get_cluster_type(); #ifdef USE_CMAN if ((cluster_iface == IF_AUTO || cluster_iface == IF_CMAN) && (clops = init_cman_cluster())) { max_csid_len = CMAN_MAX_CSID_LEN; max_cluster_message = CMAN_MAX_CLUSTER_MESSAGE; max_cluster_member_name_len = CMAN_MAX_NODENAME_LEN; syslog(LOG_NOTICE, "Cluster LVM daemon started - connected to CMAN"); } #endif #ifdef USE_COROSYNC if (!clops) if (((cluster_iface == IF_AUTO || cluster_iface == IF_COROSYNC) && (clops = init_corosync_cluster()))) { max_csid_len = COROSYNC_CSID_LEN; max_cluster_message = COROSYNC_MAX_CLUSTER_MESSAGE; max_cluster_member_name_len = COROSYNC_MAX_CLUSTER_MEMBER_NAME_LEN; syslog(LOG_NOTICE, "Cluster LVM daemon started - connected to Corosync"); } #endif #ifdef USE_OPENAIS if (!clops) if ((cluster_iface == IF_AUTO || cluster_iface == IF_OPENAIS) && (clops = init_openais_cluster())) { max_csid_len = OPENAIS_CSID_LEN; max_cluster_message = OPENAIS_MAX_CLUSTER_MESSAGE; max_cluster_member_name_len = OPENAIS_MAX_CLUSTER_MEMBER_NAME_LEN; syslog(LOG_NOTICE, "Cluster LVM daemon started - connected to OpenAIS"); } #endif #ifdef USE_SINGLENODE if (!clops) if (cluster_iface == IF_SINGLENODE && (clops = init_singlenode_cluster())) { max_csid_len = SINGLENODE_CSID_LEN; max_cluster_message = SINGLENODE_MAX_CLUSTER_MESSAGE; max_cluster_member_name_len = MAX_CLUSTER_MEMBER_NAME_LEN; syslog(LOG_NOTICE, "Cluster LVM daemon started - running in single-node mode"); } #endif if (!clops) { DEBUGLOG("Can't initialise cluster interface\n"); log_error("Can't initialise cluster interface\n"); child_init_signal_and_exit(DFAIL_CLUSTER_IF); /* NOTREACHED */ } DEBUGLOG("Cluster ready, doing some more initialisation\n"); /* Save our CSID */ clops->get_our_csid(our_csid); /* Initialise the FD list head */ local_client_head.fd = clops->get_main_cluster_fd(); local_client_head.type = CLUSTER_MAIN_SOCK; local_client_head.callback = clops->cluster_fd_callback; /* Add the local socket to the list */ newfd = malloc(sizeof(struct local_client)); if (!newfd) { child_init_signal_and_exit(DFAIL_MALLOC); /* NOTREACHED */ } newfd->fd = local_sock; newfd->removeme = 0; newfd->type = LOCAL_RENDEZVOUS; newfd->callback = local_rendezvous_callback; newfd->next = local_client_head.next; local_client_head.next = newfd; /* This needs to be started after cluster initialisation as it may need to take out locks */ DEBUGLOG("starting LVM thread\n"); /* Don't let anyone else to do work until we are started */ pthread_create(&lvm_thread, &stack_attr, lvm_thread_fn, &lvm_params); /* Don't start until the LVM thread is ready */ pthread_barrier_wait(&lvm_start_barrier); /* Tell the rest of the cluster our version number */ if (clops->cluster_init_completed) clops->cluster_init_completed(); DEBUGLOG("clvmd ready for work\n"); child_init_signal(SUCCESS); /* Try to shutdown neatly */ signal(SIGTERM, sigterm_handler); signal(SIGINT, sigterm_handler); /* Do some work */ main_loop(local_sock, cmd_timeout); pthread_mutex_lock(&lvm_thread_mutex); pthread_cond_signal(&lvm_thread_cond); pthread_mutex_unlock(&lvm_thread_mutex); if ((errno = pthread_join(lvm_thread, NULL))) log_sys_error("pthread_join", ""); close_local_sock(local_sock); destroy_lvm(); for (newfd = local_client_head.next; newfd != NULL;) { delfd = newfd; newfd = newfd->next; if (delfd->fd == local_sock) delfd->fd = -1; /* * FIXME: * needs cleanup code from read_from_local_sock() for now * break of 'clvmd' may access already free memory here. */ safe_close(&(delfd->fd)); free(delfd); } ret = 0; out: dm_hash_destroy(lvm_params.excl_uuid); return ret; } /* Called when the cluster layer has completed initialisation. We send the version message */ void clvmd_cluster_init_completed(void) { send_version_message(); } /* Data on a connected socket */ static int local_sock_callback(struct local_client *thisfd, char *buf, int len, const char *csid, struct local_client **new_client) { *new_client = NULL; return read_from_local_sock(thisfd); } /* Data on a connected socket */ static int local_rendezvous_callback(struct local_client *thisfd, char *buf, int len, const char *csid, struct local_client **new_client) { /* Someone connected to our local socket, accept it. */ struct sockaddr_un socka; struct local_client *newfd; socklen_t sl = sizeof(socka); int client_fd = accept(thisfd->fd, (struct sockaddr *) &socka, &sl); if (client_fd == -1 && errno == EINTR) return 1; if (client_fd >= 0) { newfd = malloc(sizeof(struct local_client)); if (!newfd) { if (close(client_fd)) log_sys_error("close", "socket"); return 1; } if (fcntl(client_fd, F_SETFD, 1)) DEBUGLOG("setting CLOEXEC on client fd failed: %s\n", strerror(errno)); newfd->fd = client_fd; newfd->type = LOCAL_SOCK; newfd->xid = 0; newfd->removeme = 0; newfd->callback = local_sock_callback; newfd->bits.localsock.replies = NULL; newfd->bits.localsock.expected_replies = 0; newfd->bits.localsock.cmd = NULL; newfd->bits.localsock.in_progress = FALSE; newfd->bits.localsock.sent_out = FALSE; newfd->bits.localsock.threadid = 0; newfd->bits.localsock.finished = 0; newfd->bits.localsock.pipe_client = NULL; newfd->bits.localsock.private = NULL; newfd->bits.localsock.all_success = 1; DEBUGLOG("Got new connection on fd %d\n", newfd->fd); *new_client = newfd; } return 1; } static int local_pipe_callback(struct local_client *thisfd, char *buf, int maxlen, const char *csid, struct local_client **new_client) { int len; char buffer[PIPE_BUF]; struct local_client *sock_client = thisfd->bits.pipe.client; int status = -1; /* in error by default */ len = read(thisfd->fd, buffer, sizeof(int)); if (len == -1 && errno == EINTR) return 1; if (len == sizeof(int)) { memcpy(&status, buffer, sizeof(int)); } DEBUGLOG("read on PIPE %d: %d bytes: status: %d\n", thisfd->fd, len, status); /* EOF on pipe or an error, close it */ if (len <= 0) { void *ret = &status; if (close(thisfd->fd)) log_sys_error("close", "local_pipe"); /* Clear out the cross-link */ if (thisfd->bits.pipe.client != NULL) thisfd->bits.pipe.client->bits.localsock.pipe_client = NULL; /* Reap child thread */ if (thisfd->bits.pipe.threadid) { if ((errno = pthread_join(thisfd->bits.pipe.threadid, &ret))) log_sys_error("pthread_join", ""); thisfd->bits.pipe.threadid = 0; if (thisfd->bits.pipe.client != NULL) thisfd->bits.pipe.client->bits.localsock. threadid = 0; } return -1; } else { DEBUGLOG("background routine status was %d, sock_client=%p\n", status, sock_client); /* But has the client gone away ?? */ if (sock_client == NULL) { DEBUGLOG("Got PIPE response for dead client, ignoring it\n"); } else { /* If error then just return that code */ if (status) send_local_reply(sock_client, status, sock_client->fd); else { /* FIXME: closer inspect this code since state is write thread protected */ pthread_mutex_lock(&sock_client->bits.localsock.mutex); if (sock_client->bits.localsock.state == POST_COMMAND) { pthread_mutex_unlock(&sock_client->bits.localsock.mutex); send_local_reply(sock_client, 0, sock_client->fd); } else { /* PRE_COMMAND finished. */ pthread_mutex_unlock(&sock_client->bits.localsock.mutex); if ((status = distribute_command(sock_client))) send_local_reply(sock_client, EFBIG, sock_client->fd); } } } } return len; } /* If a noed is up, look for it in the reply array, if it's not there then add one with "ETIMEDOUT". NOTE: This won't race with real replies because they happen in the same thread. */ static void timedout_callback(struct local_client *client, const char *csid, int node_up) { if (node_up) { struct node_reply *reply; char nodename[max_cluster_member_name_len]; clops->name_from_csid(csid, nodename); DEBUGLOG("Checking for a reply from %s\n", nodename); pthread_mutex_lock(&client->bits.localsock.reply_mutex); reply = client->bits.localsock.replies; while (reply && strcmp(reply->node, nodename) != 0) { reply = reply->next; } pthread_mutex_unlock(&client->bits.localsock.reply_mutex); if (!reply) { DEBUGLOG("Node %s timed-out\n", nodename); add_reply_to_list(client, ETIMEDOUT, csid, "Command timed out", 18); } } } /* Called when the request has timed out on at least one node. We fill in the remaining node entries with ETIMEDOUT and return. By the time we get here the node that caused the timeout could have gone down, in which case we will never get the expected number of replies that triggers the post command so we need to do it here */ static void request_timed_out(struct local_client *client) { DEBUGLOG("Request timed-out. padding\n"); clops->cluster_do_node_callback(client, timedout_callback); if (client->bits.localsock.num_replies != client->bits.localsock.expected_replies) { /* Post-process the command */ if (client->bits.localsock.threadid) { pthread_mutex_lock(&client->bits.localsock.mutex); client->bits.localsock.state = POST_COMMAND; pthread_cond_signal(&client->bits.localsock.cond); pthread_mutex_unlock(&client->bits.localsock.mutex); } } } /* This is where the real work happens */ static void main_loop(int local_sock, int cmd_timeout) { sigset_t ss; DEBUGLOG("Using timeout of %d seconds\n", cmd_timeout); sigemptyset(&ss); sigaddset(&ss, SIGINT); sigaddset(&ss, SIGTERM); pthread_sigmask(SIG_UNBLOCK, &ss, NULL); /* Main loop */ while (!quit) { fd_set in; int select_status; struct local_client *thisfd; struct timeval tv = { cmd_timeout, 0 }; int quorate = clops->is_quorate(); /* Wait on the cluster FD and all local sockets/pipes */ local_client_head.fd = clops->get_main_cluster_fd(); FD_ZERO(&in); for (thisfd = &local_client_head; thisfd != NULL; thisfd = thisfd->next) { if (thisfd->removeme) continue; /* if the cluster is not quorate then don't listen for new requests */ if ((thisfd->type != LOCAL_RENDEZVOUS && thisfd->type != LOCAL_SOCK) || quorate) FD_SET(thisfd->fd, &in); } select_status = select(FD_SETSIZE, &in, NULL, NULL, &tv); if (reread_config) { int saved_errno = errno; reread_config = 0; if (clops->reread_config) clops->reread_config(); errno = saved_errno; } if (select_status > 0) { struct local_client *lastfd = NULL; char csid[MAX_CSID_LEN]; char buf[max_cluster_message]; for (thisfd = &local_client_head; thisfd != NULL; thisfd = thisfd->next) { if (thisfd->removeme) { struct local_client *free_fd; lastfd->next = thisfd->next; free_fd = thisfd; DEBUGLOG("removeme set for fd %d\n", free_fd->fd); /* Queue cleanup, this also frees the client struct */ add_to_lvmqueue(free_fd, NULL, 0, NULL); break; } if (FD_ISSET(thisfd->fd, &in)) { struct local_client *newfd = NULL; int ret; /* Do callback */ ret = thisfd->callback(thisfd, buf, sizeof(buf), csid, &newfd); /* Ignore EAGAIN */ if (ret < 0 && (errno == EAGAIN || errno == EINTR)) continue; /* Got error or EOF: Remove it from the list safely */ if (ret <= 0) { struct local_client *free_fd; int type = thisfd->type; /* If the cluster socket shuts down, so do we */ if (type == CLUSTER_MAIN_SOCK || type == CLUSTER_INTERNAL) goto closedown; DEBUGLOG("ret == %d, errno = %d. removing client\n", ret, errno); lastfd->next = thisfd->next; free_fd = thisfd; safe_close(&(free_fd->fd)); /* Queue cleanup, this also frees the client struct */ add_to_lvmqueue(free_fd, NULL, 0, NULL); break; } /* New client...simply add it to the list */ if (newfd) { newfd->next = thisfd->next; thisfd->next = newfd; break; } } lastfd = thisfd; } } /* Select timed out. Check for clients that have been waiting too long for a response */ if (select_status == 0) { time_t the_time = time(NULL); for (thisfd = &local_client_head; thisfd != NULL; thisfd = thisfd->next) { if (thisfd->type == LOCAL_SOCK && thisfd->bits.localsock.sent_out && thisfd->bits.localsock.sent_time + cmd_timeout < the_time && thisfd->bits.localsock. expected_replies != thisfd->bits.localsock.num_replies) { /* Send timed out message + replies we already have */ DEBUGLOG ("Request timed-out (send: %ld, now: %ld)\n", thisfd->bits.localsock.sent_time, the_time); thisfd->bits.localsock.all_success = 0; request_timed_out(thisfd); } } } if (select_status < 0) { if (errno == EINTR) continue; #ifdef DEBUG perror("select error"); exit(-1); #endif } } closedown: clops->cluster_closedown(); } static __attribute__ ((noreturn)) void wait_for_child(int c_pipe, int timeout) { int child_status; int sstat; fd_set fds; struct timeval tv = {timeout, 0}; FD_ZERO(&fds); FD_SET(c_pipe, &fds); sstat = select(c_pipe+1, &fds, NULL, NULL, timeout? &tv: NULL); if (sstat == 0) { fprintf(stderr, "clvmd startup timed out\n"); exit(DFAIL_TIMEOUT); } if (sstat == 1) { if (read(c_pipe, &child_status, sizeof(child_status)) != sizeof(child_status)) { fprintf(stderr, "clvmd failed in initialisation\n"); exit(DFAIL_INIT); } else { switch (child_status) { case SUCCESS: break; case DFAIL_INIT: fprintf(stderr, "clvmd failed in initialisation\n"); break; case DFAIL_LOCAL_SOCK: fprintf(stderr, "clvmd could not create local socket\n"); fprintf(stderr, "Another clvmd is probably already running\n"); break; case DFAIL_CLUSTER_IF: fprintf(stderr, "clvmd could not connect to cluster manager\n"); fprintf(stderr, "Consult syslog for more information\n"); break; case DFAIL_MALLOC: fprintf(stderr, "clvmd failed, not enough memory\n"); break; default: fprintf(stderr, "clvmd failed, error was %d\n", child_status); break; } exit(child_status); } } fprintf(stderr, "clvmd startup, select failed: %s\n", strerror(errno)); exit(DFAIL_INIT); } /* * Fork into the background and detach from our parent process. * In the interests of user-friendliness we wait for the daemon * to complete initialisation before returning its status * the the user. */ static void be_daemon(int timeout) { int devnull = open("/dev/null", O_RDWR); if (devnull == -1) { perror("Can't open /dev/null"); exit(3); } if (pipe(child_pipe)) { perror("Error creating pipe"); exit(3); } switch (fork()) { case -1: perror("clvmd: can't fork"); exit(2); case 0: /* Child */ (void) close(child_pipe[0]); break; default: /* Parent */ (void) close(child_pipe[1]); wait_for_child(child_pipe[0], timeout); } /* Detach ourself from the calling environment */ if (close(0) || close(1) || close(2)) { perror("Error closing terminal FDs"); exit(4); } setsid(); if (dup2(devnull, 0) < 0 || dup2(devnull, 1) < 0 || dup2(devnull, 2) < 0) { perror("Error setting terminal FDs to /dev/null"); log_error("Error setting terminal FDs to /dev/null: %m"); exit(5); } if (chdir("/")) { log_error("Error setting current directory to /: %m"); exit(6); } } /* Called when we have a read from the local socket. was in the main loop but it's grown up and is a big girl now */ static int read_from_local_sock(struct local_client *thisfd) { int len; int argslen; int missing_len; char buffer[PIPE_BUF + 1]; len = read(thisfd->fd, buffer, sizeof(buffer) - 1); if (len == -1 && errno == EINTR) return 1; DEBUGLOG("Read on local socket %d, len = %d\n", thisfd->fd, len); /* EOF or error on socket */ if (len <= 0) { int *status; DEBUGLOG("EOF on local socket: inprogress=%d\n", thisfd->bits.localsock.in_progress); thisfd->bits.localsock.finished = 1; /* If the client went away in mid command then tidy up */ if (thisfd->bits.localsock.in_progress) { pthread_kill(thisfd->bits.localsock.threadid, SIGUSR2); pthread_mutex_lock(&thisfd->bits.localsock.mutex); thisfd->bits.localsock.state = POST_COMMAND; pthread_cond_signal(&thisfd->bits.localsock.cond); pthread_mutex_unlock(&thisfd->bits.localsock.mutex); /* Free any unsent buffers */ free_reply(thisfd); } /* Kill the subthread & free resources */ if (thisfd->bits.localsock.threadid) { DEBUGLOG("Waiting for child thread\n"); pthread_mutex_lock(&thisfd->bits.localsock.mutex); thisfd->bits.localsock.state = PRE_COMMAND; pthread_cond_signal(&thisfd->bits.localsock.cond); pthread_mutex_unlock(&thisfd->bits.localsock.mutex); if ((errno = pthread_join(thisfd->bits.localsock.threadid, (void **) &status))) log_sys_error("pthread_join", ""); DEBUGLOG("Joined child thread\n"); thisfd->bits.localsock.threadid = 0; pthread_cond_destroy(&thisfd->bits.localsock.cond); pthread_mutex_destroy(&thisfd->bits.localsock.mutex); /* Remove the pipe client */ if (thisfd->bits.localsock.pipe_client != NULL) { struct local_client *newfd; struct local_client *lastfd = NULL; struct local_client *free_fd = NULL; (void) close(thisfd->bits.localsock.pipe_client->fd); /* Close pipe */ (void) close(thisfd->bits.localsock.pipe); /* Remove pipe client */ for (newfd = &local_client_head; newfd != NULL; newfd = newfd->next) { if (thisfd->bits.localsock. pipe_client == newfd) { thisfd->bits.localsock. pipe_client = NULL; lastfd->next = newfd->next; free_fd = newfd; newfd->next = lastfd; free(free_fd); break; } lastfd = newfd; } } } /* Free the command buffer */ free(thisfd->bits.localsock.cmd); /* Clear out the cross-link */ if (thisfd->bits.localsock.pipe_client != NULL) thisfd->bits.localsock.pipe_client->bits.pipe.client = NULL; safe_close(&(thisfd->fd)); return 0; } else { int comms_pipe[2]; struct local_client *newfd; char csid[MAX_CSID_LEN]; struct clvm_header *inheader; int status; buffer[len] = 0; /* Ensure \0 terminated */ inheader = (struct clvm_header *) buffer; /* Fill in the client ID */ inheader->clientid = htonl(thisfd->fd); /* If we are already busy then return an error */ if (thisfd->bits.localsock.in_progress) { struct clvm_header reply = { .cmd = CLVMD_CMD_REPLY, .status = EBUSY }; send_message(&reply, sizeof(reply), our_csid, thisfd->fd, "Error sending EBUSY reply to local user"); return len; } /* See if we have the whole message */ argslen = len - strlen(inheader->node) - sizeof(struct clvm_header); missing_len = inheader->arglen - argslen; if (missing_len < 0) missing_len = 0; /* We need at least sizeof(struct clvm_header) bytes in buffer */ if (len < sizeof(struct clvm_header) || argslen < 0 || missing_len > MAX_MISSING_LEN) { struct clvm_header reply = { .cmd = CLVMD_CMD_REPLY, .status = EINVAL }; send_message(&reply, sizeof(reply), our_csid, thisfd->fd, "Error sending EINVAL reply to local user"); return 0; } /* Free any old buffer space */ free(thisfd->bits.localsock.cmd); /* Save the message */ thisfd->bits.localsock.cmd = malloc(len + missing_len); if (!thisfd->bits.localsock.cmd) { struct clvm_header reply = { .cmd = CLVMD_CMD_REPLY, .status = ENOMEM }; send_message(&reply, sizeof(reply), our_csid, thisfd->fd, "Error sending ENOMEM reply to local user"); return 0; } memcpy(thisfd->bits.localsock.cmd, buffer, len); thisfd->bits.localsock.cmd_len = len + missing_len; inheader = (struct clvm_header *) thisfd->bits.localsock.cmd; /* If we don't have the full message then read the rest now */ if (missing_len) { char *argptr = inheader->node + strlen(inheader->node) + 1; while (missing_len > 0) { DEBUGLOG("got %d bytes, need another %d (total %d)\n", argslen, missing_len, inheader->arglen); len = read(thisfd->fd, argptr + argslen, missing_len); if (len == -1 && errno == EINTR) continue; if (len > 0) { missing_len -= len; argslen += len; } else { /* EOF or error on socket */ DEBUGLOG("EOF on local socket\n"); free(thisfd->bits.localsock.cmd); thisfd->bits.localsock.cmd = NULL; return 0; } } } /* Initialise and lock the mutex so the subthread will wait after finishing the PRE routine */ if (!thisfd->bits.localsock.threadid) { pthread_mutex_init(&thisfd->bits.localsock.mutex, NULL); pthread_cond_init(&thisfd->bits.localsock.cond, NULL); pthread_mutex_init(&thisfd->bits.localsock.reply_mutex, NULL); } /* Only run the command if all the cluster nodes are running CLVMD */ if (((inheader->flags & CLVMD_FLAG_LOCAL) == 0) && (check_all_clvmds_running(thisfd) == -1)) { thisfd->bits.localsock.expected_replies = 0; thisfd->bits.localsock.num_replies = 0; send_local_reply(thisfd, EHOSTDOWN, thisfd->fd); return len; } /* Check the node name for validity */ if (inheader->node[0] && clops->csid_from_name(csid, inheader->node)) { /* Error, node is not in the cluster */ struct clvm_header reply = { .cmd = CLVMD_CMD_REPLY, .status = ENOENT }; DEBUGLOG("Unknown node: '%s'\n", inheader->node); send_message(&reply, sizeof(reply), our_csid, thisfd->fd, "Error sending ENOENT reply to local user"); thisfd->bits.localsock.expected_replies = 0; thisfd->bits.localsock.num_replies = 0; thisfd->bits.localsock.in_progress = FALSE; thisfd->bits.localsock.sent_out = FALSE; return len; } /* If we already have a subthread then just signal it to start */ if (thisfd->bits.localsock.threadid) { pthread_mutex_lock(&thisfd->bits.localsock.mutex); thisfd->bits.localsock.state = PRE_COMMAND; pthread_cond_signal(&thisfd->bits.localsock.cond); pthread_mutex_unlock(&thisfd->bits.localsock.mutex); return len; } /* Create a pipe and add the reading end to our FD list */ if (pipe(comms_pipe)) { struct clvm_header reply = { .cmd = CLVMD_CMD_REPLY, .status = EBUSY }; DEBUGLOG("creating pipe failed: %s\n", strerror(errno)); send_message(&reply, sizeof(reply), our_csid, thisfd->fd, "Error sending EBUSY reply to local user"); return len; } newfd = malloc(sizeof(struct local_client)); if (!newfd) { struct clvm_header reply = { .cmd = CLVMD_CMD_REPLY, .status = ENOMEM }; (void) close(comms_pipe[0]); (void) close(comms_pipe[1]); send_message(&reply, sizeof(reply), our_csid, thisfd->fd, "Error sending ENOMEM reply to local user"); return len; } DEBUGLOG("creating pipe, [%d, %d]\n", comms_pipe[0], comms_pipe[1]); if (fcntl(comms_pipe[0], F_SETFD, 1)) DEBUGLOG("setting CLOEXEC on pipe[0] failed: %s\n", strerror(errno)); if (fcntl(comms_pipe[1], F_SETFD, 1)) DEBUGLOG("setting CLOEXEC on pipe[1] failed: %s\n", strerror(errno)); newfd->fd = comms_pipe[0]; newfd->removeme = 0; newfd->type = THREAD_PIPE; newfd->callback = local_pipe_callback; newfd->next = thisfd->next; newfd->bits.pipe.client = thisfd; newfd->bits.pipe.threadid = 0; thisfd->next = newfd; /* Store a cross link to the pipe */ thisfd->bits.localsock.pipe_client = newfd; thisfd->bits.localsock.pipe = comms_pipe[1]; /* Make sure the thread has a copy of it's own ID */ newfd->bits.pipe.threadid = thisfd->bits.localsock.threadid; /* Run the pre routine */ thisfd->bits.localsock.in_progress = TRUE; thisfd->bits.localsock.state = PRE_COMMAND; DEBUGLOG("Creating pre&post thread\n"); status = pthread_create(&thisfd->bits.localsock.threadid, &stack_attr, pre_and_post_thread, thisfd); DEBUGLOG("Created pre&post thread, state = %d\n", status); } return len; } /* Add a file descriptor from the cluster or comms interface to our list of FDs for select */ int add_client(struct local_client *new_client) { new_client->next = local_client_head.next; local_client_head.next = new_client; return 0; } /* Called when the pre-command has completed successfully - we now execute the real command on all the requested nodes */ static int distribute_command(struct local_client *thisfd) { struct clvm_header *inheader = (struct clvm_header *) thisfd->bits.localsock.cmd; int len = thisfd->bits.localsock.cmd_len; thisfd->xid = global_xid++; DEBUGLOG("distribute command: XID = %d, flags=0x%x (%s%s)\n", thisfd->xid, inheader->flags, (inheader->flags & CLVMD_FLAG_LOCAL) ? "LOCAL" : "", (inheader->flags & CLVMD_FLAG_REMOTE) ? "REMOTE" : ""); /* Forward it to other nodes in the cluster if needed */ if (!(inheader->flags & CLVMD_FLAG_LOCAL)) { /* if node is empty then do it on the whole cluster */ if (inheader->node[0] == '\0') { thisfd->bits.localsock.expected_replies = clops->get_num_nodes(); thisfd->bits.localsock.num_replies = 0; thisfd->bits.localsock.sent_time = time(NULL); thisfd->bits.localsock.in_progress = TRUE; thisfd->bits.localsock.sent_out = TRUE; /* * Send to local node first, even if CLVMD_FLAG_REMOTE * is set so we still get a reply if this is the * only node. */ add_to_lvmqueue(thisfd, inheader, len, NULL); DEBUGLOG("Sending message to all cluster nodes\n"); inheader->xid = thisfd->xid; send_message(inheader, len, NULL, -1, "Error forwarding message to cluster"); } else { /* Do it on a single node */ char csid[MAX_CSID_LEN]; if (clops->csid_from_name(csid, inheader->node)) { /* This has already been checked so should not happen */ return 0; } else { /* OK, found a node... */ thisfd->bits.localsock.expected_replies = 1; thisfd->bits.localsock.num_replies = 0; thisfd->bits.localsock.in_progress = TRUE; /* Are we the requested node ?? */ if (memcmp(csid, our_csid, max_csid_len) == 0) { DEBUGLOG("Doing command on local node only\n"); add_to_lvmqueue(thisfd, inheader, len, NULL); } else { DEBUGLOG("Sending message to single node: %s\n", inheader->node); inheader->xid = thisfd->xid; send_message(inheader, len, csid, -1, "Error forwarding message to cluster node"); } } } } else { /* Local explicitly requested, ignore nodes */ thisfd->bits.localsock.in_progress = TRUE; thisfd->bits.localsock.expected_replies = 1; thisfd->bits.localsock.num_replies = 0; add_to_lvmqueue(thisfd, inheader, len, NULL); } return 0; } /* Process a command from a remote node and return the result */ static void process_remote_command(struct clvm_header *msg, int msglen, int fd, const char *csid) { char *replyargs; char nodename[max_cluster_member_name_len]; int replylen = 0; int buflen = max_cluster_message - sizeof(struct clvm_header) - 1; int status; /* Get the node name as we /may/ need it later */ clops->name_from_csid(csid, nodename); DEBUGLOG("process_remote_command %s for clientid 0x%x XID %d on node %s\n", decode_cmd(msg->cmd), msg->clientid, msg->xid, nodename); /* Check for GOAWAY and sulk */ if (msg->cmd == CLVMD_CMD_GOAWAY) { DEBUGLOG("Told to go away by %s\n", nodename); log_error("Told to go away by %s\n", nodename); exit(99); } /* Version check is internal - don't bother exposing it in clvmd-command.c */ if (msg->cmd == CLVMD_CMD_VERSION) { int version_nums[3]; char node[256]; memcpy(version_nums, msg->args, sizeof(version_nums)); clops->name_from_csid(csid, node); DEBUGLOG("Remote node %s is version %d.%d.%d\n", node, ntohl(version_nums[0]), ntohl(version_nums[1]), ntohl(version_nums[2])); if (ntohl(version_nums[0]) != CLVMD_MAJOR_VERSION) { struct clvm_header byebyemsg; DEBUGLOG ("Telling node %s to go away because of incompatible version number\n", node); log_notice ("Telling node %s to go away because of incompatible version number %d.%d.%d\n", node, ntohl(version_nums[0]), ntohl(version_nums[1]), ntohl(version_nums[2])); byebyemsg.cmd = CLVMD_CMD_GOAWAY; byebyemsg.status = 0; byebyemsg.flags = 0; byebyemsg.arglen = 0; byebyemsg.clientid = 0; clops->cluster_send_message(&byebyemsg, sizeof(byebyemsg), our_csid, "Error Sending GOAWAY message"); } else { clops->add_up_node(csid); } return; } /* Allocate a default reply buffer */ replyargs = malloc(max_cluster_message - sizeof(struct clvm_header)); if (replyargs != NULL) { /* Run the command */ /* FIXME: usage of init_test() is unprotected */ status = do_command(NULL, msg, msglen, &replyargs, buflen, &replylen); } else { status = ENOMEM; } /* If it wasn't a reply, then reply */ if (msg->cmd != CLVMD_CMD_REPLY) { char *aggreply; aggreply = realloc(replyargs, replylen + sizeof(struct clvm_header)); if (aggreply) { struct clvm_header *agghead = (struct clvm_header *) aggreply; replyargs = aggreply; /* Move it up so there's room for a header in front of the data */ memmove(aggreply + offsetof(struct clvm_header, args), replyargs, replylen); agghead->xid = msg->xid; agghead->cmd = CLVMD_CMD_REPLY; agghead->status = status; agghead->flags = 0; agghead->clientid = msg->clientid; agghead->arglen = replylen; agghead->node[0] = '\0'; send_message(aggreply, sizeof(struct clvm_header) + replylen, csid, fd, "Error sending command reply"); } else { struct clvm_header head; DEBUGLOG("Error attempting to realloc return buffer\n"); /* Return a failure response */ head.cmd = CLVMD_CMD_REPLY; head.status = ENOMEM; head.flags = 0; head.clientid = msg->clientid; head.arglen = 0; head.node[0] = '\0'; send_message(&head, sizeof(struct clvm_header), csid, fd, "Error sending ENOMEM command reply"); return; } } free(replyargs); } /* Add a reply to a command to the list of replies for this client. If we have got a full set then send them to the waiting client down the local socket */ static void add_reply_to_list(struct local_client *client, int status, const char *csid, const char *buf, int len) { struct node_reply *reply; pthread_mutex_lock(&client->bits.localsock.reply_mutex); /* Add it to the list of replies */ reply = malloc(sizeof(struct node_reply)); if (reply) { reply->status = status; clops->name_from_csid(csid, reply->node); DEBUGLOG("Reply from node %s: %d bytes\n", reply->node, len); if (len > 0) { reply->replymsg = malloc(len); if (!reply->replymsg) { reply->status = ENOMEM; } else { memcpy(reply->replymsg, buf, len); } } else { reply->replymsg = NULL; } /* Hook it onto the reply chain */ reply->next = client->bits.localsock.replies; client->bits.localsock.replies = reply; } else { /* It's all gone horribly wrong... */ pthread_mutex_unlock(&client->bits.localsock.reply_mutex); send_local_reply(client, ENOMEM, client->fd); return; } DEBUGLOG("Got %d replies, expecting: %d\n", client->bits.localsock.num_replies + 1, client->bits.localsock.expected_replies); /* If we have the whole lot then do the post-process */ if (++client->bits.localsock.num_replies == client->bits.localsock.expected_replies) { /* Post-process the command */ if (client->bits.localsock.threadid) { pthread_mutex_lock(&client->bits.localsock.mutex); client->bits.localsock.state = POST_COMMAND; pthread_cond_signal(&client->bits.localsock.cond); pthread_mutex_unlock(&client->bits.localsock.mutex); } } pthread_mutex_unlock(&client->bits.localsock.reply_mutex); } /* This is the thread that runs the PRE and post commands for a particular connection */ static __attribute__ ((noreturn)) void *pre_and_post_thread(void *arg) { struct local_client *client = (struct local_client *) arg; int status; int write_status; sigset_t ss; int pipe_fd = client->bits.localsock.pipe; DEBUGLOG("in sub thread: client = %p\n", client); pthread_mutex_lock(&client->bits.localsock.mutex); /* Ignore SIGUSR1 (handled by master process) but enable SIGUSR2 (kills subthreads) */ sigemptyset(&ss); sigaddset(&ss, SIGUSR1); pthread_sigmask(SIG_BLOCK, &ss, NULL); sigdelset(&ss, SIGUSR1); sigaddset(&ss, SIGUSR2); pthread_sigmask(SIG_UNBLOCK, &ss, NULL); /* Loop around doing PRE and POST functions until the client goes away */ while (!client->bits.localsock.finished) { /* Execute the code */ /* FIXME: usage of init_test() is unprotected as in do_command() */ status = do_pre_command(client); if (status) client->bits.localsock.all_success = 0; DEBUGLOG("Writing status %d down pipe %d\n", status, pipe_fd); /* Tell the parent process we have finished this bit */ do { write_status = write(pipe_fd, &status, sizeof(int)); if (write_status == sizeof(int)) break; if (write_status < 0 && (errno == EINTR || errno == EAGAIN)) continue; log_error("Error sending to pipe: %m\n"); break; } while(1); if (status) { client->bits.localsock.state = POST_COMMAND; goto next_pre; } /* We may need to wait for the condition variable before running the post command */ DEBUGLOG("Waiting to do post command - state = %d\n", client->bits.localsock.state); if (client->bits.localsock.state != POST_COMMAND && !client->bits.localsock.finished) { pthread_cond_wait(&client->bits.localsock.cond, &client->bits.localsock.mutex); } DEBUGLOG("Got post command condition...\n"); /* POST function must always run, even if the client aborts */ status = 0; do_post_command(client); do { write_status = write(pipe_fd, &status, sizeof(int)); if (write_status == sizeof(int)) break; if (write_status < 0 && (errno == EINTR || errno == EAGAIN)) continue; log_error("Error sending to pipe: %m\n"); break; } while(1); next_pre: DEBUGLOG("Waiting for next pre command\n"); if (client->bits.localsock.state != PRE_COMMAND && !client->bits.localsock.finished) { pthread_cond_wait(&client->bits.localsock.cond, &client->bits.localsock.mutex); } DEBUGLOG("Got pre command condition...\n"); } pthread_mutex_unlock(&client->bits.localsock.mutex); DEBUGLOG("Subthread finished\n"); pthread_exit((void *) 0); } /* Process a command on the local node and store the result */ static int process_local_command(struct clvm_header *msg, int msglen, struct local_client *client, unsigned short xid) { char *replybuf = malloc(max_cluster_message); int buflen = max_cluster_message - sizeof(struct clvm_header) - 1; int replylen = 0; int status; DEBUGLOG("process_local_command: %s msg=%p, msglen =%d, client=%p\n", decode_cmd(msg->cmd), msg, msglen, client); if (replybuf == NULL) return -1; /* If remote flag is set, just set a successful status code. */ if (msg->flags & CLVMD_FLAG_REMOTE) status = 0; else /* FIXME: usage of init_test() is unprotected */ status = do_command(client, msg, msglen, &replybuf, buflen, &replylen); if (status) client->bits.localsock.all_success = 0; /* If we took too long then discard the reply */ if (xid == client->xid) { add_reply_to_list(client, status, our_csid, replybuf, replylen); } else { DEBUGLOG ("Local command took too long, discarding xid %d, current is %d\n", xid, client->xid); } free(replybuf); return status; } static int process_reply(const struct clvm_header *msg, int msglen, const char *csid) { struct local_client *client = NULL; client = find_client(msg->clientid); if (!client) { DEBUGLOG("Got message for unknown client 0x%x\n", msg->clientid); log_error("Got message for unknown client 0x%x\n", msg->clientid); return -1; } if (msg->status) client->bits.localsock.all_success = 0; /* Gather replies together for this client id */ if (msg->xid == client->xid) { add_reply_to_list(client, msg->status, csid, msg->args, msg->arglen); } else { DEBUGLOG("Discarding reply with old XID %d, current = %d\n", msg->xid, client->xid); } return 0; } /* Send an aggregated reply back to the client */ static void send_local_reply(struct local_client *client, int status, int fd) { struct clvm_header *clientreply; struct node_reply *thisreply = client->bits.localsock.replies; char *replybuf; char *ptr; int message_len = 0; DEBUGLOG("Send local reply\n"); /* Work out the total size of the reply */ while (thisreply) { if (thisreply->replymsg) message_len += strlen(thisreply->replymsg) + 1; else message_len++; message_len += strlen(thisreply->node) + 1 + sizeof(int); thisreply = thisreply->next; } /* Add in the size of our header */ message_len = message_len + sizeof(struct clvm_header); if (!(replybuf = malloc(message_len))) { DEBUGLOG("Memory allocation fails\n"); return; } clientreply = (struct clvm_header *) replybuf; clientreply->status = status; clientreply->cmd = CLVMD_CMD_REPLY; clientreply->node[0] = '\0'; clientreply->xid = 0; clientreply->clientid = 0; clientreply->flags = 0; ptr = clientreply->args; /* Add in all the replies, and free them as we go */ thisreply = client->bits.localsock.replies; while (thisreply) { struct node_reply *tempreply = thisreply; strcpy(ptr, thisreply->node); ptr += strlen(thisreply->node) + 1; if (thisreply->status) clientreply->flags |= CLVMD_FLAG_NODEERRS; memcpy(ptr, &thisreply->status, sizeof(int)); ptr += sizeof(int); if (thisreply->replymsg) { strcpy(ptr, thisreply->replymsg); ptr += strlen(thisreply->replymsg) + 1; } else { ptr[0] = '\0'; ptr++; } thisreply = thisreply->next; free(tempreply->replymsg); free(tempreply); } /* Terminate with an empty node name */ *ptr = '\0'; clientreply->arglen = ptr - clientreply->args; /* And send it */ send_message(replybuf, message_len, our_csid, fd, "Error sending REPLY to client"); free(replybuf); /* Reset comms variables */ client->bits.localsock.replies = NULL; client->bits.localsock.expected_replies = 0; client->bits.localsock.in_progress = FALSE; client->bits.localsock.sent_out = FALSE; } /* Just free a reply chain baceuse it wasn't used. */ static void free_reply(struct local_client *client) { /* Add in all the replies, and free them as we go */ struct node_reply *thisreply = client->bits.localsock.replies; while (thisreply) { struct node_reply *tempreply = thisreply; thisreply = thisreply->next; free(tempreply->replymsg); free(tempreply); } client->bits.localsock.replies = NULL; } /* Send our version number to the cluster */ static void send_version_message(void) { char message[sizeof(struct clvm_header) + sizeof(int) * 3]; struct clvm_header *msg = (struct clvm_header *) message; int version_nums[3]; msg->cmd = CLVMD_CMD_VERSION; msg->status = 0; msg->flags = 0; msg->clientid = 0; msg->arglen = sizeof(version_nums); version_nums[0] = htonl(CLVMD_MAJOR_VERSION); version_nums[1] = htonl(CLVMD_MINOR_VERSION); version_nums[2] = htonl(CLVMD_PATCH_VERSION); memcpy(&msg->args, version_nums, sizeof(version_nums)); hton_clvm(msg); clops->cluster_send_message(message, sizeof(message), NULL, "Error Sending version number"); } /* Send a message to either a local client or another server */ static int send_message(void *buf, int msglen, const char *csid, int fd, const char *errtext) { int len = 0; int saved_errno = 0; struct timespec delay; struct timespec remtime; int retry_cnt = 0; /* Send remote messages down the cluster socket */ if (csid == NULL || !ISLOCAL_CSID(csid)) { hton_clvm((struct clvm_header *) buf); return clops->cluster_send_message(buf, msglen, csid, errtext); } else { int ptr = 0; /* Make sure it all goes */ do { if (retry_cnt > MAX_RETRIES) { errno = saved_errno; log_error("%s", errtext); errno = saved_errno; break; } len = write(fd, (char*)buf + ptr, msglen - ptr); if (len <= 0) { if (errno == EINTR) continue; if (errno == EAGAIN || errno == EIO || errno == ENOSPC) { saved_errno = errno; retry_cnt++; delay.tv_sec = 0; delay.tv_nsec = 100000; remtime.tv_sec = 0; remtime.tv_nsec = 0; (void) nanosleep (&delay, &remtime); continue; } log_error("%s", errtext); break; } ptr += len; } while (ptr < msglen); } return len; } static int process_work_item(struct lvm_thread_cmd *cmd) { /* If msg is NULL then this is a cleanup request */ if (cmd->msg == NULL) { DEBUGLOG("process_work_item: free fd %d\n", cmd->client->fd); cmd_client_cleanup(cmd->client); free(cmd->client); return 0; } if (!cmd->remote) { DEBUGLOG("process_work_item: local\n"); process_local_command(cmd->msg, cmd->msglen, cmd->client, cmd->xid); } else { DEBUGLOG("process_work_item: remote\n"); process_remote_command(cmd->msg, cmd->msglen, cmd->client->fd, cmd->csid); } return 0; } /* * Routine that runs in the "LVM thread". */ static void *lvm_thread_fn(void *arg) { sigset_t ss; struct lvm_startup_params *lvm_params = arg; struct lvm_thread_cmd *cmd; DEBUGLOG("LVM thread function started\n"); /* Ignore SIGUSR1 & 2 */ sigemptyset(&ss); sigaddset(&ss, SIGUSR1); sigaddset(&ss, SIGUSR2); pthread_sigmask(SIG_BLOCK, &ss, NULL); /* Initialise the interface to liblvm */ init_clvm(lvm_params->excl_uuid); /* Allow others to get moving */ pthread_barrier_wait(&lvm_start_barrier); DEBUGLOG("Sub thread ready for work.\n"); /* Now wait for some actual work */ pthread_mutex_lock(&lvm_thread_mutex); while (!quit) { if (dm_list_empty(&lvm_cmd_head)) { DEBUGLOG("LVM thread waiting for work\n"); pthread_cond_wait(&lvm_thread_cond, &lvm_thread_mutex); } else { cmd = dm_list_item(dm_list_first(&lvm_cmd_head), struct lvm_thread_cmd); dm_list_del(&cmd->list); pthread_mutex_unlock(&lvm_thread_mutex); process_work_item(cmd); free(cmd->msg); free(cmd); pthread_mutex_lock(&lvm_thread_mutex); } } pthread_mutex_unlock(&lvm_thread_mutex); pthread_exit(NULL); } /* Pass down some work to the LVM thread */ static int add_to_lvmqueue(struct local_client *client, struct clvm_header *msg, int msglen, const char *csid) { struct lvm_thread_cmd *cmd; cmd = malloc(sizeof(struct lvm_thread_cmd)); if (!cmd) return ENOMEM; if (msglen) { cmd->msg = malloc(msglen); if (!cmd->msg) { log_error("Unable to allocate buffer space\n"); free(cmd); return -1; } memcpy(cmd->msg, msg, msglen); } else { cmd->msg = NULL; } cmd->client = client; cmd->msglen = msglen; cmd->xid = client->xid; if (csid) { memcpy(cmd->csid, csid, max_csid_len); cmd->remote = 1; } else { cmd->remote = 0; } DEBUGLOG ("add_to_lvmqueue: cmd=%p. client=%p, msg=%p, len=%d, csid=%p, xid=%d\n", cmd, client, msg, msglen, csid, cmd->xid); pthread_mutex_lock(&lvm_thread_mutex); dm_list_add(&lvm_cmd_head, &cmd->list); pthread_cond_signal(&lvm_thread_cond); pthread_mutex_unlock(&lvm_thread_mutex); return 0; } /* Return 0 if we can talk to an existing clvmd */ static int check_local_clvmd(void) { int local_socket; int ret = 0; struct sockaddr_un sockaddr = { .sun_family = AF_UNIX }; if (!dm_strncpy(sockaddr.sun_path, CLVMD_SOCKNAME, sizeof(sockaddr.sun_path))) { log_error("%s: clvmd socket name too long.", CLVMD_SOCKNAME); return -1; } /* Open local socket */ if ((local_socket = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { log_sys_error("socket", "local socket"); return -1; } if (connect(local_socket,(struct sockaddr *) &sockaddr, sizeof(sockaddr))) { log_sys_error("connect", "local socket"); ret = -1; } if (close(local_socket)) log_sys_error("close", "local socket"); return ret; } static void close_local_sock(int local_socket) { if (local_socket != -1 && close(local_socket)) log_sys_error("close", CLVMD_SOCKNAME); if (CLVMD_SOCKNAME[0] != '\0' && unlink(CLVMD_SOCKNAME)) stack; } /* Open the local socket, that's the one we talk to libclvm down */ static int open_local_sock(void) { mode_t old_mask; int local_socket = -1; struct sockaddr_un sockaddr = { .sun_family = AF_UNIX }; if (!dm_strncpy(sockaddr.sun_path, CLVMD_SOCKNAME, sizeof(sockaddr.sun_path))) { log_error("%s: clvmd socket name too long.", CLVMD_SOCKNAME); return -1; } close_local_sock(local_socket); (void) dm_prepare_selinux_context(CLVMD_SOCKNAME, S_IFSOCK); old_mask = umask(0077); /* Open local socket */ local_socket = socket(PF_UNIX, SOCK_STREAM, 0); if (local_socket < 0) { log_error("Can't create local socket: %m"); goto error; } /* Set Close-on-exec & non-blocking */ if (fcntl(local_socket, F_SETFD, 1)) DEBUGLOG("setting CLOEXEC on local_socket failed: %s\n", strerror(errno)); if (fcntl(local_socket, F_SETFL, fcntl(local_socket, F_GETFL, 0) | O_NONBLOCK)) DEBUGLOG("setting O_NONBLOCK on local_socket failed: %s\n", strerror(errno)); if (bind(local_socket, (struct sockaddr *) &sockaddr, sizeof(sockaddr))) { log_error("can't bind local socket: %m"); goto error; } if (listen(local_socket, 1) != 0) { log_error("listen local: %m"); goto error; } umask(old_mask); (void) dm_prepare_selinux_context(NULL, 0); return local_socket; error: close_local_sock(local_socket); umask(old_mask); (void) dm_prepare_selinux_context(NULL, 0); return -1; } void process_message(struct local_client *client, char *buf, int len, const char *csid) { struct clvm_header *inheader; inheader = (struct clvm_header *) buf; ntoh_clvm(inheader); /* Byteswap fields */ if (inheader->cmd == CLVMD_CMD_REPLY) process_reply(inheader, len, csid); else add_to_lvmqueue(client, inheader, len, csid); } static void check_all_callback(struct local_client *client, const char *csid, int node_up) { if (!node_up) add_reply_to_list(client, EHOSTDOWN, csid, "CLVMD not running", 18); } /* Check to see if all CLVMDs are running (ie one on every node in the cluster). If not, returns -1 and prints out a list of errant nodes */ static int check_all_clvmds_running(struct local_client *client) { DEBUGLOG("check_all_clvmds_running\n"); return clops->cluster_do_node_callback(client, check_all_callback); } /* Return a local_client struct given a client ID. client IDs are in network byte order */ static struct local_client *find_client(int clientid) { struct local_client *thisfd; for (thisfd = &local_client_head; thisfd != NULL; thisfd = thisfd->next) { if (thisfd->fd == (int)ntohl(clientid)) return thisfd; } return NULL; } /* Byte-swapping routines for the header so we work in a heterogeneous environment */ static void hton_clvm(struct clvm_header *hdr) { hdr->status = htonl(hdr->status); hdr->arglen = htonl(hdr->arglen); hdr->xid = htons(hdr->xid); /* Don't swap clientid as it's only a token as far as remote nodes are concerned */ } static void ntoh_clvm(struct clvm_header *hdr) { hdr->status = ntohl(hdr->status); hdr->arglen = ntohl(hdr->arglen); hdr->xid = ntohs(hdr->xid); } /* Handler for SIGUSR2 - sent to kill subthreads */ static void sigusr2_handler(int sig) { DEBUGLOG("SIGUSR2 received\n"); return; } static void sigterm_handler(int sig) { DEBUGLOG("SIGTERM received\n"); quit = 1; return; } static void sighup_handler(int sig) { DEBUGLOG("got SIGHUP\n"); reread_config = 1; } int sync_lock(const char *resource, int mode, int flags, int *lockid) { return clops->sync_lock(resource, mode, flags, lockid); } int sync_unlock(const char *resource, int lockid) { return clops->sync_unlock(resource, lockid); } static if_type_t parse_cluster_interface(char *ifname) { if_type_t iface = IF_AUTO; if (!strcmp(ifname, "auto")) iface = IF_AUTO; if (!strcmp(ifname, "cman")) iface = IF_CMAN; if (!strcmp(ifname, "openais")) iface = IF_OPENAIS; if (!strcmp(ifname, "corosync")) iface = IF_COROSYNC; if (!strcmp(ifname, "singlenode")) iface = IF_SINGLENODE; return iface; } /* * Try and find a cluster system in corosync's objdb, if it is running. This is * only called if the command-line option is not present, and if it fails * we still try the interfaces in order. */ static if_type_t get_cluster_type(void) { #ifdef HAVE_COROSYNC_CONFDB_H confdb_handle_t handle; if_type_t type = IF_AUTO; int result; char buf[255]; size_t namelen = sizeof(buf); hdb_handle_t cluster_handle; hdb_handle_t clvmd_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 }; result = confdb_initialize (&handle, &callbacks); if (result != CS_OK) return type; 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_object_find_start(handle, cluster_handle); if (result != CS_OK) goto out; result = confdb_object_find(handle, cluster_handle, (void *)"clvmd", strlen("clvmd"), &clvmd_handle); if (result != CS_OK) goto out; result = confdb_key_get(handle, clvmd_handle, (void *)"interface", strlen("interface"), buf, &namelen); if (result != CS_OK) goto out; if (namelen >= sizeof(buf)) namelen = sizeof(buf) - 1; buf[namelen] = '\0'; type = parse_cluster_interface(buf); DEBUGLOG("got interface type '%s' from confdb\n", buf); out: confdb_finalize(handle); return type; #else return IF_AUTO; #endif } lvm2-2.02.98/daemons/clvmd/clvmd-comms.h0000640000175000017500000000715012037016272016640 0ustar blankblank/* * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved. * Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU General Public License v.2. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * Abstraction layer for clvmd cluster communications */ #ifndef _CLVMD_COMMS_H #define _CLVMD_COMMS_H struct local_client; struct cluster_ops { const char *name; void (*cluster_init_completed) (void); int (*cluster_send_message) (const void *buf, int msglen, const char *csid, const char *errtext); int (*name_from_csid) (const char *csid, char *name); int (*csid_from_name) (char *csid, const char *name); int (*get_num_nodes) (void); int (*cluster_fd_callback) (struct local_client *fd, char *buf, int len, const char *csid, struct local_client **new_client); int (*get_main_cluster_fd) (void); /* gets accept FD or cman cluster socket */ int (*cluster_do_node_callback) (struct local_client *client, void (*callback) (struct local_client *, const char *csid, int node_up)); int (*is_quorate) (void); void (*get_our_csid) (char *csid); void (*add_up_node) (const char *csid); void (*reread_config) (void); void (*cluster_closedown) (void); int (*get_cluster_name)(char *buf, int buflen); int (*sync_lock) (const char *resource, int mode, int flags, int *lockid); int (*sync_unlock) (const char *resource, int lockid); }; #ifdef USE_CMAN # include # 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 # include # 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 # 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 lvm2-2.02.98/daemons/Makefile.in0000640000175000017500000000211412037016272015201 0ustar blankblank# # Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved. # # This file is part of LVM2. # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions # of the GNU General Public License v.2. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation, # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA srcdir = @srcdir@ top_srcdir = @top_srcdir@ top_builddir = @top_builddir@ ifeq ("@BUILD_LVMETAD@", "yes") SUBDIRS += lvmetad endif .PHONY: dmeventd clvmd cmirrord lvmetad ifneq ("@CLVMD@", "none") SUBDIRS += clvmd endif ifeq ("@BUILD_CMIRRORD@", "yes") SUBDIRS += cmirrord endif ifeq ("@BUILD_DMEVENTD@", "yes") SUBDIRS += dmeventd ifneq ("$(CFLOW_CMD)", "") daemons.cflow: dmeventd.cflow endif endif ifeq ($(MAKECMDGOALS),distclean) SUBDIRS = clvmd cmirrord dmeventd lvmetad endif include $(top_builddir)/make.tmpl ifeq ("@BUILD_DMEVENTD@", "yes") device-mapper: dmeventd.device-mapper endif lvm2-2.02.98/daemons/cmirrord/0000750000175000017500000000000012037016272014756 5ustar blankblanklvm2-2.02.98/daemons/cmirrord/local.c0000640000175000017500000002351712037016272016225 0ustar blankblank/* * 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 #include #include #include #include #ifndef CN_IDX_DM /* Kernel 2.6.31 is required to run this code */ #define CN_IDX_DM 0x7 /* Device Mapper */ #define CN_VAL_DM_USERSPACE_LOG 0x1 #endif static int cn_fd = -1; /* Connector (netlink) socket fd */ static char recv_buf[2048]; static char send_buf[2048]; /* FIXME: merge this function with kernel_send_helper */ static int kernel_ack(uint32_t seq, int error) { int r; struct nlmsghdr *nlh = (struct nlmsghdr *)send_buf; struct cn_msg *msg = NLMSG_DATA(nlh); if (error < 0) { LOG_ERROR("Programmer error: error codes must be positive"); return -EINVAL; } memset(send_buf, 0, sizeof(send_buf)); nlh->nlmsg_seq = 0; nlh->nlmsg_pid = getpid(); nlh->nlmsg_type = NLMSG_DONE; nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct cn_msg)); nlh->nlmsg_flags = 0; msg->len = 0; msg->id.idx = CN_IDX_DM; msg->id.val = CN_VAL_DM_USERSPACE_LOG; msg->seq = seq; msg->ack = error; r = send(cn_fd, nlh, NLMSG_LENGTH(sizeof(struct cn_msg)), 0); /* FIXME: do better error processing */ if (r <= 0) return -EBADE; return 0; } /* * kernel_recv * @rq: the newly allocated request from kernel * * Read requests from the kernel and allocate space for the new request. * If there is no request from the kernel, *rq is NULL. * * This function is not thread safe due to returned stack pointer. In fact, * the returned pointer must not be in-use when this function is called again. * * Returns: 0 on success, -EXXX on error */ static int kernel_recv(struct clog_request **rq) { int r = 0; ssize_t len; char *foo; struct cn_msg *msg; struct dm_ulog_request *u_rq; struct nlmsghdr *nlmsg_h; *rq = NULL; memset(recv_buf, 0, sizeof(recv_buf)); len = recv(cn_fd, recv_buf, sizeof(recv_buf), 0); if (len < 0) { LOG_ERROR("Failed to recv message from kernel"); r = -errno; goto fail; } nlmsg_h = (struct nlmsghdr *)recv_buf; switch (nlmsg_h->nlmsg_type) { case NLMSG_ERROR: LOG_ERROR("Unable to recv message from kernel: NLMSG_ERROR"); r = -EBADE; goto fail; case NLMSG_DONE: msg = (struct cn_msg *)NLMSG_DATA((struct nlmsghdr *)recv_buf); len -= (ssize_t)sizeof(struct nlmsghdr); if (len < (ssize_t)sizeof(struct cn_msg)) { LOG_ERROR("Incomplete request from kernel received"); r = -EBADE; goto fail; } if (msg->len > DM_ULOG_REQUEST_SIZE) { LOG_ERROR("Not enough space to receive kernel request (%d/%d)", msg->len, DM_ULOG_REQUEST_SIZE); r = -EBADE; goto fail; } if (!msg->len) LOG_ERROR("Zero length message received"); len -= (ssize_t)sizeof(struct cn_msg); if (len < msg->len) LOG_ERROR("len = %zd, msg->len = %" PRIu16, len, msg->len); msg->data[msg->len] = '\0'; /* Cleaner way to ensure this? */ u_rq = (struct dm_ulog_request *)msg->data; if (!u_rq->request_type) { LOG_DBG("Bad transmission, requesting resend [%u]", msg->seq); r = -EAGAIN; if (kernel_ack(msg->seq, EAGAIN)) { LOG_ERROR("Failed to NACK kernel transmission [%u]", msg->seq); r = -EBADE; } } /* * Now we've got sizeof(struct cn_msg) + sizeof(struct nlmsghdr) * worth of space that precede the request structure from the * kernel. Since that space isn't going to be used again, we * can take it for our purposes; rather than allocating a whole * new structure and doing a memcpy. * * We should really make sure 'clog_request' doesn't grow * beyond what is available to us, but we need only check it * once... perhaps at compile time? */ foo = (char *)u_rq; foo -= (sizeof(struct clog_request) - sizeof(struct dm_ulog_request)); *rq = (struct clog_request *) foo; /* Clear the wrapper container fields */ memset(*rq, 0, (size_t)((char *)u_rq - (char *)(*rq))); break; default: LOG_ERROR("Unknown nlmsg_type"); r = -EBADE; } fail: if (r) *rq = NULL; return (r == -EAGAIN) ? 0 : r; } static int kernel_send_helper(void *data, uint16_t out_size) { int r; struct nlmsghdr *nlh; struct cn_msg *msg; memset(send_buf, 0, sizeof(send_buf)); nlh = (struct nlmsghdr *)send_buf; nlh->nlmsg_seq = 0; /* FIXME: Is this used? */ nlh->nlmsg_pid = getpid(); nlh->nlmsg_type = NLMSG_DONE; nlh->nlmsg_len = NLMSG_LENGTH(out_size + sizeof(struct cn_msg)); nlh->nlmsg_flags = 0; msg = NLMSG_DATA(nlh); memcpy(msg->data, data, out_size); msg->len = out_size; msg->id.idx = CN_IDX_DM; msg->id.val = CN_VAL_DM_USERSPACE_LOG; msg->seq = 0; r = send(cn_fd, nlh, NLMSG_LENGTH(out_size + sizeof(struct cn_msg)), 0); /* FIXME: do better error processing */ if (r <= 0) return -EBADE; return 0; } /* * do_local_work * * Any processing errors are placed in the 'rq' * structure to be reported back to the kernel. * It may be pointless for this function to * return an int. * * Returns: 0 on success, -EXXX on failure */ static int do_local_work(void *data __attribute__((unused))) { int r; struct clog_request *rq; struct dm_ulog_request *u_rq = NULL; r = kernel_recv(&rq); if (r) return r; if (!rq) return 0; u_rq = &rq->u_rq; LOG_DBG("[%s] Request from kernel received: [%s/%u]", SHORT_UUID(u_rq->uuid), RQ_TYPE(u_rq->request_type), u_rq->seq); switch (u_rq->request_type) { case DM_ULOG_CTR: case DM_ULOG_DTR: case DM_ULOG_GET_REGION_SIZE: case DM_ULOG_IN_SYNC: case DM_ULOG_GET_SYNC_COUNT: case DM_ULOG_STATUS_TABLE: case DM_ULOG_PRESUSPEND: /* We do not specify ourselves as server here */ r = do_request(rq, 0); if (r) LOG_DBG("Returning failed request to kernel [%s]", RQ_TYPE(u_rq->request_type)); r = kernel_send(u_rq); if (r) LOG_ERROR("Failed to respond to kernel [%s]", RQ_TYPE(u_rq->request_type)); break; case DM_ULOG_RESUME: /* * Resume is a special case that requires a local * component to join the CPG, and a cluster component * to handle the request. */ r = local_resume(u_rq); if (r) { LOG_DBG("Returning failed request to kernel [%s]", RQ_TYPE(u_rq->request_type)); r = kernel_send(u_rq); if (r) LOG_ERROR("Failed to respond to kernel [%s]", RQ_TYPE(u_rq->request_type)); break; } /* ELSE, fall through */ case DM_ULOG_IS_CLEAN: case DM_ULOG_FLUSH: case DM_ULOG_MARK_REGION: case DM_ULOG_GET_RESYNC_WORK: case DM_ULOG_SET_REGION_SYNC: case DM_ULOG_STATUS_INFO: case DM_ULOG_IS_REMOTE_RECOVERING: case DM_ULOG_POSTSUSPEND: r = cluster_send(rq); if (r) { u_rq->data_size = 0; u_rq->error = r; if (kernel_send(u_rq)) LOG_ERROR("Failed to respond to kernel [%s]", RQ_TYPE(u_rq->request_type)); } break; case DM_ULOG_CLEAR_REGION: r = kernel_ack(u_rq->seq, 0); r = cluster_send(rq); if (r) { /* * FIXME: store error for delivery on flush * This would allow us to optimize MARK_REGION * too. */ } break; default: LOG_ERROR("Invalid log request received (%u), ignoring.", u_rq->request_type); return 0; } if (r && !u_rq->error) u_rq->error = r; return r; } /* * kernel_send * @u_rq: result to pass back to kernel * * This function returns the u_rq structure * (containing the results) to the kernel. * It then frees the structure. * * WARNING: should the structure be freed if * there is an error? I vote 'yes'. If the * kernel doesn't get the response, it should * resend the request. * * Returns: 0 on success, -EXXX on failure */ int kernel_send(struct dm_ulog_request *u_rq) { int r; uint16_t size; if (!u_rq) return -EINVAL; size = (uint16_t)(sizeof(struct dm_ulog_request) + u_rq->data_size); if (!u_rq->data_size && !u_rq->error) { /* An ACK is all that is needed */ /* FIXME: add ACK code */ } else if (size > DM_ULOG_REQUEST_SIZE) { /* * If we gotten here, we've already overrun * our allotted space somewhere. * * We must do something, because the kernel * is waiting for a response. */ LOG_ERROR("Not enough space to respond to server"); u_rq->error = -ENOSPC; size = sizeof(struct dm_ulog_request); } r = kernel_send_helper(u_rq, size); if (r) LOG_ERROR("Failed to send msg to kernel."); return r; } /* * init_local * * Initialize kernel communication socket (netlink) * * Returns: 0 on success, values from common.h on failure */ int init_local(void) { int r = 0; unsigned opt; struct sockaddr_nl addr; cn_fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR); if (cn_fd < 0) return EXIT_KERNEL_SOCKET; /* memset to fix valgrind complaint */ memset(&addr, 0, sizeof(struct sockaddr_nl)); addr.nl_family = AF_NETLINK; addr.nl_groups = CN_IDX_DM; addr.nl_pid = 0; r = bind(cn_fd, (struct sockaddr *) &addr, sizeof(addr)); if (r < 0) { if (close(cn_fd)) LOG_ERROR("Failed to close socket: %s", strerror(errno)); return EXIT_KERNEL_BIND; } opt = addr.nl_groups; r = setsockopt(cn_fd, 270, NETLINK_ADD_MEMBERSHIP, &opt, sizeof(opt)); if (r) { if (close(cn_fd)) LOG_ERROR("Failed to close socket: %s", strerror(errno)); return EXIT_KERNEL_SETSOCKOPT; } /* r = fcntl(cn_fd, F_SETFL, FNDELAY); */ links_register(cn_fd, "local", do_local_work, NULL); return 0; } /* * cleanup_local * * Clean up before exiting */ void cleanup_local(void) { links_unregister(cn_fd); if (cn_fd >= 0 && close(cn_fd)) LOG_ERROR("Failed to close socket: %s", strerror(errno)); } lvm2-2.02.98/daemons/cmirrord/cluster.c0000640000175000017500000013763512037016272016623 0ustar blankblank/* * 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 "cluster.h" #include "common.h" #include "compat.h" #include "functions.h" #include "link_mon.h" #include "local.h" #include "xlate.h" #include #include #include #include #if CMIRROR_HAS_CHECKPOINT #include #include #endif /* Open AIS error codes */ #define str_ais_error(x) \ ((x) == SA_AIS_OK) ? "SA_AIS_OK" : \ ((x) == SA_AIS_ERR_LIBRARY) ? "SA_AIS_ERR_LIBRARY" : \ ((x) == SA_AIS_ERR_VERSION) ? "SA_AIS_ERR_VERSION" : \ ((x) == SA_AIS_ERR_INIT) ? "SA_AIS_ERR_INIT" : \ ((x) == SA_AIS_ERR_TIMEOUT) ? "SA_AIS_ERR_TIMEOUT" : \ ((x) == SA_AIS_ERR_TRY_AGAIN) ? "SA_AIS_ERR_TRY_AGAIN" : \ ((x) == SA_AIS_ERR_INVALID_PARAM) ? "SA_AIS_ERR_INVALID_PARAM" : \ ((x) == SA_AIS_ERR_NO_MEMORY) ? "SA_AIS_ERR_NO_MEMORY" : \ ((x) == SA_AIS_ERR_BAD_HANDLE) ? "SA_AIS_ERR_BAD_HANDLE" : \ ((x) == SA_AIS_ERR_BUSY) ? "SA_AIS_ERR_BUSY" : \ ((x) == SA_AIS_ERR_ACCESS) ? "SA_AIS_ERR_ACCESS" : \ ((x) == SA_AIS_ERR_NOT_EXIST) ? "SA_AIS_ERR_NOT_EXIST" : \ ((x) == SA_AIS_ERR_NAME_TOO_LONG) ? "SA_AIS_ERR_NAME_TOO_LONG" : \ ((x) == SA_AIS_ERR_EXIST) ? "SA_AIS_ERR_EXIST" : \ ((x) == SA_AIS_ERR_NO_SPACE) ? "SA_AIS_ERR_NO_SPACE" : \ ((x) == SA_AIS_ERR_INTERRUPT) ? "SA_AIS_ERR_INTERRUPT" : \ ((x) == SA_AIS_ERR_NAME_NOT_FOUND) ? "SA_AIS_ERR_NAME_NOT_FOUND" : \ ((x) == SA_AIS_ERR_NO_RESOURCES) ? "SA_AIS_ERR_NO_RESOURCES" : \ ((x) == SA_AIS_ERR_NOT_SUPPORTED) ? "SA_AIS_ERR_NOT_SUPPORTED" : \ ((x) == SA_AIS_ERR_BAD_OPERATION) ? "SA_AIS_ERR_BAD_OPERATION" : \ ((x) == SA_AIS_ERR_FAILED_OPERATION) ? "SA_AIS_ERR_FAILED_OPERATION" : \ ((x) == SA_AIS_ERR_MESSAGE_ERROR) ? "SA_AIS_ERR_MESSAGE_ERROR" : \ ((x) == SA_AIS_ERR_QUEUE_FULL) ? "SA_AIS_ERR_QUEUE_FULL" : \ ((x) == SA_AIS_ERR_QUEUE_NOT_AVAILABLE) ? "SA_AIS_ERR_QUEUE_NOT_AVAILABLE" : \ ((x) == SA_AIS_ERR_BAD_FLAGS) ? "SA_AIS_ERR_BAD_FLAGS" : \ ((x) == SA_AIS_ERR_TOO_BIG) ? "SA_AIS_ERR_TOO_BIG" : \ ((x) == SA_AIS_ERR_NO_SECTIONS) ? "SA_AIS_ERR_NO_SECTIONS" : \ "ais_error_unknown" #define _RQ_TYPE(x) \ ((x) == DM_ULOG_CHECKPOINT_READY) ? "DM_ULOG_CHECKPOINT_READY": \ ((x) == DM_ULOG_MEMBER_JOIN) ? "DM_ULOG_MEMBER_JOIN": \ RQ_TYPE((x) & ~DM_ULOG_RESPONSE) static uint32_t my_cluster_id = 0xDEAD; #if CMIRROR_HAS_CHECKPOINT static SaCkptHandleT ckpt_handle = 0; static SaCkptCallbacksT callbacks = { 0, 0 }; static SaVersionT version = { 'B', 1, 1 }; #endif #define DEBUGGING_HISTORY 100 #define LOG_SPRINT(cc, f, arg...) do { \ cc->idx++; \ cc->idx = cc->idx % DEBUGGING_HISTORY; \ sprintf(cc->debugging[cc->idx], f, ## arg); \ } while (0) static int log_resp_rec = 0; #define RECOVERING_REGION_SECTION_SIZE 64 struct checkpoint_data { uint32_t requester; char uuid[CPG_MAX_NAME_LENGTH]; int bitmap_size; /* in bytes */ char *sync_bits; char *clean_bits; char *recovering_region; struct checkpoint_data *next; }; #define INVALID 0 #define VALID 1 #define LEAVING 2 #define MAX_CHECKPOINT_REQUESTERS 10 struct clog_cpg { struct dm_list list; uint32_t lowest_id; cpg_handle_t handle; struct cpg_name name; uint64_t luid; /* Are we the first, or have we received checkpoint? */ int state; int cpg_state; /* FIXME: debugging */ int free_me; int delay; int resend_requests; struct dm_list startup_list; struct dm_list working_list; int checkpoints_needed; uint32_t checkpoint_requesters[MAX_CHECKPOINT_REQUESTERS]; struct checkpoint_data *checkpoint_list; int idx; char debugging[DEBUGGING_HISTORY][128]; }; static struct dm_list clog_cpg_list; /* * cluster_send * @rq * * Returns: 0 on success, -Exxx on error */ int cluster_send(struct clog_request *rq) { int r; int found = 0; struct iovec iov; struct clog_cpg *entry; dm_list_iterate_items(entry, &clog_cpg_list) if (!strncmp(entry->name.value, rq->u_rq.uuid, CPG_MAX_NAME_LENGTH)) { found = 1; break; } if (!found) { rq->u_rq.error = -ENOENT; return -ENOENT; } /* * Once the request heads for the cluster, the luid looses * all its meaning. */ rq->u_rq.luid = 0; iov.iov_base = rq; iov.iov_len = sizeof(struct clog_request) + rq->u_rq.data_size; rq->u.version[0] = xlate64(CLOG_TFR_VERSION); rq->u.version[1] = CLOG_TFR_VERSION; r = clog_request_to_network(rq); if (r < 0) /* FIXME: Better error code for byteswap failure? */ return -EINVAL; if (entry->cpg_state != VALID) return -EINVAL; #if CMIRROR_HAS_CHECKPOINT do { int count = 0; r = cpg_mcast_joined(entry->handle, CPG_TYPE_AGREED, &iov, 1); if (r != SA_AIS_ERR_TRY_AGAIN) break; count++; if (count < 10) LOG_PRINT("[%s] Retry #%d of cpg_mcast_joined: %s", SHORT_UUID(rq->u_rq.uuid), count, str_ais_error(r)); else if ((count < 100) && !(count % 10)) LOG_ERROR("[%s] Retry #%d of cpg_mcast_joined: %s", SHORT_UUID(rq->u_rq.uuid), count, str_ais_error(r)); else if ((count < 1000) && !(count % 100)) LOG_ERROR("[%s] Retry #%d of cpg_mcast_joined: %s", SHORT_UUID(rq->u_rq.uuid), count, str_ais_error(r)); else if ((count < 10000) && !(count % 1000)) LOG_ERROR("[%s] Retry #%d of cpg_mcast_joined: %s - " "OpenAIS not handling the load?", SHORT_UUID(rq->u_rq.uuid), count, str_ais_error(r)); usleep(1000); } while (1); #else r = cpg_mcast_joined(entry->handle, CPG_TYPE_AGREED, &iov, 1); #endif if (r == CS_OK) return 0; /* error codes found in openais/cpg.h */ LOG_ERROR("cpg_mcast_joined error: %d", r); rq->u_rq.error = -EBADE; return -EBADE; } static struct clog_request *get_matching_rq(struct clog_request *rq, struct dm_list *l) { struct clog_request *match, *n; dm_list_iterate_items_gen_safe(match, n, l, u.list) if (match->u_rq.seq == rq->u_rq.seq) { dm_list_del(&match->u.list); return match; } return NULL; } static char rq_buffer[DM_ULOG_REQUEST_SIZE]; static int handle_cluster_request(struct clog_cpg *entry __attribute__((unused)), struct clog_request *rq, int server) { int r = 0; struct clog_request *tmp = (struct clog_request *)rq_buffer; /* * We need a separate dm_ulog_request struct, one that can carry * a return payload. Otherwise, the memory address after * rq will be altered - leading to problems */ memset(rq_buffer, 0, sizeof(rq_buffer)); memcpy(tmp, rq, sizeof(struct clog_request) + rq->u_rq.data_size); /* * With resumes, we only handle our own. * Resume is a special case that requires * local action (to set up CPG), followed by * a cluster action to co-ordinate reading * the disk and checkpointing */ if (tmp->u_rq.request_type == DM_ULOG_RESUME) { if (tmp->originator == my_cluster_id) { r = do_request(tmp, server); r = kernel_send(&tmp->u_rq); if (r < 0) LOG_ERROR("Failed to send resume response to kernel"); } return r; } r = do_request(tmp, server); if (server && (tmp->u_rq.request_type != DM_ULOG_CLEAR_REGION) && (tmp->u_rq.request_type != DM_ULOG_POSTSUSPEND)) { tmp->u_rq.request_type |= DM_ULOG_RESPONSE; /* * Errors from previous functions are in the rq struct. */ r = cluster_send(tmp); if (r < 0) LOG_ERROR("cluster_send failed: %s", strerror(-r)); } return r; } static int handle_cluster_response(struct clog_cpg *entry, struct clog_request *rq) { int r = 0; struct clog_request *orig_rq; /* * If I didn't send it, then I don't care about the response */ if (rq->originator != my_cluster_id) return 0; rq->u_rq.request_type &= ~DM_ULOG_RESPONSE; orig_rq = get_matching_rq(rq, &entry->working_list); if (!orig_rq) { /* Unable to find match for response */ LOG_ERROR("[%s] No match for cluster response: %s:%u", SHORT_UUID(rq->u_rq.uuid), _RQ_TYPE(rq->u_rq.request_type), rq->u_rq.seq); LOG_ERROR("Current local list:"); if (dm_list_empty(&entry->working_list)) LOG_ERROR(" [none]"); dm_list_iterate_items_gen(orig_rq, &entry->working_list, u.list) LOG_ERROR(" [%s] %s:%u", SHORT_UUID(orig_rq->u_rq.uuid), _RQ_TYPE(orig_rq->u_rq.request_type), orig_rq->u_rq.seq); return -EINVAL; } if (log_resp_rec > 0) { LOG_COND(log_resend_requests, "[%s] Response received to %s/#%u", SHORT_UUID(rq->u_rq.uuid), _RQ_TYPE(rq->u_rq.request_type), rq->u_rq.seq); log_resp_rec--; } /* FIXME: Ensure memcpy cannot explode */ memcpy(orig_rq, rq, sizeof(*rq) + rq->u_rq.data_size); r = kernel_send(&orig_rq->u_rq); if (r) LOG_ERROR("Failed to send response to kernel"); free(orig_rq); return r; } static struct clog_cpg *find_clog_cpg(cpg_handle_t handle) { struct clog_cpg *match; dm_list_iterate_items(match, &clog_cpg_list) if (match->handle == handle) return match; return NULL; } /* * prepare_checkpoint * @entry: clog_cpg describing the log * @cp_requester: nodeid requesting the checkpoint * * Creates and fills in a new checkpoint_data struct. * * Returns: checkpoint_data on success, NULL on error */ static struct checkpoint_data *prepare_checkpoint(struct clog_cpg *entry, uint32_t cp_requester) { int r; struct checkpoint_data *new; if (entry->state != VALID) { /* * We can't store bitmaps yet, because the log is not * valid yet. */ LOG_ERROR("Forced to refuse checkpoint for nodeid %u - log not valid yet", cp_requester); return NULL; } new = malloc(sizeof(*new)); if (!new) { LOG_ERROR("Unable to create checkpoint data for %u", cp_requester); return NULL; } memset(new, 0, sizeof(*new)); new->requester = cp_requester; strncpy(new->uuid, entry->name.value, entry->name.length); new->bitmap_size = push_state(entry->name.value, entry->luid, "clean_bits", &new->clean_bits, cp_requester); if (new->bitmap_size <= 0) { LOG_ERROR("Failed to store clean_bits to checkpoint for node %u", new->requester); free(new); return NULL; } new->bitmap_size = push_state(entry->name.value, entry->luid, "sync_bits", &new->sync_bits, cp_requester); if (new->bitmap_size <= 0) { LOG_ERROR("Failed to store sync_bits to checkpoint for node %u", new->requester); free(new->clean_bits); free(new); return NULL; } r = push_state(entry->name.value, entry->luid, "recovering_region", &new->recovering_region, cp_requester); if (r <= 0) { LOG_ERROR("Failed to store recovering_region to checkpoint for node %u", new->requester); free(new->sync_bits); free(new->clean_bits); free(new); return NULL; } LOG_DBG("[%s] Checkpoint prepared for node %u:", SHORT_UUID(new->uuid), new->requester); LOG_DBG(" bitmap_size = %d", new->bitmap_size); return new; } /* * free_checkpoint * @cp: the checkpoint_data struct to free * */ static void free_checkpoint(struct checkpoint_data *cp) { free(cp->recovering_region); free(cp->sync_bits); free(cp->clean_bits); free(cp); } #if CMIRROR_HAS_CHECKPOINT static int export_checkpoint(struct checkpoint_data *cp) { SaCkptCheckpointCreationAttributesT attr; SaCkptCheckpointHandleT h; SaCkptSectionIdT section_id; SaCkptSectionCreationAttributesT section_attr; SaCkptCheckpointOpenFlagsT flags; SaNameT name; SaAisErrorT rv; struct clog_request *rq; int len, r = 0; char buf[32]; LOG_DBG("Sending checkpointed data to %u", cp->requester); len = snprintf((char *)(name.value), SA_MAX_NAME_LENGTH, "bitmaps_%s_%u", SHORT_UUID(cp->uuid), cp->requester); name.length = (SaUint16T)len; len = (int)strlen(cp->recovering_region) + 1; attr.creationFlags = SA_CKPT_WR_ALL_REPLICAS; attr.checkpointSize = cp->bitmap_size * 2 + len; attr.retentionDuration = SA_TIME_MAX; attr.maxSections = 4; /* don't know why we need +1 */ attr.maxSectionSize = (cp->bitmap_size > len) ? cp->bitmap_size : len; attr.maxSectionIdSize = 22; flags = SA_CKPT_CHECKPOINT_READ | SA_CKPT_CHECKPOINT_WRITE | SA_CKPT_CHECKPOINT_CREATE; open_retry: rv = saCkptCheckpointOpen(ckpt_handle, &name, &attr, flags, 0, &h); if (rv == SA_AIS_ERR_TRY_AGAIN) { LOG_ERROR("export_checkpoint: ckpt open retry"); usleep(1000); goto open_retry; } if (rv == SA_AIS_ERR_EXIST) { LOG_DBG("export_checkpoint: checkpoint already exists"); return -EEXIST; } if (rv != SA_AIS_OK) { LOG_ERROR("[%s] Failed to open checkpoint for %u: %s", SHORT_UUID(cp->uuid), cp->requester, str_ais_error(rv)); return -EIO; /* FIXME: better error */ } /* * Add section for sync_bits */ section_id.idLen = (SaUint16T)snprintf(buf, 32, "sync_bits"); section_id.id = (unsigned char *)buf; section_attr.sectionId = §ion_id; section_attr.expirationTime = SA_TIME_END; sync_create_retry: rv = saCkptSectionCreate(h, §ion_attr, cp->sync_bits, cp->bitmap_size); if (rv == SA_AIS_ERR_TRY_AGAIN) { LOG_ERROR("Sync checkpoint section create retry"); usleep(1000); goto sync_create_retry; } if (rv == SA_AIS_ERR_EXIST) { LOG_DBG("Sync checkpoint section already exists"); saCkptCheckpointClose(h); return -EEXIST; } if (rv != SA_AIS_OK) { LOG_ERROR("Sync checkpoint section creation failed: %s", str_ais_error(rv)); saCkptCheckpointClose(h); return -EIO; /* FIXME: better error */ } /* * Add section for clean_bits */ section_id.idLen = snprintf(buf, 32, "clean_bits"); section_id.id = (unsigned char *)buf; section_attr.sectionId = §ion_id; section_attr.expirationTime = SA_TIME_END; clean_create_retry: rv = saCkptSectionCreate(h, §ion_attr, cp->clean_bits, cp->bitmap_size); if (rv == SA_AIS_ERR_TRY_AGAIN) { LOG_ERROR("Clean checkpoint section create retry"); usleep(1000); goto clean_create_retry; } if (rv == SA_AIS_ERR_EXIST) { LOG_DBG("Clean checkpoint section already exists"); saCkptCheckpointClose(h); return -EEXIST; } if (rv != SA_AIS_OK) { LOG_ERROR("Clean checkpoint section creation failed: %s", str_ais_error(rv)); saCkptCheckpointClose(h); return -EIO; /* FIXME: better error */ } /* * Add section for recovering_region */ section_id.idLen = snprintf(buf, 32, "recovering_region"); section_id.id = (unsigned char *)buf; section_attr.sectionId = §ion_id; section_attr.expirationTime = SA_TIME_END; rr_create_retry: rv = saCkptSectionCreate(h, §ion_attr, cp->recovering_region, strlen(cp->recovering_region) + 1); if (rv == SA_AIS_ERR_TRY_AGAIN) { LOG_ERROR("RR checkpoint section create retry"); usleep(1000); goto rr_create_retry; } if (rv == SA_AIS_ERR_EXIST) { LOG_DBG("RR checkpoint section already exists"); saCkptCheckpointClose(h); return -EEXIST; } if (rv != SA_AIS_OK) { LOG_ERROR("RR checkpoint section creation failed: %s", str_ais_error(rv)); saCkptCheckpointClose(h); return -EIO; /* FIXME: better error */ } LOG_DBG("export_checkpoint: closing checkpoint"); saCkptCheckpointClose(h); rq = malloc(DM_ULOG_REQUEST_SIZE); if (!rq) { LOG_ERROR("export_checkpoint: Unable to allocate transfer structs"); return -ENOMEM; } memset(rq, 0, sizeof(*rq)); dm_list_init(&rq->u.list); rq->u_rq.request_type = DM_ULOG_CHECKPOINT_READY; rq->originator = cp->requester; /* FIXME: hack to overload meaning of originator */ strncpy(rq->u_rq.uuid, cp->uuid, CPG_MAX_NAME_LENGTH); rq->u_rq.seq = my_cluster_id; r = cluster_send(rq); if (r) LOG_ERROR("Failed to send checkpoint ready notice: %s", strerror(-r)); free(rq); return 0; } #else static int export_checkpoint(struct checkpoint_data *cp) { int r, rq_size; struct clog_request *rq; rq_size = sizeof(*rq); rq_size += RECOVERING_REGION_SECTION_SIZE; rq_size += cp->bitmap_size * 2; /* clean|sync_bits */ rq = malloc(rq_size); if (!rq) { LOG_ERROR("export_checkpoint: " "Unable to allocate transfer structs"); return -ENOMEM; } memset(rq, 0, rq_size); dm_list_init(&rq->u.list); rq->u_rq.request_type = DM_ULOG_CHECKPOINT_READY; rq->originator = cp->requester; strncpy(rq->u_rq.uuid, cp->uuid, CPG_MAX_NAME_LENGTH); rq->u_rq.seq = my_cluster_id; rq->u_rq.data_size = rq_size - sizeof(*rq); /* Sync bits */ memcpy(rq->u_rq.data, cp->sync_bits, cp->bitmap_size); /* Clean bits */ memcpy(rq->u_rq.data + cp->bitmap_size, cp->clean_bits, cp->bitmap_size); /* Recovering region */ memcpy(rq->u_rq.data + (cp->bitmap_size * 2), cp->recovering_region, strlen(cp->recovering_region)); r = cluster_send(rq); if (r) LOG_ERROR("Failed to send checkpoint ready notice: %s", strerror(-r)); free(rq); return 0; } #endif /* CMIRROR_HAS_CHECKPOINT */ #if CMIRROR_HAS_CHECKPOINT static int import_checkpoint(struct clog_cpg *entry, int no_read, struct clog_request *rq __attribute__((unused))) { int rtn = 0; SaCkptCheckpointHandleT h; SaCkptSectionIterationHandleT itr; SaCkptSectionDescriptorT desc; SaCkptIOVectorElementT iov; SaNameT name; SaAisErrorT rv; char *bitmap = NULL; int len; bitmap = malloc(1024*1024); if (!bitmap) return -ENOMEM; len = snprintf((char *)(name.value), SA_MAX_NAME_LENGTH, "bitmaps_%s_%u", SHORT_UUID(entry->name.value), my_cluster_id); name.length = (SaUint16T)len; open_retry: rv = saCkptCheckpointOpen(ckpt_handle, &name, NULL, SA_CKPT_CHECKPOINT_READ, 0, &h); if (rv == SA_AIS_ERR_TRY_AGAIN) { LOG_ERROR("import_checkpoint: ckpt open retry"); usleep(1000); goto open_retry; } if (rv != SA_AIS_OK) { LOG_ERROR("[%s] Failed to open checkpoint: %s", SHORT_UUID(entry->name.value), str_ais_error(rv)); free(bitmap); return -EIO; /* FIXME: better error */ } unlink_retry: rv = saCkptCheckpointUnlink(ckpt_handle, &name); if (rv == SA_AIS_ERR_TRY_AGAIN) { LOG_ERROR("import_checkpoint: ckpt unlink retry"); usleep(1000); goto unlink_retry; } if (no_read) { LOG_DBG("Checkpoint for this log already received"); goto no_read; } init_retry: rv = saCkptSectionIterationInitialize(h, SA_CKPT_SECTIONS_ANY, SA_TIME_END, &itr); if (rv == SA_AIS_ERR_TRY_AGAIN) { LOG_ERROR("import_checkpoint: sync create retry"); usleep(1000); goto init_retry; } if (rv != SA_AIS_OK) { LOG_ERROR("[%s] Sync checkpoint section creation failed: %s", SHORT_UUID(entry->name.value), str_ais_error(rv)); free(bitmap); return -EIO; /* FIXME: better error */ } len = 0; while (1) { rv = saCkptSectionIterationNext(itr, &desc); if (rv == SA_AIS_OK) len++; else if ((rv == SA_AIS_ERR_NO_SECTIONS) && len) break; else if (rv != SA_AIS_ERR_TRY_AGAIN) { LOG_ERROR("saCkptSectionIterationNext failure: %d", rv); break; } } saCkptSectionIterationFinalize(itr); if (len != 3) { LOG_ERROR("import_checkpoint: %d checkpoint sections found", len); usleep(1000); goto init_retry; } saCkptSectionIterationInitialize(h, SA_CKPT_SECTIONS_ANY, SA_TIME_END, &itr); while (1) { rv = saCkptSectionIterationNext(itr, &desc); if (rv == SA_AIS_ERR_NO_SECTIONS) break; if (rv == SA_AIS_ERR_TRY_AGAIN) { LOG_ERROR("import_checkpoint: ckpt iternext retry"); usleep(1000); continue; } if (rv != SA_AIS_OK) { LOG_ERROR("import_checkpoint: clean checkpoint section " "creation failed: %s", str_ais_error(rv)); rtn = -EIO; /* FIXME: better error */ goto fail; } if (!desc.sectionSize) { LOG_ERROR("Checkpoint section empty"); continue; } memset(bitmap, 0, sizeof(*bitmap)); iov.sectionId = desc.sectionId; iov.dataBuffer = bitmap; iov.dataSize = desc.sectionSize; iov.dataOffset = 0; read_retry: rv = saCkptCheckpointRead(h, &iov, 1, NULL); if (rv == SA_AIS_ERR_TRY_AGAIN) { LOG_ERROR("ckpt read retry"); usleep(1000); goto read_retry; } if (rv != SA_AIS_OK) { LOG_ERROR("import_checkpoint: ckpt read error: %s", str_ais_error(rv)); rtn = -EIO; /* FIXME: better error */ goto fail; } if (iov.readSize) { if (pull_state(entry->name.value, entry->luid, (char *)desc.sectionId.id, bitmap, iov.readSize)) { LOG_ERROR("Error loading state"); rtn = -EIO; goto fail; } } else { /* Need to request new checkpoint */ rtn = -EAGAIN; goto fail; } } fail: saCkptSectionIterationFinalize(itr); no_read: saCkptCheckpointClose(h); free(bitmap); return rtn; } #else static int import_checkpoint(struct clog_cpg *entry, int no_read, struct clog_request *rq) { int bitmap_size; bitmap_size = (rq->u_rq.data_size - RECOVERING_REGION_SECTION_SIZE) / 2; if (bitmap_size < 0) { LOG_ERROR("Checkpoint has invalid payload size."); return -EINVAL; } if (pull_state(entry->name.value, entry->luid, "sync_bits", rq->u_rq.data, bitmap_size) || pull_state(entry->name.value, entry->luid, "clean_bits", rq->u_rq.data + bitmap_size, bitmap_size) || pull_state(entry->name.value, entry->luid, "recovering_region", rq->u_rq.data + (bitmap_size * 2), RECOVERING_REGION_SECTION_SIZE)) { LOG_ERROR("Error loading bitmap state from checkpoint."); return -EIO; } return 0; } #endif /* CMIRROR_HAS_CHECKPOINT */ static void do_checkpoints(struct clog_cpg *entry, int leaving) { struct checkpoint_data *cp; for (cp = entry->checkpoint_list; cp;) { /* * FIXME: Check return code. Could send failure * notice in rq in export_checkpoint function * by setting rq->error */ switch (export_checkpoint(cp)) { case -EEXIST: LOG_SPRINT(entry, "[%s] Checkpoint for %u already handled%s", SHORT_UUID(entry->name.value), cp->requester, (leaving) ? "(L)": ""); LOG_COND(log_checkpoint, "[%s] Checkpoint for %u already handled%s", SHORT_UUID(entry->name.value), cp->requester, (leaving) ? "(L)": ""); entry->checkpoint_list = cp->next; free_checkpoint(cp); cp = entry->checkpoint_list; break; case 0: LOG_SPRINT(entry, "[%s] Checkpoint data available for node %u%s", SHORT_UUID(entry->name.value), cp->requester, (leaving) ? "(L)": ""); LOG_COND(log_checkpoint, "[%s] Checkpoint data available for node %u%s", SHORT_UUID(entry->name.value), cp->requester, (leaving) ? "(L)": ""); entry->checkpoint_list = cp->next; free_checkpoint(cp); cp = entry->checkpoint_list; break; default: /* FIXME: Skipping will cause list corruption */ LOG_ERROR("[%s] Failed to export checkpoint for %u%s", SHORT_UUID(entry->name.value), cp->requester, (leaving) ? "(L)": ""); } } } static int resend_requests(struct clog_cpg *entry) { int r = 0; struct clog_request *rq, *n; if (!entry->resend_requests || entry->delay) return 0; if (entry->state != VALID) return 0; entry->resend_requests = 0; dm_list_iterate_items_gen_safe(rq, n, &entry->working_list, u.list) { dm_list_del(&rq->u.list); if (strcmp(entry->name.value, rq->u_rq.uuid)) { LOG_ERROR("[%s] Stray request from another log (%s)", SHORT_UUID(entry->name.value), SHORT_UUID(rq->u_rq.uuid)); free(rq); continue; } switch (rq->u_rq.request_type) { case DM_ULOG_SET_REGION_SYNC: /* * Some requests simply do not need to be resent. * If it is a request that just changes log state, * then it doesn't need to be resent (everyone makes * updates). */ LOG_COND(log_resend_requests, "[%s] Skipping resend of %s/#%u...", SHORT_UUID(entry->name.value), _RQ_TYPE(rq->u_rq.request_type), rq->u_rq.seq); LOG_SPRINT(entry, "### No resend: [%s] %s/%u ###", SHORT_UUID(entry->name.value), _RQ_TYPE(rq->u_rq.request_type), rq->u_rq.seq); rq->u_rq.data_size = 0; if (kernel_send(&rq->u_rq)) LOG_ERROR("Failed to respond to kernel [%s]", RQ_TYPE(rq->u_rq.request_type)); break; default: /* * If an action or a response is required, then * the request must be resent. */ LOG_COND(log_resend_requests, "[%s] Resending %s(#%u) due to new server(%u)", SHORT_UUID(entry->name.value), _RQ_TYPE(rq->u_rq.request_type), rq->u_rq.seq, entry->lowest_id); LOG_SPRINT(entry, "*** Resending: [%s] %s/%u ***", SHORT_UUID(entry->name.value), _RQ_TYPE(rq->u_rq.request_type), rq->u_rq.seq); r = cluster_send(rq); if (r < 0) LOG_ERROR("Failed resend"); } free(rq); } return r; } static int do_cluster_work(void *data __attribute__((unused))) { int r = CS_OK; struct clog_cpg *entry, *tmp; dm_list_iterate_items_safe(entry, tmp, &clog_cpg_list) { r = cpg_dispatch(entry->handle, CS_DISPATCH_ALL); if (r != CS_OK) LOG_ERROR("cpg_dispatch failed: %d", r); if (entry->free_me) { free(entry); continue; } do_checkpoints(entry, 0); resend_requests(entry); } return (r == CS_OK) ? 0 : -1; /* FIXME: good error number? */ } static int flush_startup_list(struct clog_cpg *entry) { int r = 0; int i_was_server; struct clog_request *rq, *n; struct checkpoint_data *new; dm_list_iterate_items_gen_safe(rq, n, &entry->startup_list, u.list) { dm_list_del(&rq->u.list); if (rq->u_rq.request_type == DM_ULOG_MEMBER_JOIN) { new = prepare_checkpoint(entry, rq->originator); if (!new) { /* * FIXME: Need better error handling. Other nodes * will be trying to send the checkpoint too, and we * must continue processing the list; so report error * but continue. */ LOG_ERROR("Failed to prepare checkpoint for %u!!!", rq->originator); free(rq); continue; } LOG_SPRINT(entry, "[%s] Checkpoint prepared for %u", SHORT_UUID(entry->name.value), rq->originator); LOG_COND(log_checkpoint, "[%s] Checkpoint prepared for %u", SHORT_UUID(entry->name.value), rq->originator); new->next = entry->checkpoint_list; entry->checkpoint_list = new; } else { LOG_DBG("[%s] Processing delayed request: %s", SHORT_UUID(rq->u_rq.uuid), _RQ_TYPE(rq->u_rq.request_type)); i_was_server = (rq->pit_server == my_cluster_id) ? 1 : 0; r = handle_cluster_request(entry, rq, i_was_server); if (r) /* * FIXME: If we error out here, we will never get * another opportunity to retry these requests */ LOG_ERROR("Error while processing delayed CPG message"); } free(rq); } return 0; } static void cpg_message_callback(cpg_handle_t handle, const struct cpg_name *gname __attribute__((unused)), uint32_t nodeid, uint32_t pid __attribute__((unused)), void *msg, size_t msg_len) { int i; int r = 0; int i_am_server; int response = 0; struct clog_request *rq = msg; struct clog_request *tmp_rq; struct clog_cpg *match; match = find_clog_cpg(handle); if (!match) { LOG_ERROR("Unable to find clog_cpg for cluster message"); return; } /* * Perform necessary endian and version compatibility conversions */ if (clog_request_from_network(rq, msg_len) < 0) /* Any error messages come from 'clog_request_from_network' */ return; if ((nodeid == my_cluster_id) && !(rq->u_rq.request_type & DM_ULOG_RESPONSE) && (rq->u_rq.request_type != DM_ULOG_RESUME) && (rq->u_rq.request_type != DM_ULOG_CLEAR_REGION) && (rq->u_rq.request_type != DM_ULOG_CHECKPOINT_READY)) { tmp_rq = malloc(DM_ULOG_REQUEST_SIZE); if (!tmp_rq) { /* * FIXME: It may be possible to continue... but we * would not be able to resend any messages that might * be necessary during membership changes */ LOG_ERROR("[%s] Unable to record request: -ENOMEM", SHORT_UUID(rq->u_rq.uuid)); return; } memcpy(tmp_rq, rq, sizeof(*rq) + rq->u_rq.data_size); dm_list_init(&tmp_rq->u.list); dm_list_add(&match->working_list, &tmp_rq->u.list); } if (rq->u_rq.request_type == DM_ULOG_POSTSUSPEND) { /* * If the server (lowest_id) indicates it is leaving, * then we must resend any outstanding requests. However, * we do not want to resend them if the next server in * line is in the process of leaving. */ if (nodeid == my_cluster_id) { LOG_COND(log_resend_requests, "[%s] I am leaving.1.....", SHORT_UUID(rq->u_rq.uuid)); } else { if (nodeid < my_cluster_id) { if (nodeid == match->lowest_id) { match->resend_requests = 1; LOG_COND(log_resend_requests, "[%s] %u is leaving, resend required%s", SHORT_UUID(rq->u_rq.uuid), nodeid, (dm_list_empty(&match->working_list)) ? " -- working_list empty": ""); dm_list_iterate_items_gen(tmp_rq, &match->working_list, u.list) LOG_COND(log_resend_requests, "[%s] %s/%u", SHORT_UUID(tmp_rq->u_rq.uuid), _RQ_TYPE(tmp_rq->u_rq.request_type), tmp_rq->u_rq.seq); } match->delay++; LOG_COND(log_resend_requests, "[%s] %u is leaving, delay = %d", SHORT_UUID(rq->u_rq.uuid), nodeid, match->delay); } rq->originator = nodeid; /* don't really need this, but nice for debug */ goto out; } } /* * We can receive messages after we do a cpg_leave but before we * get our config callback. However, since we can't respond after * leaving, we simply return. */ if (match->state == LEAVING) return; i_am_server = (my_cluster_id == match->lowest_id) ? 1 : 0; if (rq->u_rq.request_type == DM_ULOG_CHECKPOINT_READY) { if (my_cluster_id == rq->originator) { /* Redundant checkpoints ignored if match->valid */ LOG_SPRINT(match, "[%s] CHECKPOINT_READY notification from %u", SHORT_UUID(rq->u_rq.uuid), nodeid); if (import_checkpoint(match, (match->state != INVALID), rq)) { LOG_SPRINT(match, "[%s] Failed to import checkpoint from %u", SHORT_UUID(rq->u_rq.uuid), nodeid); LOG_ERROR("[%s] Failed to import checkpoint from %u", SHORT_UUID(rq->u_rq.uuid), nodeid); kill(getpid(), SIGUSR1); /* Could we retry? */ goto out; } else if (match->state == INVALID) { LOG_SPRINT(match, "[%s] Checkpoint data received from %u. Log is now valid", SHORT_UUID(match->name.value), nodeid); LOG_COND(log_checkpoint, "[%s] Checkpoint data received from %u. Log is now valid", SHORT_UUID(match->name.value), nodeid); match->state = VALID; flush_startup_list(match); } else { LOG_SPRINT(match, "[%s] Redundant checkpoint from %u ignored.", SHORT_UUID(rq->u_rq.uuid), nodeid); } } goto out; } if (rq->u_rq.request_type & DM_ULOG_RESPONSE) { response = 1; r = handle_cluster_response(match, rq); } else { rq->originator = nodeid; if (match->state == LEAVING) { LOG_ERROR("[%s] Ignoring %s from %u. Reason: I'm leaving", SHORT_UUID(rq->u_rq.uuid), _RQ_TYPE(rq->u_rq.request_type), rq->originator); goto out; } if (match->state == INVALID) { LOG_DBG("Log not valid yet, storing request"); tmp_rq = malloc(DM_ULOG_REQUEST_SIZE); if (!tmp_rq) { LOG_ERROR("cpg_message_callback: Unable to" " allocate transfer structs"); r = -ENOMEM; /* FIXME: Better error #? */ goto out; } memcpy(tmp_rq, rq, sizeof(*rq) + rq->u_rq.data_size); tmp_rq->pit_server = match->lowest_id; dm_list_init(&tmp_rq->u.list); dm_list_add(&match->startup_list, &tmp_rq->u.list); goto out; } r = handle_cluster_request(match, rq, i_am_server); } /* * If the log is now valid, we can queue the checkpoints */ for (i = match->checkpoints_needed; i; ) { struct checkpoint_data *new; if (log_get_state(&rq->u_rq) != LOG_RESUMED) { LOG_DBG("[%s] Withholding checkpoints until log is valid (%s from %u)", SHORT_UUID(rq->u_rq.uuid), _RQ_TYPE(rq->u_rq.request_type), nodeid); break; } i--; new = prepare_checkpoint(match, match->checkpoint_requesters[i]); if (!new) { /* FIXME: Need better error handling */ LOG_ERROR("[%s] Failed to prepare checkpoint for %u!!!", SHORT_UUID(rq->u_rq.uuid), match->checkpoint_requesters[i]); break; } LOG_SPRINT(match, "[%s] Checkpoint prepared for %u* (%s)", SHORT_UUID(rq->u_rq.uuid), match->checkpoint_requesters[i], (log_get_state(&rq->u_rq) != LOG_RESUMED)? "LOG_RESUMED": "LOG_SUSPENDED"); LOG_COND(log_checkpoint, "[%s] Checkpoint prepared for %u*", SHORT_UUID(rq->u_rq.uuid), match->checkpoint_requesters[i]); match->checkpoints_needed--; new->next = match->checkpoint_list; match->checkpoint_list = new; } out: /* nothing happens after this point. It is just for debugging */ if (r) { LOG_ERROR("[%s] Error while processing CPG message, %s: %s", SHORT_UUID(rq->u_rq.uuid), _RQ_TYPE(rq->u_rq.request_type & ~DM_ULOG_RESPONSE), strerror(-r)); LOG_ERROR("[%s] Response : %s", SHORT_UUID(rq->u_rq.uuid), (response) ? "YES" : "NO"); LOG_ERROR("[%s] Originator: %u", SHORT_UUID(rq->u_rq.uuid), rq->originator); if (response) LOG_ERROR("[%s] Responder : %u", SHORT_UUID(rq->u_rq.uuid), nodeid); LOG_ERROR("HISTORY::"); for (i = 0; i < DEBUGGING_HISTORY; i++) { match->idx++; match->idx = match->idx % DEBUGGING_HISTORY; if (match->debugging[match->idx][0] == '\0') continue; LOG_ERROR("%d:%d) %s", i, match->idx, match->debugging[match->idx]); } } else if (!(rq->u_rq.request_type & DM_ULOG_RESPONSE) || (rq->originator == my_cluster_id)) { if (!response) LOG_SPRINT(match, "SEQ#=%u, UUID=%s, TYPE=%s, ORIG=%u, RESP=%s", rq->u_rq.seq, SHORT_UUID(rq->u_rq.uuid), _RQ_TYPE(rq->u_rq.request_type), rq->originator, (response) ? "YES" : "NO"); else LOG_SPRINT(match, "SEQ#=%u, UUID=%s, TYPE=%s, ORIG=%u, RESP=%s, RSPR=%u, error=%d", rq->u_rq.seq, SHORT_UUID(rq->u_rq.uuid), _RQ_TYPE(rq->u_rq.request_type), rq->originator, (response) ? "YES" : "NO", nodeid, rq->u_rq.error); } } static void cpg_join_callback(struct clog_cpg *match, const struct cpg_address *joined, const struct cpg_address *member_list, size_t member_list_entries) { unsigned i; uint32_t my_pid = (uint32_t)getpid(); uint32_t lowest = match->lowest_id; struct clog_request *rq; char dbuf[32] = { 0 }; /* Assign my_cluster_id */ if ((my_cluster_id == 0xDEAD) && (joined->pid == my_pid)) my_cluster_id = joined->nodeid; /* Am I the very first to join? */ if (member_list_entries == 1) { match->lowest_id = joined->nodeid; match->state = VALID; } /* If I am part of the joining list, I do not send checkpoints */ if (joined->nodeid == my_cluster_id) goto out; for (i = 0; i < member_list_entries - 1; i++) sprintf(dbuf+strlen(dbuf), "%u-", member_list[i].nodeid); sprintf(dbuf+strlen(dbuf), "(%u)", joined->nodeid); LOG_COND(log_checkpoint, "[%s] Joining node, %u needs checkpoint [%s]", SHORT_UUID(match->name.value), joined->nodeid, dbuf); /* * FIXME: remove checkpoint_requesters/checkpoints_needed, and use * the startup_list interface exclusively */ if (dm_list_empty(&match->startup_list) && (match->state == VALID) && (match->checkpoints_needed < MAX_CHECKPOINT_REQUESTERS)) { match->checkpoint_requesters[match->checkpoints_needed++] = joined->nodeid; goto out; } rq = malloc(DM_ULOG_REQUEST_SIZE); if (!rq) { LOG_ERROR("cpg_config_callback: " "Unable to allocate transfer structs"); LOG_ERROR("cpg_config_callback: " "Unable to perform checkpoint"); goto out; } rq->u_rq.request_type = DM_ULOG_MEMBER_JOIN; rq->originator = joined->nodeid; dm_list_init(&rq->u.list); dm_list_add(&match->startup_list, &rq->u.list); out: /* Find the lowest_id, i.e. the server */ match->lowest_id = member_list[0].nodeid; for (i = 0; i < member_list_entries; i++) if (match->lowest_id > member_list[i].nodeid) match->lowest_id = member_list[i].nodeid; if (lowest == 0xDEAD) LOG_COND(log_membership_change, "[%s] Server change -> %u (%u %s)", SHORT_UUID(match->name.value), match->lowest_id, joined->nodeid, (member_list_entries == 1) ? "is first to join" : "joined"); else if (lowest != match->lowest_id) LOG_COND(log_membership_change, "[%s] Server change %u -> %u (%u joined)", SHORT_UUID(match->name.value), lowest, match->lowest_id, joined->nodeid); else LOG_COND(log_membership_change, "[%s] Server unchanged at %u (%u joined)", SHORT_UUID(match->name.value), lowest, joined->nodeid); LOG_SPRINT(match, "+++ UUID=%s %u join +++", SHORT_UUID(match->name.value), joined->nodeid); } static void cpg_leave_callback(struct clog_cpg *match, const struct cpg_address *left, const struct cpg_address *member_list, size_t member_list_entries) { unsigned i; int j, fd; uint32_t lowest = match->lowest_id; struct clog_request *rq, *n; struct checkpoint_data *p_cp, *c_cp; LOG_SPRINT(match, "--- UUID=%s %u left ---", SHORT_UUID(match->name.value), left->nodeid); /* Am I leaving? */ if (my_cluster_id == left->nodeid) { LOG_DBG("Finalizing leave..."); dm_list_del(&match->list); cpg_fd_get(match->handle, &fd); links_unregister(fd); cluster_postsuspend(match->name.value, match->luid); dm_list_iterate_items_gen_safe(rq, n, &match->working_list, u.list) { dm_list_del(&rq->u.list); if (rq->u_rq.request_type == DM_ULOG_POSTSUSPEND) if (kernel_send(&rq->u_rq)) LOG_ERROR("Failed to respond to kernel [%s]", RQ_TYPE(rq->u_rq.request_type)); free(rq); } cpg_finalize(match->handle); match->free_me = 1; match->lowest_id = 0xDEAD; match->state = INVALID; } /* Remove any pending checkpoints for the leaving node. */ for (p_cp = NULL, c_cp = match->checkpoint_list; c_cp && (c_cp->requester != left->nodeid); p_cp = c_cp, c_cp = c_cp->next); if (c_cp) { if (p_cp) p_cp->next = c_cp->next; else match->checkpoint_list = c_cp->next; LOG_COND(log_checkpoint, "[%s] Removing pending checkpoint (%u is leaving)", SHORT_UUID(match->name.value), left->nodeid); free_checkpoint(c_cp); } dm_list_iterate_items_gen_safe(rq, n, &match->startup_list, u.list) { if ((rq->u_rq.request_type == DM_ULOG_MEMBER_JOIN) && (rq->originator == left->nodeid)) { LOG_COND(log_checkpoint, "[%s] Removing pending ckpt from startup list (%u is leaving)", SHORT_UUID(match->name.value), left->nodeid); dm_list_del(&rq->u.list); free(rq); } } for (i = 0, j = 0; i < match->checkpoints_needed; i++, j++) { match->checkpoint_requesters[j] = match->checkpoint_requesters[i]; if (match->checkpoint_requesters[i] == left->nodeid) { LOG_ERROR("[%s] Removing pending ckpt from needed list (%u is leaving)", SHORT_UUID(match->name.value), left->nodeid); j--; } } match->checkpoints_needed = j; if (left->nodeid < my_cluster_id) { match->delay = (match->delay > 0) ? match->delay - 1 : 0; if (!match->delay && dm_list_empty(&match->working_list)) match->resend_requests = 0; LOG_COND(log_resend_requests, "[%s] %u has left, delay = %d%s", SHORT_UUID(match->name.value), left->nodeid, match->delay, (dm_list_empty(&match->working_list)) ? " -- working_list empty": ""); } /* Find the lowest_id, i.e. the server */ if (!member_list_entries) { match->lowest_id = 0xDEAD; LOG_COND(log_membership_change, "[%s] Server change %u -> " "(%u is last to leave)", SHORT_UUID(match->name.value), left->nodeid, left->nodeid); return; } match->lowest_id = member_list[0].nodeid; for (i = 0; i < member_list_entries; i++) if (match->lowest_id > member_list[i].nodeid) match->lowest_id = member_list[i].nodeid; if (lowest != match->lowest_id) { LOG_COND(log_membership_change, "[%s] Server change %u -> %u (%u left)", SHORT_UUID(match->name.value), lowest, match->lowest_id, left->nodeid); } else LOG_COND(log_membership_change, "[%s] Server unchanged at %u (%u left)", SHORT_UUID(match->name.value), lowest, left->nodeid); if ((match->state == INVALID) && !match->free_me) { /* * If all CPG members are waiting for checkpoints and they * are all present in my startup_list, then I was the first to * join and I must assume control. * * We do not normally end up here, but if there was a quick * 'resume -> suspend -> resume' across the cluster, we may * have initially thought we were not the first to join because * of the presence of out-going (and unable to respond) members. */ i = 1; /* We do not have a DM_ULOG_MEMBER_JOIN entry of our own */ dm_list_iterate_items_gen(rq, &match->startup_list, u.list) if (rq->u_rq.request_type == DM_ULOG_MEMBER_JOIN) i++; if (i == member_list_entries) { /* * Last node who could have given me a checkpoint just left. * Setting log state to VALID and acting as 'first join'. */ match->state = VALID; flush_startup_list(match); } } } static void cpg_config_callback(cpg_handle_t handle, const struct cpg_name *gname __attribute__((unused)), 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) { struct clog_cpg *match; int found = 0; dm_list_iterate_items(match, &clog_cpg_list) if (match->handle == handle) { found = 1; break; } if (!found) { LOG_ERROR("Unable to find match for CPG config callback"); return; } if ((joined_list_entries + left_list_entries) > 1) LOG_ERROR("[%s] More than one node joining/leaving", SHORT_UUID(match->name.value)); if (joined_list_entries) cpg_join_callback(match, joined_list, member_list, member_list_entries); else cpg_leave_callback(match, left_list, member_list, member_list_entries); } cpg_callbacks_t cpg_callbacks = { .cpg_deliver_fn = cpg_message_callback, .cpg_confchg_fn = cpg_config_callback, }; /* * remove_checkpoint * @entry * * Returns: 1 if checkpoint removed, 0 if no checkpoints, -EXXX on error */ static int remove_checkpoint(struct clog_cpg *entry) { #if CMIRROR_HAS_CHECKPOINT int len; SaNameT name; SaAisErrorT rv; SaCkptCheckpointHandleT h; len = snprintf((char *)(name.value), SA_MAX_NAME_LENGTH, "bitmaps_%s_%u", SHORT_UUID(entry->name.value), my_cluster_id); name.length = len; open_retry: rv = saCkptCheckpointOpen(ckpt_handle, &name, NULL, SA_CKPT_CHECKPOINT_READ, 0, &h); if (rv == SA_AIS_ERR_TRY_AGAIN) { LOG_ERROR("abort_startup: ckpt open retry"); usleep(1000); goto open_retry; } if (rv != SA_AIS_OK) return 0; LOG_DBG("[%s] Removing checkpoint", SHORT_UUID(entry->name.value)); unlink_retry: rv = saCkptCheckpointUnlink(ckpt_handle, &name); if (rv == SA_AIS_ERR_TRY_AGAIN) { LOG_ERROR("abort_startup: ckpt unlink retry"); usleep(1000); goto unlink_retry; } if (rv != SA_AIS_OK) { LOG_ERROR("[%s] Failed to unlink checkpoint: %s", SHORT_UUID(entry->name.value), str_ais_error(rv)); return -EIO; } saCkptCheckpointClose(h); return 1; #else /* No checkpoint to remove, so 'success' */ return 1; #endif } int create_cluster_cpg(char *uuid, uint64_t luid) { int r; size_t size; struct clog_cpg *new = NULL; struct clog_cpg *tmp; dm_list_iterate_items(tmp, &clog_cpg_list) if (!strncmp(tmp->name.value, uuid, CPG_MAX_NAME_LENGTH)) { LOG_ERROR("Log entry already exists: %s", uuid); return -EEXIST; } new = malloc(sizeof(*new)); if (!new) { LOG_ERROR("Unable to allocate memory for clog_cpg"); return -ENOMEM; } memset(new, 0, sizeof(*new)); dm_list_init(&new->list); new->lowest_id = 0xDEAD; dm_list_init(&new->startup_list); dm_list_init(&new->working_list); size = ((strlen(uuid) + 1) > CPG_MAX_NAME_LENGTH) ? CPG_MAX_NAME_LENGTH : (strlen(uuid) + 1); strncpy(new->name.value, uuid, size); new->name.length = (uint32_t)size; new->luid = luid; /* * Ensure there are no stale checkpoints around before we join */ if (remove_checkpoint(new) == 1) LOG_COND(log_checkpoint, "[%s] Removing checkpoints left from previous session", SHORT_UUID(new->name.value)); r = cpg_initialize(&new->handle, &cpg_callbacks); if (r != CS_OK) { LOG_ERROR("cpg_initialize failed: Cannot join cluster"); free(new); return -EPERM; } r = cpg_join(new->handle, &new->name); if (r != CS_OK) { LOG_ERROR("cpg_join failed: Cannot join cluster"); free(new); return -EPERM; } new->cpg_state = VALID; dm_list_add(&clog_cpg_list, &new->list); LOG_DBG("New handle: %llu", (unsigned long long)new->handle); LOG_DBG("New name: %s", new->name.value); /* FIXME: better variable */ cpg_fd_get(new->handle, &r); links_register(r, "cluster", do_cluster_work, NULL); return 0; } static void abort_startup(struct clog_cpg *del) { struct clog_request *rq, *n; LOG_DBG("[%s] CPG teardown before checkpoint received", SHORT_UUID(del->name.value)); dm_list_iterate_items_gen_safe(rq, n, &del->startup_list, u.list) { dm_list_del(&rq->u.list); LOG_DBG("[%s] Ignoring request from %u: %s", SHORT_UUID(del->name.value), rq->originator, _RQ_TYPE(rq->u_rq.request_type)); free(rq); } remove_checkpoint(del); } static int _destroy_cluster_cpg(struct clog_cpg *del) { int r; int state; LOG_COND(log_resend_requests, "[%s] I am leaving.2.....", SHORT_UUID(del->name.value)); /* * We must send any left over checkpoints before * leaving. If we don't, an incoming node could * be stuck with no checkpoint and stall. do_checkpoints(del); --- THIS COULD BE CAUSING OUR PROBLEMS: - Incoming node deletes old checkpoints before joining - A stale checkpoint is issued here by leaving node - (leaving node leaves) - Incoming node joins cluster and finds stale checkpoint. - (leaving node leaves - option 2) */ do_checkpoints(del, 1); state = del->state; del->cpg_state = INVALID; del->state = LEAVING; /* * If the state is VALID, we might be processing the * startup list. If so, we certainly don't want to * clear the startup_list here by calling abort_startup */ if (!dm_list_empty(&del->startup_list) && (state != VALID)) abort_startup(del); r = cpg_leave(del->handle, &del->name); if (r != CS_OK) LOG_ERROR("Error leaving CPG!"); return 0; } int destroy_cluster_cpg(char *uuid) { struct clog_cpg *del, *tmp; dm_list_iterate_items_safe(del, tmp, &clog_cpg_list) if (!strncmp(del->name.value, uuid, CPG_MAX_NAME_LENGTH)) _destroy_cluster_cpg(del); return 0; } int init_cluster(void) { #if CMIRROR_HAS_CHECKPOINT SaAisErrorT rv; rv = saCkptInitialize(&ckpt_handle, &callbacks, &version); if (rv != SA_AIS_OK) return EXIT_CLUSTER_CKPT_INIT; #endif dm_list_init(&clog_cpg_list); return 0; } void cleanup_cluster(void) { #if CMIRROR_HAS_CHECKPOINT SaAisErrorT err; err = saCkptFinalize(ckpt_handle); if (err != SA_AIS_OK) LOG_ERROR("Failed to finalize checkpoint handle"); #endif } void cluster_debug(void) { struct checkpoint_data *cp; struct clog_cpg *entry; struct clog_request *rq; int i; LOG_ERROR(""); LOG_ERROR("CLUSTER COMPONENT DEBUGGING::"); dm_list_iterate_items(entry, &clog_cpg_list) { LOG_ERROR("%s::", SHORT_UUID(entry->name.value)); LOG_ERROR(" lowest_id : %u", entry->lowest_id); LOG_ERROR(" state : %s", (entry->state == INVALID) ? "INVALID" : (entry->state == VALID) ? "VALID" : (entry->state == LEAVING) ? "LEAVING" : "UNKNOWN"); LOG_ERROR(" cpg_state : %d", entry->cpg_state); LOG_ERROR(" free_me : %d", entry->free_me); LOG_ERROR(" delay : %d", entry->delay); LOG_ERROR(" resend_requests : %d", entry->resend_requests); LOG_ERROR(" checkpoints_needed: %d", entry->checkpoints_needed); for (i = 0, cp = entry->checkpoint_list; i < MAX_CHECKPOINT_REQUESTERS; i++) if (cp) cp = cp->next; else break; LOG_ERROR(" CKPTs waiting : %d", i); LOG_ERROR(" Working list:"); dm_list_iterate_items_gen(rq, &entry->working_list, u.list) LOG_ERROR(" %s/%u", _RQ_TYPE(rq->u_rq.request_type), rq->u_rq.seq); LOG_ERROR(" Startup list:"); dm_list_iterate_items_gen(rq, &entry->startup_list, u.list) LOG_ERROR(" %s/%u", _RQ_TYPE(rq->u_rq.request_type), rq->u_rq.seq); LOG_ERROR("Command History:"); for (i = 0; i < DEBUGGING_HISTORY; i++) { entry->idx++; entry->idx = entry->idx % DEBUGGING_HISTORY; if (entry->debugging[entry->idx][0] == '\0') continue; LOG_ERROR("%d:%d) %s", i, entry->idx, entry->debugging[entry->idx]); } } } lvm2-2.02.98/daemons/cmirrord/link_mon.c0000640000175000017500000000574512037016272016744 0ustar blankblank/* * 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 #include #include 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; } lvm2-2.02.98/daemons/cmirrord/cluster.h0000640000175000017500000000425112037016272016613 0ustar blankblank/* * 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 */ lvm2-2.02.98/daemons/cmirrord/compat.c0000640000175000017500000001201412037016272016404 0ustar blankblank/* * 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 /* * 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; } lvm2-2.02.98/daemons/cmirrord/functions.h0000640000175000017500000000214512037016272017142 0ustar blankblank/* * 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 */ lvm2-2.02.98/daemons/cmirrord/Makefile.in0000640000175000017500000000213712037016272017027 0ustar blankblank# # 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 lvm2-2.02.98/daemons/cmirrord/logging.h0000640000175000017500000000415612037016272016564 0ustar blankblank/* * 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 #include #include /* 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 */ lvm2-2.02.98/daemons/cmirrord/common.h0000640000175000017500000000227112037016272016422 0ustar blankblank/* * 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 */ lvm2-2.02.98/daemons/cmirrord/logging.c0000640000175000017500000000242412037016272016553 0ustar blankblank/* * 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 lvm2-2.02.98/daemons/cmirrord/local.h0000640000175000017500000000123212037016272016220 0ustar blankblank/* * 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 */ lvm2-2.02.98/daemons/cmirrord/link_mon.h0000640000175000017500000000136412037016272016742 0ustar blankblank/* * 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 */ lvm2-2.02.98/daemons/cmirrord/functions.c0000640000175000017500000013271412037016272017143 0ustar blankblank/* * 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 "functions.h" #include #include #include #include #include #include #include #define BYTE_SHIFT 3 /* * Magic for persistent mirrors: "MiRr" * Following on-disk header information is stolen from * drivers/md/dm-log.c */ #define MIRROR_MAGIC 0x4D695272 #define MIRROR_DISK_VERSION 2 #define LOG_OFFSET 2 #define RESYNC_HISTORY 50 //static char resync_history[RESYNC_HISTORY][128]; //static int idx = 0; #define LOG_SPRINT(_lc, f, arg...) do { \ lc->idx++; \ lc->idx = lc->idx % RESYNC_HISTORY; \ sprintf(lc->resync_history[lc->idx], f, ## arg); \ } while (0) struct log_header { uint32_t magic; uint32_t version; uint64_t nr_regions; }; struct log_c { struct dm_list list; char uuid[DM_UUID_LEN]; uint64_t luid; time_t delay; /* limits how fast a resume can happen after suspend */ int touched; int in_sync; /* An in-sync that stays set until suspend/resume */ uint32_t region_size; uint32_t region_count; uint64_t sync_count; dm_bitset_t clean_bits; dm_bitset_t sync_bits; uint32_t recoverer; uint64_t recovering_region; /* -1 means not recovering */ uint64_t skip_bit_warning; /* used to warn if region skipped */ int sync_search; int resume_override; uint32_t block_on_error; enum sync { DEFAULTSYNC, /* Synchronize if necessary */ NOSYNC, /* Devices known to be already in sync */ FORCESYNC, /* Force a sync to happen */ } sync; uint32_t state; /* current operational state of the log */ struct dm_list mark_list; uint32_t recovery_halted; struct recovery_request *recovery_request_list; int disk_fd; /* -1 means no disk log */ int log_dev_failed; uint64_t disk_nr_regions; size_t disk_size; /* size of disk_buffer in bytes */ void *disk_buffer; /* aligned memory for O_DIRECT */ int idx; char resync_history[RESYNC_HISTORY][128]; }; struct mark_entry { struct dm_list list; uint32_t nodeid; uint64_t region; }; struct recovery_request { uint64_t region; struct recovery_request *next; }; static DM_LIST_INIT(log_list); static DM_LIST_INIT(log_pending_list); static int log_test_bit(dm_bitset_t bs, int bit) { return dm_bit(bs, bit) ? 1 : 0; } static void log_set_bit(struct log_c *lc, dm_bitset_t bs, int bit) { dm_bit_set(bs, bit); lc->touched = 1; } static void log_clear_bit(struct log_c *lc, dm_bitset_t bs, int bit) { dm_bit_clear(bs, bit); lc->touched = 1; } static uint64_t find_next_zero_bit(dm_bitset_t bs, unsigned start) { for (; dm_bit(bs, start); start++) if (start >= *bs) return (uint64_t)-1; return start; } static uint64_t count_bits32(dm_bitset_t bs) { unsigned i, size = bs[0]/(unsigned)DM_BITS_PER_INT + 1; unsigned count = 0; for (i = 1; i <= size; i++) count += hweight32(bs[i]); return (uint64_t)count; } /* * get_log * * Returns: log if found, NULL otherwise */ static struct log_c *get_log(const char *uuid, uint64_t luid) { struct log_c *lc; dm_list_iterate_items(lc, &log_list) if (!strcmp(lc->uuid, uuid) && (!luid || (luid == lc->luid))) return lc; return NULL; } /* * get_pending_log * * Pending logs are logs that have been 'clog_ctr'ed, but * have not joined the CPG (via clog_resume). * * Returns: log if found, NULL otherwise */ static struct log_c *get_pending_log(const char *uuid, uint64_t luid) { struct log_c *lc; dm_list_iterate_items(lc, &log_pending_list) if (!strcmp(lc->uuid, uuid) && (!luid || (luid == lc->luid))) return lc; return NULL; } static void header_to_disk(struct log_header *mem, struct log_header *disk) { memcpy(disk, mem, sizeof(struct log_header)); } static void header_from_disk(struct log_header *mem, struct log_header *disk) { memcpy(mem, disk, sizeof(struct log_header)); } static int rw_log(struct log_c *lc, int do_write) { int r; r = (int)lseek(lc->disk_fd, 0, SEEK_SET); if (r < 0) { LOG_ERROR("[%s] rw_log: lseek failure: %s", SHORT_UUID(lc->uuid), strerror(errno)); return -errno; } if (do_write) { /* FIXME Cope with full set of non-error conditions */ r = write(lc->disk_fd, lc->disk_buffer, lc->disk_size); if (r < 0) { LOG_ERROR("[%s] rw_log: write failure: %s", SHORT_UUID(lc->uuid), strerror(errno)); return -EIO; /* Failed disk write */ } return 0; } /* Read */ /* FIXME Cope with full set of non-error conditions */ r = read(lc->disk_fd, lc->disk_buffer, lc->disk_size); if (r < 0) LOG_ERROR("[%s] rw_log: read failure: %s", SHORT_UUID(lc->uuid), strerror(errno)); if (r != lc->disk_size) return -EIO; /* Failed disk read */ return 0; } /* * read_log * @lc * * Valid return codes: * -EINVAL: Invalid header, bits not copied * -EIO: Unable to read disk log * 0: Valid header, disk bit -> lc->clean_bits * * Returns: 0 on success, -EXXX on failure */ static int read_log(struct log_c *lc) { struct log_header lh = { 0 }; size_t bitset_size; if (rw_log(lc, 0)) return -EIO; /* Failed disk read */ header_from_disk(&lh, lc->disk_buffer); if (lh.magic != MIRROR_MAGIC) return -EINVAL; lc->disk_nr_regions = lh.nr_regions; /* Read disk bits into sync_bits */ bitset_size = lc->region_count / 8; bitset_size += (lc->region_count % 8) ? 1 : 0; /* 'lc->clean_bits + 1' becasue dm_bitset_t leads with a uint32_t */ memcpy(lc->clean_bits + 1, (char *)lc->disk_buffer + 1024, bitset_size); return 0; } /* * write_log * @lc * * Returns: 0 on success, -EIO on failure */ static int write_log(struct log_c *lc) { struct log_header lh; size_t bitset_size; lh.magic = MIRROR_MAGIC; lh.version = MIRROR_DISK_VERSION; lh.nr_regions = lc->region_count; header_to_disk(&lh, lc->disk_buffer); /* Write disk bits from clean_bits */ bitset_size = lc->region_count / 8; bitset_size += (lc->region_count % 8) ? 1 : 0; /* 'lc->clean_bits + 1' becasue dm_bitset_t leads with a uint32_t */ memcpy((char *)lc->disk_buffer + 1024, lc->clean_bits + 1, bitset_size); if (rw_log(lc, 1)) { lc->log_dev_failed = 1; return -EIO; /* Failed disk write */ } return 0; } /* FIXME Rewrite this function taking advantage of the udev changes (where in use) to improve its efficiency! */ static int find_disk_path(char *major_minor_str, char *path_rtn, int *unlink_path __attribute__((unused))) { int r; DIR *dp; struct dirent *dep; struct stat statbuf; int major, minor; if (!strstr(major_minor_str, ":")) { r = stat(major_minor_str, &statbuf); if (r) return -errno; if (!S_ISBLK(statbuf.st_mode)) return -EINVAL; sprintf(path_rtn, "%s", major_minor_str); return 0; } r = sscanf(major_minor_str, "%d:%d", &major, &minor); if (r != 2) return -EINVAL; /* FIXME dm_dir() */ LOG_DBG("Checking /dev/mapper for device %d:%d", major, minor); /* Check /dev/mapper dir */ dp = opendir("/dev/mapper"); if (!dp) return -ENOENT; while ((dep = readdir(dp)) != NULL) { /* * FIXME: This is racy. By the time the path is used, * it may point to something else. 'fstat' will be * required upon opening to ensure we got what we * wanted. */ sprintf(path_rtn, "/dev/mapper/%s", dep->d_name); if (stat(path_rtn, &statbuf) < 0) { LOG_DBG("Unable to stat %s", path_rtn); continue; } if (S_ISBLK(statbuf.st_mode) && (major(statbuf.st_rdev) == major) && (minor(statbuf.st_rdev) == minor)) { LOG_DBG(" %s: YES", dep->d_name); if (closedir(dp)) LOG_DBG("Unable to closedir /dev/mapper %s", strerror(errno)); return 0; } else { LOG_DBG(" %s: NO", dep->d_name); } } if (closedir(dp)) LOG_DBG("Unable to closedir /dev/mapper %s", strerror(errno)); /* FIXME Find out why this was here and deal with underlying problem. */ LOG_DBG("Path not found for %d/%d", major, minor); return -ENOENT; // LOG_DBG("Creating /dev/mapper/%d-%d", major, minor); // sprintf(path_rtn, "/dev/mapper/%d-%d", major, minor); // r = mknod(path_rtn, S_IFBLK | S_IRUSR | S_IWUSR, MKDEV(major, minor)); /* * If we have to make the path, we unlink it after we open it */ // *unlink_path = 1; // return r ? -errno : 0; } static int _clog_ctr(char *uuid, uint64_t luid, int argc, char **argv, uint64_t device_size) { int i; int r = 0; char *p; uint64_t region_size; uint64_t region_count; struct log_c *lc = NULL; enum sync log_sync = DEFAULTSYNC; uint32_t block_on_error = 0; int disk_log; char disk_path[128]; int unlink_path = 0; long page_size; int pages; /* If core log request, then argv[0] will be region_size */ if (!strtoll(argv[0], &p, 0) || *p) { disk_log = 1; if ((argc < 2) || (argc > 4)) { LOG_ERROR("Too %s arguments to clustered-disk log type", (argc < 3) ? "few" : "many"); r = -EINVAL; goto fail; } r = find_disk_path(argv[0], disk_path, &unlink_path); if (r) { LOG_ERROR("Unable to find path to device %s", argv[0]); goto fail; } LOG_DBG("Clustered log disk is %s", disk_path); } else { disk_log = 0; if ((argc < 1) || (argc > 3)) { LOG_ERROR("Too %s arguments to clustered-core log type", (argc < 2) ? "few" : "many"); r = -EINVAL; goto fail; } } if (!(region_size = strtoll(argv[disk_log], &p, 0)) || *p) { LOG_ERROR("Invalid region_size argument to clustered-%s log type", (disk_log) ? "disk" : "core"); r = -EINVAL; goto fail; } region_count = device_size / region_size; if (device_size % region_size) { /* * I can't remember if device_size must be a multiple * of region_size, so check it anyway. */ region_count++; } for (i = 0; i < argc; i++) { if (!strcmp(argv[i], "sync")) log_sync = FORCESYNC; else if (!strcmp(argv[i], "nosync")) log_sync = NOSYNC; else if (!strcmp(argv[i], "block_on_error")) block_on_error = 1; } lc = dm_zalloc(sizeof(*lc)); if (!lc) { LOG_ERROR("Unable to allocate cluster log context"); r = -ENOMEM; goto fail; } lc->region_size = region_size; lc->region_count = region_count; lc->sync = log_sync; lc->block_on_error = block_on_error; lc->sync_search = 0; lc->recovering_region = (uint64_t)-1; lc->skip_bit_warning = region_count; lc->disk_fd = -1; lc->log_dev_failed = 0; strncpy(lc->uuid, uuid, DM_UUID_LEN); lc->luid = luid; if (get_log(lc->uuid, lc->luid) || get_pending_log(lc->uuid, lc->luid)) { LOG_ERROR("[%s/%" PRIu64 "u] Log already exists, unable to create.", SHORT_UUID(lc->uuid), lc->luid); dm_free(lc); return -EINVAL; } dm_list_init(&lc->mark_list); lc->clean_bits = dm_bitset_create(NULL, region_count); if (!lc->clean_bits) { LOG_ERROR("Unable to allocate clean bitset"); r = -ENOMEM; goto fail; } lc->sync_bits = dm_bitset_create(NULL, region_count); if (!lc->sync_bits) { LOG_ERROR("Unable to allocate sync bitset"); r = -ENOMEM; goto fail; } if (log_sync == NOSYNC) dm_bit_set_all(lc->sync_bits); lc->sync_count = (log_sync == NOSYNC) ? region_count : 0; if (disk_log) { if ((page_size = sysconf(_SC_PAGESIZE)) < 0) { LOG_ERROR("Unable to read pagesize: %s", strerror(errno)); r = errno; goto fail; } pages = *(lc->clean_bits) / page_size; pages += *(lc->clean_bits) % page_size ? 1 : 0; pages += 1; /* for header */ r = open(disk_path, O_RDWR | O_DIRECT); if (r < 0) { LOG_ERROR("Unable to open log device, %s: %s", disk_path, strerror(errno)); r = errno; goto fail; } if (unlink_path) if (unlink(disk_path) < 0) { LOG_DBG("Warning: Unable to unlink log device, %s: %s", disk_path, strerror(errno)); } lc->disk_fd = r; lc->disk_size = pages * page_size; r = posix_memalign(&(lc->disk_buffer), page_size, lc->disk_size); if (r) { LOG_ERROR("Unable to allocate memory for disk_buffer"); goto fail; } memset(lc->disk_buffer, 0, lc->disk_size); LOG_DBG("Disk log ready"); } dm_list_add(&log_pending_list, &lc->list); return 0; fail: if (lc) { if (lc->disk_fd >= 0 && close(lc->disk_fd)) LOG_ERROR("Close device error, %s: %s", disk_path, strerror(errno)); free(lc->disk_buffer); dm_free(lc->sync_bits); dm_free(lc->clean_bits); dm_free(lc); } return r; } /* * clog_ctr * @rq * * rq->data should contain constructor string as follows: * [disk] [[no]sync] * The kernel is responsible for adding the argument * to the end; otherwise, we cannot compute the region_count. * * FIXME: Currently relies on caller to fill in rq->error */ static int clog_dtr(struct dm_ulog_request *rq); static int clog_ctr(struct dm_ulog_request *rq) { int argc, i, r = 0; char *p, **argv = NULL; char *dev_size_str; uint64_t device_size; /* Sanity checks */ if (!rq->data_size) { LOG_ERROR("Received constructor request with no data"); return -EINVAL; } if (strlen(rq->data) > rq->data_size) { LOG_ERROR("Received constructor request with bad data"); LOG_ERROR("strlen(rq->data)[%d] != rq->data_size[%llu]", (int)strlen(rq->data), (unsigned long long)rq->data_size); LOG_ERROR("rq->data = '%s' [%d]", rq->data, (int)strlen(rq->data)); return -EINVAL; } /* Split up args */ for (argc = 0, p = rq->data; (p = strstr(p, " ")); p++, argc++) *p = '\0'; argv = malloc(argc * sizeof(char *)); if (!argv) return -ENOMEM; p = dev_size_str = rq->data; p += strlen(p) + 1; for (i = 0; i < argc; i++, p = p + strlen(p) + 1) argv[i] = p; if (strcmp(argv[0], "clustered-disk") && strcmp(argv[0], "clustered-core")) { LOG_ERROR("Unsupported userspace log type, \"%s\"", argv[0]); free(argv); return -EINVAL; } if (!(device_size = strtoll(dev_size_str, &p, 0)) || *p) { LOG_ERROR("Invalid device size argument: %s", dev_size_str); free(argv); return -EINVAL; } r = _clog_ctr(rq->uuid, rq->luid, argc - 1, argv + 1, device_size); /* We join the CPG when we resume */ /* No returning data */ if ((rq->version > 1) && !strcmp(argv[0], "clustered-disk")) rq->data_size = sprintf(rq->data, "%s", argv[1]) + 1; else rq->data_size = 0; if (r) { LOG_ERROR("Failed to create cluster log (%s)", rq->uuid); for (i = 0; i < argc; i++) LOG_ERROR("argv[%d] = %s", i, argv[i]); } else LOG_DBG("[%s] Cluster log created", SHORT_UUID(rq->uuid)); free(argv); return r; } /* * clog_dtr * @rq * */ static int clog_dtr(struct dm_ulog_request *rq) { struct log_c *lc = get_log(rq->uuid, rq->luid); if (lc) { /* * The log should not be on the official list. There * should have been a suspend first. */ LOG_ERROR("[%s] DTR before SUS: leaving CPG", SHORT_UUID(rq->uuid)); destroy_cluster_cpg(rq->uuid); } else if (!(lc = get_pending_log(rq->uuid, rq->luid))) { LOG_ERROR("clog_dtr called on log that is not official or pending"); return -EINVAL; } LOG_DBG("[%s] Cluster log removed", SHORT_UUID(lc->uuid)); dm_list_del(&lc->list); if (lc->disk_fd != -1 && close(lc->disk_fd)) LOG_ERROR("Failed to close disk log: %s", strerror(errno)); if (lc->disk_buffer) free(lc->disk_buffer); dm_free(lc->clean_bits); dm_free(lc->sync_bits); dm_free(lc); return 0; } /* * clog_presuspend * @rq * */ static int clog_presuspend(struct dm_ulog_request *rq) { struct log_c *lc = get_log(rq->uuid, rq->luid); if (!lc) return -EINVAL; if (lc->touched) LOG_DBG("WARNING: log still marked as 'touched' during suspend"); lc->recovery_halted = 1; return 0; } /* * clog_postsuspend * @rq * */ static int clog_postsuspend(struct dm_ulog_request *rq) { struct log_c *lc = get_log(rq->uuid, rq->luid); if (!lc) return -EINVAL; LOG_DBG("[%s] clog_postsuspend: leaving CPG", SHORT_UUID(lc->uuid)); destroy_cluster_cpg(rq->uuid); lc->state = LOG_SUSPENDED; lc->recovering_region = (uint64_t)-1; lc->recoverer = (uint32_t)-1; lc->delay = time(NULL); return 0; } /* * cluster_postsuspend * @rq * */ int cluster_postsuspend(char *uuid, uint64_t luid) { struct log_c *lc = get_log(uuid, luid); if (!lc) return -EINVAL; LOG_DBG("[%s] clog_postsuspend: finalizing", SHORT_UUID(lc->uuid)); lc->resume_override = 0; /* move log to pending list */ dm_list_del(&lc->list); dm_list_add(&log_pending_list, &lc->list); return 0; } /* * clog_resume * @rq * * Does the main work of resuming. */ static int clog_resume(struct dm_ulog_request *rq) { uint32_t i; int commit_log = 0; struct log_c *lc = get_log(rq->uuid, rq->luid); if (!lc) return -EINVAL; lc->in_sync = 0; switch (lc->resume_override) { case 1000: LOG_ERROR("[%s] Additional resume issued before suspend", SHORT_UUID(rq->uuid)); #ifdef DEBUG kill(getpid(), SIGUSR1); #endif return 0; case 0: lc->resume_override = 1000; if (lc->disk_fd == -1) { LOG_DBG("[%s] Master resume.", SHORT_UUID(lc->uuid)); goto no_disk; } LOG_DBG("[%s] Master resume: reading disk log", SHORT_UUID(lc->uuid)); commit_log = 1; break; case 1: LOG_ERROR("Error:: partial bit loading (just sync_bits)"); return -EINVAL; case 2: LOG_ERROR("Error:: partial bit loading (just clean_bits)"); return -EINVAL; case 3: LOG_DBG("[%s] Non-master resume: bits pre-loaded", SHORT_UUID(lc->uuid)); lc->resume_override = 1000; goto out; default: LOG_ERROR("Error:: multiple loading of bits (%d)", lc->resume_override); return -EINVAL; } if (lc->log_dev_failed) { LOG_ERROR("Log device has failed, unable to read bits"); rq->error = 0; /* We can handle this so far */ lc->disk_nr_regions = 0; } else rq->error = read_log(lc); switch (rq->error) { case 0: if (lc->disk_nr_regions < lc->region_count) LOG_DBG("[%s] Mirror has grown, updating log bits", SHORT_UUID(lc->uuid)); else if (lc->disk_nr_regions > lc->region_count) LOG_DBG("[%s] Mirror has shrunk, updating log bits", SHORT_UUID(lc->uuid)); break; case -EINVAL: LOG_DBG("[%s] (Re)initializing mirror log - resync issued.", SHORT_UUID(lc->uuid)); lc->disk_nr_regions = 0; break; default: LOG_ERROR("Failed to read disk log"); lc->disk_nr_regions = 0; break; } no_disk: /* If mirror has grown, set bits appropriately */ if (lc->sync == NOSYNC) for (i = lc->disk_nr_regions; i < lc->region_count; i++) log_set_bit(lc, lc->clean_bits, i); else for (i = lc->disk_nr_regions; i < lc->region_count; i++) log_clear_bit(lc, lc->clean_bits, i); /* Clear any old bits if device has shrunk */ for (i = lc->region_count; i % 32; i++) log_clear_bit(lc, lc->clean_bits, i); /* copy clean across to sync */ dm_bit_copy(lc->sync_bits, lc->clean_bits); if (commit_log && (lc->disk_fd >= 0)) { rq->error = write_log(lc); if (rq->error) LOG_ERROR("Failed initial disk log write"); else LOG_DBG("Disk log initialized"); lc->touched = 0; } out: /* * Clear any old bits if device has shrunk - necessary * for non-master resume */ for (i = lc->region_count; i % 32; i++) { log_clear_bit(lc, lc->clean_bits, i); log_clear_bit(lc, lc->sync_bits, i); } lc->sync_count = count_bits32(lc->sync_bits); LOG_SPRINT(lc, "[%s] Initial sync_count = %llu", SHORT_UUID(lc->uuid), (unsigned long long)lc->sync_count); lc->sync_search = 0; lc->state = LOG_RESUMED; lc->recovery_halted = 0; return rq->error; } /* * local_resume * @rq * * If the log is pending, we must first join the cpg and * put the log in the official list. * */ int local_resume(struct dm_ulog_request *rq) { int r; time_t t; struct log_c *lc = get_log(rq->uuid, rq->luid); if (!lc) { /* Is the log in the pending list? */ lc = get_pending_log(rq->uuid, rq->luid); if (!lc) { LOG_ERROR("clog_resume called on log that is not official or pending"); return -EINVAL; } t = time(NULL); t -= lc->delay; /* * This should be considered a temporary fix. It addresses * a problem that exists when nodes suspend/resume in rapid * succession. While the problem is very rare, it has been * seen to happen in real-world-like testing. * * The problem: * - Node A joins cluster * - Node B joins cluster * - Node A prepares checkpoint * - Node A gets ready to write checkpoint * - Node B leaves * - Node B joins * - Node A finishes write of checkpoint * - Node B receives checkpoint meant for previous session * -- Node B can now be non-coherent * * This timer will solve the problem for now, but could be * replaced by a generation number sent with the resume * command from the kernel. The generation number would * be included in the name of the checkpoint to prevent * reading stale data. */ if ((t < 3) && (t >= 0)) sleep(3 - t); /* Join the CPG */ r = create_cluster_cpg(rq->uuid, rq->luid); if (r) { LOG_ERROR("clog_resume: Failed to create cluster CPG"); return r; } /* move log to official list */ dm_list_del(&lc->list); dm_list_add(&log_list, &lc->list); } return 0; } /* * clog_get_region_size * @rq * * Since this value doesn't change, the kernel * should not need to talk to server to get this * The function is here for completness * * Returns: 0 on success, -EXXX on failure */ static int clog_get_region_size(struct dm_ulog_request *rq) { uint64_t *rtn = (uint64_t *)rq->data; struct log_c *lc = get_log(rq->uuid, rq->luid); if (!lc && !(lc = get_pending_log(rq->uuid, rq->luid))) return -EINVAL; *rtn = lc->region_size; rq->data_size = sizeof(*rtn); return 0; } /* * clog_is_clean * @rq * * Returns: 1 if clean, 0 otherwise */ static int clog_is_clean(struct dm_ulog_request *rq) { int64_t *rtn = (int64_t *)rq->data; uint64_t *region = (uint64_t *)rq->data; struct log_c *lc = get_log(rq->uuid, rq->luid); if (!lc) return -EINVAL; *rtn = log_test_bit(lc->clean_bits, *region); rq->data_size = sizeof(*rtn); return 0; } /* * clog_in_sync * @rq * * We ignore any request for non-block. That * should be handled elsewhere. (If the request * has come this far, it has already blocked.) * * Returns: 1 if in-sync, 0 otherwise */ static int clog_in_sync(struct dm_ulog_request *rq) { int64_t *rtn = (int64_t *)rq->data; uint64_t *region_p = (uint64_t *)rq->data; uint64_t region = *region_p; struct log_c *lc = get_log(rq->uuid, rq->luid); if (!lc) return -EINVAL; if (region > lc->region_count) return -EINVAL; *rtn = log_test_bit(lc->sync_bits, region); /* * If the mirror was successfully recovered, we want to always * force every machine to write to all devices - otherwise, * corruption will occur. Here's how: * Node1 suffers a failure and marks a region out-of-sync * Node2 attempts a write, gets by is_remote_recovering, * and queries the sync status of the region - finding * it out-of-sync. * Node2 thinks the write should be a nosync write, but it * hasn't suffered the drive failure that Node1 has yet. * It then issues a generic_make_request directly to * the primary image only - which is exactly the device * that has suffered the failure. * Node2 suffers a lost write - which completely bypasses the * mirror layer because it had gone through generic_m_r. * The file system will likely explode at this point due to * I/O errors. If it wasn't the primary that failed, it is * easily possible in this case to issue writes to just one * of the remaining images - also leaving the mirror inconsistent. * * We let in_sync() return 1 in a cluster regardless of what is * in the bitmap once recovery has successfully completed on a * mirror. This ensures the mirroring code will continue to * attempt to write to all mirror images. The worst that can * happen for reads is that additional read attempts may be * taken. * * Futher investigation may be required to determine if there are * similar possible outcomes when the mirror is in the process of * recovering. In that case, lc->in_sync would not have been set * yet. */ if (!*rtn && lc->in_sync) *rtn = 1; if (*rtn) LOG_DBG("[%s] Region is in-sync: %llu", SHORT_UUID(lc->uuid), (unsigned long long)region); else LOG_DBG("[%s] Region is not in-sync: %llu", SHORT_UUID(lc->uuid), (unsigned long long)region); rq->data_size = sizeof(*rtn); return 0; } /* * clog_flush * @rq * */ static int clog_flush(struct dm_ulog_request *rq, int server) { int r = 0; struct log_c *lc = get_log(rq->uuid, rq->luid); if (!lc) return -EINVAL; if (!lc->touched) return 0; /* * Do the actual flushing of the log only * if we are the server. */ if (server && (lc->disk_fd >= 0)) { r = rq->error = write_log(lc); if (r) LOG_ERROR("[%s] Error writing to disk log", SHORT_UUID(lc->uuid)); else LOG_DBG("[%s] Disk log written", SHORT_UUID(lc->uuid)); } lc->touched = 0; return r; } /* * mark_region * @lc * @region * @who * * Put a mark region request in the tree for tracking. * * Returns: 0 on success, -EXXX on error */ static int mark_region(struct log_c *lc, uint64_t region, uint32_t who) { int found = 0; struct mark_entry *m; dm_list_iterate_items(m, &lc->mark_list) if (m->region == region) { found = 1; if (m->nodeid == who) return 0; } if (!found) log_clear_bit(lc, lc->clean_bits, region); /* * Save allocation until here - if there is a failure, * at least we have cleared the bit. */ m = malloc(sizeof(*m)); if (!m) { LOG_ERROR("Unable to allocate space for mark_entry: %llu/%u", (unsigned long long)region, who); return -ENOMEM; } m->nodeid = who; m->region = region; dm_list_add(&lc->mark_list, &m->list); return 0; } /* * clog_mark_region * @rq * * rq may contain more than one mark request. We * can determine the number from the 'data_size' field. * * Returns: 0 on success, -EXXX on failure */ static int clog_mark_region(struct dm_ulog_request *rq, uint32_t originator) { int r; int count; uint64_t *region; struct log_c *lc = get_log(rq->uuid, rq->luid); if (!lc) return -EINVAL; if (rq->data_size % sizeof(uint64_t)) { LOG_ERROR("Bad data size given for mark_region request"); return -EINVAL; } count = rq->data_size / sizeof(uint64_t); region = (uint64_t *)&rq->data; for (; count > 0; count--, region++) { r = mark_region(lc, *region, originator); if (r) return r; } rq->data_size = 0; return 0; } static int clear_region(struct log_c *lc, uint64_t region, uint32_t who) { int other_matches = 0; struct mark_entry *m, *n; dm_list_iterate_items_safe(m, n, &lc->mark_list) if (m->region == region) { if (m->nodeid == who) { dm_list_del(&m->list); free(m); } else other_matches = 1; } /* * Clear region if: * 1) It is in-sync * 2) There are no other machines that have it marked */ if (!other_matches && log_test_bit(lc->sync_bits, region)) log_set_bit(lc, lc->clean_bits, region); return 0; } /* * clog_clear_region * @rq * * rq may contain more than one clear request. We * can determine the number from the 'data_size' field. * * Returns: 0 on success, -EXXX on failure */ static int clog_clear_region(struct dm_ulog_request *rq, uint32_t originator) { int r; int count; uint64_t *region; struct log_c *lc = get_log(rq->uuid, rq->luid); if (!lc) return -EINVAL; if (rq->data_size % sizeof(uint64_t)) { LOG_ERROR("Bad data size given for clear_region request"); return -EINVAL; } count = rq->data_size / sizeof(uint64_t); region = (uint64_t *)&rq->data; for (; count > 0; count--, region++) { r = clear_region(lc, *region, originator); if (r) return r; } rq->data_size = 0; return 0; } /* * clog_get_resync_work * @rq * */ static int clog_get_resync_work(struct dm_ulog_request *rq, uint32_t originator) { struct { int64_t i; uint64_t r; } *pkg = (void *)rq->data; struct log_c *lc = get_log(rq->uuid, rq->luid); if (!lc) return -EINVAL; rq->data_size = sizeof(*pkg); pkg->i = 0; if (lc->sync_search >= lc->region_count) { /* * FIXME: handle intermittent errors during recovery * by resetting sync_search... but not to many times. */ LOG_SPRINT(lc, "GET - SEQ#=%u, UUID=%s, nodeid = %u:: " "Recovery finished", rq->seq, SHORT_UUID(lc->uuid), originator); return 0; } if (lc->recovering_region != (uint64_t)-1) { if (lc->recoverer == originator) { LOG_SPRINT(lc, "GET - SEQ#=%u, UUID=%s, nodeid = %u:: " "Re-requesting work (%llu)", rq->seq, SHORT_UUID(lc->uuid), originator, (unsigned long long)lc->recovering_region); pkg->r = lc->recovering_region; pkg->i = 1; LOG_COND(log_resend_requests, "***** RE-REQUEST *****"); } else { LOG_SPRINT(lc, "GET - SEQ#=%u, UUID=%s, nodeid = %u:: " "Someone already recovering (%llu)", rq->seq, SHORT_UUID(lc->uuid), originator, (unsigned long long)lc->recovering_region); } return 0; } while (lc->recovery_request_list) { struct recovery_request *del; del = lc->recovery_request_list; lc->recovery_request_list = del->next; pkg->r = del->region; free(del); if (!log_test_bit(lc->sync_bits, pkg->r)) { LOG_SPRINT(lc, "GET - SEQ#=%u, UUID=%s, nodeid = %u:: " "Assigning priority resync work (%llu)", rq->seq, SHORT_UUID(lc->uuid), originator, (unsigned long long)pkg->r); pkg->i = 1; lc->recovering_region = pkg->r; lc->recoverer = originator; return 0; } } pkg->r = find_next_zero_bit(lc->sync_bits, lc->sync_search); if (pkg->r >= lc->region_count) { LOG_SPRINT(lc, "GET - SEQ#=%u, UUID=%s, nodeid = %u:: " "Resync work complete.", rq->seq, SHORT_UUID(lc->uuid), originator); lc->sync_search = lc->region_count + 1; return 0; } lc->sync_search = pkg->r + 1; LOG_SPRINT(lc, "GET - SEQ#=%u, UUID=%s, nodeid = %u:: " "Assigning resync work (%llu)", rq->seq, SHORT_UUID(lc->uuid), originator, (unsigned long long)pkg->r); pkg->i = 1; lc->recovering_region = pkg->r; lc->recoverer = originator; return 0; } /* * clog_set_region_sync * @rq */ static int clog_set_region_sync(struct dm_ulog_request *rq, uint32_t originator) { struct { uint64_t region; int64_t in_sync; } *pkg = (void *)rq->data; struct log_c *lc = get_log(rq->uuid, rq->luid); if (!lc) return -EINVAL; lc->recovering_region = (uint64_t)-1; if (pkg->in_sync) { if (log_test_bit(lc->sync_bits, pkg->region)) { LOG_SPRINT(lc, "SET - SEQ#=%u, UUID=%s, nodeid = %u:: " "Region already set (%llu)", rq->seq, SHORT_UUID(lc->uuid), originator, (unsigned long long)pkg->region); } else { log_set_bit(lc, lc->sync_bits, pkg->region); lc->sync_count++; /* The rest of this section is all for debugging */ LOG_SPRINT(lc, "SET - SEQ#=%u, UUID=%s, nodeid = %u:: " "Setting region (%llu)", rq->seq, SHORT_UUID(lc->uuid), originator, (unsigned long long)pkg->region); if (pkg->region == lc->skip_bit_warning) lc->skip_bit_warning = lc->region_count; if (pkg->region > (lc->skip_bit_warning + 5)) { LOG_SPRINT(lc, "*** Region #%llu skipped during recovery ***", (unsigned long long)lc->skip_bit_warning); lc->skip_bit_warning = lc->region_count; #ifdef DEBUG kill(getpid(), SIGUSR1); #endif } if (!log_test_bit(lc->sync_bits, (pkg->region) ? pkg->region - 1 : 0)) { LOG_SPRINT(lc, "*** Previous bit not set ***"); lc->skip_bit_warning = (pkg->region) ? pkg->region - 1 : 0; } } } else if (log_test_bit(lc->sync_bits, pkg->region)) { lc->sync_count--; log_clear_bit(lc, lc->sync_bits, pkg->region); LOG_SPRINT(lc, "SET - SEQ#=%u, UUID=%s, nodeid = %u:: " "Unsetting region (%llu)", rq->seq, SHORT_UUID(lc->uuid), originator, (unsigned long long)pkg->region); } if (lc->sync_count != count_bits32(lc->sync_bits)) { unsigned long long reset = count_bits32(lc->sync_bits); LOG_SPRINT(lc, "SET - SEQ#=%u, UUID=%s, nodeid = %u:: " "sync_count(%llu) != bitmap count(%llu)", rq->seq, SHORT_UUID(lc->uuid), originator, (unsigned long long)lc->sync_count, reset); #ifdef DEBUG kill(getpid(), SIGUSR1); #endif lc->sync_count = reset; } if (lc->sync_count > lc->region_count) LOG_SPRINT(lc, "SET - SEQ#=%u, UUID=%s, nodeid = %u:: " "(lc->sync_count > lc->region_count) - this is bad", rq->seq, SHORT_UUID(lc->uuid), originator); if (lc->sync_count == lc->region_count) lc->in_sync = 1; rq->data_size = 0; return 0; } /* * clog_get_sync_count * @rq */ static int clog_get_sync_count(struct dm_ulog_request *rq, uint32_t originator) { uint64_t *sync_count = (uint64_t *)rq->data; struct log_c *lc = get_log(rq->uuid, rq->luid); /* * FIXME: Mirror requires us to be able to ask for * the sync count while pending... but I don't like * it because other machines may not be suspended and * the stored value may not be accurate. */ if (!lc) lc = get_pending_log(rq->uuid, rq->luid); if (!lc) return -EINVAL; *sync_count = lc->sync_count; rq->data_size = sizeof(*sync_count); if (lc->sync_count != count_bits32(lc->sync_bits)) { unsigned long long reset = count_bits32(lc->sync_bits); LOG_SPRINT(lc, "get_sync_count - SEQ#=%u, UUID=%s, nodeid = %u:: " "sync_count(%llu) != bitmap count(%llu)", rq->seq, SHORT_UUID(lc->uuid), originator, (unsigned long long)lc->sync_count, reset); #ifdef DEBUG kill(getpid(), SIGUSR1); #endif lc->sync_count = reset; } return 0; } static int core_status_info(struct log_c *lc __attribute__((unused)), struct dm_ulog_request *rq) { int r; char *data = (char *)rq->data; r = sprintf(data, "1 clustered-core"); if (r < 0) return r; rq->data_size = r; return 0; } static int disk_status_info(struct log_c *lc, struct dm_ulog_request *rq) { int r; char *data = (char *)rq->data; struct stat statbuf; if(fstat(lc->disk_fd, &statbuf)) { rq->error = -errno; return -errno; } r = sprintf(data, "3 clustered-disk %d:%d %c", major(statbuf.st_rdev), minor(statbuf.st_rdev), (lc->log_dev_failed) ? 'D' : 'A'); if (r < 0) return r; rq->data_size = r; return 0; } /* * clog_status_info * @rq * */ static int clog_status_info(struct dm_ulog_request *rq) { int r; struct log_c *lc = get_log(rq->uuid, rq->luid); if (!lc) lc = get_pending_log(rq->uuid, rq->luid); if (!lc) return -EINVAL; if (lc->disk_fd == -1) r = core_status_info(lc, rq); else r = disk_status_info(lc, rq); return r; } static int core_status_table(struct log_c *lc, struct dm_ulog_request *rq) { int r; char *data = (char *)rq->data; r = sprintf(data, "clustered-core %u %s%s ", lc->region_size, (lc->sync == DEFAULTSYNC) ? "" : (lc->sync == NOSYNC) ? "nosync " : "sync ", (lc->block_on_error) ? "block_on_error" : ""); if (r < 0) return r; rq->data_size = r; return 0; } static int disk_status_table(struct log_c *lc, struct dm_ulog_request *rq) { int r; char *data = (char *)rq->data; struct stat statbuf; if(fstat(lc->disk_fd, &statbuf)) { rq->error = -errno; return -errno; } r = sprintf(data, "clustered-disk %d:%d %u %s%s ", major(statbuf.st_rdev), minor(statbuf.st_rdev), lc->region_size, (lc->sync == DEFAULTSYNC) ? "" : (lc->sync == NOSYNC) ? "nosync " : "sync ", (lc->block_on_error) ? "block_on_error" : ""); if (r < 0) return r; rq->data_size = r; return 0; } /* * clog_status_table * @rq * */ static int clog_status_table(struct dm_ulog_request *rq) { int r; struct log_c *lc = get_log(rq->uuid, rq->luid); if (!lc) lc = get_pending_log(rq->uuid, rq->luid); if (!lc) return -EINVAL; if (lc->disk_fd == -1) r = core_status_table(lc, rq); else r = disk_status_table(lc, rq); return r; } /* * clog_is_remote_recovering * @rq * */ static int clog_is_remote_recovering(struct dm_ulog_request *rq) { uint64_t *region_p = (uint64_t *)rq->data; uint64_t region = *region_p; struct { int64_t is_recovering; uint64_t in_sync_hint; } *pkg = (void *)rq->data; struct log_c *lc = get_log(rq->uuid, rq->luid); if (!lc) return -EINVAL; if (region > lc->region_count) return -EINVAL; if (lc->recovery_halted) { LOG_DBG("[%s] Recovery halted... [not remote recovering]: %llu", SHORT_UUID(lc->uuid), (unsigned long long)region); pkg->is_recovering = 0; pkg->in_sync_hint = lc->region_count; /* none are recovering */ } else { pkg->is_recovering = !log_test_bit(lc->sync_bits, region); /* * Remember, 'lc->sync_search' is 1 plus the region * currently being recovered. So, we must take off 1 * to account for that; but only if 'sync_search > 1'. */ pkg->in_sync_hint = lc->sync_search ? (lc->sync_search - 1) : 0; LOG_DBG("[%s] Region is %s: %llu", SHORT_UUID(lc->uuid), (region == lc->recovering_region) ? "currently remote recovering" : (pkg->is_recovering) ? "pending remote recovery" : "not remote recovering", (unsigned long long)region); } if (pkg->is_recovering && (region != lc->recovering_region)) { struct recovery_request *rr; /* Already in the list? */ for (rr = lc->recovery_request_list; rr; rr = rr->next) if (rr->region == region) goto out; /* Failure to allocated simply means we can't prioritize it */ rr = malloc(sizeof(*rr)); if (!rr) goto out; LOG_DBG("[%s] Adding region to priority list: %llu", SHORT_UUID(lc->uuid), (unsigned long long)region); rr->region = region; rr->next = lc->recovery_request_list; lc->recovery_request_list = rr; } out: rq->data_size = sizeof(*pkg); return 0; } /* * do_request * @rq: the request * @server: is this request performed by the server * * An inability to perform this function will return an error * from this function. However, an inability to successfully * perform the request will fill in the 'rq->error' field. * * 'rq' (or more correctly, rq->u_rq.data) should be of sufficient * size to hold any returning data. Currently, local.c uses 2kiB * to hold 'rq' - leaving ~1.5kiB for return data... more than * enough for all the implemented functions here. * * Returns: 0 on success, -EXXX on error */ int do_request(struct clog_request *rq, int server) { int r; if (!rq) return 0; if (rq->u_rq.error) LOG_DBG("Programmer error: rq struct has error set"); switch (rq->u_rq.request_type) { case DM_ULOG_CTR: r = clog_ctr(&rq->u_rq); break; case DM_ULOG_DTR: r = clog_dtr(&rq->u_rq); break; case DM_ULOG_PRESUSPEND: r = clog_presuspend(&rq->u_rq); break; case DM_ULOG_POSTSUSPEND: r = clog_postsuspend(&rq->u_rq); break; case DM_ULOG_RESUME: r = clog_resume(&rq->u_rq); break; case DM_ULOG_GET_REGION_SIZE: r = clog_get_region_size(&rq->u_rq); break; case DM_ULOG_IS_CLEAN: r = clog_is_clean(&rq->u_rq); break; case DM_ULOG_IN_SYNC: r = clog_in_sync(&rq->u_rq); break; case DM_ULOG_FLUSH: r = clog_flush(&rq->u_rq, server); break; case DM_ULOG_MARK_REGION: r = clog_mark_region(&rq->u_rq, rq->originator); break; case DM_ULOG_CLEAR_REGION: r = clog_clear_region(&rq->u_rq, rq->originator); break; case DM_ULOG_GET_RESYNC_WORK: r = clog_get_resync_work(&rq->u_rq, rq->originator); break; case DM_ULOG_SET_REGION_SYNC: r = clog_set_region_sync(&rq->u_rq, rq->originator); break; case DM_ULOG_GET_SYNC_COUNT: r = clog_get_sync_count(&rq->u_rq, rq->originator); break; case DM_ULOG_STATUS_INFO: r = clog_status_info(&rq->u_rq); break; case DM_ULOG_STATUS_TABLE: r = clog_status_table(&rq->u_rq); break; case DM_ULOG_IS_REMOTE_RECOVERING: r = clog_is_remote_recovering(&rq->u_rq); break; default: LOG_ERROR("Unknown request"); r = rq->u_rq.error = -EINVAL; break; } if (r && !rq->u_rq.error) rq->u_rq.error = r; else if (r != rq->u_rq.error) LOG_DBG("Warning: error from function != rq->u_rq.error"); if (rq->u_rq.error && rq->u_rq.data_size) { /* Make sure I'm handling errors correctly above */ LOG_DBG("Programmer error: rq->u_rq.error && rq->u_rq.data_size"); rq->u_rq.data_size = 0; } return 0; } static void print_bits(dm_bitset_t bs, int print) { int i, size; char outbuf[128] = { 0 }; unsigned char *buf = (unsigned char *)(bs + 1); size = (*bs % 8) ? 1 : 0; size += (*bs / 8); for (i = 0; i < size; i++) { if (!(i % 16)) { if (outbuf[0] != '\0') { if (print) LOG_PRINT("%s", outbuf); else LOG_DBG("%s", outbuf); } memset(outbuf, 0, sizeof(outbuf)); sprintf(outbuf, "[%3d - %3d]", i, i+15); } sprintf(outbuf + strlen(outbuf), " %.2X", (unsigned char)buf[i]); } if (outbuf[0] != '\0') { if (print) LOG_PRINT("%s", outbuf); else LOG_DBG("%s", outbuf); } } /* int store_bits(const char *uuid, const char *which, char **buf)*/ int push_state(const char *uuid, uint64_t luid, const char *which, char **buf, uint32_t debug_who) { int bitset_size; struct log_c *lc; if (*buf) LOG_ERROR("store_bits: *buf != NULL"); lc = get_log(uuid, luid); if (!lc) { LOG_ERROR("store_bits: No log found for %s", uuid); return -EINVAL; } if (!strcmp(which, "recovering_region")) { *buf = malloc(64); /* easily handles the 2 written numbers */ if (!*buf) return -ENOMEM; sprintf(*buf, "%llu %u", (unsigned long long)lc->recovering_region, lc->recoverer); LOG_SPRINT(lc, "CKPT SEND - SEQ#=X, UUID=%s, nodeid = %u:: " "recovering_region=%llu, recoverer=%u, sync_count=%llu", SHORT_UUID(lc->uuid), debug_who, (unsigned long long)lc->recovering_region, lc->recoverer, (unsigned long long)count_bits32(lc->sync_bits)); return 64; } /* Size in 'int's */ bitset_size = (*(lc->clean_bits) / DM_BITS_PER_INT) + 1; /* Size in bytes */ bitset_size *= 4; *buf = malloc(bitset_size); if (!*buf) { LOG_ERROR("store_bits: Unable to allocate memory"); return -ENOMEM; } if (!strncmp(which, "sync_bits", 9)) { memcpy(*buf, lc->sync_bits + 1, bitset_size); LOG_DBG("[%s] storing sync_bits (sync_count = %llu):", SHORT_UUID(uuid), (unsigned long long) count_bits32(lc->sync_bits)); print_bits(lc->sync_bits, 0); } else if (!strncmp(which, "clean_bits", 9)) { memcpy(*buf, lc->clean_bits + 1, bitset_size); LOG_DBG("[%s] storing clean_bits:", SHORT_UUID(lc->uuid)); print_bits(lc->clean_bits, 0); } return bitset_size; } /*int load_bits(const char *uuid, const char *which, char *buf, int size)*/ int pull_state(const char *uuid, uint64_t luid, const char *which, char *buf, int size) { int bitset_size; struct log_c *lc; if (!buf) { LOG_ERROR("pull_state: buf == NULL"); return -EINVAL; } lc = get_log(uuid, luid); if (!lc) { LOG_ERROR("pull_state: No log found for %s", uuid); return -EINVAL; } if (!strncmp(which, "recovering_region", 17)) { if (sscanf(buf, "%llu %u", (unsigned long long *)&lc->recovering_region, &lc->recoverer) != 2) { LOG_ERROR("cannot parse recovering region from: %s", buf); return -EINVAL; } LOG_SPRINT(lc, "CKPT INIT - SEQ#=X, UUID=%s, nodeid = X:: " "recovering_region=%llu, recoverer=%u", SHORT_UUID(lc->uuid), (unsigned long long)lc->recovering_region, lc->recoverer); return 0; } /* Size in 'int's */ bitset_size = (*(lc->clean_bits) /DM_BITS_PER_INT) + 1; /* Size in bytes */ bitset_size *= 4; if (bitset_size != size) { LOG_ERROR("pull_state(%s): bad bitset_size (%d vs %d)", which, size, bitset_size); return -EINVAL; } if (!strncmp(which, "sync_bits", 9)) { lc->resume_override += 1; memcpy(lc->sync_bits + 1, buf, bitset_size); LOG_DBG("[%s] loading sync_bits (sync_count = %llu):", SHORT_UUID(lc->uuid),(unsigned long long) count_bits32(lc->sync_bits)); print_bits(lc->sync_bits, 0); } else if (!strncmp(which, "clean_bits", 9)) { lc->resume_override += 2; memcpy(lc->clean_bits + 1, buf, bitset_size); LOG_DBG("[%s] loading clean_bits:", SHORT_UUID(lc->uuid)); print_bits(lc->clean_bits, 0); } return 0; } int log_get_state(struct dm_ulog_request *rq) { struct log_c *lc; lc = get_log(rq->uuid, rq->luid); if (!lc) /* FIXME Callers are ignoring this */ return -EINVAL; return (int)lc->state; } /* * log_status * * Returns: 1 if logs are still present, 0 otherwise */ int log_status(void) { if (!dm_list_empty(&log_list) || !dm_list_empty(&log_pending_list)) return 1; return 0; } void log_debug(void) { struct log_c *lc; uint64_t r; int i; LOG_ERROR(""); LOG_ERROR("LOG COMPONENT DEBUGGING::"); LOG_ERROR("Official log list:"); LOG_ERROR("Pending log list:"); dm_list_iterate_items(lc, &log_pending_list) { LOG_ERROR("%s", lc->uuid); LOG_ERROR("sync_bits:"); print_bits(lc->sync_bits, 1); LOG_ERROR("clean_bits:"); print_bits(lc->clean_bits, 1); } dm_list_iterate_items(lc, &log_list) { LOG_ERROR("%s", lc->uuid); LOG_ERROR(" recoverer : %" PRIu32, lc->recoverer); LOG_ERROR(" recovering_region: %" PRIu64, lc->recovering_region); LOG_ERROR(" recovery_halted : %s", (lc->recovery_halted) ? "YES" : "NO"); LOG_ERROR("sync_bits:"); print_bits(lc->sync_bits, 1); LOG_ERROR("clean_bits:"); print_bits(lc->clean_bits, 1); LOG_ERROR("Validating %s::", SHORT_UUID(lc->uuid)); r = find_next_zero_bit(lc->sync_bits, 0); LOG_ERROR(" lc->region_count = %" PRIu32, lc->region_count); LOG_ERROR(" lc->sync_count = %" PRIu64, lc->sync_count); LOG_ERROR(" next zero bit = %" PRIu64, r); if ((r > lc->region_count) || ((r == lc->region_count) && (lc->sync_count > lc->region_count))) { LOG_ERROR("ADJUSTING SYNC_COUNT"); lc->sync_count = lc->region_count; } LOG_ERROR("Resync request history:"); for (i = 0; i < RESYNC_HISTORY; i++) { lc->idx++; lc->idx = lc->idx % RESYNC_HISTORY; if (lc->resync_history[lc->idx][0] == '\0') continue; LOG_ERROR("%d:%d) %s", i, lc->idx, lc->resync_history[lc->idx]); } } } lvm2-2.02.98/daemons/cmirrord/clogd.c0000640000175000017500000001215212037016272016214 0ustar blankblank/* * 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 #include #include #include #include #include static volatile sig_atomic_t exit_now = 0; /* FIXME Review signal handling. Should be volatile sig_atomic_t */ static sigset_t signal_mask; static volatile sig_atomic_t signal_received; static void process_signals(void); static void daemonize(void); static void init_all(void); static void cleanup_all(void); int main(int argc __attribute__((unused)), char *argv[] __attribute__((unused))) { daemonize(); init_all(); /* Parent can now exit, we're ready to handle requests */ kill(getppid(), SIGTERM); LOG_PRINT("Starting cmirrord:"); LOG_PRINT(" Built: "__DATE__" "__TIME__"\n"); LOG_DBG(" Compiled with debugging."); while (!exit_now) { links_monitor(); links_issue_callbacks(); process_signals(); } exit(EXIT_SUCCESS); } /* * parent_exit_handler: exit the parent * @sig: the signal * */ static void parent_exit_handler(int sig __attribute__((unused))) { exit_now = 1; } static void sig_handler(int sig) { /* FIXME Races - don't touch signal_mask here. */ sigaddset(&signal_mask, sig); signal_received = 1; } static void process_signal(int sig){ int r = 0; switch(sig) { case SIGINT: case SIGQUIT: case SIGTERM: case SIGHUP: r += log_status(); break; case SIGUSR1: case SIGUSR2: log_debug(); /*local_debug();*/ cluster_debug(); return; default: LOG_PRINT("Unknown signal received... ignoring"); return; } if (!r) { LOG_DBG("No current cluster logs... safe to exit."); cleanup_all(); exit(EXIT_SUCCESS); } LOG_ERROR("Cluster logs exist. Refusing to exit."); } static void process_signals(void) { int x; if (!signal_received) return; signal_received = 0; for (x = 1; x < _NSIG; x++) { if (sigismember(&signal_mask, x)) { sigdelset(&signal_mask, x); process_signal(x); } } } static void remove_lockfile(void) { if (unlink(CMIRRORD_PIDFILE)) LOG_ERROR("Unable to remove \"" CMIRRORD_PIDFILE "\" %s", strerror(errno)); } /* * daemonize * * Performs the steps necessary to become a daemon. */ static void daemonize(void) { int pid; int status; int devnull; if ((devnull = open("/dev/null", O_RDWR)) == -1) { LOG_ERROR("Can't open /dev/null: %s", strerror(errno)); exit(EXIT_FAILURE); } signal(SIGTERM, &parent_exit_handler); pid = fork(); if (pid < 0) { LOG_ERROR("Unable to fork()"); exit(EXIT_FAILURE); } if (pid) { /* Parent waits here for child to get going */ while (!waitpid(pid, &status, WNOHANG) && !exit_now); if (exit_now) exit(EXIT_SUCCESS); switch (WEXITSTATUS(status)) { case EXIT_LOCKFILE: LOG_ERROR("Failed to create lockfile"); LOG_ERROR("Process already running?"); break; case EXIT_KERNEL_SOCKET: LOG_ERROR("Unable to create netlink socket"); break; case EXIT_KERNEL_BIND: LOG_ERROR("Unable to bind to netlink socket"); break; case EXIT_KERNEL_SETSOCKOPT: LOG_ERROR("Unable to setsockopt on netlink socket"); break; case EXIT_CLUSTER_CKPT_INIT: LOG_ERROR("Unable to initialize checkpoint service"); LOG_ERROR("Has the cluster infrastructure been started?"); break; case EXIT_FAILURE: LOG_ERROR("Failed to start: Generic error"); break; default: LOG_ERROR("Failed to start: Unknown error"); break; } exit(EXIT_FAILURE); } setsid(); if (chdir("/")) { LOG_ERROR("Failed to chdir /: %s", strerror(errno)); exit(EXIT_FAILURE); } umask(0); if (close(0) || close(1) || close(2)) { LOG_ERROR("Failed to close terminal FDs"); exit(EXIT_FAILURE); } if ((dup2(devnull, 0) < 0) || /* reopen stdin */ (dup2(devnull, 1) < 0) || /* reopen stdout */ (dup2(devnull, 2) < 0)) /* reopen stderr */ exit(EXIT_FAILURE); 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(); } lvm2-2.02.98/daemons/cmirrord/compat.h0000640000175000017500000000125712037016272016420 0ustar blankblank/* * 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 */ lvm2-2.02.98/daemons/lvmetad/0000750000175000017500000000000012037016272014571 5ustar blankblanklvm2-2.02.98/daemons/lvmetad/test.sh0000750000175000017500000000036012037016272016106 0ustar blankblank#!/bin/bash export LD_LIBRARY_PATH="$1" test -n "$2" && { rm -f /var/run/lvmetad.{socket,pid} chmod +rx lvmetad valgrind ./lvmetad -f & PID=$! sleep 1 ./testclient kill $PID exit 0 } sudo ./test.sh "$1" . lvm2-2.02.98/daemons/lvmetad/testclient.c0000640000175000017500000000663512037016272017126 0ustar blankblank#include "lvmetad-client.h" #include "label.h" #include "lvmcache.h" #include "metadata.h" const char *uuid1 = "abcd-efgh"; const char *uuid2 = "bbcd-efgh"; const char *vgid = "yada-yada"; const char *uuid3 = "cbcd-efgh"; const char *metadata2 = "{\n" "id = \"yada-yada\"\n" "seqno = 15\n" "status = [\"READ\", \"WRITE\"]\n" "flags = []\n" "extent_size = 8192\n" "physical_volumes {\n" " pv0 {\n" " id = \"abcd-efgh\"\n" " }\n" " pv1 {\n" " id = \"bbcd-efgh\"\n" " }\n" " pv2 {\n" " id = \"cbcd-efgh\"\n" " }\n" "}\n" "}\n"; void _handle_reply(daemon_reply reply) { const char *repl = daemon_reply_str(reply, "response", NULL); const char *status = daemon_reply_str(reply, "status", NULL); const char *vgid = daemon_reply_str(reply, "vgid", NULL); fprintf(stderr, "[C] REPLY: %s\n", repl); if (!strcmp(repl, "failed")) fprintf(stderr, "[C] REASON: %s\n", daemon_reply_str(reply, "reason", "unknown")); if (vgid) fprintf(stderr, "[C] VGID: %s\n", vgid); if (status) fprintf(stderr, "[C] STATUS: %s\n", status); daemon_reply_destroy(reply); } void _pv_add(daemon_handle h, const char *uuid, const char *metadata) { daemon_reply reply = daemon_send_simple(h, "pv_add", "uuid = %s", uuid, "metadata = %b", metadata, NULL); _handle_reply(reply); } int scan(daemon_handle h, char *fn) { struct device *dev = dev_cache_get(fn, NULL); struct label *label; if (!label_read(dev, &label, 0)) { fprintf(stderr, "[C] no label found on %s\n", fn); return; } char uuid[64]; id_write_format(dev->pvid, uuid, 64); fprintf(stderr, "[C] found PV: %s\n", uuid); struct lvmcache_info *info = (struct lvmcache_info *) label->info; struct physical_volume pv = { 0, }; if (!(info->fmt->ops->pv_read(info->fmt, dev_name(dev), &pv, 0))) { fprintf(stderr, "[C] Failed to read PV %s", dev_name(dev)); return; } struct format_instance_ctx fic; struct format_instance *fid = info->fmt->ops->create_instance(info->fmt, &fic); struct metadata_area *mda; struct volume_group *vg = NULL; dm_list_iterate_items(mda, &info->mdas) { struct volume_group *this = mda->ops->vg_read(fid, "", mda); if (this && !vg || this->seqno > vg->seqno) vg = this; } if (vg) { char *buf = NULL; /* TODO. This is not entirely correct, since export_vg_to_buffer * adds trailing garbage to the buffer. We may need to use * export_vg_to_config_tree and format the buffer ourselves. It * does, however, work for now, since the garbage is well * formatted and has no conflicting keys with the rest of the * request. */ export_vg_to_buffer(vg, &buf); daemon_reply reply = daemon_send_simple(h, "pv_add", "uuid = %s", uuid, "metadata = %b", strchr(buf, '{'), NULL); _handle_reply(reply); } } void _dump_vg(daemon_handle h, const char *uuid) { daemon_reply reply = daemon_send_simple(h, "vg_by_uuid", "uuid = %s", uuid, NULL); fprintf(stderr, "[C] reply buffer: %s\n", reply.buffer); daemon_reply_destroy(reply); } int main(int argc, char **argv) { daemon_handle h = lvmetad_open(); if (argc > 1) { int i; struct cmd_context *cmd = create_toolcontext(0, NULL, 0, 0); for (i = 1; i < argc; ++i) { const char *uuid = NULL; scan(h, argv[i]); } destroy_toolcontext(cmd); return 0; } _pv_add(h, uuid1, NULL); _pv_add(h, uuid2, metadata2); _dump_vg(h, vgid); _pv_add(h, uuid3, NULL); daemon_close(h); return 0; } lvm2-2.02.98/daemons/lvmetad/lvmetad-client.h0000640000175000017500000000460312037016272017656 0ustar blankblank/* * Copyright (C) 2011-2012 Red Hat, Inc. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU Lesser General Public License v.2.1. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _LVM_LVMETAD_CLIENT_H #define _LVM_LVMETAD_CLIENT_H #include "daemon-client.h" struct volume_group; /* Different types of replies we may get from lvmetad. */ typedef struct { daemon_reply r; const char **uuids; /* NULL terminated array */ } lvmetad_uuidlist; typedef struct { daemon_reply r; struct dm_config_tree *cft; } lvmetad_vg; /* Get a list of VG UUIDs that match a given VG name. */ lvmetad_uuidlist lvmetad_lookup_vgname(daemon_handle h, const char *name); /* Get the metadata of a single VG, identified by UUID. */ lvmetad_vg lvmetad_get_vg(daemon_handle h, const char *uuid); /* * Add and remove PVs on demand. Udev-driven systems will use this interface * instead of scanning. */ daemon_reply lvmetad_add_pv(daemon_handle h, const char *pv_uuid, const char *mda_content); daemon_reply lvmetad_remove_pv(daemon_handle h, const char *pv_uuid); /* Trigger a full disk scan, throwing away all caches. XXX do we eventually want * this? Probably not yet, anyway. * daemon_reply lvmetad_rescan(daemon_handle h); */ /* * Update the version of metadata of a volume group. The VG has to be locked for * writing for this, and the VG metadata here has to match whatever has been * written to the disk (under this lock). This initially avoids the requirement * for lvmetad to write to disk (in later revisions, lvmetad_supersede_vg may * also do the writing, or we probably add another function to do that). */ daemon_reply lvmetad_supersede_vg(daemon_handle h, struct volume_group *vg); /* Wrappers to open/close connection */ static inline daemon_handle lvmetad_open(const char *socket) { daemon_info lvmetad_info = { .path = "lvmetad", .socket = socket ?: DEFAULT_RUN_DIR "/lvmetad.socket", .protocol = "lvmetad", .protocol_version = 1, .autostart = 0 }; return daemon_open(lvmetad_info); } static inline void lvmetad_close(daemon_handle h) { return daemon_close(h); } #endif lvm2-2.02.98/daemons/lvmetad/Makefile.in0000640000175000017500000000337412037016272016646 0ustar blankblank# # Copyright (C) 2011-2012 Red Hat, Inc. # # This file is part of LVM2. # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions # of the GNU Lesser General Public License v.2.1. # # You should have received a copy of the GNU Lesser General Public License # along with this program; if not, write to the Free Software Foundation, # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA srcdir = @srcdir@ top_srcdir = @top_srcdir@ top_builddir = @top_builddir@ SOURCES = lvmetad-core.c SOURCES2 = testclient.c TARGETS = lvmetad lvmetad-testclient .PHONY: install_lvmetad CFLOW_LIST = $(SOURCES) CFLOW_LIST_TARGET = $(LIB_NAME).cflow CFLOW_TARGET = lvmetad include $(top_builddir)/make.tmpl INCLUDES += -I$(top_srcdir)/libdaemon/server LVMLIBS = -ldaemonserver $(LVMINTERNAL_LIBS) -ldevmapper LIBS += $(PTHREAD_LIBS) LDFLAGS += -L$(top_builddir)/libdaemon/server CLDFLAGS += -L$(top_builddir)/libdaemon/server lvmetad: $(OBJECTS) $(top_builddir)/libdaemon/client/libdaemonclient.a \ $(top_builddir)/libdaemon/server/libdaemonserver.a $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) \ $(DL_LIBS) $(LVMLIBS) $(LIBS) -rdynamic # TODO: No idea. No idea how to test either. #ifneq ("$(CFLOW_CMD)", "") #CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES)) #-include $(top_builddir)/libdm/libdevmapper.cflow #-include $(top_builddir)/lib/liblvm-internal.cflow #-include $(top_builddir)/lib/liblvm2cmd.cflow #-include $(top_builddir)/daemons/dmeventd/$(LIB_NAME).cflow #-include $(top_builddir)/daemons/dmeventd/plugins/mirror/$(LIB_NAME)-lvm2mirror.cflow #endif install_lvmetad: lvmetad $(INSTALL_PROGRAM) -D $< $(sbindir)/$( #include #include #include typedef struct { log_state *log; /* convenience */ const char *log_config; struct dm_hash_table *pvid_to_pvmeta; struct dm_hash_table *device_to_pvid; /* shares locks with above */ struct dm_hash_table *vgid_to_metadata; struct dm_hash_table *vgid_to_vgname; struct dm_hash_table *vgname_to_vgid; struct dm_hash_table *pvid_to_vgid; struct { struct dm_hash_table *vg; pthread_mutex_t vg_lock_map; pthread_mutex_t pvid_to_pvmeta; pthread_mutex_t vgid_to_metadata; pthread_mutex_t pvid_to_vgid; } lock; char token[128]; pthread_mutex_t token_lock; } lvmetad_state; static void destroy_metadata_hashes(lvmetad_state *s) { struct dm_hash_node *n = NULL; n = dm_hash_get_first(s->vgid_to_metadata); while (n) { dm_config_destroy(dm_hash_get_data(s->vgid_to_metadata, n)); n = dm_hash_get_next(s->vgid_to_metadata, n); } n = dm_hash_get_first(s->pvid_to_pvmeta); while (n) { dm_config_destroy(dm_hash_get_data(s->pvid_to_pvmeta, n)); n = dm_hash_get_next(s->pvid_to_pvmeta, n); } dm_hash_destroy(s->pvid_to_pvmeta); dm_hash_destroy(s->vgid_to_metadata); dm_hash_destroy(s->vgid_to_vgname); dm_hash_destroy(s->vgname_to_vgid); n = dm_hash_get_first(s->device_to_pvid); while (n) { dm_free(dm_hash_get_data(s->device_to_pvid, n)); n = dm_hash_get_next(s->device_to_pvid, n); } dm_hash_destroy(s->device_to_pvid); dm_hash_destroy(s->pvid_to_vgid); } static void create_metadata_hashes(lvmetad_state *s) { s->pvid_to_pvmeta = dm_hash_create(32); s->device_to_pvid = dm_hash_create(32); s->vgid_to_metadata = dm_hash_create(32); s->vgid_to_vgname = dm_hash_create(32); s->pvid_to_vgid = dm_hash_create(32); s->vgname_to_vgid = dm_hash_create(32); } static void lock_pvid_to_pvmeta(lvmetad_state *s) { pthread_mutex_lock(&s->lock.pvid_to_pvmeta); } static void unlock_pvid_to_pvmeta(lvmetad_state *s) { pthread_mutex_unlock(&s->lock.pvid_to_pvmeta); } static void lock_vgid_to_metadata(lvmetad_state *s) { pthread_mutex_lock(&s->lock.vgid_to_metadata); } static void unlock_vgid_to_metadata(lvmetad_state *s) { pthread_mutex_unlock(&s->lock.vgid_to_metadata); } static void lock_pvid_to_vgid(lvmetad_state *s) { pthread_mutex_lock(&s->lock.pvid_to_vgid); } static void unlock_pvid_to_vgid(lvmetad_state *s) { pthread_mutex_unlock(&s->lock.pvid_to_vgid); } static response reply_fail(const char *reason) { return daemon_reply_simple("failed", "reason = %s", reason, NULL); } static response reply_unknown(const char *reason) { return daemon_reply_simple("unknown", "reason = %s", reason, NULL); } /* * TODO: It may be beneficial to clean up the vg lock hash from time to time, * since if we have many "rogue" requests for nonexistent things, we will keep * allocating memory that we never release. Not good. */ static struct dm_config_tree *lock_vg(lvmetad_state *s, const char *id) { pthread_mutex_t *vg; struct dm_config_tree *cft; pthread_mutex_lock(&s->lock.vg_lock_map); vg = dm_hash_lookup(s->lock.vg, id); if (!vg) { pthread_mutexattr_t rec; pthread_mutexattr_init(&rec); pthread_mutexattr_settype(&rec, PTHREAD_MUTEX_RECURSIVE_NP); if (!(vg = malloc(sizeof(pthread_mutex_t)))) return NULL; pthread_mutex_init(vg, &rec); if (!dm_hash_insert(s->lock.vg, id, vg)) { free(vg); return NULL; } } /* We never remove items from s->lock.vg => the pointer remains valid. */ pthread_mutex_unlock(&s->lock.vg_lock_map); DEBUGLOG(s, "locking VG %s", id); pthread_mutex_lock(vg); /* Protect against structure changes of the vgid_to_metadata hash. */ lock_vgid_to_metadata(s); cft = dm_hash_lookup(s->vgid_to_metadata, id); unlock_vgid_to_metadata(s); return cft; } static void unlock_vg(lvmetad_state *s, const char *id) { pthread_mutex_t *vg; DEBUGLOG(s, "unlocking VG %s", id); /* Protect the s->lock.vg structure from concurrent access. */ pthread_mutex_lock(&s->lock.vg_lock_map); if ((vg = dm_hash_lookup(s->lock.vg, id))) pthread_mutex_unlock(vg); pthread_mutex_unlock(&s->lock.vg_lock_map); } static struct dm_config_node *pvs(struct dm_config_node *vg) { struct dm_config_node *pv = dm_config_find_node(vg, "metadata/physical_volumes"); if (pv) pv = pv->child; return pv; } static void filter_metadata(struct dm_config_node *vg) { struct dm_config_node *pv = pvs(vg); while (pv) { struct dm_config_node *item = pv->child; while (item) { /* Remove the advisory device nodes. */ if (item->sib && !strcmp(item->sib->key, "device")) item->sib = item->sib->sib; item = item->sib; } pv = pv->sib; } vg->sib = NULL; /* Drop any trailing garbage. */ } static void merge_pvmeta(struct dm_config_node *pv, struct dm_config_node *pvmeta) { struct dm_config_node *tmp; if (!pvmeta) return; tmp = pvmeta; while (tmp->sib) { /* drop the redundant ID and dev_size nodes */ if (!strcmp(tmp->sib->key, "id") || !strcmp(tmp->sib->key, "dev_size")) tmp->sib = tmp->sib->sib; if (!tmp->sib) break; tmp = tmp->sib; tmp->parent = pv; } tmp->sib = pv->child; pv->child = pvmeta; pvmeta->parent = pv; } /* Either the "big" vgs lock, or a per-vg lock needs to be held before entering * this function. */ static int update_pv_status(lvmetad_state *s, struct dm_config_tree *cft, struct dm_config_node *vg, int act) { struct dm_config_node *pv; int complete = 1; const char *uuid; struct dm_config_tree *pvmeta; lock_pvid_to_pvmeta(s); for (pv = pvs(vg); pv; pv = pv->sib) { if (!(uuid = dm_config_find_str(pv->child, "id", NULL))) continue; pvmeta = dm_hash_lookup(s->pvid_to_pvmeta, uuid); if (act) { set_flag(cft, pv, "status", "MISSING", !pvmeta); if (pvmeta) { struct dm_config_node *pvmeta_cn = dm_config_clone_node(cft, pvmeta->root->child, 1); merge_pvmeta(pv, pvmeta_cn); } } if (!pvmeta) { complete = 0; if (!act) { /* optimisation */ unlock_pvid_to_pvmeta(s); return complete; } } } unlock_pvid_to_pvmeta(s); return complete; } static struct dm_config_node *make_pv_node(lvmetad_state *s, const char *pvid, struct dm_config_tree *cft, struct dm_config_node *parent, struct dm_config_node *pre_sib) { struct dm_config_tree *pvmeta = dm_hash_lookup(s->pvid_to_pvmeta, pvid); const char *vgid = dm_hash_lookup(s->pvid_to_vgid, pvid), *vgname = NULL; struct dm_config_node *pv; struct dm_config_node *cn = NULL; if (!pvmeta) return NULL; if (vgid) { lock_vgid_to_metadata(s); // XXX vgname = dm_hash_lookup(s->vgid_to_vgname, vgid); unlock_vgid_to_metadata(s); } /* Nick the pvmeta config tree. */ if (!(pv = dm_config_clone_node(cft, pvmeta->root, 0))) return 0; if (pre_sib) pre_sib->sib = pv; if (parent && !parent->child) parent->child = pv; pv->parent = parent; pv->key = pvid; /* Add the "variable" bits to it. */ if (vgid && strcmp(vgid, "#orphan")) cn = make_text_node(cft, "vgid", vgid, pv, cn); if (vgname) cn = make_text_node(cft, "vgname", vgname, pv, cn); return pv; } static response pv_list(lvmetad_state *s, request r) { struct dm_config_node *cn = NULL, *cn_pvs; struct dm_hash_node *n; const char *id; response res; buffer_init( &res.buffer ); if (!(res.cft = dm_config_create())) return res; /* FIXME error reporting */ /* The response field */ res.cft->root = make_text_node(res.cft, "response", "OK", NULL, NULL); cn_pvs = make_config_node(res.cft, "physical_volumes", NULL, res.cft->root); lock_pvid_to_pvmeta(s); for (n = dm_hash_get_first(s->pvid_to_pvmeta); n; n = dm_hash_get_next(s->pvid_to_pvmeta, n)) { id = dm_hash_get_key(s->pvid_to_pvmeta, n); cn = make_pv_node(s, id, res.cft, cn_pvs, cn); } unlock_pvid_to_pvmeta(s); return res; } static response pv_lookup(lvmetad_state *s, request r) { const char *pvid = daemon_request_str(r, "uuid", NULL); int64_t devt = daemon_request_int(r, "device", 0); response res; struct dm_config_node *pv; buffer_init( &res.buffer ); if (!pvid && !devt) return reply_fail("need PVID or device"); if (!(res.cft = dm_config_create())) return reply_fail("out of memory"); if (!(res.cft->root = make_text_node(res.cft, "response", "OK", NULL, NULL))) return reply_fail("out of memory"); lock_pvid_to_pvmeta(s); if (!pvid && devt) pvid = dm_hash_lookup_binary(s->device_to_pvid, &devt, sizeof(devt)); if (!pvid) { WARN(s, "pv_lookup: could not find device %" PRIu64, devt); unlock_pvid_to_pvmeta(s); dm_config_destroy(res.cft); return reply_unknown("device not found"); } pv = make_pv_node(s, pvid, res.cft, NULL, res.cft->root); if (!pv) { unlock_pvid_to_pvmeta(s); dm_config_destroy(res.cft); return reply_unknown("PV not found"); } pv->key = "physical_volume"; unlock_pvid_to_pvmeta(s); return res; } static response vg_list(lvmetad_state *s, request r) { struct dm_config_node *cn, *cn_vgs, *cn_last = NULL; struct dm_hash_node *n; const char *id; const char *name; response res; buffer_init( &res.buffer ); if (!(res.cft = dm_config_create())) goto bad; /* FIXME: better error reporting */ /* The response field */ res.cft->root = cn = dm_config_create_node(res.cft, "response"); if (!cn) goto bad; /* FIXME */ cn->parent = res.cft->root; if (!(cn->v = dm_config_create_value(res.cft))) goto bad; /* FIXME */ cn->v->type = DM_CFG_STRING; cn->v->v.str = "OK"; cn_vgs = cn = cn->sib = dm_config_create_node(res.cft, "volume_groups"); if (!cn_vgs) goto bad; /* FIXME */ cn->parent = res.cft->root; cn->v = NULL; cn->child = NULL; lock_vgid_to_metadata(s); n = dm_hash_get_first(s->vgid_to_vgname); while (n) { id = dm_hash_get_key(s->vgid_to_vgname, n), name = dm_hash_get_data(s->vgid_to_vgname, n); if (!(cn = dm_config_create_node(res.cft, id))) goto bad; /* FIXME */ if (cn_last) cn_last->sib = cn; cn->parent = cn_vgs; cn->sib = NULL; cn->v = NULL; if (!(cn->child = dm_config_create_node(res.cft, "name"))) goto bad; /* FIXME */ cn->child->parent = cn; cn->child->sib = 0; if (!(cn->child->v = dm_config_create_value(res.cft))) goto bad; /* FIXME */ cn->child->v->type = DM_CFG_STRING; cn->child->v->v.str = name; if (!cn_vgs->child) cn_vgs->child = cn; cn_last = cn; n = dm_hash_get_next(s->vgid_to_vgname, n); } unlock_vgid_to_metadata(s); bad: return res; } static response vg_lookup(lvmetad_state *s, request r) { struct dm_config_tree *cft; struct dm_config_node *metadata, *n; response res; const char *uuid = daemon_request_str(r, "uuid", NULL); const char *name = daemon_request_str(r, "name", NULL); buffer_init( &res.buffer ); DEBUGLOG(s, "vg_lookup: uuid = %s, name = %s", uuid, name); if (!uuid || !name) { lock_vgid_to_metadata(s); if (name && !uuid) uuid = dm_hash_lookup(s->vgname_to_vgid, name); if (uuid && !name) name = dm_hash_lookup(s->vgid_to_vgname, uuid); unlock_vgid_to_metadata(s); } DEBUGLOG(s, "vg_lookup: updated uuid = %s, name = %s", uuid, name); if (!uuid) return reply_unknown("VG not found"); cft = lock_vg(s, uuid); if (!cft || !cft->root) { unlock_vg(s, uuid); return reply_unknown("UUID not found"); } metadata = cft->root; if (!(res.cft = dm_config_create())) goto bad; /* The response field */ if (!(res.cft->root = n = dm_config_create_node(res.cft, "response"))) goto bad; if (!(n->v = dm_config_create_value(cft))) goto bad; n->parent = res.cft->root; n->v->type = DM_CFG_STRING; n->v->v.str = "OK"; if (!(n = n->sib = dm_config_create_node(res.cft, "name"))) goto bad; if (!(n->v = dm_config_create_value(res.cft))) goto bad; n->parent = res.cft->root; n->v->type = DM_CFG_STRING; n->v->v.str = name; /* The metadata section */ if (!(n = n->sib = dm_config_clone_node(res.cft, metadata, 1))) goto bad; n->parent = res.cft->root; res.error = 0; unlock_vg(s, uuid); update_pv_status(s, res.cft, n, 1); /* FIXME report errors */ return res; bad: unlock_vg(s, uuid); return reply_fail("out of memory"); } static int compare_value(struct dm_config_value *a, struct dm_config_value *b) { int r = 0; if (a->type > b->type) return 1; if (a->type < b->type) return -1; switch (a->type) { case DM_CFG_STRING: r = strcmp(a->v.str, b->v.str); break; case DM_CFG_FLOAT: r = (a->v.f == b->v.f) ? 0 : (a->v.f > b->v.f) ? 1 : -1; break; case DM_CFG_INT: r = (a->v.i == b->v.i) ? 0 : (a->v.i > b->v.i) ? 1 : -1; break; case DM_CFG_EMPTY_ARRAY: return 0; } if (r == 0 && a->next && b->next) r = compare_value(a->next, b->next); return r; } static int compare_config(struct dm_config_node *a, struct dm_config_node *b) { int result = 0; if (a->v && b->v) result = compare_value(a->v, b->v); if (a->v && !b->v) result = 1; if (!a->v && b->v) result = -1; if (a->child && b->child) result = compare_config(a->child, b->child); if (result) { // DEBUGLOG("config inequality at %s / %s", a->key, b->key); return result; } if (a->sib && b->sib) result = compare_config(a->sib, b->sib); if (a->sib && !b->sib) result = 1; if (!a->sib && b->sib) result = -1; return result; } static int vg_remove_if_missing(lvmetad_state *s, const char *vgid); /* You need to be holding the pvid_to_vgid lock already to call this. */ static int update_pvid_to_vgid(lvmetad_state *s, struct dm_config_tree *vg, const char *vgid, int nuke_empty) { struct dm_config_node *pv; struct dm_hash_table *to_check; struct dm_hash_node *n; const char *pvid; const char *vgid_old; const char *check_vgid; int r = 0; if (!vgid) return 0; if (!(to_check = dm_hash_create(32))) return 0; for (pv = pvs(vg->root); pv; pv = pv->sib) { if (!(pvid = dm_config_find_str(pv->child, "id", NULL))) continue; if (nuke_empty && (vgid_old = dm_hash_lookup(s->pvid_to_vgid, pvid)) && !dm_hash_insert(to_check, vgid_old, (void*) 1)) goto out; if (!dm_hash_insert(s->pvid_to_vgid, pvid, (void*) vgid)) goto out; DEBUGLOG(s, "moving PV %s to VG %s", pvid, vgid); } for (n = dm_hash_get_first(to_check); n; n = dm_hash_get_next(to_check, n)) { check_vgid = dm_hash_get_key(to_check, n); lock_vg(s, check_vgid); vg_remove_if_missing(s, check_vgid); unlock_vg(s, check_vgid); } r = 1; out: dm_hash_destroy(to_check); return r; } /* A pvid map lock needs to be held if update_pvids = 1. */ static int remove_metadata(lvmetad_state *s, const char *vgid, int update_pvids) { struct dm_config_tree *old; const char *oldname; lock_vgid_to_metadata(s); old = dm_hash_lookup(s->vgid_to_metadata, vgid); oldname = dm_hash_lookup(s->vgid_to_vgname, vgid); unlock_vgid_to_metadata(s); if (!old) return 0; assert(oldname); if (update_pvids) /* FIXME: What should happen when update fails */ update_pvid_to_vgid(s, old, "#orphan", 0); /* need to update what we have since we found a newer version */ dm_hash_remove(s->vgid_to_metadata, vgid); dm_hash_remove(s->vgid_to_vgname, vgid); dm_hash_remove(s->vgname_to_vgid, oldname); dm_config_destroy(old); return 1; } /* The VG must be locked. */ static int vg_remove_if_missing(lvmetad_state *s, const char *vgid) { struct dm_config_tree *vg; struct dm_config_node *pv; const char *vgid_check; const char *pvid; int missing = 1; if (!vgid) return 0; if (!(vg = dm_hash_lookup(s->vgid_to_metadata, vgid))) return 1; lock_pvid_to_pvmeta(s); for (pv = pvs(vg->root); pv; pv = pv->sib) { if (!(pvid = dm_config_find_str(pv->child, "id", NULL))) continue; if ((vgid_check = dm_hash_lookup(s->pvid_to_vgid, pvid)) && dm_hash_lookup(s->pvid_to_pvmeta, pvid) && !strcmp(vgid, vgid_check)) missing = 0; /* at least one PV is around */ } if (missing) { DEBUGLOG(s, "removing empty VG %s", vgid); remove_metadata(s, vgid, 0); } unlock_pvid_to_pvmeta(s); return 1; } /* No locks need to be held. The pointers are never used outside of the scope of * this function, so they can be safely destroyed after update_metadata returns * (anything that might have been retained is copied). */ static int update_metadata(lvmetad_state *s, const char *name, const char *_vgid, struct dm_config_node *metadata, int64_t *oldseq) { struct dm_config_tree *cft = NULL; struct dm_config_tree *old; int retval = 0; int seq; int haveseq = -1; const char *oldname = NULL; const char *vgid; char *cfgname; lock_vgid_to_metadata(s); old = dm_hash_lookup(s->vgid_to_metadata, _vgid); lock_vg(s, _vgid); unlock_vgid_to_metadata(s); seq = dm_config_find_int(metadata, "metadata/seqno", -1); if (old) { haveseq = dm_config_find_int(old->root, "metadata/seqno", -1); oldname = dm_hash_lookup(s->vgid_to_vgname, _vgid); assert(oldname); } if (seq < 0) goto out; filter_metadata(metadata); /* sanitize */ if (oldseq) { if (old) *oldseq = haveseq; else *oldseq = seq; } if (seq == haveseq) { retval = 1; if (compare_config(metadata, old->root)) retval = 0; DEBUGLOG(s, "Not updating metadata for %s at %d (%s)", _vgid, haveseq, retval ? "ok" : "MISMATCH"); if (!retval) { DEBUGLOG_cft(s, "OLD: ", old->root); DEBUGLOG_cft(s, "NEW: ", metadata); } goto out; } if (seq < haveseq) { DEBUGLOG(s, "Refusing to update metadata for %s (at %d) to %d", _vgid, haveseq, seq); /* TODO: notify the client that their metadata is out of date? */ retval = 1; goto out; } if (!(cft = dm_config_create()) || !(cft->root = dm_config_clone_node(cft, metadata, 0))) { ERROR(s, "Out of memory"); goto out; } vgid = dm_config_find_str(cft->root, "metadata/id", NULL); if (!vgid || !name) { DEBUGLOG(s, "Name '%s' or uuid '%s' missing!", name, vgid); goto out; } lock_pvid_to_vgid(s); if (haveseq >= 0 && haveseq < seq) { INFO(s, "Updating metadata for %s at %d to %d", _vgid, haveseq, seq); /* temporarily orphan all of our PVs */ remove_metadata(s, vgid, 1); } lock_vgid_to_metadata(s); DEBUGLOG(s, "Mapping %s to %s", vgid, name); retval = ((cfgname = dm_pool_strdup(dm_config_memory(cft), name)) && dm_hash_insert(s->vgid_to_metadata, vgid, cft) && dm_hash_insert(s->vgid_to_vgname, vgid, cfgname) && dm_hash_insert(s->vgname_to_vgid, name, (void*) vgid)) ? 1 : 0; unlock_vgid_to_metadata(s); if (retval) /* FIXME: What should happen when update fails */ retval = update_pvid_to_vgid(s, cft, vgid, 1); unlock_pvid_to_vgid(s); out: if (!retval && cft) dm_config_destroy(cft); unlock_vg(s, _vgid); return retval; } static response pv_gone(lvmetad_state *s, request r) { const char *pvid = daemon_request_str(r, "uuid", NULL); int64_t device = daemon_request_int(r, "device", 0); struct dm_config_tree *pvmeta; char *pvid_old; DEBUGLOG(s, "pv_gone: %s / %" PRIu64, pvid, device); lock_pvid_to_pvmeta(s); if (!pvid && device > 0) pvid = dm_hash_lookup_binary(s->device_to_pvid, &device, sizeof(device)); if (!pvid) { unlock_pvid_to_pvmeta(s); return reply_unknown("device not in cache"); } DEBUGLOG(s, "pv_gone (updated): %s / %" PRIu64, pvid, device); pvmeta = dm_hash_lookup(s->pvid_to_pvmeta, pvid); pvid_old = dm_hash_lookup_binary(s->device_to_pvid, &device, sizeof(device)); dm_hash_remove_binary(s->device_to_pvid, &device, sizeof(device)); dm_hash_remove(s->pvid_to_pvmeta, pvid); vg_remove_if_missing(s, dm_hash_lookup(s->pvid_to_vgid, pvid)); unlock_pvid_to_pvmeta(s); if (pvid_old) dm_free(pvid_old); if (pvmeta) { dm_config_destroy(pvmeta); return daemon_reply_simple("OK", NULL); } else return reply_unknown("PVID does not exist"); } static response pv_clear_all(lvmetad_state *s, request r) { DEBUGLOG(s, "pv_clear_all"); lock_pvid_to_pvmeta(s); lock_vgid_to_metadata(s); lock_pvid_to_vgid(s); destroy_metadata_hashes(s); create_metadata_hashes(s); unlock_pvid_to_vgid(s); unlock_vgid_to_metadata(s); unlock_pvid_to_pvmeta(s); return daemon_reply_simple("OK", NULL); } static response pv_found(lvmetad_state *s, request r) { struct dm_config_node *metadata = dm_config_find_node(r.cft->root, "metadata"); const char *pvid = daemon_request_str(r, "pvmeta/id", NULL); const char *vgname = daemon_request_str(r, "vgname", NULL); const char *vgid = daemon_request_str(r, "metadata/id", NULL); struct dm_config_node *pvmeta = dm_config_find_node(r.cft->root, "pvmeta"); uint64_t device; struct dm_config_tree *cft, *pvmeta_old_dev = NULL, *pvmeta_old_pvid = NULL; char *old; const char *pvid_dup; int complete = 0, orphan = 0; int64_t seqno = -1, seqno_old = -1; if (!pvid) return reply_fail("need PV UUID"); if (!pvmeta) return reply_fail("need PV metadata"); if (!dm_config_get_uint64(pvmeta, "pvmeta/device", &device)) return reply_fail("need PV device number"); lock_pvid_to_pvmeta(s); if ((old = dm_hash_lookup_binary(s->device_to_pvid, &device, sizeof(device)))) { pvmeta_old_dev = dm_hash_lookup(s->pvid_to_pvmeta, old); dm_hash_remove(s->pvid_to_pvmeta, old); } pvmeta_old_pvid = dm_hash_lookup(s->pvid_to_pvmeta, pvid); DEBUGLOG(s, "pv_found %s, vgid = %s, device = %" PRIu64 ", old = %s", pvid, vgid, device, old); dm_free(old); if (!(cft = dm_config_create()) || !(cft->root = dm_config_clone_node(cft, pvmeta, 0))) { unlock_pvid_to_pvmeta(s); return reply_fail("out of memory"); } pvid_dup = dm_strdup(pvid); if (!dm_hash_insert(s->pvid_to_pvmeta, pvid, cft) || !dm_hash_insert_binary(s->device_to_pvid, &device, sizeof(device), (void*)pvid_dup)) { unlock_pvid_to_pvmeta(s); return reply_fail("out of memory"); } if (pvmeta_old_pvid) dm_config_destroy(pvmeta_old_pvid); if (pvmeta_old_dev && pvmeta_old_dev != pvmeta_old_pvid) dm_config_destroy(pvmeta_old_dev); unlock_pvid_to_pvmeta(s); if (metadata) { if (!vgid) return reply_fail("need VG UUID"); DEBUGLOG(s, "obtained vgid = %s, vgname = %s", vgid, vgname); if (!vgname) return reply_fail("need VG name"); if (daemon_request_int(r, "metadata/seqno", -1) < 0) return reply_fail("need VG seqno"); if (!update_metadata(s, vgname, vgid, metadata, &seqno_old)) return reply_fail("metadata update failed"); } else { lock_pvid_to_vgid(s); vgid = dm_hash_lookup(s->pvid_to_vgid, pvid); unlock_pvid_to_vgid(s); } if (vgid) { if ((cft = lock_vg(s, vgid))) { complete = update_pv_status(s, cft, cft->root, 0); seqno = dm_config_find_int(cft->root, "metadata/seqno", -1); } else if (!strcmp(vgid, "#orphan")) orphan = 1; else { unlock_vg(s, vgid); return reply_fail("non-orphan VG without metadata encountered"); } unlock_vg(s, vgid); } return daemon_reply_simple("OK", "status = %s", orphan ? "orphan" : (complete ? "complete" : "partial"), "vgid = %s", vgid ? vgid : "#orphan", "seqno_before = %"PRId64, seqno_old, "seqno_after = %"PRId64, seqno, NULL); } static response vg_update(lvmetad_state *s, request r) { struct dm_config_node *metadata = dm_config_find_node(r.cft->root, "metadata"); const char *vgid = daemon_request_str(r, "metadata/id", NULL); const char *vgname = daemon_request_str(r, "vgname", NULL); if (metadata) { if (!vgid) return reply_fail("need VG UUID"); if (!vgname) return reply_fail("need VG name"); if (daemon_request_int(r, "metadata/seqno", -1) < 0) return reply_fail("need VG seqno"); /* TODO defer metadata update here; add a separate vg_commit * call; if client does not commit, die */ if (!update_metadata(s, vgname, vgid, metadata, NULL)) return reply_fail("metadata update failed"); } return daemon_reply_simple("OK", NULL); } static response vg_remove(lvmetad_state *s, request r) { const char *vgid = daemon_request_str(r, "uuid", NULL); if (!vgid) return reply_fail("need VG UUID"); DEBUGLOG(s, "vg_remove: %s", vgid); lock_pvid_to_vgid(s); remove_metadata(s, vgid, 1); unlock_pvid_to_vgid(s); return daemon_reply_simple("OK", NULL); } static void _dump_cft(struct buffer *buf, struct dm_hash_table *ht, const char *key_addr) { struct dm_hash_node *n = dm_hash_get_first(ht); while (n) { struct dm_config_tree *cft = dm_hash_get_data(ht, n); const char *key_backup = cft->root->key; cft->root->key = dm_config_find_str(cft->root, key_addr, "unknown"); dm_config_write_node(cft->root, buffer_line, buf); cft->root->key = key_backup; n = dm_hash_get_next(ht, n); } } static void _dump_pairs(struct buffer *buf, struct dm_hash_table *ht, const char *name, int int_key) { char *append; struct dm_hash_node *n = dm_hash_get_first(ht); buffer_append(buf, name); buffer_append(buf, " {\n"); while (n) { const char *key = dm_hash_get_key(ht, n), *val = dm_hash_get_data(ht, n); buffer_append(buf, " "); if (int_key) dm_asprintf(&append, "%d = \"%s\"", *(int*)key, val); else dm_asprintf(&append, "%s = \"%s\"", key, val); if (append) buffer_append(buf, append); buffer_append(buf, "\n"); dm_free(append); n = dm_hash_get_next(ht, n); } buffer_append(buf, "}\n"); } static response dump(lvmetad_state *s) { response res; struct buffer *b = &res.buffer; buffer_init(b); /* Lock everything so that we get a consistent dump. */ lock_vgid_to_metadata(s); lock_pvid_to_pvmeta(s); lock_pvid_to_vgid(s); buffer_append(b, "# VG METADATA\n\n"); _dump_cft(b, s->vgid_to_metadata, "metadata/id"); buffer_append(b, "\n# PV METADATA\n\n"); _dump_cft(b, s->pvid_to_pvmeta, "pvmeta/id"); buffer_append(b, "\n# VGID to VGNAME mapping\n\n"); _dump_pairs(b, s->vgid_to_vgname, "vgid_to_vgname", 0); buffer_append(b, "\n# VGNAME to VGID mapping\n\n"); _dump_pairs(b, s->vgname_to_vgid, "vgname_to_vgid", 0); buffer_append(b, "\n# PVID to VGID mapping\n\n"); _dump_pairs(b, s->pvid_to_vgid, "pvid_to_vgid", 0); buffer_append(b, "\n# DEVICE to PVID mapping\n\n"); _dump_pairs(b, s->device_to_pvid, "device_to_pvid", 1); unlock_pvid_to_vgid(s); unlock_pvid_to_pvmeta(s); unlock_vgid_to_metadata(s); return res; } static response handler(daemon_state s, client_handle h, request r) { lvmetad_state *state = s.private; const char *rq = daemon_request_str(r, "request", "NONE"); const char *token = daemon_request_str(r, "token", "NONE"); pthread_mutex_lock(&state->token_lock); if (!strcmp(rq, "token_update")) { strncpy(state->token, token, 128); state->token[127] = 0; pthread_mutex_unlock(&state->token_lock); return daemon_reply_simple("OK", NULL); } if (strcmp(token, state->token) && strcmp(rq, "dump")) { pthread_mutex_unlock(&state->token_lock); return daemon_reply_simple("token_mismatch", "expected = %s", state->token, "received = %s", token, "reason = %s", "token mismatch", NULL); } pthread_mutex_unlock(&state->token_lock); /* * TODO Add a stats call, with transaction count/rate, time since last * update &c. */ if (!strcmp(rq, "pv_found")) return pv_found(state, r); if (!strcmp(rq, "pv_gone")) return pv_gone(state, r); if (!strcmp(rq, "pv_clear_all")) return pv_clear_all(state, r); if (!strcmp(rq, "pv_lookup")) return pv_lookup(state, r); if (!strcmp(rq, "vg_update")) return vg_update(state, r); if (!strcmp(rq, "vg_remove")) return vg_remove(state, r); if (!strcmp(rq, "vg_lookup")) return vg_lookup(state, r); if (!strcmp(rq, "pv_list")) return pv_list(state, r); if (!strcmp(rq, "vg_list")) return vg_list(state, r); if (!strcmp(rq, "dump")) return dump(state); return reply_fail("request not implemented"); } static int init(daemon_state *s) { pthread_mutexattr_t rec; lvmetad_state *ls = s->private; ls->log = s->log; pthread_mutexattr_init(&rec); pthread_mutexattr_settype(&rec, PTHREAD_MUTEX_RECURSIVE_NP); pthread_mutex_init(&ls->lock.pvid_to_pvmeta, &rec); pthread_mutex_init(&ls->lock.vgid_to_metadata, &rec); pthread_mutex_init(&ls->lock.pvid_to_vgid, NULL); pthread_mutex_init(&ls->lock.vg_lock_map, NULL); pthread_mutex_init(&ls->token_lock, NULL); create_metadata_hashes(ls); ls->lock.vg = dm_hash_create(32); ls->token[0] = 0; /* Set up stderr logging depending on the -l option. */ if (!daemon_log_parse(ls->log, DAEMON_LOG_OUTLET_STDERR, ls->log_config, 1)) return 0; DEBUGLOG(s, "initialised state: vgid_to_metadata = %p", ls->vgid_to_metadata); if (!ls->pvid_to_vgid || !ls->vgid_to_metadata) return 0; /* if (ls->initial_registrations) _process_initial_registrations(ds->initial_registrations); */ return 1; } static int fini(daemon_state *s) { lvmetad_state *ls = s->private; struct dm_hash_node *n; DEBUGLOG(s, "fini"); destroy_metadata_hashes(ls); /* Destroy the lock hashes now. */ n = dm_hash_get_first(ls->lock.vg); while (n) { pthread_mutex_destroy(dm_hash_get_data(ls->lock.vg, n)); free(dm_hash_get_data(ls->lock.vg, n)); n = dm_hash_get_next(ls->lock.vg, n); } dm_hash_destroy(ls->lock.vg); return 1; } static void usage(char *prog, FILE *file) { fprintf(file, "Usage:\n" "%s [-V] [-h] [-f] [-l {all|wire|debug}] [-s path]\n\n" " -V Show version of lvmetad\n" " -h Show this help information\n" " -f Don't fork, run in the foreground\n" " -l Logging message level (-l {all|wire|debug})\n" " -s Set path to the socket to listen on\n\n", prog); } int main(int argc, char *argv[]) { signed char opt; daemon_state s = { .private = NULL }; lvmetad_state ls; int _socket_override = 1; s.name = "lvmetad"; s.private = &ls; s.daemon_init = init; s.daemon_fini = fini; s.handler = handler; s.socket_path = getenv("LVM_LVMETAD_SOCKET"); if (!s.socket_path) { _socket_override = 0; s.socket_path = DEFAULT_RUN_DIR "/lvmetad.socket"; } s.pidfile = LVMETAD_PIDFILE; s.protocol = "lvmetad"; s.protocol_version = 1; ls.log_config = ""; // use getopt_long while ((opt = getopt(argc, argv, "?fhVl:s:")) != EOF) { switch (opt) { case 'h': usage(argv[0], stdout); exit(0); case '?': usage(argv[0], stderr); exit(0); case 'f': s.foreground = 1; break; case 'l': ls.log_config = optarg; break; case 's': // --socket s.socket_path = optarg; _socket_override = 1; break; case 'V': printf("lvmetad version: " LVM_VERSION "\n"); exit(1); } } if (s.foreground) { if (!_socket_override) { fprintf(stderr, "A socket path (-s) is required in foreground mode."); exit(2); } else { s.pidfile = NULL; } } daemon_start(s); return 0; } lvm2-2.02.98/configure0000750000175000017500000124674512037016272013441 0ustar blankblank#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.66. # # # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, # 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software # Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV export CONFIG_SHELL exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -p'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -p' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi if test -x / >/dev/null 2>&1; then as_test_x='test -x' else if ls -dL / >/dev/null 2>&1; then as_ls_L_option=L else as_ls_L_option= fi as_test_x=' eval sh -c '\'' if test -d "$1"; then test -d "$1/."; else case $1 in #( -*)set "./$1";; esac; case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( ???[sx]*):;;*)false;;esac;fi '\'' sh ' fi as_executable_p=$as_test_x # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME= PACKAGE_TARNAME= PACKAGE_VERSION= PACKAGE_STRING= PACKAGE_BUGREPORT= PACKAGE_URL= ac_unique_file="lib/device/dev-cache.h" # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_header_list= ac_default_prefix=/usr ac_subst_vars='LTLIBOBJS usrsbindir usrlibdir tmpfilesdir systemdutildir systemdsystemunitdir udevdir udev_prefix tmpdir kernelvsn missingkernel kerneldir interface LVMETAD_PIDFILE DMEVENTD_PIDFILE WRITE_INSTALL UDEV_HAS_BUILTIN_BLKID UDEV_RULE_EXEC_DETECTION UDEV_SYNC UDEV_RULES UDEV_PC THIN TESTING STATIC_LINK STATICDIR SNAPSHOTS SELINUX_PC SELINUX_LIBS REPLICATORS READLINE_LIBS RAID PYTHON_LIBDIRS PYTHON_INCDIRS PYTHON_BINDINGS PTHREAD_LIBS POOL PKGCONFIG OCFDIR OCF MIRRORS LVM_RELEASE_DATE LVM_RELEASE LVM_PATH LVM_PATCHLEVEL LVM_MINOR LVM_MAJOR LVM_LIBAPI LVM_VERSION LVM1_FALLBACK LVM1 LOCALEDIR LIB_SUFFIX LDDEPS JOBS INTL_PACKAGE INTL HAVE_REALTIME HAVE_LIBDL BLKDEACTIVATE FSADM ELDFLAGS DM_LIB_PATCHLEVEL DM_LIB_VERSION DM_IOCTLS DM_DEVICE_UID DM_DEVICE_MODE DM_DEVICE_GID DM_COMPAT DMEVENTD_PATH DMEVENTD DL_LIBS DEVMAPPER DEFAULT_RUN_DIR DEFAULT_DM_RUN_DIR DEFAULT_LOCK_DIR DEFAULT_DATA_ALIGNMENT DEFAULT_CACHE_SUBDIR DEFAULT_BACKUP_SUBDIR DEFAULT_ARCHIVE_SUBDIR DEFAULT_SYS_DIR DEBUG COPTIMISE_FLAG CONFDIR CMDLIB CLVMD_PATH CLVMD_CMANAGERS CLVMD CLUSTER CLDWHOLEARCHIVE CLDNOWHOLEARCHIVE CLDFLAGS BUILD_LVMETAD BUILD_DMEVENTD BUILD_CMIRRORD APPLIB MODPROBE_CMD MSGFMT PYTHON_CONFIG PYTHON LVM2CMD_LIB LVM2APP_LIB UDEV_LIBS UDEV_CFLAGS VALGRIND_POOL VALGRIND_LIBS VALGRIND_CFLAGS CUNIT_LIBS CUNIT_CFLAGS GENPNG GENHTML LCOV SACKPT_LIBS SACKPT_CFLAGS DLM_LIBS DLM_CFLAGS CPG_LIBS CPG_CFLAGS CMAP_LIBS CMAP_CFLAGS CONFDB_LIBS CONFDB_CFLAGS SALCK_LIBS SALCK_CFLAGS QUORUM_LIBS QUORUM_CFLAGS COROSYNC_LIBS COROSYNC_CFLAGS CMAN_LIBS CMAN_CFLAGS PKGCONFIGINIT_LIBS PKGCONFIGINIT_CFLAGS PKG_CONFIG_LIBDIR PKG_CONFIG_PATH PKG_CONFIG THIN_CHECK_CMD POW_LIB LIBOBJS ALLOCA CSCOPE_CMD CFLOW_CMD RANLIB MKDIR_P SET_MAKE LN_S INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM EGREP GREP CPP OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC AWK SED target_os target_vendor target_cpu target host_os host_vendor host_cpu host build_os build_vendor build_cpu build target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking enable_static_link with_user with_group with_device_uid with_device_gid with_device_mode with_device_nodes_on with_default_name_mangling enable_lvm1_fallback with_lvm1 with_pool with_cluster with_snapshots with_mirrors with_raid with_replicators with_thin with_thin_check enable_readline enable_realtime enable_ocf with_ocfdir with_default_pid_dir with_default_dm_run_dir with_default_run_dir with_clvmd with_clvmd_pidfile enable_cmirrord with_cmirrord_pidfile enable_debug with_optimisation enable_profiling enable_testing enable_valgrind_pool enable_devmapper enable_lvmetad with_lvmetad_pidfile enable_udev_sync enable_udev_rules enable_udev_rule_exec_detection enable_compat enable_units_compat enable_ioctl enable_o_direct enable_applib enable_cmdlib enable_python_bindings enable_pkgconfig enable_write_install enable_fsadm enable_blkdeactivate enable_dmeventd enable_selinux enable_nls with_localedir with_confdir with_staticdir with_usrlibdir with_usrsbindir with_udev_prefix with_udevdir with_systemdsystemunitdir with_tmpfilesdir with_dmeventd_pidfile with_dmeventd_path with_default_system_dir with_default_archive_subdir with_default_backup_subdir with_default_cache_subdir with_default_locking_dir with_default_data_alignment with_interface ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP PKG_CONFIG PKG_CONFIG_PATH PKG_CONFIG_LIBDIR PKGCONFIGINIT_CFLAGS PKGCONFIGINIT_LIBS CMAN_CFLAGS CMAN_LIBS COROSYNC_CFLAGS COROSYNC_LIBS QUORUM_CFLAGS QUORUM_LIBS SALCK_CFLAGS SALCK_LIBS CONFDB_CFLAGS CONFDB_LIBS CMAP_CFLAGS CMAP_LIBS CPG_CFLAGS CPG_LIBS DLM_CFLAGS DLM_LIBS SACKPT_CFLAGS SACKPT_LIBS CUNIT_CFLAGS CUNIT_LIBS VALGRIND_CFLAGS VALGRIND_LIBS UDEV_CFLAGS UDEV_LIBS' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host. If a cross compiler is detected then cross compile mode will be used" >&2 elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures this package to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] --target=TARGET configure for building compilers for TARGET [HOST] _ACEOF fi if test -n "$ac_init_help"; then cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-static_link use this to link the tools to their libraries statically (default is dynamic linking --enable-lvm1_fallback use this to fall back and use LVM1 binaries if device-mapper is missing from the kernel --disable-readline disable readline support --enable-realtime enable realtime clock support --enable-ocf enable Open Cluster Framework (OCF) compliant resource agents --enable-cmirrord enable the cluster mirror log daemon --enable-debug enable debugging --enable-profiling gather gcov profiling data --enable-testing enable testing targets in the makefile --enable-valgrind-pool enable valgrind awareness of pools --disable-devmapper disable LVM2 device-mapper interaction --enable-lvmetad enable the LVM Metadata Daemon --enable-udev_sync enable synchronisation with udev processing --enable-udev_rules install rule files needed for udev synchronisation --enable-udev-rule-exec-detection enable executable path detection in udev rules --enable-compat enable support for old device-mapper versions --enable-units-compat enable output compatibility with old versions that that do not use KiB-style unit suffixes --disable-driver disable calls to device-mapper in the kernel --disable-o_direct disable O_DIRECT --enable-applib build application library --enable-cmdlib build shared command library --enable-python_bindings build Python applib bindings --enable-pkgconfig install pkgconfig support --enable-write_install install user writable files --disable-fsadm disable fsadm --disable-blkdeactivate disable blkdeactivate --enable-dmeventd enable the device-mapper event daemon --disable-selinux disable selinux support --enable-nls enable Native Language Support Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-user=USER set the owner of installed files [[USER=]] --with-group=GROUP set the group owner of installed files [[GROUP=]] --with-device-uid=UID set the owner used for new device nodes [[UID=0]] --with-device-gid=GID set the group used for new device nodes [[GID=0]] --with-device-mode=MODE set the mode used for new device nodes [[MODE=0600]] --with-device-nodes-on=ON create nodes on resume or create [[ON=resume]] --with-default-name-mangling=MANGLING default name mangling: auto/none/hex [[MANGLING=auto]] --with-lvm1=TYPE LVM1 metadata support: internal/shared/none [[TYPE=internal]] --with-pool=TYPE GFS pool read-only support: internal/shared/none [[TYPE=internal]] --with-cluster=TYPE cluster LVM locking support: internal/shared/none [[TYPE=internal]] --with-snapshots=TYPE snapshot support: internal/shared/none [[TYPE=internal]] --with-mirrors=TYPE mirror support: internal/shared/none [[TYPE=internal]] --with-raid=TYPE mirror support: internal/shared/none [[TYPE=internal]] --with-replicators=TYPE replicator support: internal/shared/none [[TYPE=none]] --with-thin=TYPE thin provisioning support: internal/shared/none [[TYPE=none]] --with-thin-check=PATH thin_check tool: [[autodetect]] --with-ocfdir=DIR install OCF files in DIR [[PREFIX/lib/ocf/resource.d/lvm2]] --with-default-pid-dir=PID_DIR Default directory to keep PID files in. [[/var/run]] --with-default-dm-run-dir=DM_RUN_DIR Default DM run directory. [[/var/run]] --with-default-run-dir=RUN_DIR Default LVM run directory. [[/var/run/lvm]] --with-clvmd=TYPE build cluster LVM Daemon The following cluster manager combinations are valid: * cman (RHEL5 or equivalent) * cman,corosync,openais (or selection of them) * singlenode (localhost only) * all (autodetect) * none (disable build) [TYPE=none] --with-clvmd-pidfile=PATH clvmd pidfile [[PID_DIR/clvmd.pid]] --with-cmirrord-pidfile=PATH cmirrord pidfile [[PID_DIR/cmirrord.pid]] --with-optimisation=OPT C optimisation flag [[OPT=-O2]] --with-lvmetad-pidfile=PATH lvmetad pidfile [[PID_DIR/lvmetad.pid]] --with-localedir=DIR translation files in DIR [[PREFIX/share/locale]] --with-confdir=DIR configuration files in DIR [[/etc]] --with-staticdir=DIR static binaries in DIR [[EPREFIX/sbin]] --with-usrlibdir=DIR usrlib in DIR [[PREFIX/lib]] --with-usrsbindir=DIR usrsbin executables in DIR [[PREFIX/sbin]] --with-udev-prefix=UPREFIX install udev rule files in UPREFIX [[EPREFIX]] --with-udevdir=DIR udev rules in DIR [[UPREFIX/lib/udev/rules.d]] --with-systemdsystemunitdir=DIR systemd service files in DIR --with-tmpfilesdir=DIR install configuration files for management of volatile files and directories in DIR [[PREFIX/lib/tmpfiles.d]] --with-dmeventd-pidfile=PATH dmeventd pidfile [[PID_DIR/dmeventd.pid]] --with-dmeventd-path=PATH dmeventd path [[EPREFIX/sbin/dmeventd]] --with-default-system-dir=DIR default LVM system directory [[/etc/lvm]] --with-default-archive-subdir=SUBDIR default metadata archive subdir [[archive]] --with-default-backup-subdir=SUBDIR default metadata backup subdir [[backup]] --with-default-cache-subdir=SUBDIR default metadata cache subdir [[cache]] --with-default-locking-dir=DIR default locking directory [[/var/lock/lvm]] --with-default-data-alignment=NUM set the default data alignment in MiB [[1]] --with-interface=IFACE choose kernel interface (ioctl) [[ioctl]] Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor PKG_CONFIG path to pkg-config utility PKG_CONFIG_PATH directories to add to pkg-config's search path PKG_CONFIG_LIBDIR path overriding pkg-config's built-in search path PKGCONFIGINIT_CFLAGS C compiler flags for PKGCONFIGINIT, overriding pkg-config PKGCONFIGINIT_LIBS linker flags for PKGCONFIGINIT, overriding pkg-config CMAN_CFLAGS C compiler flags for CMAN, overriding pkg-config CMAN_LIBS linker flags for CMAN, overriding pkg-config COROSYNC_CFLAGS C compiler flags for COROSYNC, overriding pkg-config COROSYNC_LIBS linker flags for COROSYNC, overriding pkg-config QUORUM_CFLAGS C compiler flags for QUORUM, overriding pkg-config QUORUM_LIBS linker flags for QUORUM, overriding pkg-config SALCK_CFLAGS C compiler flags for SALCK, overriding pkg-config SALCK_LIBS linker flags for SALCK, overriding pkg-config CONFDB_CFLAGS C compiler flags for CONFDB, overriding pkg-config CONFDB_LIBS linker flags for CONFDB, overriding pkg-config CMAP_CFLAGS C compiler flags for CMAP, overriding pkg-config CMAP_LIBS linker flags for CMAP, overriding pkg-config CPG_CFLAGS C compiler flags for CPG, overriding pkg-config CPG_LIBS linker flags for CPG, overriding pkg-config DLM_CFLAGS C compiler flags for DLM, overriding pkg-config DLM_LIBS linker flags for DLM, overriding pkg-config SACKPT_CFLAGS C compiler flags for SACKPT, overriding pkg-config SACKPT_LIBS linker flags for SACKPT, overriding pkg-config CUNIT_CFLAGS C compiler flags for CUNIT, overriding pkg-config CUNIT_LIBS linker flags for CUNIT, overriding pkg-config VALGRIND_CFLAGS C compiler flags for VALGRIND, overriding pkg-config VALGRIND_LIBS linker flags for VALGRIND, overriding pkg-config UDEV_CFLAGS C compiler flags for UDEV, overriding pkg-config UDEV_LIBS linker flags for UDEV, overriding pkg-config Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to the package provider. _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF configure generated by GNU Autoconf 2.66 Copyright (C) 2010 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } >/dev/null && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if eval "test \"\${$3+set}\"" = set; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_check_header_mongrel # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_check_header_compile # ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES # ---------------------------------------------------- # Tries to find if the field MEMBER exists in type AGGR, after including # INCLUDES, setting cache variable VAR accordingly. ac_fn_c_check_member () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 $as_echo_n "checking for $2.$3... " >&6; } if eval "test \"\${$4+set}\"" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $5 int main () { static $2 ac_aggr; if (ac_aggr.$3) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$4=yes" else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $5 int main () { static $2 ac_aggr; if (sizeof ac_aggr.$3) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$4=yes" else eval "$4=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$4 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_check_member # ac_fn_c_check_type LINENO TYPE VAR INCLUDES # ------------------------------------------- # Tests whether TYPE exists after having included INCLUDES, setting cache # variable VAR accordingly. ac_fn_c_check_type () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 else eval "$3=no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof ($2)) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof (($2))) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else eval "$3=yes" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_check_type # ac_fn_c_find_intX_t LINENO BITS VAR # ----------------------------------- # Finds a signed integer type with width BITS, setting cache variable VAR # accordingly. ac_fn_c_find_intX_t () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for int$2_t" >&5 $as_echo_n "checking for int$2_t... " >&6; } if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 else eval "$3=no" # Order is important - never check a type that is potentially smaller # than half of the expected target width. for ac_type in int$2_t 'int' 'long int' \ 'long long int' 'short int' 'signed char'; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default enum { N = $2 / 2 - 1 }; int main () { static int test_array [1 - 2 * !(0 < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1))]; test_array [0] = 0 ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default enum { N = $2 / 2 - 1 }; int main () { static int test_array [1 - 2 * !(($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1) < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 2))]; test_array [0] = 0 ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else case $ac_type in #( int$2_t) : eval "$3=yes" ;; #( *) : eval "$3=\$ac_type" ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if eval test \"x\$"$3"\" = x"no"; then : else break fi done fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_find_intX_t # ac_fn_c_find_uintX_t LINENO BITS VAR # ------------------------------------ # Finds an unsigned integer type with width BITS, setting cache variable VAR # accordingly. ac_fn_c_find_uintX_t () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uint$2_t" >&5 $as_echo_n "checking for uint$2_t... " >&6; } if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 else eval "$3=no" # Order is important - never check a type that is potentially smaller # than half of the expected target width. for ac_type in uint$2_t 'unsigned int' 'unsigned long int' \ 'unsigned long long int' 'unsigned short int' 'unsigned char'; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { static int test_array [1 - 2 * !((($ac_type) -1 >> ($2 / 2 - 1)) >> ($2 / 2 - 1) == 3)]; test_array [0] = 0 ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : case $ac_type in #( uint$2_t) : eval "$3=yes" ;; #( *) : eval "$3=\$ac_type" ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if eval test \"x\$"$3"\" = x"no"; then : else break fi done fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_find_uintX_t # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_check_func cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by $as_me, which was generated by GNU Autoconf 2.66. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi as_fn_append ac_header_list " stdlib.h" as_fn_append ac_header_list " unistd.h" as_fn_append ac_header_list " sys/param.h" # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_config_headers="$ac_config_headers lib/misc/configure.h" ################################################################################ ac_aux_dir= for ac_dir in autoconf "$srcdir"/autoconf; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then as_fn_error $? "cannot find install-sh, install.sh, or shtool in autoconf \"$srcdir\"/autoconf" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. ################################################################################ # Make sure we can run config.sub. $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 $as_echo_n "checking build system type... " >&6; } if test "${ac_cv_build+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 $as_echo "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' set x $ac_cv_build shift build_cpu=$1 build_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: build_os=$* IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 $as_echo_n "checking host system type... " >&6; } if test "${ac_cv_host+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 $as_echo "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' set x $ac_cv_host shift host_cpu=$1 host_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: host_os=$* IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking target system type" >&5 $as_echo_n "checking target system type... " >&6; } if test "${ac_cv_target+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "x$target_alias" = x; then ac_cv_target=$ac_cv_host else ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $target_alias failed" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5 $as_echo "$ac_cv_target" >&6; } case $ac_cv_target in *-*-*) ;; *) as_fn_error $? "invalid value of canonical target" "$LINENO" 5;; esac target=$ac_cv_target ac_save_IFS=$IFS; IFS='-' set x $ac_cv_target shift target_cpu=$1 target_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: target_os=$* IFS=$ac_save_IFS case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac # The aliases save the names the user supplied, while $host etc. # will get canonicalized. test -n "$target_alias" && test "$program_prefix$program_suffix$program_transform_name" = \ NONENONEs,x,x, && program_prefix=${target_alias}- case "$host_os" in linux*) CFLAGS="$CFLAGS" COPTIMISE_FLAG="-O2" CLDFLAGS="$CLDFLAGS -Wl,--version-script,.export.sym" ELDFLAGS="-Wl,--export-dynamic" # FIXME Generate list and use --dynamic-list=.dlopen.sym CLDWHOLEARCHIVE="-Wl,-whole-archive" CLDNOWHOLEARCHIVE="-Wl,-no-whole-archive" LDDEPS="$LDDEPS .export.sym" LIB_SUFFIX=so DEVMAPPER=yes LVMETAD=no ODIRECT=yes DM_IOCTLS=yes SELINUX=yes CLUSTER=internal FSADM=yes BLKDEACTIVATE=yes ;; darwin*) CFLAGS="$CFLAGS -no-cpp-precomp -fno-common" COPTIMISE_FLAG="-O2" CLDFLAGS="$CLDFLAGS" ELDFLAGS= CLDWHOLEARCHIVE="-all_load" CLDNOWHOLEARCHIVE= LIB_SUFFIX=dylib DEVMAPPER=yes ODIRECT=no DM_IOCTLS=no SELINUX=no CLUSTER=none FSADM=no BLKDEACTIVATE=no ;; esac ################################################################################ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 $as_echo_n "checking for a sed that does not truncate output... " >&6; } if test "${ac_cv_path_SED+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ for ac_i in 1 2 3 4 5 6 7; do ac_script="$ac_script$as_nl$ac_script" done echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed { ac_script=; unset ac_script;} if test -z "$SED"; then ac_path_SED_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" { test -f "$ac_path_SED" && $as_test_x "$ac_path_SED"; } || continue # Check for GNU ac_path_SED and select it if it is found. # Check for GNU $ac_path_SED case `"$ac_path_SED" --version 2>&1` in *GNU*) ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo '' >> "conftest.nl" "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_SED_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_SED="$ac_path_SED" ac_path_SED_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_SED_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_SED"; then as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 fi else ac_cv_path_SED=$SED fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 $as_echo "$ac_cv_path_SED" >&6; } SED="$ac_cv_path_SED" rm -f conftest.sed for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_AWK+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_AWK="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 $as_echo "$AWK" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AWK" && break done ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if test "${ac_cv_objext+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if test "${ac_cv_c_compiler_gnu+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if test "${ac_cv_prog_cc_g+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if test "${ac_cv_prog_cc_c89+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if test "${ac_cv_prog_CPP+set}" = set; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if test "${ac_cv_path_GREP+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if test "${ac_cv_path_EGREP+set}" = set; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" if test $ac_cv_c_compiler_gnu = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC needs -traditional" >&5 $as_echo_n "checking whether $CC needs -traditional... " >&6; } if test "${ac_cv_prog_gcc_traditional+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_pattern="Autoconf.*'x'" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include Autoconf TIOCGETP _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "$ac_pattern" >/dev/null 2>&1; then : ac_cv_prog_gcc_traditional=yes else ac_cv_prog_gcc_traditional=no fi rm -f conftest* if test $ac_cv_prog_gcc_traditional = no; then cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include Autoconf TCGETA _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "$ac_pattern" >/dev/null 2>&1; then : ac_cv_prog_gcc_traditional=yes fi rm -f conftest* fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_gcc_traditional" >&5 $as_echo "$ac_cv_prog_gcc_traditional" >&6; } if test $ac_cv_prog_gcc_traditional = yes; then CC="$CC -traditional" fi fi # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if test "${ac_cv_path_install+set}" = set; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 $as_echo_n "checking whether ln -s works... " >&6; } LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 $as_echo "no, using $LN_S" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 $as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\"" = set; then : $as_echo_n "(cached) " >&6 else cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } SET_MAKE= else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 $as_echo_n "checking for a thread-safe mkdir -p... " >&6; } if test -z "$MKDIR_P"; then if test "${ac_cv_path_mkdir+set}" = set; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in mkdir gmkdir; do for ac_exec_ext in '' $ac_executable_extensions; do { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( 'mkdir (GNU coreutils) '* | \ 'mkdir (coreutils) '* | \ 'mkdir (fileutils) '4.1*) ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext break 3;; esac done done done IFS=$as_save_IFS fi test -d ./--version && rmdir ./--version if test "${ac_cv_path_mkdir+set}" = set; then MKDIR_P="$ac_cv_path_mkdir -p" else # As a last resort, use the slow shell script. Don't cache a # value for MKDIR_P within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. MKDIR_P="$ac_install_sh -d" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 $as_echo "$MKDIR_P" >&6; } if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_RANLIB+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 $as_echo "$RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_RANLIB="ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 $as_echo "$ac_ct_RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB fi else RANLIB="$ac_cv_prog_RANLIB" fi # Extract the first word of "cflow", so it can be a program name with args. set dummy cflow; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_CFLOW_CMD+set}" = set; then : $as_echo_n "(cached) " >&6 else case $CFLOW_CMD in [\\/]* | ?:[\\/]*) ac_cv_path_CFLOW_CMD="$CFLOW_CMD" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_CFLOW_CMD="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi CFLOW_CMD=$ac_cv_path_CFLOW_CMD if test -n "$CFLOW_CMD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CFLOW_CMD" >&5 $as_echo "$CFLOW_CMD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "cscope", so it can be a program name with args. set dummy cscope; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_CSCOPE_CMD+set}" = set; then : $as_echo_n "(cached) " >&6 else case $CSCOPE_CMD in [\\/]* | ?:[\\/]*) ac_cv_path_CSCOPE_CMD="$CSCOPE_CMD" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_CSCOPE_CMD="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi CSCOPE_CMD=$ac_cv_path_CSCOPE_CMD if test -n "$CSCOPE_CMD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CSCOPE_CMD" >&5 $as_echo "$CSCOPE_CMD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi ################################################################################ ac_header_dirent=no for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do as_ac_Header=`$as_echo "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_hdr that defines DIR" >&5 $as_echo_n "checking for $ac_hdr that defines DIR... " >&6; } if eval "test \"\${$as_ac_Header+set}\"" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include <$ac_hdr> int main () { if ((DIR *) 0) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$as_ac_Header=yes" else eval "$as_ac_Header=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$as_ac_Header { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_hdr" | $as_tr_cpp` 1 _ACEOF ac_header_dirent=$ac_hdr; break fi done # Two versions of opendir et al. are in -ldir and -lx on SCO Xenix. if test $ac_header_dirent = dirent.h; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 $as_echo_n "checking for library containing opendir... " >&6; } if test "${ac_cv_search_opendir+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char opendir (); int main () { return opendir (); ; return 0; } _ACEOF for ac_lib in '' dir; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_opendir=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if test "${ac_cv_search_opendir+set}" = set; then : break fi done if test "${ac_cv_search_opendir+set}" = set; then : else ac_cv_search_opendir=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5 $as_echo "$ac_cv_search_opendir" >&6; } ac_res=$ac_cv_search_opendir if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 $as_echo_n "checking for library containing opendir... " >&6; } if test "${ac_cv_search_opendir+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char opendir (); int main () { return opendir (); ; return 0; } _ACEOF for ac_lib in '' x; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_opendir=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if test "${ac_cv_search_opendir+set}" = set; then : break fi done if test "${ac_cv_search_opendir+set}" = set; then : else ac_cv_search_opendir=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5 $as_echo "$ac_cv_search_opendir" >&6; } ac_res=$ac_cv_search_opendir if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if test "${ac_cv_header_stdc+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether sys/types.h defines makedev" >&5 $as_echo_n "checking whether sys/types.h defines makedev... " >&6; } if test "${ac_cv_header_sys_types_h_makedev+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { return makedev(0, 0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_header_sys_types_h_makedev=yes else ac_cv_header_sys_types_h_makedev=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_sys_types_h_makedev" >&5 $as_echo "$ac_cv_header_sys_types_h_makedev" >&6; } if test $ac_cv_header_sys_types_h_makedev = no; then ac_fn_c_check_header_mongrel "$LINENO" "sys/mkdev.h" "ac_cv_header_sys_mkdev_h" "$ac_includes_default" if test "x$ac_cv_header_sys_mkdev_h" = x""yes; then : $as_echo "#define MAJOR_IN_MKDEV 1" >>confdefs.h fi if test $ac_cv_header_sys_mkdev_h = no; then ac_fn_c_check_header_mongrel "$LINENO" "sys/sysmacros.h" "ac_cv_header_sys_sysmacros_h" "$ac_includes_default" if test "x$ac_cv_header_sys_sysmacros_h" = x""yes; then : $as_echo "#define MAJOR_IN_SYSMACROS 1" >>confdefs.h fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if test "${ac_cv_header_stdc+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sys/wait.h that is POSIX.1 compatible" >&5 $as_echo_n "checking for sys/wait.h that is POSIX.1 compatible... " >&6; } if test "${ac_cv_header_sys_wait_h+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #ifndef WEXITSTATUS # define WEXITSTATUS(stat_val) ((unsigned int) (stat_val) >> 8) #endif #ifndef WIFEXITED # define WIFEXITED(stat_val) (((stat_val) & 255) == 0) #endif int main () { int s; wait (&s); s = WIFEXITED (s) ? WEXITSTATUS (s) : 1; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_sys_wait_h=yes else ac_cv_header_sys_wait_h=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_sys_wait_h" >&5 $as_echo "$ac_cv_header_sys_wait_h" >&6; } if test $ac_cv_header_sys_wait_h = yes; then $as_echo "#define HAVE_SYS_WAIT_H 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether time.h and sys/time.h may both be included" >&5 $as_echo_n "checking whether time.h and sys/time.h may both be included... " >&6; } if test "${ac_cv_header_time+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include int main () { if ((struct tm *) 0) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_time=yes else ac_cv_header_time=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_time" >&5 $as_echo "$ac_cv_header_time" >&6; } if test $ac_cv_header_time = yes; then $as_echo "#define TIME_WITH_SYS_TIME 1" >>confdefs.h fi for ac_header in locale.h stddef.h syslog.h sys/file.h sys/time.h assert.h \ langinfo.h libgen.h signal.h sys/mman.h sys/resource.h sys/utsname.h \ sys/wait.h time.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF else as_fn_error $? "bailing out" "$LINENO" 5 fi done case "$host_os" in linux*) for ac_header in asm/byteorder.h linux/fs.h malloc.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF else as_fn_error $? "bailing out" "$LINENO" 5 fi done ;; darwin*) for ac_header in machine/endian.h sys/disk.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF else as_fn_error $? "bailing out" "$LINENO" 5 fi done ;; esac for ac_header in ctype.h dirent.h errno.h fcntl.h getopt.h inttypes.h limits.h \ stdarg.h stdio.h stdlib.h string.h sys/ioctl.h sys/param.h sys/stat.h \ sys/types.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF else as_fn_error $? "bailing out" "$LINENO" 5 fi done for ac_header in termios.h sys/statvfs.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done ################################################################################ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5 $as_echo_n "checking for an ANSI C-conforming const... " >&6; } if test "${ac_cv_c_const+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { /* FIXME: Include the comments suggested by Paul. */ #ifndef __cplusplus /* Ultrix mips cc rejects this. */ typedef int charset[2]; const charset cs; /* SunOS 4.1.1 cc rejects this. */ char const *const *pcpcc; char **ppc; /* NEC SVR4.0.2 mips cc rejects this. */ struct point {int x, y;}; static struct point const zero = {0,0}; /* AIX XL C 1.02.0.0 rejects this. It does not let you subtract one const X* pointer from another in an arm of an if-expression whose if-part is not a constant expression */ const char *g = "string"; pcpcc = &g + (g ? g-g : 0); /* HPUX 7.0 cc rejects these. */ ++pcpcc; ppc = (char**) pcpcc; pcpcc = (char const *const *) ppc; { /* SCO 3.2v4 cc rejects this. */ char *t; char const *s = 0 ? (char *) 0 : (char const *) 0; *t++ = 0; if (s) return 0; } { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ int x[] = {25, 17}; const int *foo = &x[0]; ++foo; } { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ typedef const int *iptr; iptr p = 0; ++p; } { /* AIX XL C 1.02.0.0 rejects this saying "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ struct s { int j; const int *ap[3]; }; struct s *b; b->j = 5; } { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ const int foo = 10; if (!foo) return 0; } return !cs[0] && !zero.x; #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_const=yes else ac_cv_c_const=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5 $as_echo "$ac_cv_c_const" >&6; } if test $ac_cv_c_const = no; then $as_echo "#define const /**/" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5 $as_echo_n "checking for inline... " >&6; } if test "${ac_cv_c_inline+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_cv_c_inline=no for ac_kw in inline __inline__ __inline; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifndef __cplusplus typedef int foo_t; static $ac_kw foo_t static_foo () {return 0; } $ac_kw foo_t foo () {return 0; } #endif _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_inline=$ac_kw fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext test "$ac_cv_c_inline" != no && break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5 $as_echo "$ac_cv_c_inline" >&6; } case $ac_cv_c_inline in inline | yes) ;; *) case $ac_cv_c_inline in no) ac_val=;; *) ac_val=$ac_cv_c_inline;; esac cat >>confdefs.h <<_ACEOF #ifndef __cplusplus #define inline $ac_val #endif _ACEOF ;; esac ac_fn_c_check_member "$LINENO" "struct stat" "st_rdev" "ac_cv_member_struct_stat_st_rdev" "$ac_includes_default" if test "x$ac_cv_member_struct_stat_st_rdev" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_STAT_ST_RDEV 1 _ACEOF fi ac_fn_c_check_type "$LINENO" "off_t" "ac_cv_type_off_t" "$ac_includes_default" if test "x$ac_cv_type_off_t" = x""yes; then : else cat >>confdefs.h <<_ACEOF #define off_t long int _ACEOF fi ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default" if test "x$ac_cv_type_pid_t" = x""yes; then : else cat >>confdefs.h <<_ACEOF #define pid_t int _ACEOF fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking return type of signal handlers" >&5 $as_echo_n "checking return type of signal handlers... " >&6; } if test "${ac_cv_type_signal+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { return *(signal (0, 0)) (0) == 1; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_type_signal=int else ac_cv_type_signal=void fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_signal" >&5 $as_echo "$ac_cv_type_signal" >&6; } cat >>confdefs.h <<_ACEOF #define RETSIGTYPE $ac_cv_type_signal _ACEOF ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" if test "x$ac_cv_type_size_t" = x""yes; then : else cat >>confdefs.h <<_ACEOF #define size_t unsigned int _ACEOF fi ac_fn_c_check_type "$LINENO" "mode_t" "ac_cv_type_mode_t" "$ac_includes_default" if test "x$ac_cv_type_mode_t" = x""yes; then : else cat >>confdefs.h <<_ACEOF #define mode_t int _ACEOF fi ac_fn_c_find_intX_t "$LINENO" "8" "ac_cv_c_int8_t" case $ac_cv_c_int8_t in #( no|yes) ;; #( *) cat >>confdefs.h <<_ACEOF #define int8_t $ac_cv_c_int8_t _ACEOF ;; esac ac_fn_c_find_intX_t "$LINENO" "16" "ac_cv_c_int16_t" case $ac_cv_c_int16_t in #( no|yes) ;; #( *) cat >>confdefs.h <<_ACEOF #define int16_t $ac_cv_c_int16_t _ACEOF ;; esac ac_fn_c_find_intX_t "$LINENO" "32" "ac_cv_c_int32_t" case $ac_cv_c_int32_t in #( no|yes) ;; #( *) cat >>confdefs.h <<_ACEOF #define int32_t $ac_cv_c_int32_t _ACEOF ;; esac ac_fn_c_find_intX_t "$LINENO" "64" "ac_cv_c_int64_t" case $ac_cv_c_int64_t in #( no|yes) ;; #( *) cat >>confdefs.h <<_ACEOF #define int64_t $ac_cv_c_int64_t _ACEOF ;; esac ac_fn_c_check_type "$LINENO" "ssize_t" "ac_cv_type_ssize_t" "$ac_includes_default" if test "x$ac_cv_type_ssize_t" = x""yes; then : else cat >>confdefs.h <<_ACEOF #define ssize_t int _ACEOF fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uid_t in sys/types.h" >&5 $as_echo_n "checking for uid_t in sys/types.h... " >&6; } if test "${ac_cv_type_uid_t+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "uid_t" >/dev/null 2>&1; then : ac_cv_type_uid_t=yes else ac_cv_type_uid_t=no fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uid_t" >&5 $as_echo "$ac_cv_type_uid_t" >&6; } if test $ac_cv_type_uid_t = no; then $as_echo "#define uid_t int" >>confdefs.h $as_echo "#define gid_t int" >>confdefs.h fi ac_fn_c_find_uintX_t "$LINENO" "8" "ac_cv_c_uint8_t" case $ac_cv_c_uint8_t in #( no|yes) ;; #( *) $as_echo "#define _UINT8_T 1" >>confdefs.h cat >>confdefs.h <<_ACEOF #define uint8_t $ac_cv_c_uint8_t _ACEOF ;; esac ac_fn_c_find_uintX_t "$LINENO" "16" "ac_cv_c_uint16_t" case $ac_cv_c_uint16_t in #( no|yes) ;; #( *) cat >>confdefs.h <<_ACEOF #define uint16_t $ac_cv_c_uint16_t _ACEOF ;; esac ac_fn_c_find_uintX_t "$LINENO" "32" "ac_cv_c_uint32_t" case $ac_cv_c_uint32_t in #( no|yes) ;; #( *) $as_echo "#define _UINT32_T 1" >>confdefs.h cat >>confdefs.h <<_ACEOF #define uint32_t $ac_cv_c_uint32_t _ACEOF ;; esac ac_fn_c_find_uintX_t "$LINENO" "64" "ac_cv_c_uint64_t" case $ac_cv_c_uint64_t in #( no|yes) ;; #( *) $as_echo "#define _UINT64_T 1" >>confdefs.h cat >>confdefs.h <<_ACEOF #define uint64_t $ac_cv_c_uint64_t _ACEOF ;; esac ac_fn_c_check_member "$LINENO" "struct stat" "st_rdev" "ac_cv_member_struct_stat_st_rdev" "$ac_includes_default" if test "x$ac_cv_member_struct_stat_st_rdev" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_STAT_ST_RDEV 1 _ACEOF fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether struct tm is in sys/time.h or time.h" >&5 $as_echo_n "checking whether struct tm is in sys/time.h or time.h... " >&6; } if test "${ac_cv_struct_tm+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { struct tm tm; int *p = &tm.tm_sec; return !p; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_struct_tm=time.h else ac_cv_struct_tm=sys/time.h fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_tm" >&5 $as_echo "$ac_cv_struct_tm" >&6; } if test $ac_cv_struct_tm = sys/time.h; then $as_echo "#define TM_IN_SYS_TIME 1" >>confdefs.h fi ################################################################################ for ac_func in ftruncate gethostname getpagesize \ gettimeofday memset mkdir mkfifo rmdir munmap nl_langinfo setenv setlocale \ strcasecmp strchr strcspn strspn strdup strncasecmp strerror strrchr \ strstr strtol strtoul uname do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF else as_fn_error $? "bailing out" "$LINENO" 5 fi done for ac_func in siginterrupt do : ac_fn_c_check_func "$LINENO" "siginterrupt" "ac_cv_func_siginterrupt" if test "x$ac_cv_func_siginterrupt" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SIGINTERRUPT 1 _ACEOF fi done # The Ultrix 4.2 mips builtin alloca declared by alloca.h only works # for constant arguments. Useless! { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working alloca.h" >&5 $as_echo_n "checking for working alloca.h... " >&6; } if test "${ac_cv_working_alloca_h+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { char *p = (char *) alloca (2 * sizeof (int)); if (p) return 0; ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_working_alloca_h=yes else ac_cv_working_alloca_h=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_working_alloca_h" >&5 $as_echo "$ac_cv_working_alloca_h" >&6; } if test $ac_cv_working_alloca_h = yes; then $as_echo "#define HAVE_ALLOCA_H 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for alloca" >&5 $as_echo_n "checking for alloca... " >&6; } if test "${ac_cv_func_alloca_works+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __GNUC__ # define alloca __builtin_alloca #else # ifdef _MSC_VER # include # define alloca _alloca # else # ifdef HAVE_ALLOCA_H # include # else # ifdef _AIX #pragma alloca # else # ifndef alloca /* predefined by HP cc +Olibcalls */ char *alloca (); # endif # endif # endif # endif #endif int main () { char *p = (char *) alloca (1); if (p) return 0; ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_func_alloca_works=yes else ac_cv_func_alloca_works=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_alloca_works" >&5 $as_echo "$ac_cv_func_alloca_works" >&6; } if test $ac_cv_func_alloca_works = yes; then $as_echo "#define HAVE_ALLOCA 1" >>confdefs.h else # The SVR3 libPW and SVR4 libucb both contain incompatible functions # that cause trouble. Some versions do not even contain alloca or # contain a buggy version. If you still want to use their alloca, # use ar to extract alloca.o from them instead of compiling alloca.c. ALLOCA=\${LIBOBJDIR}alloca.$ac_objext $as_echo "#define C_ALLOCA 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether \`alloca.c' needs Cray hooks" >&5 $as_echo_n "checking whether \`alloca.c' needs Cray hooks... " >&6; } if test "${ac_cv_os_cray+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if defined CRAY && ! defined CRAY2 webecray #else wenotbecray #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "webecray" >/dev/null 2>&1; then : ac_cv_os_cray=yes else ac_cv_os_cray=no fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_os_cray" >&5 $as_echo "$ac_cv_os_cray" >&6; } if test $ac_cv_os_cray = yes; then for ac_func in _getb67 GETB67 getb67; do as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define CRAY_STACKSEG_END $ac_func _ACEOF break fi done fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking stack direction for C alloca" >&5 $as_echo_n "checking stack direction for C alloca... " >&6; } if test "${ac_cv_c_stack_direction+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_c_stack_direction=0 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int find_stack_direction () { static char *addr = 0; auto char dummy; if (addr == 0) { addr = &dummy; return find_stack_direction (); } else return (&dummy > addr) ? 1 : -1; } int main () { return find_stack_direction () < 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_c_stack_direction=1 else ac_cv_c_stack_direction=-1 fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_stack_direction" >&5 $as_echo "$ac_cv_c_stack_direction" >&6; } cat >>confdefs.h <<_ACEOF #define STACK_DIRECTION $ac_cv_c_stack_direction _ACEOF fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether closedir returns void" >&5 $as_echo_n "checking whether closedir returns void... " >&6; } if test "${ac_cv_func_closedir_void+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_closedir_void=yes else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default #include <$ac_header_dirent> #ifndef __cplusplus int closedir (); #endif int main () { return closedir (opendir (".")) != 0; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_closedir_void=no else ac_cv_func_closedir_void=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_closedir_void" >&5 $as_echo "$ac_cv_func_closedir_void" >&6; } if test $ac_cv_func_closedir_void = yes; then $as_echo "#define CLOSEDIR_VOID 1" >>confdefs.h fi for ac_header in unistd.h do : ac_fn_c_check_header_mongrel "$LINENO" "unistd.h" "ac_cv_header_unistd_h" "$ac_includes_default" if test "x$ac_cv_header_unistd_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_UNISTD_H 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working chown" >&5 $as_echo_n "checking for working chown... " >&6; } if test "${ac_cv_func_chown_works+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_chown_works=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default #include int main () { char *f = "conftest.chown"; struct stat before, after; if (creat (f, 0600) < 0) return 1; if (stat (f, &before) < 0) return 1; if (chown (f, (uid_t) -1, (gid_t) -1) == -1) return 1; if (stat (f, &after) < 0) return 1; return ! (before.st_uid == after.st_uid && before.st_gid == after.st_gid); ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_chown_works=yes else ac_cv_func_chown_works=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f conftest.chown fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_chown_works" >&5 $as_echo "$ac_cv_func_chown_works" >&6; } if test $ac_cv_func_chown_works = yes; then $as_echo "#define HAVE_CHOWN 1" >>confdefs.h fi for ac_header in vfork.h do : ac_fn_c_check_header_mongrel "$LINENO" "vfork.h" "ac_cv_header_vfork_h" "$ac_includes_default" if test "x$ac_cv_header_vfork_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_VFORK_H 1 _ACEOF fi done for ac_func in fork vfork do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done if test "x$ac_cv_func_fork" = xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working fork" >&5 $as_echo_n "checking for working fork... " >&6; } if test "${ac_cv_func_fork_works+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_fork_works=cross else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { /* By Ruediger Kuhlmann. */ return fork () < 0; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_fork_works=yes else ac_cv_func_fork_works=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_fork_works" >&5 $as_echo "$ac_cv_func_fork_works" >&6; } else ac_cv_func_fork_works=$ac_cv_func_fork fi if test "x$ac_cv_func_fork_works" = xcross; then case $host in *-*-amigaos* | *-*-msdosdjgpp*) # Override, as these systems have only a dummy fork() stub ac_cv_func_fork_works=no ;; *) ac_cv_func_fork_works=yes ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: result $ac_cv_func_fork_works guessed because of cross compilation" >&5 $as_echo "$as_me: WARNING: result $ac_cv_func_fork_works guessed because of cross compilation" >&2;} fi ac_cv_func_vfork_works=$ac_cv_func_vfork if test "x$ac_cv_func_vfork" = xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working vfork" >&5 $as_echo_n "checking for working vfork... " >&6; } if test "${ac_cv_func_vfork_works+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_vfork_works=cross else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Thanks to Paul Eggert for this test. */ $ac_includes_default #include #ifdef HAVE_VFORK_H # include #endif /* On some sparc systems, changes by the child to local and incoming argument registers are propagated back to the parent. The compiler is told about this with #include , but some compilers (e.g. gcc -O) don't grok . Test for this by using a static variable whose address is put into a register that is clobbered by the vfork. */ static void #ifdef __cplusplus sparc_address_test (int arg) # else sparc_address_test (arg) int arg; #endif { static pid_t child; if (!child) { child = vfork (); if (child < 0) { perror ("vfork"); _exit(2); } if (!child) { arg = getpid(); write(-1, "", 0); _exit (arg); } } } int main () { pid_t parent = getpid (); pid_t child; sparc_address_test (0); child = vfork (); if (child == 0) { /* Here is another test for sparc vfork register problems. This test uses lots of local variables, at least as many local variables as main has allocated so far including compiler temporaries. 4 locals are enough for gcc 1.40.3 on a Solaris 4.1.3 sparc, but we use 8 to be safe. A buggy compiler should reuse the register of parent for one of the local variables, since it will think that parent can't possibly be used any more in this routine. Assigning to the local variable will thus munge parent in the parent process. */ pid_t p = getpid(), p1 = getpid(), p2 = getpid(), p3 = getpid(), p4 = getpid(), p5 = getpid(), p6 = getpid(), p7 = getpid(); /* Convince the compiler that p..p7 are live; otherwise, it might use the same hardware register for all 8 local variables. */ if (p != p1 || p != p2 || p != p3 || p != p4 || p != p5 || p != p6 || p != p7) _exit(1); /* On some systems (e.g. IRIX 3.3), vfork doesn't separate parent from child file descriptors. If the child closes a descriptor before it execs or exits, this munges the parent's descriptor as well. Test for this by closing stdout in the child. */ _exit(close(fileno(stdout)) != 0); } else { int status; struct stat st; while (wait(&status) != child) ; return ( /* Was there some problem with vforking? */ child < 0 /* Did the child fail? (This shouldn't happen.) */ || status /* Did the vfork/compiler bug occur? */ || parent != getpid() /* Did the file descriptor bug occur? */ || fstat(fileno(stdout), &st) != 0 ); } } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_vfork_works=yes else ac_cv_func_vfork_works=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_vfork_works" >&5 $as_echo "$ac_cv_func_vfork_works" >&6; } fi; if test "x$ac_cv_func_fork_works" = xcross; then ac_cv_func_vfork_works=$ac_cv_func_vfork { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: result $ac_cv_func_vfork_works guessed because of cross compilation" >&5 $as_echo "$as_me: WARNING: result $ac_cv_func_vfork_works guessed because of cross compilation" >&2;} fi if test "x$ac_cv_func_vfork_works" = xyes; then $as_echo "#define HAVE_WORKING_VFORK 1" >>confdefs.h else $as_echo "#define vfork fork" >>confdefs.h fi if test "x$ac_cv_func_fork_works" = xyes; then $as_echo "#define HAVE_WORKING_FORK 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether lstat correctly handles trailing slash" >&5 $as_echo_n "checking whether lstat correctly handles trailing slash... " >&6; } if test "${ac_cv_func_lstat_dereferences_slashed_symlink+set}" = set; then : $as_echo_n "(cached) " >&6 else rm -f conftest.sym conftest.file echo >conftest.file if test "$as_ln_s" = "ln -s" && ln -s conftest.file conftest.sym; then if test "$cross_compiling" = yes; then : ac_cv_func_lstat_dereferences_slashed_symlink=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { struct stat sbuf; /* Linux will dereference the symlink and fail, as required by POSIX. That is better in the sense that it means we will not have to compile and use the lstat wrapper. */ return lstat ("conftest.sym/", &sbuf) == 0; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_lstat_dereferences_slashed_symlink=yes else ac_cv_func_lstat_dereferences_slashed_symlink=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi else # If the `ln -s' command failed, then we probably don't even # have an lstat function. ac_cv_func_lstat_dereferences_slashed_symlink=no fi rm -f conftest.sym conftest.file fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_lstat_dereferences_slashed_symlink" >&5 $as_echo "$ac_cv_func_lstat_dereferences_slashed_symlink" >&6; } test $ac_cv_func_lstat_dereferences_slashed_symlink = yes && cat >>confdefs.h <<_ACEOF #define LSTAT_FOLLOWS_SLASHED_SYMLINK 1 _ACEOF if test "x$ac_cv_func_lstat_dereferences_slashed_symlink" = xno; then case " $LIBOBJS " in *" lstat.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS lstat.$ac_objext" ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether lstat accepts an empty string" >&5 $as_echo_n "checking whether lstat accepts an empty string... " >&6; } if test "${ac_cv_func_lstat_empty_string_bug+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_lstat_empty_string_bug=yes else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { struct stat sbuf; return lstat ("", &sbuf) == 0; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_lstat_empty_string_bug=no else ac_cv_func_lstat_empty_string_bug=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_lstat_empty_string_bug" >&5 $as_echo "$ac_cv_func_lstat_empty_string_bug" >&6; } if test $ac_cv_func_lstat_empty_string_bug = yes; then case " $LIBOBJS " in *" lstat.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS lstat.$ac_objext" ;; esac cat >>confdefs.h <<_ACEOF #define HAVE_LSTAT_EMPTY_STRING_BUG 1 _ACEOF fi for ac_header in stdlib.h do : ac_fn_c_check_header_mongrel "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default" if test "x$ac_cv_header_stdlib_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STDLIB_H 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU libc compatible malloc" >&5 $as_echo_n "checking for GNU libc compatible malloc... " >&6; } if test "${ac_cv_func_malloc_0_nonnull+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_malloc_0_nonnull=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if defined STDC_HEADERS || defined HAVE_STDLIB_H # include #else char *malloc (); #endif int main () { return ! malloc (0); ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_malloc_0_nonnull=yes else ac_cv_func_malloc_0_nonnull=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_malloc_0_nonnull" >&5 $as_echo "$ac_cv_func_malloc_0_nonnull" >&6; } if test $ac_cv_func_malloc_0_nonnull = yes; then : $as_echo "#define HAVE_MALLOC 1" >>confdefs.h else $as_echo "#define HAVE_MALLOC 0" >>confdefs.h case " $LIBOBJS " in *" malloc.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS malloc.$ac_objext" ;; esac $as_echo "#define malloc rpl_malloc" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working memcmp" >&5 $as_echo_n "checking for working memcmp... " >&6; } if test "${ac_cv_func_memcmp_working+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_memcmp_working=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { /* Some versions of memcmp are not 8-bit clean. */ char c0 = '\100', c1 = '\200', c2 = '\201'; if (memcmp(&c0, &c2, 1) >= 0 || memcmp(&c1, &c2, 1) >= 0) return 1; /* The Next x86 OpenStep bug shows up only when comparing 16 bytes or more and with at least one buffer not starting on a 4-byte boundary. William Lewis provided this test program. */ { char foo[21]; char bar[21]; int i; for (i = 0; i < 4; i++) { char *a = foo + i; char *b = bar + i; strcpy (a, "--------01111111"); strcpy (b, "--------10000000"); if (memcmp (a, b, 16) >= 0) return 1; } return 0; } ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_memcmp_working=yes else ac_cv_func_memcmp_working=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_memcmp_working" >&5 $as_echo "$ac_cv_func_memcmp_working" >&6; } test $ac_cv_func_memcmp_working = no && case " $LIBOBJS " in *" memcmp.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS memcmp.$ac_objext" ;; esac for ac_header in $ac_header_list do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_func in getpagesize do : ac_fn_c_check_func "$LINENO" "getpagesize" "ac_cv_func_getpagesize" if test "x$ac_cv_func_getpagesize" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_GETPAGESIZE 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working mmap" >&5 $as_echo_n "checking for working mmap... " >&6; } if test "${ac_cv_func_mmap_fixed_mapped+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_mmap_fixed_mapped=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default /* malloc might have been renamed as rpl_malloc. */ #undef malloc /* Thanks to Mike Haertel and Jim Avera for this test. Here is a matrix of mmap possibilities: mmap private not fixed mmap private fixed at somewhere currently unmapped mmap private fixed at somewhere already mapped mmap shared not fixed mmap shared fixed at somewhere currently unmapped mmap shared fixed at somewhere already mapped For private mappings, we should verify that changes cannot be read() back from the file, nor mmap's back from the file at a different address. (There have been systems where private was not correctly implemented like the infamous i386 svr4.0, and systems where the VM page cache was not coherent with the file system buffer cache like early versions of FreeBSD and possibly contemporary NetBSD.) For shared mappings, we should conversely verify that changes get propagated back to all the places they're supposed to be. Grep wants private fixed already mapped. The main things grep needs to know about mmap are: * does it exist and is it safe to write into the mmap'd area * how to use it (BSD variants) */ #include #include #if !defined STDC_HEADERS && !defined HAVE_STDLIB_H char *malloc (); #endif /* This mess was copied from the GNU getpagesize.h. */ #ifndef HAVE_GETPAGESIZE # ifdef _SC_PAGESIZE # define getpagesize() sysconf(_SC_PAGESIZE) # else /* no _SC_PAGESIZE */ # ifdef HAVE_SYS_PARAM_H # include # ifdef EXEC_PAGESIZE # define getpagesize() EXEC_PAGESIZE # else /* no EXEC_PAGESIZE */ # ifdef NBPG # define getpagesize() NBPG * CLSIZE # ifndef CLSIZE # define CLSIZE 1 # endif /* no CLSIZE */ # else /* no NBPG */ # ifdef NBPC # define getpagesize() NBPC # else /* no NBPC */ # ifdef PAGESIZE # define getpagesize() PAGESIZE # endif /* PAGESIZE */ # endif /* no NBPC */ # endif /* no NBPG */ # endif /* no EXEC_PAGESIZE */ # else /* no HAVE_SYS_PARAM_H */ # define getpagesize() 8192 /* punt totally */ # endif /* no HAVE_SYS_PARAM_H */ # endif /* no _SC_PAGESIZE */ #endif /* no HAVE_GETPAGESIZE */ int main () { char *data, *data2, *data3; const char *cdata2; int i, pagesize; int fd, fd2; pagesize = getpagesize (); /* First, make a file with some known garbage in it. */ data = (char *) malloc (pagesize); if (!data) return 1; for (i = 0; i < pagesize; ++i) *(data + i) = rand (); umask (0); fd = creat ("conftest.mmap", 0600); if (fd < 0) return 2; if (write (fd, data, pagesize) != pagesize) return 3; close (fd); /* Next, check that the tail of a page is zero-filled. File must have non-zero length, otherwise we risk SIGBUS for entire page. */ fd2 = open ("conftest.txt", O_RDWR | O_CREAT | O_TRUNC, 0600); if (fd2 < 0) return 4; cdata2 = ""; if (write (fd2, cdata2, 1) != 1) return 5; data2 = (char *) mmap (0, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd2, 0L); if (data2 == MAP_FAILED) return 6; for (i = 0; i < pagesize; ++i) if (*(data2 + i)) return 7; close (fd2); if (munmap (data2, pagesize)) return 8; /* Next, try to mmap the file at a fixed address which already has something else allocated at it. If we can, also make sure that we see the same garbage. */ fd = open ("conftest.mmap", O_RDWR); if (fd < 0) return 9; if (data2 != mmap (data2, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED, fd, 0L)) return 10; for (i = 0; i < pagesize; ++i) if (*(data + i) != *(data2 + i)) return 11; /* Finally, make sure that changes to the mapped area do not percolate back to the file as seen by read(). (This is a bug on some variants of i386 svr4.0.) */ for (i = 0; i < pagesize; ++i) *(data2 + i) = *(data2 + i) + 1; data3 = (char *) malloc (pagesize); if (!data3) return 12; if (read (fd, data3, pagesize) != pagesize) return 13; for (i = 0; i < pagesize; ++i) if (*(data + i) != *(data3 + i)) return 14; close (fd); return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_mmap_fixed_mapped=yes else ac_cv_func_mmap_fixed_mapped=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_mmap_fixed_mapped" >&5 $as_echo "$ac_cv_func_mmap_fixed_mapped" >&6; } if test $ac_cv_func_mmap_fixed_mapped = yes; then $as_echo "#define HAVE_MMAP 1" >>confdefs.h fi rm -f conftest.mmap conftest.txt for ac_header in stdlib.h do : ac_fn_c_check_header_mongrel "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default" if test "x$ac_cv_header_stdlib_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STDLIB_H 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU libc compatible realloc" >&5 $as_echo_n "checking for GNU libc compatible realloc... " >&6; } if test "${ac_cv_func_realloc_0_nonnull+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_realloc_0_nonnull=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if defined STDC_HEADERS || defined HAVE_STDLIB_H # include #else char *realloc (); #endif int main () { return ! realloc (0, 0); ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_realloc_0_nonnull=yes else ac_cv_func_realloc_0_nonnull=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_realloc_0_nonnull" >&5 $as_echo "$ac_cv_func_realloc_0_nonnull" >&6; } if test $ac_cv_func_realloc_0_nonnull = yes; then : $as_echo "#define HAVE_REALLOC 1" >>confdefs.h else $as_echo "#define HAVE_REALLOC 0" >>confdefs.h case " $LIBOBJS " in *" realloc.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS realloc.$ac_objext" ;; esac $as_echo "#define realloc rpl_realloc" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stat accepts an empty string" >&5 $as_echo_n "checking whether stat accepts an empty string... " >&6; } if test "${ac_cv_func_stat_empty_string_bug+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_stat_empty_string_bug=yes else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { struct stat sbuf; return stat ("", &sbuf) == 0; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_stat_empty_string_bug=no else ac_cv_func_stat_empty_string_bug=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_stat_empty_string_bug" >&5 $as_echo "$ac_cv_func_stat_empty_string_bug" >&6; } if test $ac_cv_func_stat_empty_string_bug = yes; then case " $LIBOBJS " in *" stat.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS stat.$ac_objext" ;; esac cat >>confdefs.h <<_ACEOF #define HAVE_STAT_EMPTY_STRING_BUG 1 _ACEOF fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working strtod" >&5 $as_echo_n "checking for working strtod... " >&6; } if test "${ac_cv_func_strtod+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_strtod=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default #ifndef strtod double strtod (); #endif int main() { { /* Some versions of Linux strtod mis-parse strings with leading '+'. */ char *string = " +69"; char *term; double value; value = strtod (string, &term); if (value != 69 || term != (string + 4)) return 1; } { /* Under Solaris 2.4, strtod returns the wrong value for the terminating character under some conditions. */ char *string = "NaN"; char *term; strtod (string, &term); if (term != string && *(term - 1) == 0) return 1; } return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_strtod=yes else ac_cv_func_strtod=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_strtod" >&5 $as_echo "$ac_cv_func_strtod" >&6; } if test $ac_cv_func_strtod = no; then case " $LIBOBJS " in *" strtod.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS strtod.$ac_objext" ;; esac ac_fn_c_check_func "$LINENO" "pow" "ac_cv_func_pow" if test "x$ac_cv_func_pow" = x""yes; then : fi if test $ac_cv_func_pow = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pow in -lm" >&5 $as_echo_n "checking for pow in -lm... " >&6; } if test "${ac_cv_lib_m_pow+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lm $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pow (); int main () { return pow (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_m_pow=yes else ac_cv_lib_m_pow=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_pow" >&5 $as_echo "$ac_cv_lib_m_pow" >&6; } if test "x$ac_cv_lib_m_pow" = x""yes; then : POW_LIB=-lm else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cannot find library containing definition of pow" >&5 $as_echo "$as_me: WARNING: cannot find library containing definition of pow" >&2;} fi fi fi for ac_func in vprintf do : ac_fn_c_check_func "$LINENO" "vprintf" "ac_cv_func_vprintf" if test "x$ac_cv_func_vprintf" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_VPRINTF 1 _ACEOF ac_fn_c_check_func "$LINENO" "_doprnt" "ac_cv_func__doprnt" if test "x$ac_cv_func__doprnt" = x""yes; then : $as_echo "#define HAVE_DOPRNT 1" >>confdefs.h fi fi done ################################################################################ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use static linking" >&5 $as_echo_n "checking whether to use static linking... " >&6; } # Check whether --enable-static_link was given. if test "${enable_static_link+set}" = set; then : enableval=$enable_static_link; STATIC_LINK=$enableval else STATIC_LINK=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STATIC_LINK" >&5 $as_echo "$STATIC_LINK" >&6; } ################################################################################ ################################################################################ { $as_echo "$as_me:${as_lineno-$LINENO}: checking file owner" >&5 $as_echo_n "checking file owner... " >&6; } # Check whether --with-user was given. if test "${with_user+set}" = set; then : withval=$with_user; OWNER=$withval fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OWNER" >&5 $as_echo "$OWNER" >&6; } if test x$OWNER != x; then INSTALL="$INSTALL -o $OWNER" fi ################################################################################ { $as_echo "$as_me:${as_lineno-$LINENO}: checking group owner" >&5 $as_echo_n "checking group owner... " >&6; } # Check whether --with-group was given. if test "${with_group+set}" = set; then : withval=$with_group; GROUP=$withval fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GROUP" >&5 $as_echo "$GROUP" >&6; } if test x$GROUP != x; then INSTALL="$INSTALL -g $GROUP" fi ################################################################################ { $as_echo "$as_me:${as_lineno-$LINENO}: checking device node uid" >&5 $as_echo_n "checking device node uid... " >&6; } # Check whether --with-device-uid was given. if test "${with_device_uid+set}" = set; then : withval=$with_device_uid; DM_DEVICE_UID=$withval else DM_DEVICE_UID=0 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DM_DEVICE_UID" >&5 $as_echo "$DM_DEVICE_UID" >&6; } ################################################################################ { $as_echo "$as_me:${as_lineno-$LINENO}: checking device node gid" >&5 $as_echo_n "checking device node gid... " >&6; } # Check whether --with-device-gid was given. if test "${with_device_gid+set}" = set; then : withval=$with_device_gid; DM_DEVICE_GID=$withval else DM_DEVICE_GID=0 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DM_DEVICE_GID" >&5 $as_echo "$DM_DEVICE_GID" >&6; } ################################################################################ { $as_echo "$as_me:${as_lineno-$LINENO}: checking device node mode" >&5 $as_echo_n "checking device node mode... " >&6; } # Check whether --with-device-mode was given. if test "${with_device_mode+set}" = set; then : withval=$with_device_mode; DM_DEVICE_MODE=$withval else DM_DEVICE_MODE=0600 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DM_DEVICE_MODE" >&5 $as_echo "$DM_DEVICE_MODE" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking when to create device nodes" >&5 $as_echo_n "checking when to create device nodes... " >&6; } # Check whether --with-device-nodes-on was given. if test "${with_device_nodes_on+set}" = set; then : withval=$with_device_nodes_on; ADD_NODE=$withval else ADD_NODE=resume fi case "$ADD_NODE" in resume) add_on=DM_ADD_NODE_ON_RESUME;; create) add_on=DM_ADD_NODE_ON_CREATE;; *) as_fn_error $? "--with-device-nodes-on parameter invalid" "$LINENO" 5;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: on $ADD_NODE" >&5 $as_echo "on $ADD_NODE" >&6; } cat >>confdefs.h <<_ACEOF #define DEFAULT_DM_ADD_NODE $add_on _ACEOF { $as_echo "$as_me:${as_lineno-$LINENO}: checking default name mangling" >&5 $as_echo_n "checking default name mangling... " >&6; } # Check whether --with-default-name-mangling was given. if test "${with_default_name_mangling+set}" = set; then : withval=$with_default_name_mangling; MANGLING=$withval else MANGLING=auto fi case "$MANGLING" in auto) mangling=DM_STRING_MANGLING_AUTO;; disabled) mangling=DM_STRING_MANGLING_NONE;; hex) mangling=DM_STRING_MANGLING_HEX;; *) as_fn_error $? "--with-default-name-mangling parameter invalid" "$LINENO" 5;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MANGLING" >&5 $as_echo "$MANGLING" >&6; } cat >>confdefs.h <<_ACEOF #define DEFAULT_DM_NAME_MANGLING $mangling _ACEOF ################################################################################ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable lvm1 fallback" >&5 $as_echo_n "checking whether to enable lvm1 fallback... " >&6; } # Check whether --enable-lvm1_fallback was given. if test "${enable_lvm1_fallback+set}" = set; then : enableval=$enable_lvm1_fallback; LVM1_FALLBACK=$enableval else LVM1_FALLBACK=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LVM1_FALLBACK" >&5 $as_echo "$LVM1_FALLBACK" >&6; } if test x$LVM1_FALLBACK = xyes; then $as_echo "#define LVM1_FALLBACK 1" >>confdefs.h fi ################################################################################ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to include support for lvm1 metadata" >&5 $as_echo_n "checking whether to include support for lvm1 metadata... " >&6; } # Check whether --with-lvm1 was given. if test "${with_lvm1+set}" = set; then : withval=$with_lvm1; LVM1=$withval else LVM1=internal fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LVM1" >&5 $as_echo "$LVM1" >&6; } if [ "x$LVM1" != xnone -a "x$LVM1" != xinternal -a "x$LVM1" != xshared ]; then as_fn_error $? "--with-lvm1 parameter invalid " "$LINENO" 5 fi; if test x$LVM1 = xinternal; then $as_echo "#define LVM1_INTERNAL 1" >>confdefs.h fi ################################################################################ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to include support for GFS pool metadata" >&5 $as_echo_n "checking whether to include support for GFS pool metadata... " >&6; } # Check whether --with-pool was given. if test "${with_pool+set}" = set; then : withval=$with_pool; POOL=$withval else POOL=internal fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $POOL" >&5 $as_echo "$POOL" >&6; } if [ "x$POOL" != xnone -a "x$POOL" != xinternal -a "x$POOL" != xshared ]; then as_fn_error $? "--with-pool parameter invalid " "$LINENO" 5 fi; if test x$POOL = xinternal; then $as_echo "#define POOL_INTERNAL 1" >>confdefs.h fi ################################################################################ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to include support for cluster locking" >&5 $as_echo_n "checking whether to include support for cluster locking... " >&6; } # Check whether --with-cluster was given. if test "${with_cluster+set}" = set; then : withval=$with_cluster; CLUSTER=$withval fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CLUSTER" >&5 $as_echo "$CLUSTER" >&6; } if [ "x$CLUSTER" != xnone -a "x$CLUSTER" != xinternal -a "x$CLUSTER" != xshared ]; then as_fn_error $? "--with-cluster parameter invalid " "$LINENO" 5 fi; if test x$CLUSTER = xinternal; then $as_echo "#define CLUSTER_LOCKING_INTERNAL 1" >>confdefs.h fi ################################################################################ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to include snapshots" >&5 $as_echo_n "checking whether to include snapshots... " >&6; } # Check whether --with-snapshots was given. if test "${with_snapshots+set}" = set; then : withval=$with_snapshots; SNAPSHOTS=$withval else SNAPSHOTS=internal fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $SNAPSHOTS" >&5 $as_echo "$SNAPSHOTS" >&6; } if [ "x$SNAPSHOTS" != xnone -a "x$SNAPSHOTS" != xinternal -a "x$SNAPSHOTS" != xshared ]; then as_fn_error $? "--with-snapshots parameter invalid " "$LINENO" 5 fi; if test x$SNAPSHOTS = xinternal; then $as_echo "#define SNAPSHOT_INTERNAL 1" >>confdefs.h fi ################################################################################ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to include mirrors" >&5 $as_echo_n "checking whether to include mirrors... " >&6; } # Check whether --with-mirrors was given. if test "${with_mirrors+set}" = set; then : withval=$with_mirrors; MIRRORS=$withval else MIRRORS=internal fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MIRRORS" >&5 $as_echo "$MIRRORS" >&6; } if [ "x$MIRRORS" != xnone -a "x$MIRRORS" != xinternal -a "x$MIRRORS" != xshared ]; then as_fn_error $? "--with-mirrors parameter invalid " "$LINENO" 5 fi; if test x$MIRRORS = xinternal; then $as_echo "#define MIRRORED_INTERNAL 1" >>confdefs.h fi ################################################################################ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to include raid" >&5 $as_echo_n "checking whether to include raid... " >&6; } # Check whether --with-raid was given. if test "${with_raid+set}" = set; then : withval=$with_raid; RAID=$withval else RAID=internal fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RAID" >&5 $as_echo "$RAID" >&6; } if [ "x$RAID" != xnone -a "x$RAID" != xinternal -a "x$RAID" != xshared ]; then as_fn_error $? "--with-raid parameter invalid " "$LINENO" 5 fi; if test x$RAID = xinternal; then $as_echo "#define RAID_INTERNAL 1" >>confdefs.h fi ################################################################################ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to include replicators" >&5 $as_echo_n "checking whether to include replicators... " >&6; } # Check whether --with-replicators was given. if test "${with_replicators+set}" = set; then : withval=$with_replicators; REPLICATORS=$withval else REPLICATORS=none fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $REPLICATORS" >&5 $as_echo "$REPLICATORS" >&6; } case "$REPLICATORS" in none|shared) ;; internal) $as_echo "#define REPLICATOR_INTERNAL 1" >>confdefs.h ;; *) as_fn_error $? "--with-replicators parameter invalid ($REPLICATORS)" "$LINENO" 5 ;; esac ################################################################################ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to include thin provisioning" >&5 $as_echo_n "checking whether to include thin provisioning... " >&6; } # Check whether --with-thin was given. if test "${with_thin+set}" = set; then : withval=$with_thin; THIN=$withval else THIN=none fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $THIN" >&5 $as_echo "$THIN" >&6; } case "$THIN" in none|shared) ;; internal) $as_echo "#define THIN_INTERNAL 1" >>confdefs.h ;; *) as_fn_error $? "--with-thin parameter invalid ($THIN)" "$LINENO" 5 ;; esac case "$THIN" in internal|shared) # Check whether --with-thin-check was given. if test "${with_thin_check+set}" = set; then : withval=$with_thin_check; THIN_CHECK_CMD=$withval else THIN_CHECK_CMD="autodetect" fi # Empty means a config way to ignore thin checking if test "$THIN_CHECK_CMD" = "autodetect"; then # Extract the first word of "thin_check", so it can be a program name with args. set dummy thin_check; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_THIN_CHECK_CMD+set}" = set; then : $as_echo_n "(cached) " >&6 else case $THIN_CHECK_CMD in [\\/]* | ?:[\\/]*) ac_cv_path_THIN_CHECK_CMD="$THIN_CHECK_CMD" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_THIN_CHECK_CMD="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi THIN_CHECK_CMD=$ac_cv_path_THIN_CHECK_CMD if test -n "$THIN_CHECK_CMD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $THIN_CHECK_CMD" >&5 $as_echo "$THIN_CHECK_CMD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -z "$THIN_CHECK_CMD" && as_fn_error $? "thin_check not found in path $PATH" "$LINENO" 5 fi ;; esac cat >>confdefs.h <<_ACEOF #define THIN_CHECK_CMD "$THIN_CHECK_CMD" _ACEOF ################################################################################ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable readline" >&5 $as_echo_n "checking whether to enable readline... " >&6; } # Check whether --enable-readline was given. if test "${enable_readline+set}" = set; then : enableval=$enable_readline; READLINE=$enableval else READLINE=maybe fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $READLINE" >&5 $as_echo "$READLINE" >&6; } ################################################################################ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable realtime support" >&5 $as_echo_n "checking whether to enable realtime support... " >&6; } # Check whether --enable-realtime was given. if test "${enable_realtime+set}" = set; then : enableval=$enable_realtime; REALTIME=$enableval fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $REALTIME" >&5 $as_echo "$REALTIME" >&6; } ################################################################################ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable OCF resource agents" >&5 $as_echo_n "checking whether to enable OCF resource agents... " >&6; } # Check whether --enable-ocf was given. if test "${enable_ocf+set}" = set; then : enableval=$enable_ocf; OCF=$enableval else OCF=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OCF" >&5 $as_echo "$OCF" >&6; } # Check whether --with-ocfdir was given. if test "${with_ocfdir+set}" = set; then : withval=$with_ocfdir; OCFDIR=$withval else OCFDIR='${prefix}/lib/ocf/resource.d/lvm2' fi ################################################################################ pkg_config_init() { if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_PKG_CONFIG+set}" = set; then : $as_echo_n "(cached) " >&6 else case $PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi PKG_CONFIG=$ac_cv_path_PKG_CONFIG if test -n "$PKG_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 $as_echo "$PKG_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_path_PKG_CONFIG"; then ac_pt_PKG_CONFIG=$PKG_CONFIG # Extract the first word of "pkg-config", so it can be a program name with args. set dummy pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_ac_pt_PKG_CONFIG+set}" = set; then : $as_echo_n "(cached) " >&6 else case $ac_pt_PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG if test -n "$ac_pt_PKG_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 $as_echo "$ac_pt_PKG_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_pt_PKG_CONFIG" = x; then PKG_CONFIG="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac PKG_CONFIG=$ac_pt_PKG_CONFIG fi else PKG_CONFIG="$ac_cv_path_PKG_CONFIG" fi fi if test -n "$PKG_CONFIG"; then _pkg_min_version=0.9.0 { $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5 $as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; } if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } PKG_CONFIG="" fi fi pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PKGCONFIGINIT" >&5 $as_echo_n "checking for PKGCONFIGINIT... " >&6; } if test -n "$PKGCONFIGINIT_CFLAGS"; then pkg_cv_PKGCONFIGINIT_CFLAGS="$PKGCONFIGINIT_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"pkgconfiginit\""; } >&5 ($PKG_CONFIG --exists --print-errors "pkgconfiginit") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_PKGCONFIGINIT_CFLAGS=`$PKG_CONFIG --cflags "pkgconfiginit" 2>/dev/null` else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$PKGCONFIGINIT_LIBS"; then pkg_cv_PKGCONFIGINIT_LIBS="$PKGCONFIGINIT_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"pkgconfiginit\""; } >&5 ($PKG_CONFIG --exists --print-errors "pkgconfiginit") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_PKGCONFIGINIT_LIBS=`$PKG_CONFIG --libs "pkgconfiginit" 2>/dev/null` else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then PKGCONFIGINIT_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "pkgconfiginit" 2>&1` else PKGCONFIGINIT_PKG_ERRORS=`$PKG_CONFIG --print-errors "pkgconfiginit" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$PKGCONFIGINIT_PKG_ERRORS" >&5 { $as_echo "$as_me:${as_lineno-$LINENO}: result: pkg-config initialized" >&5 $as_echo "pkg-config initialized" >&6; } elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: pkg-config initialized" >&5 $as_echo "pkg-config initialized" >&6; } else PKGCONFIGINIT_CFLAGS=$pkg_cv_PKGCONFIGINIT_CFLAGS PKGCONFIGINIT_LIBS=$pkg_cv_PKGCONFIGINIT_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi PKGCONFIG_INIT=1 } ################################################################################ # Check whether --with-default-pid-dir was given. if test "${with_default_pid_dir+set}" = set; then : withval=$with_default_pid_dir; DEFAULT_PID_DIR="$withval" else DEFAULT_PID_DIR="/var/run" fi cat >>confdefs.h <<_ACEOF #define DEFAULT_PID_DIR "$DEFAULT_PID_DIR" _ACEOF # Check whether --with-default-dm-run-dir was given. if test "${with_default_dm_run_dir+set}" = set; then : withval=$with_default_dm_run_dir; DEFAULT_DM_RUN_DIR="$withval" else DEFAULT_DM_RUN_DIR="/var/run" fi cat >>confdefs.h <<_ACEOF #define DEFAULT_DM_RUN_DIR "$DEFAULT_DM_RUN_DIR" _ACEOF # Check whether --with-default-run-dir was given. if test "${with_default_run_dir+set}" = set; then : withval=$with_default_run_dir; DEFAULT_RUN_DIR="$withval" else DEFAULT_RUN_DIR="/var/run/lvm" fi cat >>confdefs.h <<_ACEOF #define DEFAULT_RUN_DIR "$DEFAULT_RUN_DIR" _ACEOF ################################################################################ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build cluster LVM daemon" >&5 $as_echo_n "checking whether to build cluster LVM daemon... " >&6; } # Check whether --with-clvmd was given. if test "${with_clvmd+set}" = set; then : withval=$with_clvmd; CLVMD=$withval else CLVMD=none fi if test x$CLVMD = xyes; then CLVMD=all fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CLVMD" >&5 $as_echo "$CLVMD" >&6; } if test x$CLVMD != xnone && test x$CLUSTER = xnone; then CLUSTER=internal fi if test x$CLVMD != xnone && test x$PKGCONFIG_INIT != x1; then pkg_config_init fi CLVMD_CMANAGERS="" CLVMD_NEEDS_QDISKD=no if [ `expr x"$CLVMD" : '.*gulm.*'` != 0 ]; then as_fn_error $? "Since version 2.02.87 GULM locking is no longer supported." "$LINENO" 5; fi if [ `expr x"$CLVMD" : '.*cman.*'` != 0 ]; then BUILDCMAN=yes CLVMD_CMANAGERS="$CLVMD_CMANAGERS cman" CLVMD_NEEDS_QDISKD=yes fi if [ `expr x"$CLVMD" : '.*corosync.*'` != 0 ]; then BUILDCOROSYNC=yes CLVMD_CMANAGERS="$CLVMD_CMANAGERS corosync" fi if [ `expr x"$CLVMD" : '.*openais.*'` != 0 ]; then BUILDOPENAIS=yes CLVMD_CMANAGERS="$CLVMD_CMANAGERS openais" fi if test x$CLVMD_NEEDS_QDISKD != xno; then CLVMD_CMANAGERS="$CLVMD_CMANAGERS qdiskd" fi soft_bailout() { NOTFOUND=1 } hard_bailout() { as_fn_error $? "bailing out" "$LINENO" 5 } if test x$CLVMD = xall; then bailout=soft_bailout BUILDCMAN=yes BUILDCOROSYNC=yes BUILDOPENAIS=yes else bailout=hard_bailout fi check_lib_no_libs() { lib_no_libs_arg1=$1 shift lib_no_libs_arg2=$1 shift lib_no_libs_args=$@ as_ac_Lib=`$as_echo "ac_cv_lib_$lib_no_libs_arg1''_$lib_no_libs_arg2" | $as_tr_sh` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $lib_no_libs_arg2 in -l$lib_no_libs_arg1" >&5 $as_echo_n "checking for $lib_no_libs_arg2 in -l$lib_no_libs_arg1... " >&6; } if eval "test \"\${$as_ac_Lib+set}\"" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-l$lib_no_libs_arg1 $lib_no_libs_args $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $lib_no_libs_arg2 (); int main () { return $lib_no_libs_arg2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$as_ac_Lib=yes" else eval "$as_ac_Lib=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi eval ac_res=\$$as_ac_Lib { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_LIB$lib_no_libs_arg1" | $as_tr_cpp` 1 _ACEOF LIBS="-l$lib_no_libs_arg1 $LIBS" else $bailout fi LIBS=$ac_check_lib_save_LIBS } if test x$BUILDCMAN = xyes; then pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for CMAN" >&5 $as_echo_n "checking for CMAN... " >&6; } if test -n "$CMAN_CFLAGS"; then pkg_cv_CMAN_CFLAGS="$CMAN_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libcman\""; } >&5 ($PKG_CONFIG --exists --print-errors "libcman") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_CMAN_CFLAGS=`$PKG_CONFIG --cflags "libcman" 2>/dev/null` else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$CMAN_LIBS"; then pkg_cv_CMAN_LIBS="$CMAN_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libcman\""; } >&5 ($PKG_CONFIG --exists --print-errors "libcman") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_CMAN_LIBS=`$PKG_CONFIG --libs "libcman" 2>/dev/null` else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then CMAN_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "libcman" 2>&1` else CMAN_PKG_ERRORS=`$PKG_CONFIG --print-errors "libcman" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$CMAN_PKG_ERRORS" >&5 NOTFOUND=0 for ac_header in libcman.h do : ac_fn_c_check_header_mongrel "$LINENO" "libcman.h" "ac_cv_header_libcman_h" "$ac_includes_default" if test "x$ac_cv_header_libcman_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBCMAN_H 1 _ACEOF else $bailout fi done check_lib_no_libs cman cman_init if test $NOTFOUND = 0; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no pkg for libcman, using -lcman" >&5 $as_echo "no pkg for libcman, using -lcman" >&6; } CMAN_LIBS="-lcman" HAVE_CMAN=yes fi elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } NOTFOUND=0 for ac_header in libcman.h do : ac_fn_c_check_header_mongrel "$LINENO" "libcman.h" "ac_cv_header_libcman_h" "$ac_includes_default" if test "x$ac_cv_header_libcman_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBCMAN_H 1 _ACEOF else $bailout fi done check_lib_no_libs cman cman_init if test $NOTFOUND = 0; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no pkg for libcman, using -lcman" >&5 $as_echo "no pkg for libcman, using -lcman" >&6; } CMAN_LIBS="-lcman" HAVE_CMAN=yes fi else CMAN_CFLAGS=$pkg_cv_CMAN_CFLAGS CMAN_LIBS=$pkg_cv_CMAN_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } HAVE_CMAN=yes fi CHECKCONFDB=yes CHECKDLM=yes fi if test x$BUILDCOROSYNC = xyes || \ test x$BUILDOPENAIS = xyes; then pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for COROSYNC" >&5 $as_echo_n "checking for COROSYNC... " >&6; } if test -n "$COROSYNC_CFLAGS"; then pkg_cv_COROSYNC_CFLAGS="$COROSYNC_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"corosync\""; } >&5 ($PKG_CONFIG --exists --print-errors "corosync") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_COROSYNC_CFLAGS=`$PKG_CONFIG --cflags "corosync" 2>/dev/null` else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$COROSYNC_LIBS"; then pkg_cv_COROSYNC_LIBS="$COROSYNC_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"corosync\""; } >&5 ($PKG_CONFIG --exists --print-errors "corosync") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_COROSYNC_LIBS=`$PKG_CONFIG --libs "corosync" 2>/dev/null` else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then COROSYNC_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "corosync" 2>&1` else COROSYNC_PKG_ERRORS=`$PKG_CONFIG --print-errors "corosync" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$COROSYNC_PKG_ERRORS" >&5 $bailout elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $bailout else COROSYNC_CFLAGS=$pkg_cv_COROSYNC_CFLAGS COROSYNC_LIBS=$pkg_cv_COROSYNC_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } HAVE_COROSYNC=yes fi CHECKCONFDB=yes CHECKCMAP=yes fi if test x$BUILDCOROSYNC = xyes; then pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for QUORUM" >&5 $as_echo_n "checking for QUORUM... " >&6; } if test -n "$QUORUM_CFLAGS"; then pkg_cv_QUORUM_CFLAGS="$QUORUM_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libquorum\""; } >&5 ($PKG_CONFIG --exists --print-errors "libquorum") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_QUORUM_CFLAGS=`$PKG_CONFIG --cflags "libquorum" 2>/dev/null` else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$QUORUM_LIBS"; then pkg_cv_QUORUM_LIBS="$QUORUM_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libquorum\""; } >&5 ($PKG_CONFIG --exists --print-errors "libquorum") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_QUORUM_LIBS=`$PKG_CONFIG --libs "libquorum" 2>/dev/null` else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then QUORUM_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "libquorum" 2>&1` else QUORUM_PKG_ERRORS=`$PKG_CONFIG --print-errors "libquorum" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$QUORUM_PKG_ERRORS" >&5 $bailout elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $bailout else QUORUM_CFLAGS=$pkg_cv_QUORUM_CFLAGS QUORUM_LIBS=$pkg_cv_QUORUM_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } HAVE_QUORUM=yes fi CHECKCPG=yes CHECKDLM=yes fi if test x$BUILDOPENAIS = xyes; then pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SALCK" >&5 $as_echo_n "checking for SALCK... " >&6; } if test -n "$SALCK_CFLAGS"; then pkg_cv_SALCK_CFLAGS="$SALCK_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libSaLck\""; } >&5 ($PKG_CONFIG --exists --print-errors "libSaLck") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_SALCK_CFLAGS=`$PKG_CONFIG --cflags "libSaLck" 2>/dev/null` else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$SALCK_LIBS"; then pkg_cv_SALCK_LIBS="$SALCK_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libSaLck\""; } >&5 ($PKG_CONFIG --exists --print-errors "libSaLck") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_SALCK_LIBS=`$PKG_CONFIG --libs "libSaLck" 2>/dev/null` else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then SALCK_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "libSaLck" 2>&1` else SALCK_PKG_ERRORS=`$PKG_CONFIG --print-errors "libSaLck" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$SALCK_PKG_ERRORS" >&5 $bailout elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $bailout else SALCK_CFLAGS=$pkg_cv_SALCK_CFLAGS SALCK_LIBS=$pkg_cv_SALCK_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } HAVE_SALCK=yes fi CHECKCPG=yes fi if test x$CHECKCONFDB = xyes; then pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for CONFDB" >&5 $as_echo_n "checking for CONFDB... " >&6; } if test -n "$CONFDB_CFLAGS"; then pkg_cv_CONFDB_CFLAGS="$CONFDB_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libconfdb\""; } >&5 ($PKG_CONFIG --exists --print-errors "libconfdb") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_CONFDB_CFLAGS=`$PKG_CONFIG --cflags "libconfdb" 2>/dev/null` else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$CONFDB_LIBS"; then pkg_cv_CONFDB_LIBS="$CONFDB_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libconfdb\""; } >&5 ($PKG_CONFIG --exists --print-errors "libconfdb") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_CONFDB_LIBS=`$PKG_CONFIG --libs "libconfdb" 2>/dev/null` else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then CONFDB_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "libconfdb" 2>&1` else CONFDB_PKG_ERRORS=`$PKG_CONFIG --print-errors "libconfdb" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$CONFDB_PKG_ERRORS" >&5 HAVE_CONFDB=no elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } HAVE_CONFDB=no else CONFDB_CFLAGS=$pkg_cv_CONFDB_CFLAGS CONFDB_LIBS=$pkg_cv_CONFDB_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } HAVE_CONFDB=yes fi for ac_header in corosync/confdb.h do : ac_fn_c_check_header_mongrel "$LINENO" "corosync/confdb.h" "ac_cv_header_corosync_confdb_h" "$ac_includes_default" if test "x$ac_cv_header_corosync_confdb_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_COROSYNC_CONFDB_H 1 _ACEOF HAVE_CONFDB_H=yes else HAVE_CONFDB_H=no fi done if test x$HAVE_CONFDB != xyes && \ test x$HAVE_CONFDB_H = xyes; then check_lib_no_libs confdb confdb_initialize { $as_echo "$as_me:${as_lineno-$LINENO}: result: no pkg for confdb, using -lconfdb" >&5 $as_echo "no pkg for confdb, using -lconfdb" >&6; } CONFDB_LIBS="-lconfdb" HAVE_CONFDB=yes fi fi if test x$CHECKCMAP = xyes; then pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for CMAP" >&5 $as_echo_n "checking for CMAP... " >&6; } if test -n "$CMAP_CFLAGS"; then pkg_cv_CMAP_CFLAGS="$CMAP_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libcmap\""; } >&5 ($PKG_CONFIG --exists --print-errors "libcmap") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_CMAP_CFLAGS=`$PKG_CONFIG --cflags "libcmap" 2>/dev/null` else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$CMAP_LIBS"; then pkg_cv_CMAP_LIBS="$CMAP_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libcmap\""; } >&5 ($PKG_CONFIG --exists --print-errors "libcmap") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_CMAP_LIBS=`$PKG_CONFIG --libs "libcmap" 2>/dev/null` else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then CMAP_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "libcmap" 2>&1` else CMAP_PKG_ERRORS=`$PKG_CONFIG --print-errors "libcmap" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$CMAP_PKG_ERRORS" >&5 HAVE_CMAP=no elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } HAVE_CMAP=no else CMAP_CFLAGS=$pkg_cv_CMAP_CFLAGS CMAP_LIBS=$pkg_cv_CMAP_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } HAVE_CMAP=yes fi for ac_header in corosync/cmap.h do : ac_fn_c_check_header_mongrel "$LINENO" "corosync/cmap.h" "ac_cv_header_corosync_cmap_h" "$ac_includes_default" if test "x$ac_cv_header_corosync_cmap_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_COROSYNC_CMAP_H 1 _ACEOF HAVE_CMAP_H=yes else HAVE_CMAP_H=no fi done if test x$HAVE_CMAP != xyes && \ test x$HAVE_CMAP_H = xyes; then check_lib_no_libs cmap cmap_initialize { $as_echo "$as_me:${as_lineno-$LINENO}: result: no pkg for cmap, using -lcmap" >&5 $as_echo "no pkg for cmap, using -lcmap" >&6; } CMAP_LIBS="-lcmap" HAVE_CMAP=yes fi fi if test x$BUILDCOROSYNC = xyes; then if test x$HAVE_CMAP != xyes && \ test x$HAVE_CONFDB != xyes && \ test x$CLVMD != xall; then as_fn_error $? "bailing out... cmap (corosync >= 2.0) or confdb (corosync < 2.0) library is required" "$LINENO" 5 fi fi if test x$CHECKCPG = xyes; then pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for CPG" >&5 $as_echo_n "checking for CPG... " >&6; } if test -n "$CPG_CFLAGS"; then pkg_cv_CPG_CFLAGS="$CPG_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libcpg\""; } >&5 ($PKG_CONFIG --exists --print-errors "libcpg") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_CPG_CFLAGS=`$PKG_CONFIG --cflags "libcpg" 2>/dev/null` else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$CPG_LIBS"; then pkg_cv_CPG_LIBS="$CPG_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libcpg\""; } >&5 ($PKG_CONFIG --exists --print-errors "libcpg") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_CPG_LIBS=`$PKG_CONFIG --libs "libcpg" 2>/dev/null` else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then CPG_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "libcpg" 2>&1` else CPG_PKG_ERRORS=`$PKG_CONFIG --print-errors "libcpg" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$CPG_PKG_ERRORS" >&5 $bailout elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $bailout else CPG_CFLAGS=$pkg_cv_CPG_CFLAGS CPG_LIBS=$pkg_cv_CPG_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } HAVE_CPG=yes fi fi if test x$CHECKDLM = xyes; then pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for DLM" >&5 $as_echo_n "checking for DLM... " >&6; } if test -n "$DLM_CFLAGS"; then pkg_cv_DLM_CFLAGS="$DLM_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libdlm\""; } >&5 ($PKG_CONFIG --exists --print-errors "libdlm") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_DLM_CFLAGS=`$PKG_CONFIG --cflags "libdlm" 2>/dev/null` else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$DLM_LIBS"; then pkg_cv_DLM_LIBS="$DLM_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libdlm\""; } >&5 ($PKG_CONFIG --exists --print-errors "libdlm") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_DLM_LIBS=`$PKG_CONFIG --libs "libdlm" 2>/dev/null` else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then DLM_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "libdlm" 2>&1` else DLM_PKG_ERRORS=`$PKG_CONFIG --print-errors "libdlm" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$DLM_PKG_ERRORS" >&5 NOTFOUND=0 for ac_header in libdlm.h do : ac_fn_c_check_header_mongrel "$LINENO" "libdlm.h" "ac_cv_header_libdlm_h" "$ac_includes_default" if test "x$ac_cv_header_libdlm_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBDLM_H 1 _ACEOF else $bailout fi done check_lib_no_libs dlm dlm_lock -lpthread if test $NOTFOUND = 0; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no pkg for libdlm, using -ldlm" >&5 $as_echo "no pkg for libdlm, using -ldlm" >&6; } DLM_LIBS="-ldlm -lpthread" HAVE_DLM=yes fi elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } NOTFOUND=0 for ac_header in libdlm.h do : ac_fn_c_check_header_mongrel "$LINENO" "libdlm.h" "ac_cv_header_libdlm_h" "$ac_includes_default" if test "x$ac_cv_header_libdlm_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBDLM_H 1 _ACEOF else $bailout fi done check_lib_no_libs dlm dlm_lock -lpthread if test $NOTFOUND = 0; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no pkg for libdlm, using -ldlm" >&5 $as_echo "no pkg for libdlm, using -ldlm" >&6; } DLM_LIBS="-ldlm -lpthread" HAVE_DLM=yes fi else DLM_CFLAGS=$pkg_cv_DLM_CFLAGS DLM_LIBS=$pkg_cv_DLM_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } HAVE_DLM=yes fi fi if test x$CLVMD = xall; then CLVMD=none CLVMD_CMANAGERS="" CLVMD_NEEDS_QDISKD=no if test x$HAVE_CMAN = xyes && \ test x$HAVE_DLM = xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: Enabling clvmd cman cluster manager" >&5 $as_echo "Enabling clvmd cman cluster manager" >&6; } CLVMD="$CLVMD,cman" CLVMD_CMANAGERS="$CLVMD_CMANAGERS cman" CLVMD_NEEDS_QDISKD=yes fi if test x$HAVE_COROSYNC = xyes && \ test x$HAVE_QUORUM = xyes && \ test x$HAVE_CPG = xyes && \ test x$HAVE_DLM = xyes; then if test x$HAVE_CONFDB = xyes || test x$HAVE_CMAP = xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: Enabling clvmd corosync cluster manager" >&5 $as_echo "Enabling clvmd corosync cluster manager" >&6; } CLVMD="$CLVMD,corosync" CLVMD_CMANAGERS="$CLVMD_CMANAGERS corosync" fi fi if test x$HAVE_COROSYNC = xyes && \ test x$HAVE_CPG = xyes && \ test x$HAVE_SALCK = xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: Enabling clvmd openais cluster manager" >&5 $as_echo "Enabling clvmd openais cluster manager" >&6; } CLVMD="$CLVMD,openais" CLVMD_CMANAGERS="$CLVMD_CMANAGERS openais" fi if test x$CLVMD_NEEDS_QDISKD != xno; then CLVMD_CMANAGERS="$CLVMD_CMANAGERS qdiskd" fi if test x$CLVMD = xnone; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: Disabling clvmd build. No cluster manager detected." >&5 $as_echo "Disabling clvmd build. No cluster manager detected." >&6; } fi fi if [ `expr x"$CLVMD" : '.*corosync.*'` != 0 ]; then if test x$HAVE_CMAP = xyes; then CLVMD_CMANAGERS="$CLVMD_CMANAGERS dlm" fi fi ################################################################################ if test "x$CLVMD" != xnone; then # Check whether --with-clvmd-pidfile was given. if test "${with_clvmd_pidfile+set}" = set; then : withval=$with_clvmd_pidfile; CLVMD_PIDFILE=$withval else CLVMD_PIDFILE="$DEFAULT_PID_DIR/clvmd.pid" fi cat >>confdefs.h <<_ACEOF #define CLVMD_PIDFILE "$CLVMD_PIDFILE" _ACEOF fi ################################################################################ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build cluster mirror log daemon" >&5 $as_echo_n "checking whether to build cluster mirror log daemon... " >&6; } # Check whether --enable-cmirrord was given. if test "${enable_cmirrord+set}" = set; then : enableval=$enable_cmirrord; CMIRRORD=$enableval else CMIRRORD=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CMIRRORD" >&5 $as_echo "$CMIRRORD" >&6; } BUILD_CMIRRORD=$CMIRRORD ################################################################################ if test "x$BUILD_CMIRRORD" = xyes; then # Check whether --with-cmirrord-pidfile was given. if test "${with_cmirrord_pidfile+set}" = set; then : withval=$with_cmirrord_pidfile; CMIRRORD_PIDFILE=$withval else CMIRRORD_PIDFILE="$DEFAULT_PID_DIR/cmirrord.pid" fi cat >>confdefs.h <<_ACEOF #define CMIRRORD_PIDFILE "$CMIRRORD_PIDFILE" _ACEOF fi ################################################################################ if [ "x$BUILD_CMIRRORD" = xyes ]; then if test x$PKGCONFIG_INIT != x1; then pkg_config_init fi $as_echo "#define CMIRROR_HAS_CHECKPOINT 1" >>confdefs.h pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SACKPT" >&5 $as_echo_n "checking for SACKPT... " >&6; } if test -n "$SACKPT_CFLAGS"; then pkg_cv_SACKPT_CFLAGS="$SACKPT_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libSaCkpt\""; } >&5 ($PKG_CONFIG --exists --print-errors "libSaCkpt") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_SACKPT_CFLAGS=`$PKG_CONFIG --cflags "libSaCkpt" 2>/dev/null` else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$SACKPT_LIBS"; then pkg_cv_SACKPT_LIBS="$SACKPT_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libSaCkpt\""; } >&5 ($PKG_CONFIG --exists --print-errors "libSaCkpt") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_SACKPT_LIBS=`$PKG_CONFIG --libs "libSaCkpt" 2>/dev/null` else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then SACKPT_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "libSaCkpt" 2>&1` else SACKPT_PKG_ERRORS=`$PKG_CONFIG --print-errors "libSaCkpt" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$SACKPT_PKG_ERRORS" >&5 { $as_echo "$as_me:${as_lineno-$LINENO}: result: no libSaCkpt, compiling without it" >&5 $as_echo "no libSaCkpt, compiling without it" >&6; } $as_echo "#define CMIRROR_HAS_CHECKPOINT 0" >>confdefs.h elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: no libSaCkpt, compiling without it" >&5 $as_echo "no libSaCkpt, compiling without it" >&6; } $as_echo "#define CMIRROR_HAS_CHECKPOINT 0" >>confdefs.h else SACKPT_CFLAGS=$pkg_cv_SACKPT_CFLAGS SACKPT_LIBS=$pkg_cv_SACKPT_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } HAVE_SACKPT=yes fi if test x$HAVE_CPG != xyes; then pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for CPG" >&5 $as_echo_n "checking for CPG... " >&6; } if test -n "$CPG_CFLAGS"; then pkg_cv_CPG_CFLAGS="$CPG_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libcpg\""; } >&5 ($PKG_CONFIG --exists --print-errors "libcpg") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_CPG_CFLAGS=`$PKG_CONFIG --cflags "libcpg" 2>/dev/null` else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$CPG_LIBS"; then pkg_cv_CPG_LIBS="$CPG_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libcpg\""; } >&5 ($PKG_CONFIG --exists --print-errors "libcpg") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_CPG_LIBS=`$PKG_CONFIG --libs "libcpg" 2>/dev/null` else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then CPG_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "libcpg" 2>&1` else CPG_PKG_ERRORS=`$PKG_CONFIG --print-errors "libcpg" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$CPG_PKG_ERRORS" >&5 as_fn_error $? "Package requirements (libcpg) were not met: $CPG_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. Alternatively, you may set the environment variables CPG_CFLAGS and CPG_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details." "$LINENO" 5 elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "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. Alternatively, you may set the environment variables CPG_CFLAGS and CPG_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. To get pkg-config, see . See \`config.log' for more details" "$LINENO" 5; } else CPG_CFLAGS=$pkg_cv_CPG_CFLAGS CPG_LIBS=$pkg_cv_CPG_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi fi fi ################################################################################ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable debugging" >&5 $as_echo_n "checking whether to enable debugging... " >&6; } # Check whether --enable-debug was given. if test "${enable_debug+set}" = set; then : enableval=$enable_debug; DEBUG=$enableval else DEBUG=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DEBUG" >&5 $as_echo "$DEBUG" >&6; } if test x$DEBUG = xyes; then COPTIMISE_FLAG= else CSCOPE_CMD= fi ################################################################################ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C optimisation flag" >&5 $as_echo_n "checking for C optimisation flag... " >&6; } # Check whether --with-optimisation was given. if test "${with_optimisation+set}" = set; then : withval=$with_optimisation; COPTIMISE_FLAG=$withval fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $COPTIMISE_FLAG" >&5 $as_echo "$COPTIMISE_FLAG" >&6; } ################################################################################ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to gather gcov profiling data" >&5 $as_echo_n "checking whether to gather gcov profiling data... " >&6; } # Check whether --enable-profiling was given. if test "${enable_profiling+set}" = set; then : enableval=$enable_profiling; PROFILING=$enableval else PROFILING=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PROFILING" >&5 $as_echo "$PROFILING" >&6; } if test "x$PROFILING" = xyes; then COPTIMISE_FLAG="$COPTIMISE_FLAG -fprofile-arcs -ftest-coverage" # Extract the first word of "lcov", so it can be a program name with args. set dummy lcov; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_LCOV+set}" = set; then : $as_echo_n "(cached) " >&6 else case $LCOV in [\\/]* | ?:[\\/]*) ac_cv_path_LCOV="$LCOV" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_LCOV="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi LCOV=$ac_cv_path_LCOV if test -n "$LCOV"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LCOV" >&5 $as_echo "$LCOV" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "genhtml", so it can be a program name with args. set dummy genhtml; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_GENHTML+set}" = set; then : $as_echo_n "(cached) " >&6 else case $GENHTML in [\\/]* | ?:[\\/]*) ac_cv_path_GENHTML="$GENHTML" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_GENHTML="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi GENHTML=$ac_cv_path_GENHTML if test -n "$GENHTML"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GENHTML" >&5 $as_echo "$GENHTML" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test -z "$LCOV" -o -z "$GENHTML"; then as_fn_error $? "lcov and genhtml are required for profiling" "$LINENO" 5 fi # Extract the first word of "genpng", so it can be a program name with args. set dummy genpng; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_GENPNG+set}" = set; then : $as_echo_n "(cached) " >&6 else case $GENPNG in [\\/]* | ?:[\\/]*) ac_cv_path_GENPNG="$GENPNG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_GENPNG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi GENPNG=$ac_cv_path_GENPNG if test -n "$GENPNG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GENPNG" >&5 $as_echo "$GENPNG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test -n "$GENPNG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $GENPNG has all required modules" >&5 $as_echo_n "checking whether $GENPNG has all required modules... " >&6; } if $GENPNG --help > /dev/null 2>&1 ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 $as_echo "ok" >&6; } GENHTML="$GENHTML --frames" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: not supported" >&5 $as_echo "not supported" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: GD.pm perl module is not installed" >&5 $as_echo "$as_me: WARNING: GD.pm perl module is not installed" >&2;} GENPNG= fi fi fi ################################################################################ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable unit testing" >&5 $as_echo_n "checking whether to enable unit testing... " >&6; } # Check whether --enable-testing was given. if test "${enable_testing+set}" = set; then : enableval=$enable_testing; TESTING=$enableval else TESTING=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $TESTING" >&5 $as_echo "$TESTING" >&6; } if test "$TESTING" = yes; then if test x$PKGCONFIG_INIT != x1; then pkg_config_init fi pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for CUNIT" >&5 $as_echo_n "checking for CUNIT... " >&6; } if test -n "$CUNIT_CFLAGS"; then pkg_cv_CUNIT_CFLAGS="$CUNIT_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"cunit >= 2.0\""; } >&5 ($PKG_CONFIG --exists --print-errors "cunit >= 2.0") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_CUNIT_CFLAGS=`$PKG_CONFIG --cflags "cunit >= 2.0" 2>/dev/null` else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$CUNIT_LIBS"; then pkg_cv_CUNIT_LIBS="$CUNIT_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"cunit >= 2.0\""; } >&5 ($PKG_CONFIG --exists --print-errors "cunit >= 2.0") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_CUNIT_LIBS=`$PKG_CONFIG --libs "cunit >= 2.0" 2>/dev/null` else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then CUNIT_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "cunit >= 2.0" 2>&1` else CUNIT_PKG_ERRORS=`$PKG_CONFIG --print-errors "cunit >= 2.0" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$CUNIT_PKG_ERRORS" >&5 as_fn_error $? "Package requirements (cunit >= 2.0) were not met: $CUNIT_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. Alternatively, you may set the environment variables CUNIT_CFLAGS and CUNIT_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details." "$LINENO" 5 elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "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. Alternatively, you may set the environment variables CUNIT_CFLAGS and CUNIT_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. To get pkg-config, see . See \`config.log' for more details" "$LINENO" 5; } else CUNIT_CFLAGS=$pkg_cv_CUNIT_CFLAGS CUNIT_LIBS=$pkg_cv_CUNIT_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi fi ################################################################################ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable valgrind awareness of pools" >&5 $as_echo_n "checking whether to enable valgrind awareness of pools... " >&6; } # Check whether --enable-valgrind_pool was given. if test "${enable_valgrind_pool+set}" = set; then : enableval=$enable_valgrind_pool; VALGRIND_POOL=$enableval else VALGRIND_POOL=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $VALGRIND_POOL" >&5 $as_echo "$VALGRIND_POOL" >&6; } if test "$VALGRIND_POOL" = yes; then pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for VALGRIND" >&5 $as_echo_n "checking for VALGRIND... " >&6; } if test -n "$VALGRIND_CFLAGS"; then pkg_cv_VALGRIND_CFLAGS="$VALGRIND_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"valgrind\""; } >&5 ($PKG_CONFIG --exists --print-errors "valgrind") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_VALGRIND_CFLAGS=`$PKG_CONFIG --cflags "valgrind" 2>/dev/null` else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$VALGRIND_LIBS"; then pkg_cv_VALGRIND_LIBS="$VALGRIND_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"valgrind\""; } >&5 ($PKG_CONFIG --exists --print-errors "valgrind") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_VALGRIND_LIBS=`$PKG_CONFIG --libs "valgrind" 2>/dev/null` else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then VALGRIND_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "valgrind" 2>&1` else VALGRIND_PKG_ERRORS=`$PKG_CONFIG --print-errors "valgrind" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$VALGRIND_PKG_ERRORS" >&5 as_fn_error $? "bailing out" "$LINENO" 5 elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } as_fn_error $? "bailing out" "$LINENO" 5 else VALGRIND_CFLAGS=$pkg_cv_VALGRIND_CFLAGS VALGRIND_LIBS=$pkg_cv_VALGRIND_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi $as_echo "#define VALGRIND_POOL 1" >>confdefs.h fi ################################################################################ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use device-mapper" >&5 $as_echo_n "checking whether to use device-mapper... " >&6; } # Check whether --enable-devmapper was given. if test "${enable_devmapper+set}" = set; then : enableval=$enable_devmapper; DEVMAPPER=$enableval fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DEVMAPPER" >&5 $as_echo "$DEVMAPPER" >&6; } if test x$DEVMAPPER = xyes; then $as_echo "#define DEVMAPPER_SUPPORT 1" >>confdefs.h fi ################################################################################ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build LVMetaD" >&5 $as_echo_n "checking whether to build LVMetaD... " >&6; } # Check whether --enable-lvmetad was given. if test "${enable_lvmetad+set}" = set; then : enableval=$enable_lvmetad; LVMETAD=$enableval fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LVMETAD" >&5 $as_echo "$LVMETAD" >&6; } BUILD_LVMETAD=$LVMETAD if test x$BUILD_LVMETAD = xyes; then $as_echo "#define LVMETAD_SUPPORT 1" >>confdefs.h # Check whether --with-lvmetad-pidfile was given. if test "${with_lvmetad_pidfile+set}" = set; then : withval=$with_lvmetad_pidfile; LVMETAD_PIDFILE=$withval else LVMETAD_PIDFILE="$DEFAULT_PID_DIR/lvmetad.pid" fi cat >>confdefs.h <<_ACEOF #define LVMETAD_PIDFILE "$LVMETAD_PIDFILE" _ACEOF fi ################################################################################ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable synchronisation with udev processing" >&5 $as_echo_n "checking whether to enable synchronisation with udev processing... " >&6; } # Check whether --enable-udev_sync was given. if test "${enable_udev_sync+set}" = set; then : enableval=$enable_udev_sync; UDEV_SYNC=$enableval else UDEV_SYNC=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $UDEV_SYNC" >&5 $as_echo "$UDEV_SYNC" >&6; } if test x$UDEV_SYNC = xyes; then if test x$PKGCONFIG_INIT != x1; then pkg_config_init fi pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for UDEV" >&5 $as_echo_n "checking for UDEV... " >&6; } if test -n "$UDEV_CFLAGS"; then pkg_cv_UDEV_CFLAGS="$UDEV_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libudev >= 143\""; } >&5 ($PKG_CONFIG --exists --print-errors "libudev >= 143") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_UDEV_CFLAGS=`$PKG_CONFIG --cflags "libudev >= 143" 2>/dev/null` else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$UDEV_LIBS"; then pkg_cv_UDEV_LIBS="$UDEV_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libudev >= 143\""; } >&5 ($PKG_CONFIG --exists --print-errors "libudev >= 143") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_UDEV_LIBS=`$PKG_CONFIG --libs "libudev >= 143" 2>/dev/null` else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then UDEV_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "libudev >= 143" 2>&1` else UDEV_PKG_ERRORS=`$PKG_CONFIG --print-errors "libudev >= 143" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$UDEV_PKG_ERRORS" >&5 as_fn_error $? "Package requirements (libudev >= 143) were not met: $UDEV_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. Alternatively, you may set the environment variables UDEV_CFLAGS and UDEV_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details." "$LINENO" 5 elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "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. Alternatively, you may set the environment variables UDEV_CFLAGS and UDEV_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. To get pkg-config, see . See \`config.log' for more details" "$LINENO" 5; } else UDEV_CFLAGS=$pkg_cv_UDEV_CFLAGS UDEV_LIBS=$pkg_cv_UDEV_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } UDEV_PC="libudev" fi $as_echo "#define UDEV_SYNC_SUPPORT 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable installation of udev rules required for synchronisation" >&5 $as_echo_n "checking whether to enable installation of udev rules required for synchronisation... " >&6; } # Check whether --enable-udev_rules was given. if test "${enable_udev_rules+set}" = set; then : enableval=$enable_udev_rules; UDEV_RULES=$enableval else UDEV_RULES=$UDEV_SYNC fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $UDEV_RULES" >&5 $as_echo "$UDEV_RULES" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable executable path detection in udev rules" >&5 $as_echo_n "checking whether to enable executable path detection in udev rules... " >&6; } # Check whether --enable-udev_rule_exec_detection was given. if test "${enable_udev_rule_exec_detection+set}" = set; then : enableval=$enable_udev_rule_exec_detection; UDEV_RULE_EXEC_DETECTION=$enableval else UDEV_RULE_EXEC_DETECTION=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $UDEV_RULE_EXEC_DETECTION" >&5 $as_echo "$UDEV_RULE_EXEC_DETECTION" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether udev supports built-in blkid" >&5 $as_echo_n "checking whether udev supports built-in blkid... " >&6; } test x$PKGCONFIG_INIT != x1 && pkg_config_init if $($PKG_CONFIG --atleast-version=176 libudev); then UDEV_HAS_BUILTIN_BLKID=yes else UDEV_HAS_BUILTIN_BLKID=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $UDEV_HAS_BUILTIN_BLKID" >&5 $as_echo "$UDEV_HAS_BUILTIN_BLKID" >&6; } ################################################################################ # Check whether --enable-compat was given. if test "${enable_compat+set}" = set; then : enableval=$enable_compat; DM_COMPAT=$enableval else DM_COMPAT=no fi if test x$DM_COMPAT = xyes; then as_fn_error $? "--enable-compat is not currently supported. Since device-mapper version 1.02.66, only one version (4) of the device-mapper ioctl protocol is supported. " "$LINENO" 5 fi ################################################################################ # Check whether --enable-units-compat was given. if test "${enable_units_compat+set}" = set; then : enableval=$enable_units_compat; UNITS_COMPAT=$enableval else UNITS_COMPAT=no fi if test x$UNITS_COMPAT = xyes; then $as_echo "#define DEFAULT_SI_UNIT_CONSISTENCY 0" >>confdefs.h fi ################################################################################ # Check whether --enable-ioctl was given. if test "${enable_ioctl+set}" = set; then : enableval=$enable_ioctl; DM_IOCTLS=$enableval fi ################################################################################ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable O_DIRECT" >&5 $as_echo_n "checking whether to enable O_DIRECT... " >&6; } # Check whether --enable-o_direct was given. if test "${enable_o_direct+set}" = set; then : enableval=$enable_o_direct; ODIRECT=$enableval fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ODIRECT" >&5 $as_echo "$ODIRECT" >&6; } if test x$ODIRECT = xyes; then $as_echo "#define O_DIRECT_SUPPORT 1" >>confdefs.h fi ################################################################################ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build liblvm2app.so application library" >&5 $as_echo_n "checking whether to build liblvm2app.so application library... " >&6; } # Check whether --enable-applib was given. if test "${enable_applib+set}" = set; then : enableval=$enable_applib; APPLIB=$enableval else APPLIB=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $APPLIB" >&5 $as_echo "$APPLIB" >&6; } test x$APPLIB = xyes \ && LVM2APP_LIB=-llvm2app \ || LVM2APP_LIB= ################################################################################ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to compile liblvm2cmd.so" >&5 $as_echo_n "checking whether to compile liblvm2cmd.so... " >&6; } # Check whether --enable-cmdlib was given. if test "${enable_cmdlib+set}" = set; then : enableval=$enable_cmdlib; CMDLIB=$enableval else CMDLIB=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CMDLIB" >&5 $as_echo "$CMDLIB" >&6; } test x$CMDLIB = xyes \ && LVM2CMD_LIB=-llvm2cmd \ || LVM2CMD_LIB= ################################################################################ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build Python wrapper for liblvm2app.so" >&5 $as_echo_n "checking whether to build Python wrapper for liblvm2app.so... " >&6; } # Check whether --enable-python_bindings was given. if test "${enable_python_bindings+set}" = set; then : enableval=$enable_python_bindings; PYTHON_BINDINGS=$enableval else PYTHON_BINDINGS=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYTHON_BINDINGS" >&5 $as_echo "$PYTHON_BINDINGS" >&6; } if test x$PYTHON_BINDINGS = xyes; then if test x$APPLIB != xyes; then as_fn_error $? "--enable-python_bindings requires --enable-applib " "$LINENO" 5 fi # Extract the first word of "python", so it can be a program name with args. set dummy python; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_PYTHON+set}" = set; then : $as_echo_n "(cached) " >&6 else case $PYTHON in [\\/]* | ?:[\\/]*) ac_cv_path_PYTHON="$PYTHON" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_PYTHON="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_PYTHON" && ac_cv_path_PYTHON="notfound" ;; esac fi PYTHON=$ac_cv_path_PYTHON if test -n "$PYTHON"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYTHON" >&5 $as_echo "$PYTHON" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test x$PYTHON == xnotfound; then as_fn_error $? "python is required for --enable-python_bindings but cannot be found " "$LINENO" 5 fi # Extract the first word of "python-config", so it can be a program name with args. set dummy python-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_PYTHON_CONFIG+set}" = set; then : $as_echo_n "(cached) " >&6 else case $PYTHON_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_PYTHON_CONFIG="$PYTHON_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_PYTHON_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_PYTHON_CONFIG" && ac_cv_path_PYTHON_CONFIG="notfound" ;; esac fi PYTHON_CONFIG=$ac_cv_path_PYTHON_CONFIG if test -n "$PYTHON_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYTHON_CONFIG" >&5 $as_echo "$PYTHON_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test x$PYTHON_CONFIG == xnotfound; then as_fn_error $? "python headers are required for --enable-python_bindings but cannot be found " "$LINENO" 5 fi PYTHON_INCDIRS=`$PYTHON_CONFIG --includes` PYTHON_LIBDIRS=`$PYTHON_CONFIG --libs` fi ################################################################################ # Check whether --enable-pkgconfig was given. if test "${enable_pkgconfig+set}" = set; then : enableval=$enable_pkgconfig; PKGCONFIG=$enableval else PKGCONFIG=no fi ################################################################################ # Check whether --enable-write_install was given. if test "${enable_write_install+set}" = set; then : enableval=$enable_write_install; WRITE_INSTALL=$enableval else WRITE_INSTALL=no fi ################################################################################ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to install fsadm" >&5 $as_echo_n "checking whether to install fsadm... " >&6; } # Check whether --enable-fsadm was given. if test "${enable_fsadm+set}" = set; then : enableval=$enable_fsadm; FSADM=$enableval fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $FSADM" >&5 $as_echo "$FSADM" >&6; } ################################################################################ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to install blkdeactivate" >&5 $as_echo_n "checking whether to install blkdeactivate... " >&6; } # Check whether --enable-blkdeactivate was given. if test "${enable_blkdeactivate+set}" = set; then : enableval=$enable_blkdeactivate; BLKDEACTIVATE=$enableval fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $BLKDEACTIVATE" >&5 $as_echo "$BLKDEACTIVATE" >&6; } ################################################################################ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use dmeventd" >&5 $as_echo_n "checking whether to use dmeventd... " >&6; } # Check whether --enable-dmeventd was given. if test "${enable_dmeventd+set}" = set; then : enableval=$enable_dmeventd; DMEVENTD=$enableval fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DMEVENTD" >&5 $as_echo "$DMEVENTD" >&6; } BUILD_DMEVENTD=$DMEVENTD if test x$DMEVENTD = xyes; then if test x$MIRRORS != xinternal; then as_fn_error $? "--enable-dmeventd currently requires --with-mirrors=internal " "$LINENO" 5 fi if test x$CMDLIB = xno; then as_fn_error $? "--enable-dmeventd requires --enable-cmdlib to be used as well " "$LINENO" 5 fi fi if test x$DMEVENTD = xyes; then $as_echo "#define DMEVENTD 1" >>confdefs.h fi ################################################################################ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for getline in -lc" >&5 $as_echo_n "checking for getline in -lc... " >&6; } if test "${ac_cv_lib_c_getline+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lc $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char getline (); int main () { return getline (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_c_getline=yes else ac_cv_lib_c_getline=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_getline" >&5 $as_echo "$ac_cv_lib_c_getline" >&6; } if test "x$ac_cv_lib_c_getline" = x""yes; then : $as_echo "#define HAVE_GETLINE 1" >>confdefs.h fi ################################################################################ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for canonicalize_file_name in -lc" >&5 $as_echo_n "checking for canonicalize_file_name in -lc... " >&6; } if test "${ac_cv_lib_c_canonicalize_file_name+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lc $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char canonicalize_file_name (); int main () { return canonicalize_file_name (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_c_canonicalize_file_name=yes else ac_cv_lib_c_canonicalize_file_name=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_canonicalize_file_name" >&5 $as_echo "$ac_cv_lib_c_canonicalize_file_name" >&6; } if test "x$ac_cv_lib_c_canonicalize_file_name" = x""yes; then : $as_echo "#define HAVE_CANONICALIZE_FILE_NAME 1" >>confdefs.h fi ################################################################################ if [ "x$exec_prefix" = xNONE -a "x$prefix" = xNONE ]; then exec_prefix=""; fi; ################################################################################ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if test "${ac_cv_lib_dl_dlopen+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = x""yes; then : $as_echo "#define HAVE_LIBDL 1" >>confdefs.h DL_LIBS="-ldl" HAVE_LIBDL=yes else DL_LIBS= HAVE_LIBDL=no fi ################################################################################ if [ \( "x$LVM1" = xshared -o "x$POOL" = xshared -o "x$CLUSTER" = xshared \ -o "x$SNAPSHOTS" = xshared -o "x$MIRRORS" = xshared \ -o "x$RAID" = xshared \ \) -a "x$STATIC_LINK" = xyes ]; then as_fn_error $? "Features cannot be 'shared' when building statically " "$LINENO" 5 fi ################################################################################ if [ "$DMEVENTD" = yes -o "$CLVMD" != none ] ; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_lock in -lpthread" >&5 $as_echo_n "checking for pthread_mutex_lock in -lpthread... " >&6; } if test "${ac_cv_lib_pthread_pthread_mutex_lock+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpthread $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pthread_mutex_lock (); int main () { return pthread_mutex_lock (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_pthread_pthread_mutex_lock=yes else ac_cv_lib_pthread_pthread_mutex_lock=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_mutex_lock" >&5 $as_echo "$ac_cv_lib_pthread_pthread_mutex_lock" >&6; } if test "x$ac_cv_lib_pthread_pthread_mutex_lock" = x""yes; then : PTHREAD_LIBS="-lpthread" else hard_bailout fi fi ################################################################################ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable selinux support" >&5 $as_echo_n "checking whether to enable selinux support... " >&6; } # Check whether --enable-selinux was given. if test "${enable_selinux+set}" = set; then : enableval=$enable_selinux; SELINUX=$enableval fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $SELINUX" >&5 $as_echo "$SELINUX" >&6; } ################################################################################ if test x$SELINUX = xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sepol_check_context in -lsepol" >&5 $as_echo_n "checking for sepol_check_context in -lsepol... " >&6; } if test "${ac_cv_lib_sepol_sepol_check_context+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsepol $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char sepol_check_context (); int main () { return sepol_check_context (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_sepol_sepol_check_context=yes else ac_cv_lib_sepol_sepol_check_context=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sepol_sepol_check_context" >&5 $as_echo "$ac_cv_lib_sepol_sepol_check_context" >&6; } if test "x$ac_cv_lib_sepol_sepol_check_context" = x""yes; then : $as_echo "#define HAVE_SEPOL 1" >>confdefs.h SELINUX_LIBS="-lsepol" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for is_selinux_enabled in -lselinux" >&5 $as_echo_n "checking for is_selinux_enabled in -lselinux... " >&6; } if test "${ac_cv_lib_selinux_is_selinux_enabled+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lselinux $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char is_selinux_enabled (); int main () { return is_selinux_enabled (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_selinux_is_selinux_enabled=yes else ac_cv_lib_selinux_is_selinux_enabled=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_selinux_is_selinux_enabled" >&5 $as_echo "$ac_cv_lib_selinux_is_selinux_enabled" >&6; } if test "x$ac_cv_lib_selinux_is_selinux_enabled" = x""yes; then : for ac_header in selinux/selinux.h do : ac_fn_c_check_header_mongrel "$LINENO" "selinux/selinux.h" "ac_cv_header_selinux_selinux_h" "$ac_includes_default" if test "x$ac_cv_header_selinux_selinux_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SELINUX_SELINUX_H 1 _ACEOF else hard_bailout fi done for ac_header in selinux/label.h do : ac_fn_c_check_header_mongrel "$LINENO" "selinux/label.h" "ac_cv_header_selinux_label_h" "$ac_includes_default" if test "x$ac_cv_header_selinux_label_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SELINUX_LABEL_H 1 _ACEOF fi done $as_echo "#define HAVE_SELINUX 1" >>confdefs.h SELINUX_LIBS="-lselinux $SELINUX_LIBS" SELINUX_PC="libselinux" HAVE_SELINUX=yes else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Disabling selinux" >&5 $as_echo "$as_me: WARNING: Disabling selinux" >&2;} SELINUX_LIBS= SELINUX_PC= HAVE_SELINUX=no fi fi ################################################################################ if test x$REALTIME = xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5 $as_echo_n "checking for clock_gettime in -lrt... " >&6; } if test "${ac_cv_lib_rt_clock_gettime+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lrt $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char clock_gettime (); int main () { return clock_gettime (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_rt_clock_gettime=yes else ac_cv_lib_rt_clock_gettime=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5 $as_echo "$ac_cv_lib_rt_clock_gettime" >&6; } if test "x$ac_cv_lib_rt_clock_gettime" = x""yes; then : HAVE_REALTIME=yes else HAVE_REALTIME=no fi if test x$HAVE_REALTIME = xyes; then $as_echo "#define HAVE_REALTIME 1" >>confdefs.h LIBS="-lrt $LIBS" else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Disabling realtime clock" >&5 $as_echo "$as_me: WARNING: Disabling realtime clock" >&2;} fi fi ################################################################################ for ac_header in getopt.h do : ac_fn_c_check_header_mongrel "$LINENO" "getopt.h" "ac_cv_header_getopt_h" "$ac_includes_default" if test "x$ac_cv_header_getopt_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_GETOPT_H 1 _ACEOF $as_echo "#define HAVE_GETOPTLONG 1" >>confdefs.h fi done ################################################################################ if test x$READLINE != xno; then lvm_saved_libs=$LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing tgetent" >&5 $as_echo_n "checking for library containing tgetent... " >&6; } if test "${ac_cv_search_tgetent+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char tgetent (); int main () { return tgetent (); ; return 0; } _ACEOF for ac_lib in '' tinfo ncurses curses termcap termlib; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_tgetent=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if test "${ac_cv_search_tgetent+set}" = set; then : break fi done if test "${ac_cv_search_tgetent+set}" = set; then : else ac_cv_search_tgetent=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_tgetent" >&5 $as_echo "$ac_cv_search_tgetent" >&6; } ac_res=$ac_cv_search_tgetent if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" READLINE_LIBS=$ac_cv_search_tgetent else if test "$READLINE" = yes; then as_fn_error $? "termcap could not be found which is required for the --enable-readline option (which is enabled by default). Either disable readline support with --disable-readline or download and install termcap from: ftp.gnu.org/gnu/termcap Note: if you are using precompiled packages you will also need the development package as well (which may be called termcap-devel or something similar). Note: (n)curses also seems to work as a substitute for termcap. This was not found either - but you could try installing that as well." "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for readline in -lreadline" >&5 $as_echo_n "checking for readline in -lreadline... " >&6; } if test "${ac_cv_lib_readline_readline+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lreadline $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char readline (); int main () { return readline (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_readline_readline=yes else ac_cv_lib_readline_readline=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_readline" >&5 $as_echo "$ac_cv_lib_readline_readline" >&6; } if test "x$ac_cv_lib_readline_readline" = x""yes; then : $as_echo "#define READLINE_SUPPORT 1" >>confdefs.h LIBS=$lvm_saved_libs { $as_echo "$as_me:${as_lineno-$LINENO}: checking for rl_line_buffer in -lreadline" >&5 $as_echo_n "checking for rl_line_buffer in -lreadline... " >&6; } if test "${ac_cv_lib_readline_rl_line_buffer+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lreadline $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char rl_line_buffer (); int main () { return rl_line_buffer (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_readline_rl_line_buffer=yes else ac_cv_lib_readline_rl_line_buffer=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_rl_line_buffer" >&5 $as_echo "$ac_cv_lib_readline_rl_line_buffer" >&6; } if test "x$ac_cv_lib_readline_rl_line_buffer" = x""yes; then : READLINE_LIBS="-lreadline" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: linking -lreadline with $READLINE_LIBS needed" >&5 $as_echo "linking -lreadline with $READLINE_LIBS needed" >&6; } READLINE_LIBS="-lreadline $READLINE_LIBS" fi else READLINE_LIBS= if test "$READLINE" = yes; then as_fn_error $? "GNU Readline could not be found which is required for the --enable-readline option (which is enabled by default). Either disable readline support with --disable-readline or download and install readline from: ftp.gnu.org/gnu/readline Note: if you are using precompiled packages you will also need the development package as well (which may be called readline-devel or something similar)." "$LINENO" 5 fi fi LIBS="$READLINE_LIBS $lvm_saved_libs" for ac_func in rl_completion_matches do : ac_fn_c_check_func "$LINENO" "rl_completion_matches" "ac_cv_func_rl_completion_matches" if test "x$ac_cv_func_rl_completion_matches" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_RL_COMPLETION_MATCHES 1 _ACEOF fi done LIBS=$lvm_saved_libs fi ################################################################################ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable internationalisation" >&5 $as_echo_n "checking whether to enable internationalisation... " >&6; } # Check whether --enable-nls was given. if test "${enable_nls+set}" = set; then : enableval=$enable_nls; INTL=$enableval else INTL=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INTL" >&5 $as_echo "$INTL" >&6; } if test x$INTL = xyes; then # FIXME - Move this - can be device-mapper too INTL_PACKAGE="lvm2" # Extract the first word of "msgfmt", so it can be a program name with args. set dummy msgfmt; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_MSGFMT+set}" = set; then : $as_echo_n "(cached) " >&6 else case $MSGFMT in [\\/]* | ?:[\\/]*) ac_cv_path_MSGFMT="$MSGFMT" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_MSGFMT="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi MSGFMT=$ac_cv_path_MSGFMT if test -n "$MSGFMT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MSGFMT" >&5 $as_echo "$MSGFMT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if [ "x$MSGFMT" == x ]; then as_fn_error $? "msgfmt not found in path $PATH " "$LINENO" 5 fi; # Check whether --with-localedir was given. if test "${with_localedir+set}" = set; then : withval=$with_localedir; LOCALEDIR=$withval else LOCALEDIR='${prefix}/share/locale' fi fi ################################################################################ # Check whether --with-confdir was given. if test "${with_confdir+set}" = set; then : withval=$with_confdir; CONFDIR=$withval else CONFDIR="/etc" fi # Check whether --with-staticdir was given. if test "${with_staticdir+set}" = set; then : withval=$with_staticdir; STATICDIR=$withval else STATICDIR='${exec_prefix}/sbin' fi # Check whether --with-usrlibdir was given. if test "${with_usrlibdir+set}" = set; then : withval=$with_usrlibdir; usrlibdir=$withval else usrlibdir='${prefix}/lib' fi # Check whether --with-usrsbindir was given. if test "${with_usrsbindir+set}" = set; then : withval=$with_usrsbindir; usrsbindir=$withval else usrsbindir='${prefix}/sbin' fi ################################################################################ # Check whether --with-udev_prefix was given. if test "${with_udev_prefix+set}" = set; then : withval=$with_udev_prefix; udev_prefix=$withval else udev_prefix='${exec_prefix}' fi # Check whether --with-udevdir was given. if test "${with_udevdir+set}" = set; then : withval=$with_udevdir; udevdir=$withval else udevdir='${udev_prefix}/lib/udev/rules.d' fi ################################################################################ # Check whether --with-systemdsystemunitdir was given. if test "${with_systemdsystemunitdir+set}" = set; then : withval=$with_systemdsystemunitdir; systemdsystemunitdir=$withval else test x$PKGCONFIG_INIT != x1 && pkg_config_init pkg_systemdsystemunitdir=$($PKG_CONFIG --variable=systemdsystemunitdir systemd) fi if test -n "$pkg_systemdsystemunitdir"; then systemdsystemunitdir=$pkg_systemdsystemunitdir; fi if test -z "$systemdsystemunitdir"; then systemdsystemunitdir='${exec_prefix}/lib/systemd/system'; fi systemdutildir=$($PKG_CONFIG --variable=systemdutildir systemd) if test -z "$systemdutildir"; then systemdutildir='${exec_prefix}/lib/systemd'; fi ################################################################################ # Check whether --with-tmpfilesdir was given. if test "${with_tmpfilesdir+set}" = set; then : withval=$with_tmpfilesdir; tmpfilesdir=$withval else tmpfilesdir='${prefix}/lib/tmpfiles.d' fi ################################################################################ if test x$READLINE = xyes; then for ac_header in readline/readline.h readline/history.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF else as_fn_error $? "bailing out" "$LINENO" 5 fi done fi if test x$CLVMD != xnone; then for ac_header in mntent.h netdb.h netinet/in.h pthread.h search.h sys/mount.h sys/socket.h sys/uio.h sys/un.h utmpx.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF else as_fn_error $? "bailing out" "$LINENO" 5 fi done for ac_func in dup2 getmntent memmove select socket do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF else as_fn_error $? "bailing out" "$LINENO" 5 fi done # getmntent is in the standard C library on UNICOS, in -lsun on Irix 4, # -lseq on Dynix/PTX, -lgen on Unixware. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing getmntent" >&5 $as_echo_n "checking for library containing getmntent... " >&6; } if test "${ac_cv_search_getmntent+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char getmntent (); int main () { return getmntent (); ; return 0; } _ACEOF for ac_lib in '' sun seq gen; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_getmntent=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if test "${ac_cv_search_getmntent+set}" = set; then : break fi done if test "${ac_cv_search_getmntent+set}" = set; then : else ac_cv_search_getmntent=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_getmntent" >&5 $as_echo "$ac_cv_search_getmntent" >&6; } ac_res=$ac_cv_search_getmntent if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" ac_cv_func_getmntent=yes $as_echo "#define HAVE_GETMNTENT 1" >>confdefs.h else ac_cv_func_getmntent=no fi for ac_header in sys/select.h sys/socket.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking types of arguments for select" >&5 $as_echo_n "checking types of arguments for select... " >&6; } if test "${ac_cv_func_select_args+set}" = set; then : $as_echo_n "(cached) " >&6 else for ac_arg234 in 'fd_set *' 'int *' 'void *'; do for ac_arg1 in 'int' 'size_t' 'unsigned long int' 'unsigned int'; do for ac_arg5 in 'struct timeval *' 'const struct timeval *'; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default #ifdef HAVE_SYS_SELECT_H # include #endif #ifdef HAVE_SYS_SOCKET_H # include #endif int main () { extern int select ($ac_arg1, $ac_arg234, $ac_arg234, $ac_arg234, $ac_arg5); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_func_select_args="$ac_arg1,$ac_arg234,$ac_arg5"; break 3 fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done done done # Provide a safe default value. : ${ac_cv_func_select_args='int,int *,struct timeval *'} fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_select_args" >&5 $as_echo "$ac_cv_func_select_args" >&6; } ac_save_IFS=$IFS; IFS=',' set dummy `echo "$ac_cv_func_select_args" | sed 's/\*/\*/g'` IFS=$ac_save_IFS shift cat >>confdefs.h <<_ACEOF #define SELECT_TYPE_ARG1 $1 _ACEOF cat >>confdefs.h <<_ACEOF #define SELECT_TYPE_ARG234 ($2) _ACEOF cat >>confdefs.h <<_ACEOF #define SELECT_TYPE_ARG5 ($3) _ACEOF rm -f conftest* fi if test x$CLUSTER != xnone; then for ac_header in sys/socket.h sys/un.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF else as_fn_error $? "bailing out" "$LINENO" 5 fi done for ac_func in socket do : ac_fn_c_check_func "$LINENO" "socket" "ac_cv_func_socket" if test "x$ac_cv_func_socket" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SOCKET 1 _ACEOF else as_fn_error $? "bailing out" "$LINENO" 5 fi done fi if test x$DMEVENTD = xyes; then for ac_header in arpa/inet.h do : ac_fn_c_check_header_mongrel "$LINENO" "arpa/inet.h" "ac_cv_header_arpa_inet_h" "$ac_includes_default" if test "x$ac_cv_header_arpa_inet_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_ARPA_INET_H 1 _ACEOF else as_fn_error $? "bailing out" "$LINENO" 5 fi done fi if test x$HAVE_LIBDL = xyes; then for ac_header in dlfcn.h do : ac_fn_c_check_header_mongrel "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default" if test "x$ac_cv_header_dlfcn_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_DLFCN_H 1 _ACEOF else as_fn_error $? "bailing out" "$LINENO" 5 fi done fi if test x$INTL = xyes; then for ac_header in libintl.h do : ac_fn_c_check_header_mongrel "$LINENO" "libintl.h" "ac_cv_header_libintl_h" "$ac_includes_default" if test "x$ac_cv_header_libintl_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBINTL_H 1 _ACEOF else as_fn_error $? "bailing out" "$LINENO" 5 fi done fi if test x$UDEV_SYNC = xyes; then for ac_header in sys/ipc.h sys/sem.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF else as_fn_error $? "bailing out" "$LINENO" 5 fi done fi ################################################################################ # Extract the first word of "modprobe", so it can be a program name with args. set dummy modprobe; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_MODPROBE_CMD+set}" = set; then : $as_echo_n "(cached) " >&6 else case $MODPROBE_CMD in [\\/]* | ?:[\\/]*) ac_cv_path_MODPROBE_CMD="$MODPROBE_CMD" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_MODPROBE_CMD="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi MODPROBE_CMD=$ac_cv_path_MODPROBE_CMD if test -n "$MODPROBE_CMD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MODPROBE_CMD" >&5 $as_echo "$MODPROBE_CMD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test x$MODPROBE_CMD != x; then cat >>confdefs.h <<_ACEOF #define MODPROBE_CMD "$MODPROBE_CMD" _ACEOF fi lvm_exec_prefix=$exec_prefix test "$lvm_exec_prefix" = NONE && lvm_exec_prefix=$prefix test "$lvm_exec_prefix" = NONE && lvm_exec_prefix=$ac_default_prefix LVM_PATH="$lvm_exec_prefix/sbin/lvm" cat >>confdefs.h <<_ACEOF #define LVM_PATH "$LVM_PATH" _ACEOF if test "$CLVMD" != none; then clvmd_prefix=$ac_default_prefix CLVMD_PATH="$clvmd_prefix/sbin/clvmd" test "$prefix" != NONE && clvmd_prefix=$prefix cat >>confdefs.h <<_ACEOF #define CLVMD_PATH "$CLVMD_PATH" _ACEOF fi ################################################################################ if test "$BUILD_DMEVENTD" = yes; then # Check whether --with-dmeventd-pidfile was given. if test "${with_dmeventd_pidfile+set}" = set; then : withval=$with_dmeventd_pidfile; DMEVENTD_PIDFILE=$withval else DMEVENTD_PIDFILE="$DEFAULT_PID_DIR/dmeventd.pid" fi cat >>confdefs.h <<_ACEOF #define DMEVENTD_PIDFILE "$DMEVENTD_PIDFILE" _ACEOF fi if test "$BUILD_DMEVENTD" = yes; then # Check whether --with-dmeventd-path was given. if test "${with_dmeventd_path+set}" = set; then : withval=$with_dmeventd_path; DMEVENTD_PATH=$withval else DMEVENTD_PATH="$lvm_exec_prefix/sbin/dmeventd" fi cat >>confdefs.h <<_ACEOF #define DMEVENTD_PATH "$DMEVENTD_PATH" _ACEOF fi ################################################################################ # Check whether --with-default-system-dir was given. if test "${with_default_system_dir+set}" = set; then : withval=$with_default_system_dir; DEFAULT_SYS_DIR=$withval else DEFAULT_SYS_DIR="/etc/lvm" fi cat >>confdefs.h <<_ACEOF #define DEFAULT_SYS_DIR "$DEFAULT_SYS_DIR" _ACEOF # Check whether --with-default-archive-subdir was given. if test "${with_default_archive_subdir+set}" = set; then : withval=$with_default_archive_subdir; DEFAULT_ARCHIVE_SUBDIR=$withval else DEFAULT_ARCHIVE_SUBDIR=archive fi cat >>confdefs.h <<_ACEOF #define DEFAULT_ARCHIVE_SUBDIR "$DEFAULT_ARCHIVE_SUBDIR" _ACEOF # Check whether --with-default-backup-subdir was given. if test "${with_default_backup_subdir+set}" = set; then : withval=$with_default_backup_subdir; DEFAULT_BACKUP_SUBDIR=$withval else DEFAULT_BACKUP_SUBDIR=backup fi cat >>confdefs.h <<_ACEOF #define DEFAULT_BACKUP_SUBDIR "$DEFAULT_BACKUP_SUBDIR" _ACEOF # Check whether --with-default-cache-subdir was given. if test "${with_default_cache_subdir+set}" = set; then : withval=$with_default_cache_subdir; DEFAULT_CACHE_SUBDIR=$withval else DEFAULT_CACHE_SUBDIR=cache fi cat >>confdefs.h <<_ACEOF #define DEFAULT_CACHE_SUBDIR "$DEFAULT_CACHE_SUBDIR" _ACEOF # Check whether --with-default-locking-dir was given. if test "${with_default_locking_dir+set}" = set; then : withval=$with_default_locking_dir; DEFAULT_LOCK_DIR=$withval else DEFAULT_LOCK_DIR="/var/lock/lvm" fi cat >>confdefs.h <<_ACEOF #define DEFAULT_LOCK_DIR "$DEFAULT_LOCK_DIR" _ACEOF ################################################################################ # Check whether --with-default-data-alignment was given. if test "${with_default_data_alignment+set}" = set; then : withval=$with_default_data_alignment; DEFAULT_DATA_ALIGNMENT=$withval else DEFAULT_DATA_ALIGNMENT=1 fi cat >>confdefs.h <<_ACEOF #define DEFAULT_DATA_ALIGNMENT $DEFAULT_DATA_ALIGNMENT _ACEOF ################################################################################ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for kernel interface choice" >&5 $as_echo_n "checking for kernel interface choice... " >&6; } # Check whether --with-interface was given. if test "${with_interface+set}" = set; then : withval=$with_interface; interface=$withval else interface=ioctl fi if [ "x$interface" != xioctl ]; then as_fn_error $? "--with-interface=ioctl required. fs no longer supported." "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $interface" >&5 $as_echo "$interface" >&6; } ################################################################################ DM_LIB_VERSION="\"`cat "$srcdir"/VERSION_DM 2>/dev/null || echo Unknown`\"" cat >>confdefs.h <<_ACEOF #define DM_LIB_VERSION $DM_LIB_VERSION _ACEOF DM_LIB_PATCHLEVEL=`cat "$srcdir"/VERSION_DM | $AWK -F '[-. ]' '{printf "%s.%s.%s",$1,$2,$3}'` LVM_VERSION="\"`cat "$srcdir"/VERSION 2>/dev/null || echo Unknown`\"" VER=`cat "$srcdir"/VERSION` LVM_RELEASE_DATE="\"`echo $VER | $SED 's/.* (//;s/).*//'`\"" VER=`echo "$VER" | $AWK '{print $1}'` LVM_RELEASE="\"`echo "$VER" | $AWK -F '-' '{print $2}'`\"" VER=`echo "$VER" | $AWK -F '-' '{print $1}'` LVM_MAJOR=`echo "$VER" | $AWK -F '.' '{print $1}'` LVM_MINOR=`echo "$VER" | $AWK -F '.' '{print $2}'` LVM_PATCHLEVEL=`echo "$VER" | $AWK -F '[(.]' '{print $3}'` LVM_LIBAPI=`echo "$VER" | $AWK -F '[()]' '{print $2}'` ################################################################################ ################################################################################ ac_config_files="$ac_config_files Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile daemons/cmirrord/Makefile daemons/dmeventd/Makefile daemons/dmeventd/libdevmapper-event.pc daemons/dmeventd/plugins/Makefile daemons/dmeventd/plugins/lvm2/Makefile daemons/dmeventd/plugins/raid/Makefile daemons/dmeventd/plugins/mirror/Makefile daemons/dmeventd/plugins/snapshot/Makefile daemons/dmeventd/plugins/thin/Makefile daemons/lvmetad/Makefile doc/Makefile doc/example.conf include/.symlinks include/Makefile lib/Makefile lib/format1/Makefile lib/format_pool/Makefile lib/locking/Makefile lib/mirror/Makefile lib/replicator/Makefile lib/misc/lvm-version.h lib/raid/Makefile lib/snapshot/Makefile lib/thin/Makefile libdaemon/Makefile libdaemon/client/Makefile libdaemon/server/Makefile libdm/Makefile libdm/libdevmapper.pc liblvm/Makefile liblvm/liblvm2app.pc man/Makefile po/Makefile python/Makefile python/setup.py scripts/blkdeactivate.sh scripts/blk_availability_init_red_hat scripts/blk_availability_systemd_red_hat.service scripts/clvmd_init_red_hat scripts/cmirrord_init_red_hat scripts/lvm2_lvmetad_init_red_hat scripts/lvm2_lvmetad_systemd_red_hat.socket scripts/lvm2_lvmetad_systemd_red_hat.service scripts/lvm2_monitoring_init_red_hat scripts/dm_event_systemd_red_hat.socket scripts/dm_event_systemd_red_hat.service scripts/lvm2_monitoring_systemd_red_hat.service scripts/lvm2_tmpfiles_red_hat.conf scripts/Makefile test/Makefile test/api/Makefile test/unit/Makefile tools/Makefile udev/Makefile unit-tests/datastruct/Makefile unit-tests/regex/Makefile unit-tests/mm/Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then test "x$cache_file" != "x/dev/null" && { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} cat confcache >$cache_file else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : ${CONFIG_STATUS=./config.status} ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -p'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -p' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi if test -x / >/dev/null 2>&1; then as_test_x='test -x' else if ls -dL / >/dev/null 2>&1; then as_ls_L_option=L else as_ls_L_option= fi as_test_x=' eval sh -c '\'' if test -d "$1"; then test -d "$1/."; else case $1 in #( -*)set "./$1";; esac; case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( ???[sx]*):;;*)false;;esac;fi '\'' sh ' fi as_executable_p=$as_test_x # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by $as_me, which was generated by GNU Autoconf 2.66. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Report bugs to the package provider." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ config.status configured by $0, generated by GNU Autoconf 2.66, with options \\"\$ac_cs_config\\" Copyright (C) 2010 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' MKDIR_P='$MKDIR_P' AWK='$AWK' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "lib/misc/configure.h") CONFIG_HEADERS="$CONFIG_HEADERS lib/misc/configure.h" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "make.tmpl") CONFIG_FILES="$CONFIG_FILES make.tmpl" ;; "daemons/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/Makefile" ;; "daemons/clvmd/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/clvmd/Makefile" ;; "daemons/cmirrord/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/cmirrord/Makefile" ;; "daemons/dmeventd/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/dmeventd/Makefile" ;; "daemons/dmeventd/libdevmapper-event.pc") CONFIG_FILES="$CONFIG_FILES daemons/dmeventd/libdevmapper-event.pc" ;; "daemons/dmeventd/plugins/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/dmeventd/plugins/Makefile" ;; "daemons/dmeventd/plugins/lvm2/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/dmeventd/plugins/lvm2/Makefile" ;; "daemons/dmeventd/plugins/raid/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/dmeventd/plugins/raid/Makefile" ;; "daemons/dmeventd/plugins/mirror/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/dmeventd/plugins/mirror/Makefile" ;; "daemons/dmeventd/plugins/snapshot/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/dmeventd/plugins/snapshot/Makefile" ;; "daemons/dmeventd/plugins/thin/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/dmeventd/plugins/thin/Makefile" ;; "daemons/lvmetad/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/lvmetad/Makefile" ;; "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;; "doc/example.conf") CONFIG_FILES="$CONFIG_FILES doc/example.conf" ;; "include/.symlinks") CONFIG_FILES="$CONFIG_FILES include/.symlinks" ;; "include/Makefile") CONFIG_FILES="$CONFIG_FILES include/Makefile" ;; "lib/Makefile") CONFIG_FILES="$CONFIG_FILES lib/Makefile" ;; "lib/format1/Makefile") CONFIG_FILES="$CONFIG_FILES lib/format1/Makefile" ;; "lib/format_pool/Makefile") CONFIG_FILES="$CONFIG_FILES lib/format_pool/Makefile" ;; "lib/locking/Makefile") CONFIG_FILES="$CONFIG_FILES lib/locking/Makefile" ;; "lib/mirror/Makefile") CONFIG_FILES="$CONFIG_FILES lib/mirror/Makefile" ;; "lib/replicator/Makefile") CONFIG_FILES="$CONFIG_FILES lib/replicator/Makefile" ;; "lib/misc/lvm-version.h") CONFIG_FILES="$CONFIG_FILES lib/misc/lvm-version.h" ;; "lib/raid/Makefile") CONFIG_FILES="$CONFIG_FILES lib/raid/Makefile" ;; "lib/snapshot/Makefile") CONFIG_FILES="$CONFIG_FILES lib/snapshot/Makefile" ;; "lib/thin/Makefile") CONFIG_FILES="$CONFIG_FILES lib/thin/Makefile" ;; "libdaemon/Makefile") CONFIG_FILES="$CONFIG_FILES libdaemon/Makefile" ;; "libdaemon/client/Makefile") CONFIG_FILES="$CONFIG_FILES libdaemon/client/Makefile" ;; "libdaemon/server/Makefile") CONFIG_FILES="$CONFIG_FILES libdaemon/server/Makefile" ;; "libdm/Makefile") CONFIG_FILES="$CONFIG_FILES libdm/Makefile" ;; "libdm/libdevmapper.pc") CONFIG_FILES="$CONFIG_FILES libdm/libdevmapper.pc" ;; "liblvm/Makefile") CONFIG_FILES="$CONFIG_FILES liblvm/Makefile" ;; "liblvm/liblvm2app.pc") CONFIG_FILES="$CONFIG_FILES liblvm/liblvm2app.pc" ;; "man/Makefile") CONFIG_FILES="$CONFIG_FILES man/Makefile" ;; "po/Makefile") CONFIG_FILES="$CONFIG_FILES po/Makefile" ;; "python/Makefile") CONFIG_FILES="$CONFIG_FILES python/Makefile" ;; "python/setup.py") CONFIG_FILES="$CONFIG_FILES python/setup.py" ;; "scripts/blkdeactivate.sh") CONFIG_FILES="$CONFIG_FILES scripts/blkdeactivate.sh" ;; "scripts/blk_availability_init_red_hat") CONFIG_FILES="$CONFIG_FILES scripts/blk_availability_init_red_hat" ;; "scripts/blk_availability_systemd_red_hat.service") CONFIG_FILES="$CONFIG_FILES scripts/blk_availability_systemd_red_hat.service" ;; "scripts/clvmd_init_red_hat") CONFIG_FILES="$CONFIG_FILES scripts/clvmd_init_red_hat" ;; "scripts/cmirrord_init_red_hat") CONFIG_FILES="$CONFIG_FILES scripts/cmirrord_init_red_hat" ;; "scripts/lvm2_lvmetad_init_red_hat") CONFIG_FILES="$CONFIG_FILES scripts/lvm2_lvmetad_init_red_hat" ;; "scripts/lvm2_lvmetad_systemd_red_hat.socket") CONFIG_FILES="$CONFIG_FILES scripts/lvm2_lvmetad_systemd_red_hat.socket" ;; "scripts/lvm2_lvmetad_systemd_red_hat.service") CONFIG_FILES="$CONFIG_FILES scripts/lvm2_lvmetad_systemd_red_hat.service" ;; "scripts/lvm2_monitoring_init_red_hat") CONFIG_FILES="$CONFIG_FILES scripts/lvm2_monitoring_init_red_hat" ;; "scripts/dm_event_systemd_red_hat.socket") CONFIG_FILES="$CONFIG_FILES scripts/dm_event_systemd_red_hat.socket" ;; "scripts/dm_event_systemd_red_hat.service") CONFIG_FILES="$CONFIG_FILES scripts/dm_event_systemd_red_hat.service" ;; "scripts/lvm2_monitoring_systemd_red_hat.service") CONFIG_FILES="$CONFIG_FILES scripts/lvm2_monitoring_systemd_red_hat.service" ;; "scripts/lvm2_tmpfiles_red_hat.conf") CONFIG_FILES="$CONFIG_FILES scripts/lvm2_tmpfiles_red_hat.conf" ;; "scripts/Makefile") CONFIG_FILES="$CONFIG_FILES scripts/Makefile" ;; "test/Makefile") CONFIG_FILES="$CONFIG_FILES test/Makefile" ;; "test/api/Makefile") CONFIG_FILES="$CONFIG_FILES test/api/Makefile" ;; "test/unit/Makefile") CONFIG_FILES="$CONFIG_FILES test/unit/Makefile" ;; "tools/Makefile") CONFIG_FILES="$CONFIG_FILES tools/Makefile" ;; "udev/Makefile") CONFIG_FILES="$CONFIG_FILES udev/Makefile" ;; "unit-tests/datastruct/Makefile") CONFIG_FILES="$CONFIG_FILES unit-tests/datastruct/Makefile" ;; "unit-tests/regex/Makefile") CONFIG_FILES="$CONFIG_FILES unit-tests/regex/Makefile" ;; "unit-tests/mm/Makefile") CONFIG_FILES="$CONFIG_FILES unit-tests/mm/Makefile" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= trap 'exit_status=$? { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_t=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_t"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS " shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac ac_MKDIR_P=$MKDIR_P case $MKDIR_P in [\\/$]* | ?:[\\/]* ) ;; */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t s&@MKDIR_P@&$ac_MKDIR_P&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$tmp/stdin" case $ac_file in -) cat "$tmp/out" && rm -f "$tmp/out";; *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" } >"$tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi if test x$ODIRECT != xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Warning: O_DIRECT disabled: low-memory pvmove may lock up" >&5 $as_echo "$as_me: WARNING: Warning: O_DIRECT disabled: low-memory pvmove may lock up" >&2;} fi lvm2-2.02.98/COPYING0000640000175000017500000004311012037016272012542 0ustar blankblank 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. Copyright (C) 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. , 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. lvm2-2.02.98/man/0000750000175000017500000000000012037016272012262 5ustar blankblanklvm2-2.02.98/man/clvmd.8.in0000640000175000017500000000757012037016272014077 0ustar blankblank.TH CLVMD 8 "LVM TOOLS #VERSION#" "Red Hat Inc" \" -*- nroff -*- .SH NAME clvmd \- cluster LVM daemon .SH SYNOPSIS .B clvmd .RB [ \-d .RI [< value >] .RB [ \-C ]] .RB [ \-E .RI < "lock uuid" >] .RB [ \-f ] .RB [ \-h ] .RB [ \-I .IR "cluster_manager" ] .RB [ \-R ] .RB [ \-S ] .RB [ \-t .RI < timeout >] .RB [ \-T .RI < "start timeout" >] .RB [ \-V ] .SH DESCRIPTION clvmd is the daemon that distributes LVM metadata updates around a cluster. It must be running on all nodes in the cluster and will give an error if a node in the cluster does not have this daemon running. .SH OPTIONS .TP .BR \-d [< \fIvalue >] Enable debug logging. Value can be 0, 1 or 2. .br 0 disables debug logging .br 1 sends debug logs to stderr (implies \fB\-f\fP option) .br 2 sends debug logs to syslog .br If .B \-d is specified without a value then 1 is assumed. .TP .B \-C Only valid if .B \-d is also specified. Tells all clvmds in a cluster to enable/disable debug logging. Without this switch, only the local clvmd will change its debug level to that given with .B \-d . .br This does not work correctly if specified on the command-line that starts clvmd. If you want to start clvmd .B and enable cluster-wide logging then the command needs to be issued twice, eg: .br .B clvmd .br .B clvmd -d2 .br .TP .BR \-E < "\fIlock uuid" > Pass lock uuid to be reacquired exclusively when clvmd is restarted. .TP .B \-f Don't fork, run in the foreground. .TP .B \-h Show help information. .TP .B \-I \fIcluster manager Selects the cluster manager to use for locking and internal communications, the available managers will be listed as part of the \fBclvmd -h\fP output. clvmd will use the first cluster manager that succeeds, and it checks them in the order cman,corosync,openais. As it is quite possible to have (eg) corosync and cman available on the same system you might have to manually specify this option to override the search. .TP .B \-R Tells all the running clvmds in the cluster to reload their device cache and re-read the lvm configuration file. This command should be run whenever the devices on a cluster system are changed. .TP .B \-S Tells the running clvmd to exit and reexecute itself, for example at the end of a package upgrade. The new instance is instructed to reacquire any locks in the same state as they were previously held. (Alternative methods of restarting the daemon have the side effect of changing exclusive LV locks into shared locks.) .TP .BR \-t < \fItimeout > Specifies the timeout for commands to run around the cluster. This should not be so small that commands with many disk updates to do will fail, so you may need to increase this on systems with very large disk farms. The default is 30 seconds. .TP .BR \-T < "\fIstart timeout" > Specifies the timeout for clvmd daemon startup. If the daemon does not report that it has started up within this time then the parent command will exit with status of 5. This does NOT mean that clvmd has not started! What it means is that the startup of clvmd has been delayed for some reason; the most likely cause of this is an inquorate cluster though it could be due to locking latencies on a cluster with large numbers of logical volumes. If you get the return code of 5 it is usually not necessary to restart clvmd - it will start as soon as that blockage has cleared. This flag is to allow startup scripts to exit in a timely fashion even if the cluster is stalled for some reason. .br The default is 0 (no timeout) and the value is in seconds. Don't set this too small or you will experience spurious errors. 10 or 20 seconds might be sensible. .br This timeout will be ignored if you start clvmd with the -d switch. .TP .B \-V Display the version of the cluster LVM daemon. .SH ENVIRONMENT VARIABLES .TP .B LVM_CLVMD_BINARY The CLVMD binary to use when clmvd restart is requested. Defaults to #CLVMD_PATH#. .TP .B LVM_BINARY The LVM2 binary to use. Defaults to #LVM_PATH#. .SH SEE ALSO .BR lvm (8) lvm2-2.02.98/man/vgexport.8.in0000640000175000017500000000136712037016272014646 0ustar blankblank.TH VGEXPORT 8 "LVM TOOLS #VERSION#" "Sistina Software UK" \" -*- nroff -*- .SH NAME vgexport \- make volume groups unknown to the system .SH SYNOPSIS .B vgexport .RB [ \-a | \-\-all ] .RB [ \-d | \-\-debug ] .RB [ \-h | \-? | \-\-help ] .RB [ \-v | \-\-verbose ] .I VolumeGroupName .RI [ VolumeGroupName ...] .SH DESCRIPTION vgexport allows you to make the inactive .IR VolumeGroupName (s) unknown to the system. You can then move all the Physical Volumes in that Volume Group to a different system for later .BR vgimport (8). Most LVM2 tools ignore exported Volume Groups. .SH OPTIONS See \fBlvm\fP(8) for common options. .TP .BR \-a ", " \-\-all Export all inactive Volume Groups. .SH SEE ALSO .BR lvm (8), .BR pvscan (8), .BR vgimport (8), .BR vgscan (8) lvm2-2.02.98/man/vgrename.8.in0000640000175000017500000000301212037016272014561 0ustar blankblank.TH VGRENAME 8 "LVM TOOLS #VERSION#" "Sistina Software UK" \" -*- nroff -*- .SH NAME vgrename \- rename a volume group .SH SYNOPSIS .B vgrename .RB [ \-A | \-\-autobackup .RI { y | n }] .RB [ \-d | \-\-debug ] .RB [ \-h | \-? | \-\-help ] .RB [ \-t | \-\-test ] .RB [ \-v | \-\-verbose ] .IR OldVolumeGroup { Path | Name | UUID } .IR NewVolumeGroup { Path | Name } .SH DESCRIPTION vgrename renames an existing (see .BR vgcreate (8)) volume group from .IR OldVolumeGroup { Name | Path | UUID } to .IR NewVolumeGroup { Name | Path }. All the Volume Groups visible to a system need to have different names. Otherwise many LVM2 commands will refuse to run or give warning messages. This situation could arise when disks are moved between machines. If a disk is connected and it contains a Volume Group with the same name as the Volume Group containing your root filesystem the machine might not even boot correctly. However, the two Volume Groups should have different UUIDs (unless the disk was cloned) so you can rename one of the conflicting Volume Groups with \fBvgrename\fP. .SH OPTIONS See \fBlvm\fP(8) for common options. .SH Examples Renames existing volume group vg02 to my_volume_group: .sp .B vgrename /dev/vg02 /dev/my_volume_group or .sp .B vgrename vg02 my_volume_group Changes the name of the Volume Group with UUID .br Zvlifi-Ep3t-e0Ng-U42h-o0ye-KHu1-nl7Ns4 to VolGroup00_tmp: .sp .B vgrename Zvlifi-Ep3t-e0Ng-U42h-o0ye-KHu1-nl7Ns4 VolGroup00_tmp .SH SEE ALSO .BR lvm (8), .BR vgchange (8), .BR vgcreate (8), .BR lvrename (8) lvm2-2.02.98/man/vgmknodes.8.in0000640000175000017500000000152312037016272014757 0ustar blankblank.TH VGMKNODES 8 "LVM TOOLS #VERSION#" "Sistina Software UK" \" -*- nroff -*- .SH NAME vgmknodes \- recreate volume group directory and logical volume special files .SH SYNOPSIS .B vgmknodes .RB [ \-d | \-\-debug ] .RB [ \-h | \-\-help ] .RB [ \-\-refresh ] .RB [ \-v | \-\-verbose ] .RI [[ VolumeGroupName | LogicalVolumePath ]...] .SH DESCRIPTION Checks the LVM2 special files in /dev that are needed for active logical volumes and creates any missing ones and removes unused ones. .SH OPTIONS .TP See \fBlvm\fP(8) for common options. .TP .BR \-\-refresh If any logical volume in the volume group is active, reload its metadata. This is not necessary in normal operation, but may be useful if something has gone wrong or if you're doing clustering manually without a clustered lock manager. .SH SEE ALSO .BR lvm (8), .BR vgscan (8), .BR dmsetup (8) lvm2-2.02.98/man/blkdeactivate.8.in0000640000175000017500000000457212037016272015573 0ustar blankblank.TH "BLKDEACTIVATE" "8" "LVM TOOLS #VERSION#" "Red Hat, Inc" "\"" .SH "NAME" blkdeactivate \- utility to deactivate block devices .SH SYNOPSIS .B blkdeactivate .RI [ options ] .RI [ device... ] .sp .SH DESCRIPTION blkdeactivate utility deactivates block devices. If a device is mounted, the utility can unmount it automatically before trying to deactivate. The utility currently supports \fIdevice-mapper\fP devices, including \fILVM\fP volumes. LVM volumes are handled directly using the \fIlvm\fP command. Other device-mapper based devices are handled using the \fIdmsetup\fP command. .SH OPTIONS .IP "\fB\-h, \-\-help\fP" Display the help text. .IP "\fB\-u, \-\-umount\fP" Unmount a mounted device before trying to deactivate it. Without this option used, a device that is mounted is not deactivated. .IP "\fB\-d, \-\-dmoption\fP \fIdm_options\fP" Comma separated list of device-mapper specific options. .IP "\fB\-l, \-\-lvmoption\fP \fIlvm_options\fP" Comma separated list of LVM specific options. .SH DM_OPTIONS .IP "\fBretry\fP" Retry removal several times in case of failure. .IP "\fBforce\fP" Force device removal. See \fBdmsetup\fP(8) for more information. .SH LVM_OPTIONS .IP "\fBretry\fP" Retry removal several times in case of failure. .IP "\fBwholevg\fP" Deactivate the whole LVM Volume Group when processing a Logical Volume. Deactivating Volume Group as a whole takes less time than deactivating each Logical Volume separately. .SH EXAMPLES .sp Deactivate all supported block devices found in the system. If a device is mounted, skip its deactivation. .sp .B blkdeactivate Deactivate all supported block devices found in the system. If a device is mounted, unmount it first if possible. .sp .B blkdeactivate \-u Deactivate supplied device together with all its holders. If any of the devices processed is mounted, unmount it first if possible. .sp .B blkdeactivate \-u /dev/vg/lvol0 Deactivate all supported block devices found in the system. Retry deactivation of device-mapper devices in case the deactivation fails. Deactivate the whole Volume Group at once when processing an LVM Logical Volume. .sp .B blkdeactivate \-u -d retry -l wholevg Deactivate all supported block devices found in the system. Retry deactivation of device-mapper devices in case the deactivation fails and force removal. .sp .B blkdeactivate -d force,retry .SH SEE ALSO .BR lsblk (8) .BR umount (8) .BR dmsetup (8) .BR lvm (8) lvm2-2.02.98/man/fsadm.8.in0000640000175000017500000000376012037016272014061 0ustar blankblank.TH "FSADM" "8" "LVM TOOLS #VERSION#" "Red Hat, Inc" "\"" .SH "NAME" fsadm \- utility to resize or check filesystem on a device .SH SYNOPSIS .B fsadm .RI [ options ] .B check .I device .sp .B fsadm .RI [ options ] .B resize .I device .RI [ new_size [ BKMGTEP ]] .sp .SH DESCRIPTION fsadm utility checks or resizes the filesystem on a device. It tries to use the same API for .IR ext2 ", " ext3 ", " ext4 ", " ReiserFS " and " XFS filesystem. .SH OPTIONS .TP .BR \-e ", " \-\-ext\-offline Unmount ext2/ext3/ext4 filesystem before doing resize. .TP .BR \-f ", " \-\-force Bypass some sanity checks. .TP .BR \-h ", " \-\-help Display the help text. .TP .BR \-n ", " \-\-dry\-run Print commands without running them. .TP .BR \-v ", " \-\-verbose Be more verbose. .TP .BR \-y ", " \-\-yes Answer "yes" at any prompts. .TP .I new_size Absolute number of filesystem blocks to be in the filesystem, or an absolute size using a suffix (in powers of 1024). If new_size is not supplied, the whole device is used. .SH DIAGNOSTICS On successful completion, the status code is 0. A status code of 2 indicates the operation was interrupted by the user. A status code of 3 indicates the requested check operation could not be performed because the filesystem is mounted and does not support an online .BR fsck (8). A status code of 1 is used for other failures. .SH EXAMPLES Resize the filesystem on logical volume /dev/vg/test to 1000 megabytes. If /dev/vg/test contains ext2/ext3/ext4 filesystem it will be unmounted prior the resize. All [y|n] questions will be answered 'y'. .sp .B fsadm \-e \-y resize /dev/vg/test 1000M .SH ENVIRONMENT VARIABLES .TP .B TMPDIR The temporary directory name for mount points. Defaults to "/tmp". .TP .B DM_DEV_DIR The device directory name. Defaults to "/dev" and must be an absolute path. .SH SEE ALSO .BR lvm (8), .BR lvresize (8), .BR lvm.conf (5), .BR fsck (8), .BR tune2fs (8), .BR resize2fs (8), .BR reiserfstune (8), .BR resize_reiserfs (8), .BR xfs_info (8), .BR xfs_growfs (8), .BR xfs_check (8) lvm2-2.02.98/man/lvmdiskscan.8.in0000640000175000017500000000136612037016272015305 0ustar blankblank.TH LVMDISKSCAN 8 "LVM TOOLS #VERSION#" "Sistina Software UK" \" -*- nroff -*- .SH NAME lvmdiskscan \- scan for all devices visible to LVM2 .SH SYNOPSIS .B lvmdiskscan .RB [ \-d | \-\-debug ] .RB [ \-h | \-? | \-\-help ] .RB [ \-l | \-\-lvmpartition ] .RB [ \-v | \-\-verbose ] .SH DESCRIPTION lvmdiskscan scans all SCSI, (E)IDE disks, multiple devices and a bunch of other block devices in the system looking for LVM physical volumes. The size reported is the real device size. Define a filter in \fBlvm.conf\fP(5) to restrict the scan to avoid a CD ROM, for example. .SH OPTIONS See \fBlvm\fP(8) for common options. .TP .BR \-l ", " \-\-lvmpartition Only reports Physical Volumes. .SH SEE ALSO .BR lvm (8), .BR lvm.conf (5), .BR pvscan (8), .BR vgscan (8) lvm2-2.02.98/man/vgchange.8.in0000640000175000017500000002027712037016272014553 0ustar blankblank.TH VGCHANGE 8 "LVM TOOLS #VERSION#" "Sistina Software UK" \" -*- nroff -*- .SH NAME vgchange \- change attributes of a volume group .SH SYNOPSIS .B vgchange .RB [ \-\-addtag .IR Tag ] .RB [ \-\-alloc .IR AllocationPolicy ] .RB [ \-A | \-\-autobackup .RI { y | n }] .RB [ \-a | \-\-activate .RI [ a | e | l ] .RI { y | n }] .RB [ \-\-monitor .RI { y | n }] .RB [ \-\-poll .RI { y | n }] .RB [ \-c | \-\-clustered .RI { y | n }] .RB [ \-u | \-\-uuid ] .RB [ \-d | \-\-debug ] .RB [ \-\-deltag .IR Tag ] .RB [ \-h | \-\-help ] .RB [ \-\-ignorelockingfailure ] .RB [ \-\-ignoremonitoring ] .RB [ \-\-sysinit ] .RB [ \-\-noudevsync ] .RB [ \-l | \-\-logicalvolume .IR MaxLogicalVolumes ] .RB [ -p | \-\-maxphysicalvolumes .IR MaxPhysicalVolumes ] .RB [ \-\- [ vg ] metadatacopies ] .IR NumberOfCopies | unmanaged | all ] .RB [ \-P | \-\-partial ] .RB [ \-s | \-\-physicalextentsize .IR PhysicalExtentSize [ bBsSkKmMgGtTpPeE ]] .RB [ \-\-refresh ] .RB [ -t | \-\-test ] .RB [ \-v | \-\-verbose ] .RB [ \-\-version ] .RB [ \-x | \-\-resizeable .RI { y | n }] .RI [ VolumeGroupName ...] .SH DESCRIPTION vgchange allows you to change the attributes of one or more volume groups. Its main purpose is to activate and deactivate .IR VolumeGroupName , or all volume groups if none is specified. Only active volume groups are subject to changes and allow access to their logical volumes. [Not yet implemented: During volume group activation, if .B vgchange recognizes snapshot logical volumes which were dropped because they ran out of space, it displays a message informing the administrator that such snapshots should be removed (see .BR lvremove (8)). ] .SH OPTIONS See \fBlvm\fP(8) for common options. .TP .BR \-A ", " \-\-autobackup " {" \fIy | \fIn } Controls automatic backup of metadata after the change. See .BR vgcfgbackup (8). Default is yes. .TP .BR \-a ", " \-\-activate " [" \fIa | \fIe | \fIl ]{ \fIy | \fIn } Controls the availability of the logical volumes in the volume group for input/output. In other words, makes the logical volumes known/unknown to the kernel. If autoactivation option is used (\-aay), each logical volume in the volume group is activated only if it matches an item in the activation/auto_activation_volume_list set in lvm.conf. Autoactivation is not yet supported for partial or clustered volume groups. .IP If clustered locking is enabled, add 'e' to activate/deactivate exclusively on one node or 'l' to activate/deactivate only on the local node. Logical volumes with single-host snapshots are always activated exclusively because they can only be used on one node at once. .TP .BR \-c ", " \-\-clustered " {" \fIy | \fIn } If clustered locking is enabled, this indicates whether this Volume Group is shared with other nodes in the cluster or whether it contains only local disks that are not visible on the other nodes. If the cluster infrastructure is unavailable on a particular node at a particular time, you may still be able to use Volume Groups that are not marked as clustered. .TP .BR \-u ", " \-\-uuid Generate new random UUID for specified Volume Groups. .TP .BR \-\-monitor " {" \fIy | \fIn } Start or stop monitoring a mirrored or snapshot logical volume with dmeventd, if it is installed. If a device used by a monitored mirror reports an I/O error, the failure is handled according to .B mirror_image_fault_policy and .B mirror_log_fault_policy set in .BR lvm.conf (5). .TP .BR \-\-poll " {" \fIy | \fIn } Without polling a logical volume's backgrounded transformation process will never complete. If there is an incomplete pvmove or lvconvert (for example, on rebooting after a crash), use \fB\-\-poll y\fP to restart the process from its last checkpoint. However, it may not be appropriate to immediately poll a logical volume when it is activated, use \fB\-\-poll n\fP to defer and then \fB\-\-poll y\fP to restart the process. .TP .BR \-\-sysinit Indicates that vgchange(8) is being invoked from early system initialisation scripts (e.g. rc.sysinit or an initrd), before writeable filesystems are available. As such, some functionality needs to be disabled and this option acts as a shortcut which selects an appropriate set of options. Currently this is equivalent to using .BR \-\-ignorelockingfailure , .BR \-\-ignoremonitoring , .B \-\-poll n and setting \fBLVM_SUPPRESS_LOCKING_FAILURE_MESSAGES\fP environment variable. If \fB\-\-sysinit\fP is used in conjunction with lvmetad(8) enabled and running, autoactivation is preferred over manual activation via direct vgchange call. Logical volumes are autoactivated according to auto_activation_volume_list set in lvm.conf(5). .TP .BR \-\-noudevsync Disable udev synchronisation. The process will not wait for notification from udev. It 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. .TP .BR \-\-ignoremonitoring Make no attempt to interact with dmeventd unless .BR \-\-monitor is specified. Do not use this if dmeventd is already monitoring a device. .TP .BR \-l ", " \-\-logicalvolume " " \fIMaxLogicalVolumes Changes the maximum logical volume number of an existing inactive volume group. .TP .BR \-p ", " \-\-maxphysicalvolumes " " \fIMaxPhysicalVolumes Changes the maximum number of physical volumes that can belong to this volume group. For volume groups with metadata in lvm1 format, the limit is 255. If the metadata uses lvm2 format, the value 0 removes this restriction: there is then no limit. If you have a large number of physical volumes in a volume group with metadata in lvm2 format, for tool performance reasons, you should consider some use of \fB--pvmetadatacopies 0\fP as described in \fBpvcreate(8)\fP, and/or use \fB--vgmetadatacopies\fP. .TP .BR \-\- [ vg ] metadatacopies " " \fINumberOfCopies | \fIunmanaged | \fIall Sets the desired number of metadata copies in the volume group. If set to a non-zero value, LVM will automatically manage the 'metadataignore' flags on the physical volumes (see \fBpvchange\fP or \fBpvcreate --metadataignore\fP) in order to achieve \fINumberOfCopies\fP copies of metadata. If set to \fIunmanaged\fP, LVM will not automatically manage the 'metadataignore' flags. If set to \fIall\fP, LVM will first clear all of the 'metadataignore' flags on all metadata areas in the volume group, then set the value to \fIunmanaged\fP. The \fBvgmetadatacopies\fP option is useful for volume groups containing large numbers of physical volumes with metadata as it may be used to minimize metadata read and write overhead. .TP .BR \-s ", " \-\-physicalextentsize " " \fIPhysicalExtentSize [ \fIBbBsSkKmMgGtTpPeE ] Changes the physical extent size on physical volumes of this volume group. A size suffix (k for kilobytes up to t for terabytes) is optional, megabytes is the default if no suffix is present. The default is 4 MiB and it must be at least 1 KiB and a power of 2. Before increasing the physical extent size, you might need to use lvresize, pvresize and/or pvmove so that everything fits. For example, every contiguous range of extents used in a logical volume must start and end on an extent boundary. If the volume group metadata uses lvm1 format, extents can vary in size from 8KiB to 16GiB and there is a limit of 65534 extents in each logical volume. The default of 4 MiB leads to a maximum logical volume size of around 256GiB. If the volume group metadata uses lvm2 format those restrictions do not apply, but having a large number of extents will slow down the tools but have no impact on I/O performance to the logical volume. The smallest PE is 1KiB. The 2.4 kernel has a limitation of 2TiB per block device. .TP .BR \-\-refresh If any logical volume in the volume group is active, reload its metadata. This is not necessary in normal operation, but may be useful if something has gone wrong or if you're doing clustering manually without a clustered lock manager. .TP .BR \-x ", " \-\-resizeable " {" \fIy | \fIn } Enables or disables the extension/reduction of this volume group with/by physical volumes. .SH Examples To activate all known volume groups in the system: .sp .B vgchange -a y To change the maximum number of logical volumes of inactive volume group vg00 to 128. .sp .B vgchange -l 128 /dev/vg00 .SH SEE ALSO .BR lvchange (8), .BR lvm (8), .BR vgcreate (8) lvm2-2.02.98/man/dmsetup.8.in0000640000175000017500000004502212037016272014445 0ustar blankblank.TH DMSETUP 8 "Apr 06 2006" "Linux" "MAINTENANCE COMMANDS" .SH NAME dmsetup \- low level logical volume management .SH SYNOPSIS .ad l .B dmsetup clear .I device_name .br .B dmsetup create .I device_name .RB [ \-u .IR uuid ] .RB [ \-\-notable | \-\-table .RI < table >| .RS .IR table_file ] .RB [{ \-\-addnodeoncreate | \-\-addnodeonresume }] .RB [ \-\-readahead .RI [ \+ ]< sectors >| auto | none ] .RE .br .B dmsetup deps .RB [ \-o .IR options ] .RI [ device_name ] .br .B dmsetup help .RB [ \-c | \-C | \-\-columns ] .br .B dmsetup info .RI [ device_name ] .br .B dmsetup info .BR \-c | \-C | \-\-columns .RB [ \-\-noheadings ] .RB [ \-\-separator .IR separator ] .RS .RB [ \-o .IR fields ] .RB [ \-O | \-\-sort .IR sort_fields ] .RI [ device_name ] .RE .br .B dmsetup load .I device_name .RB [ \-\-table .RI < table >| table_file ] .br .B dmsetup ls .RB [ \-\-target .IR target_type ] .RB [ \-\-exec .IR command ] .RB [ \-\-tree ] .RB [ \-o .IR options ] .RE .br .B dmsetup message .I device_name sector message .br .B dmsetup mknodes .RI [ device_name ] .br .B dmsetup mangle .RI [ device_name ] .br .B dmsetup reload .I device_name .RB [ \-\-table .RI < table >| table_file ] .br .B dmsetup wipe_table .I device_name .br .B dmsetup remove .RB [ \-f | \-\-force ] .RB [ \-\-retry ] .I device_name .br .B dmsetup remove_all .RB [ \-f | \-\-force ] .br .B dmsetup rename .I device_name new_name .br .B dmsetup rename .I device_name .B \-\-setuuid .I uuid .br .B dmsetup resume .I device_name .RB [{ \-\-addnodeoncreate | \-\-addnodeonresume }] .RS .RB [ \-\-readahead .RI [ \+ ]< sectors >| auto | none ] .RE .br .B dmsetup setgeometry .I device_name cyl head sect start .br .B dmsetup splitname .I device_name .RI [ subsystem ] .br .B dmsetup status .RB [ \-\-target .IR target_type ] .RB [ \-\-noflush ] .RI [ device_name ] .br .B dmsetup suspend .RB [ \-\-nolockfs ] .RB [ \-\-noflush ] .I device_name .br .B dmsetup table .RB [ \-\-target .IR target_type ] .RB [ \-\-showkeys ] .RI [ device_name ] .br .B dmsetup targets .br .B dmsetup udevcomplete .I cookie .br .B dmsetup udevcomplete_all .RI [ age_in_minutes ] .br .B dmsetup udevcookies .br .B dmsetup udevcreatecookie .br .B dmsetup udevflags .I cookie .br .B dmsetup udevreleasecookie .RI [ cookie ] .br .B dmsetup version .br .B dmsetup wait .RB [ \-\-noflush ] .I device_name .RI [ event_nr ] .br .B devmap_name .I major minor .br .B devmap_name .I major:minor .ad b .SH DESCRIPTION dmsetup manages logical devices that use the device-mapper driver. Devices are created by loading a table that specifies a target for each sector (512 bytes) in the logical device. The first argument to dmsetup is a command. The second argument is the logical device name or uuid. Invoking the command as \fBdevmap_name\fP is equivalent to .br \fBdmsetup info \-c \-\-noheadings \-j \fImajor\fB \-m \fIminor\fP. .SH OPTIONS .TP .B \-\-addnodeoncreate Ensure /dev/mapper node exists after dmsetup create. .TP .B \-\-addnodeonresume Ensure /dev/mapper node exists after dmsetup resume (default with udev). .TP .B \-\-checks Perform additional checks on the operations requested and report potential problems. Useful when debugging scripts. In some cases these checks may slow down operations noticeably. .TP .BR \-c | \-C | \-\-columns Display output in columns rather than as Field: Value lines. .TP .BR \-h | \-\-help Outputs a summary of the commands available, optionally including the list of report fields (synonym with \fBhelp\fP command). .TP .B \-\-inactive When returning any table information from the kernel report on the inactive table instead of the live table. Requires kernel driver version 4.16.0 or above. .TP .IR \fB\-\-manglename \ < mangling_mode > Mangle any character not on a whitelist using mangling_mode when processing device-mapper device names and UUIDs. The names and UUIDs are mangled on input and unmangled on output where the mangling_mode is one of: none (no mangling), hex (always do the mangling) and auto (only do the mangling if not mangled yet, do nothing if already mangled, error on mixed; this is used by default). Character whitelist: 0-9, A-Z, a-z, #+-.:=@_. This whitelist is also supported by udev. Any character not on a whitelist is replaced with its hex value (two digits) prefixed by \\x. .TP .BR \-j | \-\-major\ \fImajor Specify the major number. .TP .BR \-m | \-\-minor\ \fIminor Specify the minor number. .TP .BR \-n | \-\-noheadings Suppress the headings line when using columnar output. .TP .B \-\-noopencount Tell the kernel not to supply the open reference count for the device. .TP .B \-\-notable When creating a device, don't load any table. .TP .B \-\-noudevrules Do not allow udev to manage nodes for devices in device-mapper directory. .TP .B \-\-noudevsync Do not synchronise with udev when creating, renaming or removing devices. .TP .BR \-o | \-\-options Specify which fields to display. .TP .IR \fB\-\-readahead \ [ \+ ]< sectors >| auto | none Specify read ahead size in units of sectors. The default value is \fIauto\fP which allows the kernel to choose a suitable value automatically. The \fI\+\fP prefix lets you specify a minimum value which will not be used if it is smaller than the value chosen by the kernel. The value \fInone\fP is equivalent to specifying zero. .TP .BR \-r | \-\-readonly Set the table being loaded read-only. .TP .IR \fB\-\-table \ < table > Specify a one-line table directly on the command line. .TP .B \-\-udevcookie \fIcookie Use cookie for udev synchronisation. .TP .BR \-u | \-\-uuid Specify the uuid. .TP .BR \-y | \-\-yes Answer yes to all prompts automatically. .TP .BR \-v | \-\-verbose \ [ \-v | \-\-verbose ] Produce additional output. .TP .B \-\-verifyudev If udev synchronisation is enabled, verify that udev operations get performed correctly and try to fix up the device nodes afterwards if not. .TP .B \-\-version Display the library and kernel driver version. .br .SH COMMANDS .TP .B clear .I device_name .br Destroys the table in the inactive table slot for device_name. .br .TP .B create .I device_name .RB [ \-u .IR uuid ] .RB [ \-\-notable | \-\-table .RI < \fItable >| table_file ] .RB [{ \-\-addnodeoncreate | \-\-addnodeonresume }] .RB [ \-\-readahead .RI [ + ]< sectors >| auto | none ] .br Creates a device with the given name. If table_file or is supplied, the table is loaded and made live. Otherwise a table is read from standard input unless \-\-notable is used. The optional uuid can be used in place of device_name in subsequent dmsetup commands. If successful a device will appear as /dev/mapper/. See below for information on the table format. .br .TP .B deps .RB [ \-o .IR options ] .RI [ device_name ] .br Outputs a list of devices referenced by the live table for the specified device. Device names on output can be customised by following options: devno (major and minor pair, used by default), blkdevname (block device name), devname (map name for device-mapper devices, equal to blkdevname otherwise). .br .TP .B help .RB [ \-c | \-C | \-\-columns ] .br Outputs a summary of the commands available, optionally including the list of report fields. .br .TP .B info .RI [ device_name ] .br Outputs some brief information about the device in the form: .RS .RS State: SUSPENDED|ACTIVE, READ-ONLY Tables present: LIVE and/or INACTIVE Open reference count Last event sequence number (used by \fBwait\fP) Major and minor device number Number of targets in the live table UUID .RE .RE .br .TP .B info .BR \-c | \-C | \-\-columns .RB [ \-\-noheadings ] .RB [ \-\-separator .IR separator ] .RB [ \-o .IR fields ] .RB [ \-O | \-\-sort .IR sort_fields ] .RI [ device_name ] .br Output you can customise. Fields are comma-separated and chosen from the following list: name, major, minor, attr, open, segments, events, uuid. Attributes are: (L)ive, (I)nactive, (s)uspended, (r)ead-only, read-(w)rite. Precede the list with '+' to append to the default selection of columns instead of replacing it. Precede any sort_field with - for a reverse sort on that column. .br .TP .B ls .RB [ \-\-target .IR target_type ] .RB [ \-\-exec .IR command ] .RB [ \-\-tree ] .RB [ \-o .IR options ] .br List device names. Optionally only list devices that have at least one target of the specified type. Optionally execute a command for each device. The device name is appended to the supplied command. Device names on output can be customised by following options: devno (major and minor pair, used by default), blkdevname (block device name), devname (map name for device-mapper devices, equal to blkdevname otherwise). --tree displays dependencies between devices as a tree. It accepts a comma-separate list of options. Some specify the information displayed against each node: device/nodevice; blkdevname; active, open, rw, uuid. Others specify how the tree is displayed: ascii, utf, vt100; compact, inverted, notrunc. .br .HP .BR load | reload .I device_name .RB [ \-\-table .RI < table >| table_file ] .br Loads
or table_file into the inactive table slot for device_name. If neither is supplied, reads a table from standard input. .br .HP .B wipe_table .I device_name .br Wait for any I/O in-flight through the device to complete, then replace the table with a new table that fails any new I/O sent to the device. If successful, this should release any devices held open by the device's table(s). .br .HP .B message .I device_name sector message .br Send message to target. If sector not needed use 0. .br .HP .B mknodes .RI [ device_name ] .br Ensure that the node in /dev/mapper for device_name is correct. If no device_name is supplied, ensure that all nodes in /dev/mapper correspond to mapped devices currently loaded by the device-mapper kernel driver, adding, changing or removing nodes as necessary. .br .HP .B mangle .RI [ device_name ] .br Ensure existing device-mapper device name and UUID is in the correct mangled form containing only whitelisted characters (supported by udev) and do a rename if necessary. Any character not on the whitelist will be mangled based on the --manglename setting. Automatic rename works only for device names and not for device UUIDs because the kernel does not allow changing the UUID of active devices. Any incorrect UUIDs are reported only and they must be manually corrected by deactivating the device first and then reactivating it with proper mangling mode used (see also --manglename). .br .HP .B remove .RB [ \-f | \-\-force ] .RB [ \-\-retry ] .I device_name .br Removes a device. It will no longer be visible to dmsetup. Open devices cannot be removed except with older kernels that contain a version of device-mapper prior to 4.8.0. In this case the device will be deleted when its open_count drops to zero. From version 4.8.0 onwards, if a device can't be removed because an uninterruptible process is waiting for I/O to return from it, adding \-\-force will replace the table with one that fails all I/O, which might allow the process to be killed. If an attempt to remove a device fails, perhaps because a process run from a quick udev rule temporarily opened the device, the \-\-retry option will cause the operation to be retried for a few seconds before failing. .br .HP .B remove_all .RB [ \-f | \-\-force ] .br Attempts to remove all device definitions i.e. reset the driver. Use with care! From version 4.8.0 onwards, if devices can't be removed because uninterruptible processes are waiting for I/O to return from them, adding \-\-force will replace the table with one that fails all I/O, which might allow the process to be killed. This also runs \fBmknodes\fP afterwards. .br .HP .B rename .I device_name new_name .br Renames a device. .br .HP .B rename .I device_name .B \-\-setuuid .I uuid .br Sets the uuid of a device that was created without a uuid. After a uuid has been set it cannot be changed. .br .TP .B resume .I device_name .RB [{ \-\-addnodeoncreate | \-\-addnodeonresume }] .RB [ \-\-readahead .RI [ + ]< sectors >| auto | none ] .br Un-suspends a device. If an inactive table has been loaded, it becomes live. Postponed I/O then gets re-queued for processing. .br .TP .B setgeometry \fIdevice_name cyl head sect start .br Sets the device geometry to C/H/S. .br .HP .B splitname .I device_name .RI [ subsystem ] .br Splits given device name into subsystem constituents. Default subsystem is LVM. .br .TP .B status .RB [ \-\-target .IR target_type ] .RB [ \-\-noflush ] .RI [ device_name ] .br Outputs status information for each of the device's targets. With \-\-target, only information relating to the specified target type any is displayed. With \-\-noflush, the thin target (from version 1.3.0) doesn't commit any outstanding changes to disk before reporting its statistics. .br .HP .B suspend .RB [ \-\-nolockfs ] .RB [ \-\-noflush ] .I device_name .br Suspends a device. Any I/O that has already been mapped by the device but has not yet completed will be flushed. Any further I/O to that device will be postponed for as long as the device is suspended. If there's a filesystem on the device which supports the operation, an attempt will be made to sync it first unless \-\-nolockfs is specified. Some targets such as recent (October 2006) versions of multipath may support the \-\-noflush option. This lets outstanding I/O that has not yet reached the device to remain unflushed. .br .TP .B table .RB [ \-\-target .IR target_type ] .RB [ \-\-showkeys ] .RI [ device_name ] .br Outputs the current table for the device in a format that can be fed back in using the create or load commands. With \-\-target, only information relating to the specified target type is displayed. Encryption keys are suppressed in the table output for the crypt target unless the \-\-showkeys parameter is supplied. .br .TP .B targets .br Displays the names and versions of the currently-loaded targets. .br .HP .B udevcomplete .I cookie .br Wake any processes that are waiting for udev to complete processing the specified cookie. .br .HP .B udevcomplete_all .RI [ age_in_minutes ] .br Remove all cookies older than the specified number of minutes. Any process waiting on a cookie will be resumed immediately. .br .HP .B udevcookies .br List all existing cookies. Cookies are system-wide semaphores with keys prefixed by two predefined bytes (0x0D4D). .br .TP .B udevcreatecookie .br Creates a new cookie to synchronize actions with udev processing. The output is a cookie value. Normally we don't need to create cookies since dmsetup creates and destroys them for each action automatically. However, we can generate one explicitly to group several actions together and use only one cookie instead. We can define a cookie to use for each relevant command by using \-\-udevcookie option. Alternatively, we can export this value into the environment of the dmsetup process as DM_UDEV_COOKIE variable and it will be used automatically with all subsequent commands until it is unset. Invoking this command will create system-wide semaphore that needs to be cleaned up explicitly by calling udevreleasecookie command. .br .HP .B udevflags .I cookie .br Parses given cookie value and extracts any udev control flags encoded. The output is in environment key format that is suitable for use in udev rules. If the flag has its symbolic name assigned then the output is DM_UDEV_FLAG_='1', DM_UDEV_FLAG='1' otherwise. Subsystem udev flags don't have symbolic names assigned and these ones are always reported as DM_SUBSYSTEM_UDEV_FLAG='1'. There are 16 udev flags altogether. .br .HP .B udevreleasecookie .RI [ cookie ] .br Waits for all pending udev processing bound to given cookie value and clean up the cookie with underlying semaphore. If the cookie is not given directly, the command will try to use a value defined by DM_UDEV_COOKIE environment variable. .br .TP .B version .br Outputs version information. .TP .B wait .RB [ \-\-noflush ] .I device_name .RI [ event_nr ] .br Sleeps until the event counter for device_name exceeds event_nr. Use \-v to see the event number returned. To wait until the next event is triggered, use \fBinfo\fP to find the last event number. With \-\-noflush, the thin target (from version 1.3.0) doesn't commit any outstanding changes to disk before reporting its statistics. .SH TABLE FORMAT Each line of the table specifies a single target and is of the form: .P .I logical_start_sector num_sectors .B target_type .RI < target_args > .P Simple target types and include: .HP .B linear .I destination_device start_sector .br The traditional linear mapping. .HP .B striped .I num_stripes chunk_size .RI [ destination .IR start_sector ]+ .br Creates a striped area. .br e.g. striped 2 32 /dev/hda1 0 /dev/hdb1 0 will map the first chunk (16k) as follows: .RS .RS LV chunk 1 -> hda1, chunk 1 LV chunk 2 -> hdb1, chunk 1 LV chunk 3 -> hda1, chunk 2 LV chunk 4 -> hdb1, chunk 2 etc. .RE .RE .TP .B error .br Errors any I/O that goes to this area. Useful for testing or for creating devices with holes in them. .TP .B zero .br Returns blocks of zeroes on reads. Any data written is discarded silently. This is a block-device equivalent of the /dev/zero character-device data sink described in \fBnull(4)\fP. .P More complex targets include: .TP .B crypt .br Transparent encryption of block devices using the kernel crypto API. .TP .B delay .br Delays reads and/or writes to different devices. Useful for testing. .TP .B flakey .br Creates a similar mapping to the linear target but exhibits unreliable behaviour periodically. Useful for simulating failing devices when testing. .TP .B mirror .br Mirrors data across two or more devices. .HP .B multipath .br Mediates access through multiple paths to the same device. .TP .BR raid .br Offers an interface to the kernel's software raid driver, md. .HP .B snapshot .br Supports snapshots of devices. .P To find out more about the various targets and their table formats and status lines, please read the files in the Documentation/device-mapper directory in the kernel source tree. (Your distribution might include a copy of this information in the documentation directory for the device-mapper package.) .SH EXAMPLES # A table to join two disks together .br .br 0 1028160 linear /dev/hda 0 .br 1028160 3903762 linear /dev/hdb 0 # A table to stripe across the two disks, .br # and add the spare space from .br # hdb to the back of the volume 0 2056320 striped 2 32 /dev/hda 0 /dev/hdb 0 .br 2056320 2875602 linear /dev/hdb 1028160 .SH ENVIRONMENT VARIABLES .TP .B DM_DEV_DIR The device directory name. Defaults to "/dev" and must be an absolute path. .TP .B DM_UDEV_COOKIE A cookie to use for all relevant commands to synchronize with udev processing. It is an alternative to using \-\-udevcookie option. .SH AUTHORS Original version: Joe Thornber (thornber@sistina.com) .SH SEE ALSO Device-mapper resource page: http://sources.redhat.com/dm/ lvm2-2.02.98/man/lvmsar.8.in0000640000175000017500000000034512037016272014267 0ustar blankblank.TH "LVMSAR" "8" "LVM TOOLS #VERSION#" "Red Hat, Inc" "\"" .SH "NAME" lvmsar \- LVM system activity reporter .SH "SYNOPSIS" .B lvmsar .SH "DESCRIPTION" lvmsar is not currently supported under LVM2. .SH "SEE ALSO" .BR lvm (8) lvm2-2.02.98/man/lvconvert.8.in0000640000175000017500000002540112037016272015005 0ustar blankblank.TH LVCONVERT 8 "LVM TOOLS #VERSION#" "Red Hat, Inc" \" -*- nroff -*- .SH NAME lvconvert \- convert a logical volume from linear to mirror or snapshot .SH SYNOPSIS .B lvconvert .BR \-m | \-\-mirrors .I Mirrors .RB [ \-\-mirrorlog .RI { disk | core | mirrored }] .RB [ \-\-corelog ] .RB [ \-R | \-\-regionsize .IR MirrorLogRegionSize ] .RB [ \-\-type .IR SegmentType ] .RB [ \-A | \-\-alloc .IR AllocationPolicy ] .RB [ \-b | \-\-background ] .RB [ \-f | \-\-force ] .RB [ \-i | \-\-interval .IR Seconds ] .RB [ \-h | \-? | \-\-help ] .RB [ \-\-stripes .I Stripes .RB [ \-I | \-\-stripesize .IR StripeSize ]] .RB [ \-\-noudevsync ] .RB [ \-v | \-\-verbose ] .RB [ \-y | \-\-yes ] .RB [ \-\-version ] .IR LogicalVolume [ Path ] .RI [ PhysicalVolume [ Path ][ :PE [ -PE ]]...] .sp .B lvconvert \-\-splitmirrors \fIImages .RB [ \-\-name .IR SplitLogicalVolumeName ] .RB [ \-\-trackchanges ] .IR MirrorLogicalVolume [ Path ] .RI [ SplittablePhysicalVolume [ Path ][ :PE [ -PE ]]...] .sp .B lvconvert .BR \-s | \-\-snapshot .RB [ \-c | \-\-chunksize .IR ChunkSize ] .RB [ \-h | \-? | \-\-help ] .RB [ \-\-noudevsync ] .RB [ \-v | \-\-verbose ] .RB [ \-Z | \-\-zero .RI { y | n }] .RB [ \-\-version ] .IR OriginalLogicalVolume [ Path ] .IR SnapshotLogicalVolume [ Path ] .sp .B lvconvert \-\-merge .RB [ \-b | \-\-background ] .RB [ \-i | \-\-interval .IR Seconds ] .RB [ \-h | \-? | \-\-help ] .RB [ \-v | \-\-verbose ] .RB [ \-\-version ] .IR LogicalVolume [ Path ]... .sp .B lvconvert \-\-thinpool .IR ThinPoolLogicalVolume { Name | Path } .RB [ \-c | \-\-chunksize .IR ChunkSize ] .RB [ \-h | \-? | \-\-help ] .RB [ \-v | \-\-verbose ] .RB [ \-\-version ] .RB [ \-Z | \-\-zero .RI { y | n }] .IR ThinMetadataLogicalVolume { Name | Path } .sp .B lvconvert \-\-repair .RB [ \-h | \-? | \-\-help ] .RB [ \-v | \-\-verbose ] .RB [ \-\-version ] .IR LogicalVolume [ Path ] .RI [ PhysicalVolume [ Path ]...] .sp .B lvconvert \-\-replace \fIPhysicalVolume .RB [ \-h | \-? | \-\-help ] .RB [ \-v | \-\-verbose ] .RB [ \-\-version ] .IR LogicalVolume [ Path ] .RI [ PhysicalVolume [ Path ]...] .SH DESCRIPTION lvconvert is used to change the segment type (i.e. linear, mirror, etc) or characteristics of a logical volume. For example, it can add or remove the redundant images of a logical volume, change the log type of a mirror, or designate a logical volume as a snapshot repository. .br If the conversion requires allocation of physical extents (for example, when converting from linear to mirror) and you specify one or more PhysicalVolumes (optionally with ranges of physical extents), allocation of physical extents will be restricted to these physical extents. If the conversion frees physical extents (for example, when converting from a mirror to a linear, or reducing mirror legs) and you specify one or more PhysicalVolumes, the freed extents come first from the specified PhysicalVolumes. .SH OPTIONS See \fBlvm\fP(8) for common options. .br Exactly one of .BR \-\-splitmirrors ", " \-\-mirrors ", " \-\-repair ", " \-\-snapshot or \fB\-\-merge\fP arguments is required. .TP .BR \-m ", " \-\-mirrors " " \fIMirrors Specifies the degree of the mirror you wish to create. For example, "\fB-m 1\fP" would convert the original logical volume to a mirror volume with 2-sides; that is, a linear volume plus one copy. .TP .IR \fB\-\-mirrorlog " {" disk | core | mirrored } Specifies the type of log to use. The default is disk, which is persistent and requires a small amount of storage space, usually on a separate device from the data being mirrored. Core may be useful for short-lived mirrors: It means the mirror is regenerated by copying the data from the first device again every time the device is activated - perhaps, for example, after every reboot. Using "mirrored" will create a persistent log that is itself mirrored. .TP .B \-\-corelog The optional argument \fB--corelog\fP is the same as specifying \fB--mirrorlog core\fP. .TP .BR \-R ", " \-\-regionsize " " \fIMirrorLogRegionSize A mirror is divided into regions of this size (in MB), and the mirror log uses this granularity to track which regions are in sync. .TP .B \-\-type \fISegmentType Used to convert a logical volume to another segment type or to explicitly state the desired RAID1 segment type (\fImirror\fP or \fIraid1\fP) when converting a linear logical volume to a mirror with the \fB-m\fP argument. .TP .BR \-b ", " \-\-background Run the daemon in the background. .TP .BR \-i ", " \-\-interval " " \fISeconds Report progress as a percentage at regular intervals. .TP .B \-\-noudevsync Disable udev synchronisation. The process will not wait for notification from udev. It 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. .TP .B \-\-splitmirrors \fIImages The number of redundant Images of a mirror to be split off and used to form a new logical volume. A name must be supplied for the newly-split-off logical volume using the \fB\-\-name\fP argument, unless the \fB\-\-trackchanges\fP argument is given. .TP .B \-n \fIName The name to apply to a logical volume which has been split off from a mirror logical volume. .TP .B \-\-trackchanges Used with \fB\-\-splitmirrors\fP on a raid1 device, this tracks changes so that the read-only detached image can be merged efficiently back into the mirror later. Only the regions of the detatched device where the data changed get resynchronized. Please note that this feature is only supported with the new md-based mirror implementation and not with the original device-mapper mirror implementation. .TP .B \-s, \-\-snapshot Create a snapshot from existing logical volume using another existing logical volume as its origin. .TP .BR \-c ", " \-\-chunksize " " \fIChunkSize Power of 2 chunk size for the snapshot logical volume between 4KiB and 512KiB. .TP .BR \-Z ", " \-\-zero " {" \fIy | \fIn } Controls zeroing of the first KB of data in the snapshot. If the volume is read-only the snapshot will not be zeroed. .TP .B \-\-merge Merges a snapshot into its origin volume or merges a raid1 image that has been split from its mirror with \fB\-\-trackchanges\fP back into its mirror. To check if your kernel supports the snapshot merge feature, look for 'snapshot-merge' in the output of \fBdmsetup targets\fP. If both the origin and snapshot volume are not open the merge will start immediately. Otherwise, the merge will start the first time either the origin or snapshot are activated and both are closed. Merging a snapshot into an origin that cannot be closed, for example a root filesystem, is deferred until the next time the origin volume is activated. When merging starts, the resulting logical volume will have the origin's name, minor number and UUID. While the merge is in progress, reads or writes to the origin appear as they were directed to the snapshot being merged. When the merge finishes, the merged snapshot is removed. Multiple snapshots may be specified on the commandline or a @tag may be used to specify multiple snapshots be merged to their respective origin. .TP .B \-\-repair Repair a mirror after suffering a disk failure. The mirror will be brought back into a consistent state. By default, the original number of mirrors will be restored if possible. Specify \fB\-y\fP on the command line to skip the prompts. Use \fB\-f\fP if you do not want any replacement. Additionally, you may use \fB\-\-use-policies\fP to use the device replacement policy specified in \fBlvm.conf\fP(5), viz. activation/mirror_log_fault_policy or activation/mirror_device_fault_policy. .TP .B \-\-replace \fIPhysicalVolume Remove the specified device (\fIPhysicalVolume\fP) and replace it with one that is available in the volume group or from the specific list provided. This option is only available to RAID segment types (e.g. "raid1", "raid5", etc). .SH Examples Converts the linear logical volume "vg00/lvol1" to a two-way mirror logical volume: .sp .B lvconvert \-m1 vg00/lvol1 Converts the linear logical volume "vg00/lvol1" to a two-way RAID1 logical volume: .sp .B lvconvert \-\-type raid1 \-m1 vg00/lvol1 Converts a mirror with a disk log to a mirror with an in-memory log: .sp .B lvconvert \-\-mirrorlog core vg00/lvol1 Converts a mirror with an in-memory log to a mirror with a disk log: .sp .B lvconvert \-\-mirrorlog disk vg00/lvol1 Converts a mirror logical volume to a linear logical volume: .sp .B lvconvert \-m0 vg00/lvol1 Converts a mirror logical volume to a RAID1 logical volume with the same number of images: .sp .B lvconvert \-\-type raid1 vg00/mirror_lv Converts logical volume "vg00/lvol2" to snapshot of original volume "vg00/lvol1": .sp .B lvconvert \-s vg00/lvol1 vg00/lvol2 Converts linear logical volume "vg00/lvol1" to a two-way mirror, using physical extents /dev/sda:0-15 and /dev/sdb:0-15 for allocation of new extents: .sp .B lvconvert \-m1 vg00/lvol1 /dev/sda:0-15 /dev/sdb:0-15 Converts mirror logical volume "vg00/lvmirror1" to linear, freeing physical extents from /dev/sda: .sp .B lvconvert \-m0 vg00/lvmirror1 /dev/sda Merges "vg00/lvol1_snap" into its origin: .sp .B lvconvert \-\-merge vg00/lvol1_snap If "vg00/lvol1", "vg00/lvol2" and "vg00/lvol3" are all tagged with "some_tag" each snapshot logical volume will be merged serially, e.g.: "vg00/lvol1", then "vg00/lvol2", then "vg00/lvol3". If \-\-background were used it would start all snapshot logical volume merges in parallel. .sp .B lvconvert \-\-merge @some_tag Extracts one image from the mirror, making it a new logical volume named "lv_split". The mirror the image is extracted from is reduced accordingly. If it was a 2-way mirror (created with '-m 1'), then the resulting original volume will be linear. .sp .B lvconvert \-\-splitmirrors 1 \-\-name lv_split vg00/lvmirror1 A mirrored logical volume created with \-\-type raid1 can use the \-\-trackchanges argument when splitting off an image. Detach one image from the mirrored logical volume lv_raid1 as a separate read-only device and track the changes made to the mirror while it is detached. The split-off device has a name of the form lv_raid1_rimage_N, where N is a number, and it cannot be renamed. .sp .B lvconvert \-\-splitmirrors 1 \-\-trackchanges vg00/lv_raid1 Merge an image that was detached temporarily from its mirror with the \-\-trackchanges argument back into its original mirror and bring its contents back up-to-date. .sp .B lvconvert \-\-merge vg00/lv_raid1_rimage_1 Replaces the physical volume "/dev/sdb1" in the RAID1 logical volume "my_raid1" with the specified physical volume "/dev/sdf1". Had the argument "/dev/sdf1" been left out, lvconvert would attempt to find a suitable device from those available in the volume group. .sp .B lvconvert \-\-replace /dev/sdb1 vg00/my_raid1 /dev/sdf1 .SH SEE ALSO .BR lvm (8), .BR vgcreate (8), .BR lvremove (8), .BR lvrename (8), .BR lvextend (8), .BR lvreduce (8), .BR lvdisplay (8), .BR lvscan (8) lvm2-2.02.98/man/pvs.8.in0000640000175000017500000000661212037016272013576 0ustar blankblank.TH PVS 8 "LVM TOOLS #VERSION#" "Sistina Software UK" \" -*- nroff -*- .SH NAME pvs \- report information about physical volumes .SH SYNOPSIS .B pvs .RB [ \-a | \-\-all ] .RB [ \-\-aligned ] .RB [ \-d | \-\-debug ] .RB [ \-h | \-? | \-\-help ] .RB [ \-\-ignorelockingfailure ] .RB [ \-\-nameprefixes ] .RB [ \-\-noheadings ] .RB [ \-\-nosuffix ] .RB [ \-o | \-\-options .RI [ + ] Field [ ,Field ...]] .RB [ \-O | \-\-sort .RI [ + | \- ] Key1 [ , [ + | \- ] Key2 ...]] .RB [ \-P | \-\-partial ] .RB [ \-\-rows ] .RB [ \-\-segments ] .RB [ \-\-separator .IR Separator ] .RB [ \-\-unbuffered ] .RB [ \-\-units .IR hHbBsSkKmMgGtTpPeE ] .RB [ \-\-unquoted ] .RB [ \-v|\-\-verbose ] .RB [ \-\-version] .RI [ PhysicalVolume .RI [ PhysicalVolume ...]] .SH DESCRIPTION pvs produces formatted output about physical volumes. .SH OPTIONS See \fBlvm\fP(8) for common options. .TP .B \-\-all Include information in the output about devices that have not been initialized with \fBpvcreate\fP(8). .TP .B \-\-aligned Use with \fB\-\-separator\fP to align the output columns. .TP .B \-\-nameprefixes Add an "LVM2_" prefix plus the field name to the output. Useful with \fB\-\-noheadings\fP to produce a list of field=value pairs that can be used to set environment variables (for example, in \fBudev\fP(7) rules). .TP .B \-\-noheadings Suppress the headings line that is normally the first line of output. Useful if grepping the output. .TP .B \-\-nosuffix Suppress the suffix on output sizes. Use with \fB\-\-units\fP (except h and H) if processing the output. .TP .BR \-o ", " \-\-options Comma-separated ordered list of columns. Precede the list with '\fI+\fP' to append to the default selection of columns. .IP Use \fB-o pv_all\fP to select all physical volume columns, and \fB-o pvseg_all\fP to select all Physical Volume segment columns. .IP Use \fB-o help\fP to view the full list of columns available. .IP Column names include: pv_fmt, pv_uuid, dev_size, pv_name, pv_mda_free, pv_mda_size, pe_start, pv_size, pv_free, pv_used, pv_attr, pv_pe_count, pv_pe_alloc_count, pv_tags, pv_mda_count, pv_mda_used_count, pvseg_start, and pvseg_size. .IP With \fB\-\-segments\fP, any "pvseg_" prefixes are optional; otherwise any "pv_" prefixes are optional. Columns mentioned in \fBvgs\fP(8) can also be chosen. The pv_attr bits are: (a)llocatable, e(x)ported and (m)issing. .TP .B \-\-segments Produces one line of output for each contiguous allocation of space on each Physical Volume, showing the start (pvseg_start) and length (pvseg_size) in units of physical extents. .TP .BR \-O ", " \-\-sort Comma-separated ordered list of columns to sort by. Replaces the default selection. Precede any column with '\fI\-\fP' for a reverse sort on that column. .TP .B \-\-rows Output columns as rows. .TP .B \-\-separator \fISeparator String to use to separate each column. Useful if grepping the output. .TP .B \-\-unbuffered Produce output immediately without sorting or aligning the columns properly. .TP .B \-\-units \fIhHbBsSkKmMgGtTpPeE All sizes are output in these units: (h)uman-readable, (b)ytes, (s)ectors, (k)ilobytes, (m)egabytes, (g)igabytes, (t)erabytes, (p)etabytes, (e)xabytes. Capitalise to use multiples of 1000 (S.I.) instead of 1024. Can also specify custom units e.g. \-\-units 3M .TP .B \-\-unquoted When used with \fB\-\-nameprefixes\fP, output values in the field=value pairs are not quoted. .SH SEE ALSO .BR lvm (8), .BR pvdisplay (8), .BR lvs (8), .BR vgs (8) lvm2-2.02.98/man/vgextend.8.in0000640000175000017500000000427512037016272014615 0ustar blankblank.TH VGEXTEND 8 "LVM TOOLS #VERSION#" "Sistina Software UK" \" -*- nroff -*- .SH NAME vgextend \- add physical volumes to a volume group .SH SYNOPSIS .B vgextend .RB [ \-A | \-\-autobackup .RI { y | n }] .RB [ \-d | \-\-debug ] .RB [ \-h | \-? | \-\-help ] .RB [ \-\-restoremissing ] .RB [ \-f | \-\-force ] .RB [ \-t | \-\-test ] .RB [ \-v | \-\-verbose ] .RB [ "PHYSICAL DEVICE OPTIONS" ] .I VolumeGroupName PhysicalDevicePath .RI [ PhysicalDevicePath ...] .SH DESCRIPTION vgextend allows you to add one or more initialized physical volumes (see \fBpvcreate\fP(8)) to an existing volume group to extend it in size. Moreover, it allows you to re-add a physical volume that has gone missing previously, due to a transient device failure, without re-initialising it. Use \fBvgextend \-\-restoremissing\fP to that effect. .sp If \fIPhysicalDevicePath\fP was not previously configured for LVM with \fBpvcreate\fP(8), the device will be initialized with the same default values used with \fBpvcreate\fP(8). If non-default \fPpvcreate\fP(8) values are desired, they may be given on the commandline with the same options as \fPpvcreate\fP(8). See .B PHYSICAL DEVICE OPTIONS for available options. Note that the restore-related options such as .BR \-\-restorefile ", " \-\-uuid " and " \-\-physicalvolumesize are not available. If a restore operation is needed, use \fBpvcreate\fP(8) and \fBvgcfgrestore\fP(8). .SH OPTIONS See \fBlvm\fP(8) for common options. .SH PHYSICAL DEVICE OPTIONS The following options are available for initializing physical devices in the volume group. These options are further described in the \fBpvcreate\fP(8) man page. .TP .BR \-f ", " \-\-force .TP .BR \-y ", " \-\-yes .TP .BR \-Z ", " \-\-zero " {" \fIy | \fIn } .TP .B \-\-labelsector \fIsector .TP .B \-\-metadatasize \fIsize .TP .BR \-\-metadataignore " {" \fIy | \fIn } .TP .B \-\-pvmetadatacopies \fIcopies .TP .B \-\-dataalignment \fIalignment .TP .B \-\-dataalignmentoffset \fIalignment_offset .SH Examples Extends the existing volume group "vg00" by the new physical volumes (see \fBpvcreate\fP(8)) "/dev/sda4" and "/dev/sdn1". .sp .B vgextend vg00 /dev/sda4 /dev/sdn1 .SH SEE ALSO .BR lvm (8), .BR vgcreate (8), .BR vgreduce (8), .BR pvcreate (8) lvm2-2.02.98/man/pvck.8.in0000640000175000017500000000223112037016272013722 0ustar blankblank.TH PVCK 8 "LVM TOOLS #VERSION#" "Sistina Software UK" \" -*- nroff -*- .SH NAME pvck \- check physical volume metadata .SH SYNOPSIS .B pvck .RB [ \-d | \-\-debug ] .RB [ \-h | \-\-help ] .RB [ \-v | \-\-verbose ] .RB [ \-\-labelsector .IR sector ] .I PhysicalVolume .RI [ PhysicalVolume ...] .SH DESCRIPTION pvck checks physical volume LVM metadata for consistency. .SH OPTIONS See \fBlvm\fP(8) for common options. .TP .B \-\-labelsector \fIsector By default, 4 sectors of \fBPhysicalVolume\fP are scanned for an LVM label, starting at sector 0. This parameter allows you to specify a different starting sector for the scan and is useful for recovery situations. For example, suppose the partition table is corrupted or lost on /dev/sda, but you suspect there was an LVM partition at approximately 100 MiB. This area of the disk may be scanned by using the \fB\-\-labelsector\fP parameter with a value of 204800 (100 * 1024 * 1024 / 512 = 204800): .sp .B pvck \-\-labelsector 204800 /dev/sda .sp Note that a script can be used with \fB\-\-labelsector\fP to automate the process of finding LVM labels. .SH SEE ALSO .BR lvm (8), .BR pvcreate (8), .BR pvscan (8) .BR vgck (8) lvm2-2.02.98/man/lvmsadc.8.in0000640000175000017500000000035712037016272014417 0ustar blankblank.TH "LVMSADC" "8" "LVM TOOLS #VERSION#" "Red Hat, Inc" "\"" .SH "NAME" lvmsadc \- LVM system activity data collector .SH "SYNOPSIS" .B lvmsadc .SH "DESCRIPTION" lvmsadc is not currently supported under LVM2. .SH "SEE ALSO" .BR lvm (8) lvm2-2.02.98/man/lvmconf.8.in0000640000175000017500000000177612037016272014440 0ustar blankblank.TH "LVMCONF" "8" "LVM TOOLS #VERSION#" "Red Hat, Inc" "\"" .SH "NAME" .B lvmconf \- LVM configuration modifier .SH "SYNOPSIS" .B lvmconf .RB [ \-\-disable-cluster ] .RB [ \-\-enable-cluster ] .RB [ \-\-file .RI < configfile >] .RB [ \-\-lockinglib .RI < lib >] .RB [ \-\-lockinglibdir .RI < dir >] .SH "DESCRIPTION" lvmconf is a script that modifies the locking configuration in an lvm configuration file. See \fBlvm.conf\fP(5). .SH "OPTIONS" .TP .BR \-\-disable-cluster Set \fBlocking_type\fR to the default non-clustered type. .TP .BR \-\-enable-cluster Set \fBlocking_type\fR to the default clustered type on this system. .TP .BR \-\-file " <" \fIconfigfile > Apply the changes to \fIconfigfile\fP instead of the default \fI#DEFAULT_SYS_DIR#/lvm.conf\fP. .TP .BR \-\-lockinglib " <" \fIlib > Set external \fBlocking_library\fR locking library to load if an external locking type is used. .TP .BR \-\-lockinglibdir " <" \fIdir > .SH FILES .I #DEFAULT_SYS_DIR#/lvm.conf .SH "SEE ALSO" .BR lvm (8), .BR lvm.conf (5) lvm2-2.02.98/man/lvdisplay.8.in0000640000175000017500000000645612037016272015003 0ustar blankblank.TH LVDISPLAY 8 "LVM TOOLS #VERSION#" "Sistina Software UK" \" -*- nroff -*- .SH NAME lvdisplay \- display attributes of a logical volume .SH SYNOPSIS .B lvdisplay .RB [ \-a | \-\-all ] .RB [ \-c | \-\-colon ] .RB [ \-d | \-\-debug ] .RB [ \-h | \-? | \-\-help ] .RB [ \-\-ignorelockingfailure ] .RB [ \-\-maps ] .RB [ \-\-nosuffix ] .RB [ \-P | \-\-partial ] .RB [ \-\-units .IR hHbBsSkKmMgGtTpPeE ] .RB [ \-v | \-\-verbose ] .RB [ \-\-version ] .RI [ LogicalVolumePath .RI [ LogicalVolumePath ...]] .br .B lvdisplay .BR \-\-columns | \-C .RB [ \-\-aligned ] .RB [ \-a | \-\-all ] .RB [ \-d | \-\-debug ] .RB [ \-h | \-? | \-\-help ] .RB [ \-\-ignorelockingfailure ] .RB [ \-\-noheadings ] .RB [ \-\-nosuffix ] .RB [ \-o | \-\-options .RI [ + ] Field [ ,Field ...]] .RB [ \-O | \-\-sort .RI [ + | - ] Key1 [ , [ + | - ] Key2 ...]] .RB [ \-P | \-\-partial ] .RB [ \-\-segments ] .RB [ \-\-separator .IR Separator ] .RB [ \-\-unbuffered ] .RB [ \-\-units .IR hHbBsSkKmMgGtTpPeE ] .RB [ \-v | \-\-verbose ] .RB [ \-\-version ] .RI [ LogicalVolumePath .RI [ LogicalVolumePath ...]] .SH DESCRIPTION lvdisplay allows you to see the attributes of a logical volume like size, read/write status, snapshot information etc. .P \fBlvs\fP(8) is an alternative that provides the same information in the style of \fBps\fP(1). \fBlvs\fP(8) is recommended over \fBlvdisplay\fP. .SH OPTIONS See \fBlvm\fP(8) for common options and \fBlvs\fP for options given with \fB\-\-columns\fP. .TP .B \-\-all Include information in the output about internal Logical Volumes that are components of normally-accessible Logical Volumes, such as mirrors, but which are not independently accessible (e.g. not mountable). For example, after creating a mirror using \fBlvcreate \-m1 \-\-mirrorlog disk\fP, this option will reveal three internal Logical Volumes, with suffixes mimage_0, mimage_1, and mlog. .TP .BR \-c ", " \-\-colon Generate colon separated output for easier parsing in scripts or programs. N.B. \fBlvs\fP(8) provides considerably more control over the output. .nf The values are: * logical volume name * volume group name * logical volume access * logical volume status * internal logical volume number * open count of logical volume * logical volume size in sectors * current logical extents associated to logical volume * allocated logical extents of logical volume * allocation policy of logical volume * read ahead sectors of logical volume * major device number of logical volume * minor device number of logical volume .fi .TP .BR \-m ", " \-\-maps Display the mapping of logical extents to physical volumes and physical extents. To map physical extents to logical extents use: .B pvs \-\-segments \-o+lv_name,seg_start_pe,segtype .TP .BR \-\-columns ", " \-C Display output in columns, the equivalent of \fBlvs\fP. Options listed are the same as options given in \fBlvs\fP(8). .SH Examples Shows attributes of that logical volume. If snapshot logical volumes have been created for this original logical volume, this command shows a list of all snapshot logical volumes and their status (active or inactive) as well: .sp .B lvdisplay \-v /dev/vg00/lvol2 Shows the attributes of this snapshot logical volume and also which original logical volume it is associated with: .sp .B lvdisplay /dev/vg00/snapshot .SH SEE ALSO .BR lvm (8), .BR lvcreate (8), .BR lvscan (8), .BR pvs (8) lvm2-2.02.98/man/vgscan.8.in0000640000175000017500000000214112037016272014240 0ustar blankblank.TH VGSCAN 8 "LVM TOOLS #VERSION#" "Sistina Software UK" \" -*- nroff -*- .SH NAME vgscan \- scan all disks for volume groups and rebuild caches .SH SYNOPSIS .B vgscan .RB [ \-d | \-\-debug ] .RB [ \-h | \-? | \-\-help ] .RB [ \-\-ignorelockingfailure ] .RB [ \-\-mknodes ] .RB [ \-P | \-\-partial ] .RB [ \-v | \-\-verbose ] .SH DESCRIPTION vgscan scans all SCSI, (E)IDE disks, multiple devices and a bunch of other disk devices in the system looking for LVM physical volumes and volume groups. Define a filter in \fBlvm.conf\fP(5) to restrict the scan to avoid a CD ROM, for example. .LP In LVM2, vgscans take place automatically; but you might still need to run one explicitly after changing hardware. .SH OPTIONS See \fBlvm\fP(8) for common options. .TP .B \-\-mknodes Also checks the LVM special files in /dev that are needed for active logical volumes and creates any missing ones and removes unused ones. .TP .B \-\-cache Scan devices for LVM physical volumes and volume groups and instruct the lvmetad daemon to update its cached state accordingly. .SH SEE ALSO .BR lvm (8), .BR vgcreate (8), .BR vgchange (8) lvm2-2.02.98/man/lvreduce.8.in0000640000175000017500000000703712037016272014601 0ustar blankblank.TH LVREDUCE 8 "LVM TOOLS #VERSION#" "Sistina Software UK" \" -*- nroff -*- .SH NAME lvreduce \- reduce the size of a logical volume .SH SYNOPSIS .B lvreduce .RB [ \-A | \-\-autobackup .RI { y | n }] .RB [ \-d | \-\-debug ] .RB [ \-h | \-\-help ] .RB [ \-t | \-\-test ] .RB [ \-v | \-\-verbose ] .RB [ \-\-version ] .RB [ \-f | \-\-force ] .RB [ \-\-noudevsync ] .RB { \-l | \-\-extents .RI [ \- ] LogicalExtentsNumber [ % { VG | LV | FREE | ORIGIN "}] |" .RB [ \-L | \-\-size .RI [ \- ] LogicalVolumeSize [ bBsSkKmMgGtTpPeE ]} .RB [ \-n | \-\-nofsck ] .RB [ \-r | \-\-resizefs ] .IR LogicalVolume { Name | Path } .SH DESCRIPTION lvreduce allows you to reduce the size of a logical volume. Be careful when reducing a logical volume's size, because data in the reduced part is lost!!! .br You should therefore ensure that any filesystem on the volume is resized .I before running lvreduce so that the extents that are to be removed are not in use. .br Shrinking snapshot logical volumes (see .BR lvcreate (8) for information to create snapshots) is supported as well. But to change the number of copies in a mirrored logical volume use .BR lvconvert (8). .br Sizes will be rounded if necessary - for example, the volume size must be an exact number of extents and the size of a striped segment must be a multiple of the number of stripes. .br .SH OPTIONS See \fBlvm\fP(8) for common options. .TP .BR \-f ", " \-\-force Force size reduction without prompting even when it may cause data loss. .TP .IR \fB\-l ", " \fB\-\-extents " [" \- ] LogicalExtentsNumber [ % { VG | LV | FREE | ORIGIN }] Reduce or set the logical volume size in units of logical extents. With the \fI-\fP sign the value will be subtracted from the logical volume's actual size and without it the value will be taken as an absolute size. The number can also be expressed as a percentage of the total space in the Volume Group with the suffix \fI%VG\fP, relative to the existing size of the Logical Volume with the suffix \fI%LV\fP, as a percentage of the remaining free space in the Volume Group with the suffix \fI%FREE\fP, or (for a snapshot) as a percentage of the total space in the Origin Logical Volume with the suffix \fI%ORIGIN\fP. The resulting value for the substraction is rounded downward, for the absolute size it is rounded upward. .TP .IR \fB\-L ", " \fB\-\-size " [" \- ] LogicalVolumeSize [ bBsSkKmMgGtTpPeE ] Reduce or set the logical volume size in units of megabytes. A size suffix of \fIk\fP for kilobyte, \fIm\fP for megabyte, \fIg\fP for gigabytes, \fIt\fP for terabytes, \fIp\fP for petabytes or \fIe\fP for exabytes is optional. With the \fI\-\fP sign the value will be subtracted from the logical volume's actual size and without it it will be taken as an absolute size. .TP .BR \-n ", " \-\-nofsck Do not perform fsck before resizing filesystem when filesystem requires it. You may need to use \fB\-\-force\fR to proceed with this option. .TP .BR \-\-noudevsync Disable udev synchronisation. The process will not wait for notification from udev. It 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. .TP .BR \-r ", " \-\-resizefs Resize underlying filesystem together with the logical volume using .BR fsadm (8). .SH Examples Reduce the size of logical volume lvol1 in volume group vg00 by 3 logical extents: .sp .B lvreduce \-l \-3 vg00/lvol1 .SH SEE ALSO .BR fsadm (8), .BR lvchange (8), .BR lvconvert (8), .BR lvcreate (8), .BR lvextend (8), .BR lvm (8), .BR lvresize (8), .BR vgreduce (8) lvm2-2.02.98/man/pvdisplay.8.in0000640000175000017500000000466612037016272015010 0ustar blankblank.TH PVDISPLAY 8 "LVM TOOLS #VERSION#" "Sistina Software UK" \" -*- nroff -*- .SH NAME pvdisplay \- display attributes of a physical volume .SH SYNOPSIS .B pvdisplay .RB [ \-c | \-\-colon ] .RB [ \-d | \-\-debug ] .RB [ \-h | \-? | \-\-help ] .RB [ \-\-ignorelockingfailure ] .RB [ \-\-maps ] .RB [ \-\-nosuffix ] .RB [ \-s | \-\-short ] .RB [ \-\-units .IR hsbkmgtHKMGT ] .RB [ \-v [ v ]| \-\-verbose .RB [ \-\-verbose ]] .RB [ \-\-version ] .RI [ PhysicalVolumePath .RI [ PhysicalVolumePath ...]] .br .br .B pvdisplay .BR \-\-columns | \-C .RB [ \-\-aligned ] .RB [ \-a | \-\-all ] .RB [ \-d | \-\-debug ] .RB [ \-h | \-? | \-\-help ] .RB [ \-\-ignorelockingfailure ] .RB [ \-\-noheadings ] .RB [ \-\-nosuffix ] .RB [ \-o | \-\-options .RI [ + ] Field [ ,Field ...]] .RB [ \-O | \-\-sort .RI [ + | \- ] Key1 [ , [ + | \- ] Key2 ... .RI ]] .RB [ \-\-separator .IR Separator ] .RB [ \-\-unbuffered ] .RB [ \-\-units .IR hHbBsSkKmMgGtTpPeE ] .RB [ \-v [ v ]| \-\-verbose .RB [ \-\-verbose ]] .RB [ \-\-version ] .RI [ PhysicalVolumePath .RI [ PhysicalVolumePath ...]] .SH DESCRIPTION pvdisplay allows you to see the attributes of one or more physical volumes like size, physical extent size, space used for the volume group descriptor area and so on. .P \fBpvs\fP(8) is an alternative that provides the same information in the style of \fBps\fP(1). .SH OPTIONS See \fBlvm\fP for common options and \fBpvs\fP for options given with \fB\-\-columns\fP. .TP .BR \-c ", " \-\-colon Generate colon separated output for easier parsing in scripts or programs. N.B. \fBpvs\fP(8) provides considerably more control over the output. .nf The values are: * physical volume device name * volume group name * physical volume size in kilobytes * internal physical volume number (obsolete) * physical volume status * physical volume (not) allocatable * current number of logical volumes on this physical volume * physical extent size in kilobytes * total number of physical extents * free number of physical extents * allocated number of physical extents .fi .TP .BR \-s ", " \-\-short Only display the size of the given physical volumes. .TP .BR \-m ", " \-\-maps Display the mapping of physical extents to logical volumes and logical extents. .TP .BR \-\-columns ", " \-C Display output in columns, the equivalent of \fBpvs\fP(8). See \fBpvs\fP(8) for a description of other options with this form of \fBpvdisplay\fP. .SH SEE ALSO .BR lvm (8), .BR pvcreate (8), .BR lvcreate (8), .BR vgcreate (8) lvm2-2.02.98/man/vgmerge.8.in0000640000175000017500000000221312037016272014413 0ustar blankblank.TH VGMERGE 8 "LVM TOOLS #VERSION#" "Sistina Software UK" \" -*- nroff -*- .SH NAME vgmerge \- merge two volume groups .SH SYNOPSIS .B vgmerge .RB [ \-A | \-\-autobackup .RI { y | n }] .RB [ \-d | \-\-debug ] .RB [ \-h | \-? | \-\-help ] .RB [ \-l | \-\-list ] .RB [ \-t | \-\-test ] .RB [ \-v | \-\-verbose ] .I DestinationVolumeGroupName .I SourceVolumeGroupName .SH DESCRIPTION vgmerge merges two existing volume groups. The inactive \fISourceVolumeGroupName\fP will be merged into the \fIDestinationVolumeGroupName\fP if physical extent sizes are equal and physical and logical volume summaries of both volume groups fit into \fIDestinationVolumeGroupName\fP's limits. .SH OPTIONS See \fBlvm\fP(8) for common options. .TP .BR \-l ", " \-\-list Display merged \fIDestinationVolumeGroupName\fP like \fBvgdisplay -v\fP. .TP .BR \-t ", " \-\-test Do a test run WITHOUT making any real changes. .SH Examples Merge the inactive volume group named "my_vg" into the active or inactive volume group named "databases" giving verbose runtime information: .sp .B vgmerge -v databases my_vg .SH SEE ALSO .BR lvm (8), .BR vgcreate (8), .BR vgextend (8), .BR vgreduce (8) lvm2-2.02.98/man/lvremove.8.in0000640000175000017500000000325412037016272014624 0ustar blankblank.TH LVREMOVE 8 "LVM TOOLS #VERSION#" "Sistina Software UK" \" -*- nroff -*- .SH NAME lvremove \- remove a logical volume .SH SYNOPSIS .B lvremove .RB [ \-A | \-\-autobackup .RI { y | n }] .RB [ \-d | \-\-debug ] .RB [ \-h | \-\-help ] .RB [ \-t | \-\-test ] .RB [ \-v | \-\-verbose ] .RB [ \-\-version ] .RB [ \-f | \-\-force ] .RB [ \-\-noudevsync ] .IR LogicalVolume { Name | Path } .RI [ LogicalVolume { Name | Path }...] .SH DESCRIPTION lvremove removes one or more logical volumes. Confirmation will be requested before deactivating any active logical volume prior to removal. Logical volumes cannot be deactivated or removed while they are open (e.g. if they contain a mounted filesystem). Removing an origin logical volume will also remove all dependent snapshots. .sp If the logical volume is clustered then it must be deactivated on all nodes in the cluster before it can be removed. A single lvchange command issued from one node can do this. .SH OPTIONS See \fBlvm\fP(8) for common options. .TP .BR \-f ", " \-\-force Remove active logical volumes without confirmation. .TP .B \-\-noudevsync Disable udev synchronisation. The process will not wait for notification from udev. It 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. .SH Examples Remove the active logical volume lvol1 in volume group vg00 without asking for confirmation: .sp .B lvremove \-f vg00/lvol1 .sp Remove all logical volumes in volume group vg00: .sp .B lvremove vg00 .SH SEE ALSO .BR lvcreate (8), .BR lvdisplay (8), .BR lvchange (8), .BR lvm (8), .BR lvs (8), .BR lvscan (8), .BR vgremove (8) lvm2-2.02.98/man/vgremove.8.in0000640000175000017500000000233412037016272014615 0ustar blankblank.TH VGREMOVE 8 "LVM TOOLS #VERSION#" "Sistina Software UK" \" -*- nroff -*- .SH NAME vgremove \- remove a volume group .SH SYNOPSIS .B vgremove .RB [ \-d | \-\-debug ] .RB [ \-f | \-\-force ] .RB [ \-h | \-? | \-\-help ] .RB [ \-\-noudevsync ] .RB [ \-t | \-\-test ] .RB [ \-v | \-\-verbose ] .I VolumeGroupName .RI [ VolumeGroupName ...] .SH DESCRIPTION vgremove allows you to remove one or more volume groups. If one or more physical volumes in the volume group are lost, consider \fBvgreduce --removemissing\fP to make the volume group metadata consistent again. .sp If there are logical volumes that exist in the volume group, a prompt will be given to confirm removal. You can override the prompt with \fB-f\fP. .SH OPTIONS See \fBlvm\fP(8) for common options. .TP .BR \-f ", " \-\-force Force the removal of any logical volumes on the volume group without confirmation. .TP .BR \-\-noudevsync Disable udev synchronisation. The process will not wait for notification from udev. It 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. .SH SEE ALSO .BR lvm (8), .BR lvremove (8), .BR vgcreate (8), .BR vgreduce (8) lvm2-2.02.98/man/vgreduce.8.in0000640000175000017500000000302112037016272014561 0ustar blankblank.TH VGREDUCE 8 "LVM TOOLS #VERSION#" "Sistina Software UK" \" -*- nroff -*- .SH NAME vgreduce \- reduce a volume group .SH SYNOPSIS .B vgreduce .RB [ \-a | \-\-all ] .RB [ \-A | \-\-autobackup .RI { y | n }] .RB [ \-d | \-\-debug ] .RB [ \-h | \-? | \-\-help ] .RB [ \-\-removemissing ] .RB [ \-t | \-\-test ] .RB [ \-v | \-\-verbose ] .I VolumeGroupName .RI [ PhysicalVolumePath ...] .SH DESCRIPTION vgreduce allows you to remove one or more unused physical volumes from a volume group. .SH OPTIONS See \fBlvm\fP(8) for common options. .TP .BR \-a ", " \-\-all Removes all empty physical volumes if none are given on command line. .TP .B \-\-removemissing Removes all missing physical volumes from the volume group, if there are no logical volumes allocated on those. This resumes normal operation of the volume group (new logical volumes may again be created, changed and so on). If this is not possible (there are logical volumes referencing the missing physical volumes) and you cannot or do not want to remove them manually, you can run this option with \fB--force\fP to have \fBvgreduce\fP remove any partial LVs. Any logical volumes and dependent snapshots that were partly on the missing disks get removed completely. This includes those parts that lie on disks that are still present. If your logical volumes spanned several disks including the ones that are lost, you might want to try to salvage data first by activating your logical volumes with \fB--partial\fP as described in \fBlvm\fP(8). .SH SEE ALSO .BR lvm (8), .BR vgextend (8) lvm2-2.02.98/man/vgsplit.8.in0000640000175000017500000000543212037016272014455 0ustar blankblank.TH VGSPLIT 8 "LVM TOOLS #VERSION#" "Sistina Software UK" \" -*- nroff -*- .SH NAME vgsplit \- split a volume group into two .SH SYNOPSIS .B vgsplit .RB [ \-\-alloc .IR AllocationPolicy ] .RB [ \-A | \-\-autobackup .RI { y | n }] .RB [ \-c | \-\-clustered .RI { y | n }] .RB [ \-d | \-\-debug ] .RB [ \-h | \-\-help ] .RB [ \-l | \-\-maxlogicalvolumes .IR MaxLogicalVolumes ] .RB [ -M | \-\-metadatatype .IR type ] .RB [ -p | \-\-maxphysicalvolumes .IR MaxPhysicalVolumes ] .RB [ \-\- [ vg ] metadatacopies .IR NumberOfCopies | unmanaged | all ] .RB [ \-n | \-\-name .IR LogicalVolumeName ] .RB [ \-t | \-\-test ] .RB [ \-v | \-\-verbose ] .I SourceVolumeGroupName DestinationVolumeGroupName .RI [ PhysicalVolumePath ...] .SH DESCRIPTION vgsplit moves one or more physical volumes from \fISourceVolumeGroupName\fP into \fIDestinationVolumeGroupName\fP. The physical volumes moved can be specified either explicitly via \fIPhysicalVolumePath\fP, or implicitly by \fB\-n\fP \fILogicalVolumeName\fP, in which case only physical volumes underlying the specified logical volume will be moved. If \fIDestinationVolumeGroupName\fP does not exist, a new volume group will be created. The default attributes for the new volume group can be specified with .BR \-\-alloc , .BR \-\-clustered , .BR \-\-maxlogicalvolumes , .BR \-\-metadatatype , .B \-\-maxphysicalvolumes \fRand .BR \-\- [ vg ] metadatacopies (see \fBvgcreate\fP(8) for a description of these options). If any of these options are not given, default attribute(s) are taken from \fISourceVolumeGroupName\fP. If a non-LVM2 metadata type (e.g. lvm1) is being used, you should use the \fB\-M\fP option to specify the metadata type directly. If .I DestinationVolumeGroupName does exist, it will be checked for compatibility with .I SourceVolumeGroupName before the physical volumes are moved. Specifying any of the above default volume group attributes with an existing destination volume group is an error, and no split will occur. Logical volumes cannot be split between volume groups. \fBvgsplit\fP(8) only moves complete physical volumes: To move part of a physical volume, use \fBpvmove\fP(8). Each existing logical volume must be entirely on the physical volumes forming either the source or the destination volume group. For this reason, \fBvgsplit\fP(8) may fail with an error if a split would result in a logical volume being split across volume groups. A vgsplit into an existing volume group retains the existing volume group's value of \fPvgmetadatacopies\fP (see \fBvgcreate\fP(8) and \fBlvm.conf\fP(5) for further explanation of \fPvgmetadatacopies\fP). To change the value of \fBvgmetadatacopies\fP, use \fBvgchange\fP(8). .SH OPTIONS See \fBlvm\fP(8) for common options. .SH SEE ALSO .BR lvm (8), .BR vgcreate (8), .BR vgextend (8), .BR vgreduce (8), .BR vgmerge (8) lvm2-2.02.98/man/lvscan.8.in0000640000175000017500000000260312037016272014250 0ustar blankblank.TH LVSCAN 8 "LVM TOOLS #VERSION#" "Sistina Software UK" \" -*- nroff -*- .SH NAME lvscan \- scan (all disks) for Logical Volumes .SH SYNOPSIS .B lvscan .RB [ \-a | \-\-all] .RB [ \-b | \-\-blockdevice ] .RB [ \-d | \-\-debug ] .RB [ \-h | \-\-help ] .RB [ \-\-ignorelockingfailure ] .RB [ \-P | \-\-partial ] .RB [ \-v | \-\-verbose ] .SH DESCRIPTION lvscan scans all known volume groups or all supported LVM block devices in the system for defined Logical Volumes. The output consists of one line for each Logical Volume indicating whether or not it is active, a snapshot or origin, the size of the device and its allocation policy. Use \fBlvs\fP(8) or \fBlvdisplay\fP(8) to obtain more-comprehensive information about the Logical Volumes. .SH OPTIONS See \fBlvm\fP(8) for common options. .TP .BR \-\-all Include information in the output about internal Logical Volumes that are components of normally-accessible Logical Volumes, such as mirrors, but which are not independently accessible (e.g. not mountable). For example, after creating a mirror using .B lvcreate \-m1 \-\-mirrorlog disk\fR, this option will reveal three internal Logical Volumes, with suffixes mimage_0, mimage_1, and mlog. .TP .BR \-b ", " \-\-blockdevice This option is now ignored. Instead, use \fBlvs\fP(8) or \fBlvdisplay\fP(8) to obtain the device number. .SH SEE ALSO .BR lvm (8), .BR lvcreate (8), .BR lvdisplay (8) .BR lvs (8) lvm2-2.02.98/man/cmirrord.8.in0000640000175000017500000000200712037016272014601 0ustar blankblank.TH CMIRRORD 8 "LVM TOOLS #VERSION#" "Red Hat Inc" \" -*- nroff -*- .SH NAME cmirrord \- cluster mirror log daemon .SH SYNOPSIS .B cmirrord .SH DESCRIPTION cmirrord is the daemon that tracks mirror log information in a cluster. It is specific to device-mapper based mirrors (and by extension, LVM cluster mirrors). Cluster mirrors are not possible without this daemon running. This daemon relies on the cluster infrastructure provided by the Cluster MANager (CMAN), which must be set up and running in order for cmirrord to function. (The cluster infrastructure is also required for clvmd.) Output is logged via syslog. The USR1 signal can be issued to cmirrord to gather current status information for debugging purposes. Once started, cmirrord will run until it is shutdown via INT signal. If there are still active cluster mirrors, however, the signal will be ignored. Active cluster mirrors should be shutdown before stopping the cluster mirror log daemon. .SH SEE ALSO .BR lvm (8) .BR clvmd (8) .BR cluster.conf (5)lvm2-2.02.98/man/vgdisplay.8.in0000640000175000017500000000556412037016272014775 0ustar blankblank.TH VGDISPLAY 8 "LVM TOOLS #VERSION#" "Sistina Software UK" \" -*- nroff -*- .SH NAME vgdisplay \- display attributes of volume groups .SH SYNOPSIS .B vgdisplay .RB [ \-A | \-\-activevolumegroups ] .RB [ \-c | \-\-colon ] .RB [ \-s | \-\-short ] .RB [ \-v | \-\-verbose ] .RB [ \-d | \-\-debug ] .RB [ \-h | \-\-help ] .RB [ \-\-ignorelockingfailure ] .RB [ \-\-nosuffix ] .RB [ \-P | \-\-partial ] .RB [ \-\-units .IR hHbBsSkKmMgGtTpPeE ] .RB [ \-\-version ] .RI [ VolumeGroupName .RI [ VolumeGroupName ...]] .br .br .B vgdisplay .BR \-\-columns | \-C .RB [ \-\-aligned ] .RB [ \-d | \-\-debug ] .RB [ \-h | \-? | \-\-help ] .RB [ \-\-ignorelockingfailure ] .RB [ \-\-noheadings ] .RB [ \-\-nosuffix ] .RB [ \-o|\-\-options .RI [ + ] Field1 [ ,Field2 ...]] .RB [ \-O | \-\-sort .RI [ + | - ] Key1 [ , [ + | - ] Key2 ...]] .RB [ \-P | \-\-partial ] .RB [ \-\-separator .IR Separator ] .RB [ \-\-unbuffered ] .RB [ \-\-units .IR hHbBsSkKmMgGtTpPeE ] .RB [ \-v | \-\-verbose ] .RB [ \-\-version ] .RI [ VolumeGroupName .RI [ VolumeGroupName ...]] .SH DESCRIPTION vgdisplay allows you to see the attributes of .I VolumeGroupName (or all volume groups if none is given) with it's physical and logical volumes and their sizes etc. .P \fBvgs\fP(8) is an alternative that provides the same information in the style of \fBps\fP(1). .SH OPTIONS See \fBlvm\fP(8) for common options and \fBvgs\fP(8) for options given with \fB\-\-columns\fP. .TP .BR \-A ", " \-\-activevolumegroups Only select the active volume groups. .TP .BR \-c ", " \-\-colon Generate colon separated output for easier parsing in scripts or programs. N.B. \fBvgs\fP(8) provides considerably more control over the output. .nf The values are: 1 volume group name 2 volume group access 3 volume group status 4 internal volume group number 5 maximum number of logical volumes 6 current number of logical volumes 7 open count of all logical volumes in this volume group 8 maximum logical volume size 9 maximum number of physical volumes 10 current number of physical volumes 11 actual number of physical volumes 12 size of volume group in kilobytes 13 physical extent size 14 total number of physical extents for this volume group 15 allocated number of physical extents for this volume group 16 free number of physical extents for this volume group 17 uuid of volume group .fi .TP .BR \-s ", " \-\-short Give a short listing showing the existence of volume groups. .TP .BR \-v ", " \-\-verbose Display verbose information containing long listings of physical and logical volumes. If given twice, also display verbose runtime information of vgdisplay's activities. .TP .B \-\-version Display version and exit successfully. .TP .BR \-\-columns | \-C Display output in columns, the equivalent of \fBvgs\fP(8). Options listed are the same as options given in \fPvgs\fP(8). .SH SEE ALSO .BR lvm (8), .BR vgs (8), .BR pvcreate (8), .BR vgcreate (8), .BR lvcreate (8) lvm2-2.02.98/man/vgcfgbackup.8.in0000640000175000017500000000213412037016272015243 0ustar blankblank.TH VGCFGBACKUP 8 "LVM TOOLS #VERSION#" "Sistina Software UK" \" -*- nroff -*- .SH NAME vgcfgbackup \- backup volume group descriptor area .SH SYNOPSIS .B vgcfgbackup .RB [ \-d | \-\-debug ] .RB [ \-f | \-\-file .RI < filename >] .RB [ \-h | \-\-help ] .RB [ \-\-ignorelockingfailure ] .RB [ \-P | \-\-partial ] .RB [ \-v | \-\-verbose ] .RI [ VolumeGroupName ...] .SH DESCRIPTION vgcfgbackup allows you to backup the metadata of your volume groups. If you don't name any volume groups on the command line, all of them will be backed up. .sp In a default installation, each volume group gets backed up into a separate file bearing the name of the volume group in the directory #DEFAULT_BACKUP_DIR#. You can write the backup to an alternative file using \fB-f\fP. In this case if you are backing up more than one volume group the filename is treated as a template, and %s gets replaced by the volume group name. .sp NB. This DOESN'T backup user/system data in logical volume(s)! Backup #DEFAULT_SYS_DIR# regularly too. .SH OPTIONS See \fBlvm\fP(8) for common options. .SH SEE ALSO .BR lvm (8), .BR vgcfgrestore (8) lvm2-2.02.98/man/Makefile.in0000640000175000017500000000577612037016272014347 0ustar blankblank# # 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 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 ("@FSADM@", "yes") FSADMMAN = fsadm.8 else FSADMMAN = endif ifeq ("@BLKDEACTIVATE@", "yes") BLKDEACTIVATEMAN = blkdeactivate.8 else BLKDEACTIVATEMAN = endif ifeq ("@DMEVENTD@", "yes") DMEVENTDMAN = dmeventd.8 else DMEVENTDMAN = endif ifeq ("@BUILD_LVMETAD@", "yes") LVMETAD = lvmetad.8 else LVMETAD = endif MAN5=lvm.conf.5 MAN8=lvchange.8 lvconvert.8 lvcreate.8 lvdisplay.8 lvextend.8 lvm.8 \ lvmchange.8 lvmconf.8 lvmdiskscan.8 lvmdump.8 lvmsadc.8 lvmsar.8 \ lvreduce.8 lvremove.8 lvrename.8 lvresize.8 lvs.8 \ lvscan.8 pvchange.8 pvck.8 pvcreate.8 pvdisplay.8 pvmove.8 pvremove.8 \ pvresize.8 pvs.8 pvscan.8 vgcfgbackup.8 vgcfgrestore.8 vgchange.8 \ vgck.8 vgcreate.8 vgconvert.8 vgdisplay.8 vgexport.8 vgextend.8 \ vgimport.8 vgimportclone.8 vgmerge.8 vgmknodes.8 vgreduce.8 vgremove.8 \ vgrename.8 vgs.8 vgscan.8 vgsplit.8 $(FSADMMAN) $(BLKDEACTIVATEMAN) $(LVMETAD) ifneq ("@CLVMD@", "none") MAN8CLUSTER=clvmd.8 else MAN8CLUSTER= endif ifeq ("@BUILD_CMIRRORD@", "yes") MAN8CLUSTER+=cmirrord.8 endif MAN8DM=dmsetup.8 $(DMEVENTDMAN) MAN5DIR=$(mandir)/man5 MAN8DIR=$(mandir)/man8 CLEAN_TARGETS=$(MAN5) $(MAN8) $(MAN8CLUSTER) $(FSADMMAN) $(BLKDEACTIVATEMAN) $(DMEVENTDMAN) $(MAN8DM) DISTCLEAN_TARGETS=fsadm.8 clvmd.8 cmirrord.8 dmeventd.8 include $(top_builddir)/make.tmpl ifneq ("@CLVMD@", "none") install: install_cluster endif all: man device-mapper .PHONY: man install_man5 install_man8 device-mapper: $(MAN8DM) man: $(MAN5) $(MAN8) $(MAN8CLUSTER) $(MAN5) $(MAN8) $(MAN8DM) $(MAN8CLUSTER): Makefile %: %.in @case "$@" in \ */*) ;; \ *) echo "Creating $@" ; $(SED) -e "s+#VERSION#+$(LVM_VERSION)+;s+#DEFAULT_SYS_DIR#+$(DEFAULT_SYS_DIR)+;s+#DEFAULT_ARCHIVE_DIR#+$(DEFAULT_ARCHIVE_DIR)+;s+#DEFAULT_BACKUP_DIR#+$(DEFAULT_BACKUP_DIR)+;s+#DEFAULT_CACHE_DIR#+$(DEFAULT_CACHE_DIR)+;s+#DEFAULT_LOCK_DIR#+$(DEFAULT_LOCK_DIR)+;s+#CLVMD_PATH#+@CLVMD_PATH@+;s+#LVM_PATH#+@LVM_PATH@+;s+#DEFAULT_RUN_DIR#+@DEFAULT_RUN_DIR@+;" $< > $@ ;; \ esac install_man5: $(MAN5) $(INSTALL) -d $(MAN5DIR) $(INSTALL_DATA) $(MAN5) $(MAN5DIR)/ install_man8: $(MAN8) $(INSTALL) -d $(MAN8DIR) $(INSTALL_DATA) $(MAN8) $(MAN8DIR)/ install_lvm2: install_man5 install_man8 install_cluster: $(MAN8CLUSTER) $(INSTALL) -d $(MAN8DIR) $(INSTALL_DATA) $(MAN8CLUSTER) $(MAN8DIR)/ install_device-mapper: $(MAN8DM) $(INSTALL) -d $(MAN8DIR) $(INSTALL_DATA) $(MAN8DM) $(MAN8DIR)/ install: install_lvm2 install_device-mapper lvm2-2.02.98/man/vgimportclone.8.in0000640000175000017500000000326312037016272015655 0ustar blankblank.TH VGIMPORTCLONE 8 "LVM TOOLS #VERSION#" "Red Hat, Inc." \" -*- nroff -*- .SH NAME vgimportclone \- import and rename duplicated volume group (e.g. a hardware snapshot) .SH SYNOPSIS .B vgimportclone .RB [ \-n | \-\-basevgname .IR VolumeGroupName ] .RB [ \-i | \-\-import ] .I PhysicalVolume .RI [ PhysicalVolume ...] .SH DESCRIPTION vgimportclone is used to import a duplicated VG (e.g. hardware snapshot). Duplicate VG(s) and PV(s) are not able to be used until they are made to coexist with the origin VG(s) and PV(s). vgimportclone renames the VG associated with the specified PV(s) and changes the associated VG and PV UUIDs. .SH OPTIONS See \fBlvm\fP(8) for common options. .TP .BR \-n ", " \-\-basevgname " " \fIVolumeGroupName By default the snapshot VG will be renamed to the original name plus a numeric suffix to avoid duplicate naming (e.g. 'test_vg' would be renamed to 'test_vg1'). This option will override the base VG name that is used for all VG renames. If a VG already exists with the specified name a numeric suffix will be added (like the previous example) to make it unique. .TP .BR \-i ", " \-\-import Import exported Volume Groups. Otherwise VGs that have been exported will not be changed (nor will their associated PVs). .SH ENVIRONMENT VARIABLES .TP .B LVM_BINARY The LVM2 binary to use. Defaults to "lvm". .SH Examples The origin VG "vg00" has origin PVs "/dev/sda" and "/dev/sdb" and the respective snapshot PVs are "/dev/sdc" and "/dev/sdd". To rename the VG associated with "/dev/sdc" and "/dev/sdd" from "vg00" to "vg00_snap" (and to change associated VG and PV UUIDs) do: .sp .B vgimportclone --basevgname vg00_snap /dev/sdc /dev/sdd .SH SEE ALSO .BR lvm (8), .BR vgrename (8) lvm2-2.02.98/man/pvcreate.8.in0000640000175000017500000001607712037016272014605 0ustar blankblank.TH PVCREATE 8 "LVM TOOLS #VERSION#" "Sistina Software UK" \" -*- nroff -*- .SH NAME pvcreate \- initialize a disk or partition for use by LVM .SH SYNOPSIS .B pvcreate .RB [ \-d | \-\-debug ] .RB [ \-h | \-\-help ] .RB [ \-t | \-\-test ] .RB [ \-v | \-\-verbose ] .RB [ \-\-version ] .RB [ \-f [ f ]| \-\-force .RB [ \-\-force ]] .RB [ \-y | \-\-yes ] .RB [ \-\-labelsector ] .RB [ \-M | \-\-metadatatype .IR type ] .RB [ \-\- [ pv ] metadatacopies .IR NumberOfCopies ] .RB [ \-\-metadatasize .IR size ] .RB [ \-\-metadataignore .RI { y | n }] .RB [ \-\-dataalignment .IR alignment ] .RB [ \-\-dataalignmentoffset .IR alignment_offset ] .RB [ \-\-restorefile .IR file ] .RB [ \-\-norestorefile ] .RB [ \-\-setphysicalvolumesize .IR size ] .RB [ \-u | \-\-uuid .IR uuid ] .RB [ \-Z | \-\-zero .RI { y | n }] .I PhysicalVolume .RI [ PhysicalVolume ...] .SH DESCRIPTION pvcreate initializes .I PhysicalVolume for later use by the Logical Volume Manager (LVM). Each .I PhysicalVolume can be a disk partition, whole disk, meta device, or loopback file. For DOS disk partitions, the partition id should be set to 0x8e using .BR fdisk (8), .BR cfdisk (8), or a equivalent. For .B whole disk devices only the partition table must be erased, which will effectively destroy all data on that disk. This can be done by zeroing the first sector with: .sp .BI "dd if=/dev/zero of=" PhysicalVolume " bs=512 count=1" .sp Continue with .BR vgcreate (8) to create a new volume group on .IR PhysicalVolume , or .BR vgextend (8) to add .I PhysicalVolume to an existing volume group. .SH OPTIONS See \fBlvm\fP(8) for common options. .TP .BR \-f ", " \-\-force Force the creation without any confirmation. You can not recreate (reinitialize) a physical volume belonging to an existing volume group. In an emergency you can override this behaviour with \fB-ff\fP. .TP .BR \-u ", " \-\-uuid " " \fIuuid Specify the uuid for the device. Without this option, \fBpvcreate\fP(8) generates a random uuid. All of your physical volumes must have unique uuids. You need to use this option before restoring a backup of LVM metadata onto a replacement device - see \fBvgcfgrestore\fP(8). As such, use of \fB\-\-restorefile\fP is compulsory unless the \fB\-\-norestorefile\fP is used. .TP .BR \-y ", " \-\-yes Answer yes to all questions. .TP .BR \-Z ", " \-\-zero " {" \fIy | \fIn } Whether or not the first 4 sectors (2048 bytes) of the device should be wiped. If this option is not given, the default is to wipe these sectors unless either or both of the \fB\-\-restorefile\fP or \fB\-\-uuid\fP options were specified. .SH NEW METADATA OPTIONS LVM2 introduces a new format for storing metadata on disk. This new format is more efficient and resilient than the format the original version of LVM used and offers the advanced user greater flexibility and control. .P The new format may be selected on the command line with \fB\-M2\fP or by setting \fBformat = "lvm2"\fP in the \fBglobal\fP section of \fBlvm.conf\fP(5). Each physical volume in the same volume group must use the same format, but different volume groups on a machine may use different formats simultaneously: the tools can handle both formats. Additional formats can be added as shared libraries. .P Additional tools for manipulating the locations and sizes of metadata areas will be written in due course. Use the verbose/debug options on the tools to see where the metadata areas are placed. .TP .B \-\-metadatasize \fIsize The approximate amount of space to be set aside for each metadata area. (The size you specify may get rounded.) .TP .B \-\-dataalignment \fIalignment Align the start of the data to a multiple of this number. You should also specify an appropriate \fIPhysicalExtentSize\fP when creating the Volume Group with \fBvgcreate\fP. .sp To see the location of the first Physical Extent of an existing Physical Volume use \fBpvs -o +pe_start\fP . It will be a multiple of the requested alignment. In addition it may be shifted by \fIalignment_offset\fP from \fIdata_alignment_offset_detection\fP (if enabled in \fBlvm.conf\fP(5)) or \fB\-\-dataalignmentoffset\fP. .TP .B \-\-dataalignmentoffset \fIalignment_offset Shift the start of the data area by this additional \fIalignment_offset\fP. .TP .BR \-\- [ pv ] metadatacopies " " \fINumberOfCopies The number of metadata areas to set aside on each PV. Currently this can be 0, 1 or 2. If set to 2, two copies of the volume group metadata are held on the PV, one at the front of the PV and one at the end. If set to 1 (the default), one copy is kept at the front of the PV (starting in the 5th sector). If set to 0, no copies are kept on this PV - you might wish to use this with VGs containing large numbers of PVs. But if you do this and then later use \fBvgsplit\fP(8) you must ensure that each VG is still going to have a suitable number of copies of the metadata after the split! .TP .BR \-\-metadataignore " {" \fIy | \fIn } Ignore or un-ignore metadata areas on this physical volume. The default is "n". This setting can be changed with \fBpvchange\fP. If metadata areas on a physical volume are ignored, LVM will not store metadata in the metadata areas present on this Physical Volume. Metadata areas cannot be created or extended after Logical Volumes have been allocated on the device. If you do not want to store metadata on this device, it is still wise always to allocate a metadata area in case you need it in the future and to use this option to instruct LVM2 to ignore it. .TP .B \-\-restorefile \fIfile In conjunction with \fB--uuid\fP, this extracts the location and size of the data on the PV from the file (produced by \fBvgcfgbackup\fP) and ensures that the metadata that the program produces is consistent with the contents of the file i.e. the physical extents will be in the same place and not get overwritten by new metadata. This provides a mechanism to upgrade the metadata format or to add/remove metadata areas. Use with care. See also \fBvgconvert\fP(8). .TP .B \-\-norestorefile In conjunction with \fB\-\-uuid\fP, this allows a \fIuuid\fP to be specified without also requiring that a backup of the metadata be provided. .TP .B \-\-labelsector \fIsector By default the PV is labelled with an LVM2 identifier in its second sector (sector 1). This lets you use a different sector near the start of the disk (between 0 and 3 inclusive - see LABEL_SCAN_SECTORS in the source). Use with care. .TP .B \-\-setphysicalvolumesize \fIsize Overrides the automatically-detected size of the PV. Use with care. .SH Examples Initialize partition #4 on the third SCSI disk and the entire fifth SCSI disk for later use by LVM: .sp .B pvcreate /dev/sdc4 /dev/sde If the 2nd SCSI disk is a 4KiB sector drive that compensates for windows partitioning (sector 7 is the lowest aligned logical block, the 4KiB sectors start at LBA -1, and consequently sector 63 is aligned on a 4KiB boundary) manually account for this when initializing for use by LVM: .sp .B pvcreate \-\-dataalignmentoffset 7s /dev/sdb .SH SEE ALSO .BR lvm.conf (5), .BR lvm (8), .BR vgcreate (8), .BR vgextend (8), .BR lvcreate (8), .BR cfdisk (8), .BR fdisk (8), .BR losetup (8), .BR mdadm (8), .BR vgcfgrestore (8), .BR vgconvert (8) lvm2-2.02.98/man/pvchange.8.in0000640000175000017500000000275712037016272014567 0ustar blankblank.TH PVCHANGE 8 "LVM TOOLS #VERSION#" "Sistina Software UK" \" -*- nroff -*- .SH NAME pvchange \- change attributes of a physical volume .SH SYNOPSIS .B pvchange .RB [ \-\-addtag .IR Tag ] .RB [ \-A | \-\-autobackup .RI { y | n }] .RB [ \-d | \-\-debug ] .RB [ \-f | \-\-force ] .RB [ \-\-deltag .IR Tag ] .RB [ \-\-metadataignore .RI { y | n }] .RB [ \-h | \-? | \-\-help ] .RB [ \-t | \-\-test ] .RB [ \-v | \-\-verbose ] .RB [ \-a | \-\-all ] .RB [ \-x | \-\-allocatable .RI { y | n }] .RB [ \-u | \-\-uuid ] .RI [ PhysicalVolumePath ...] .SH DESCRIPTION pvchange allows you to change the allocation permissions of one or more physical volumes. .SH OPTIONS See \fBlvm\fP(8) for common options. .TP .BR \-a ", " \-\-all If PhysicalVolumePath is not specified on the command line all physical volumes are searched for and used. .TP .BR \-\-metadataignore " {" \fIy | \fIn } Ignore or un-ignore metadata areas on this physical volume. If metadata areas on a physical volume are ignored, LVM will not not store metadata in the metadata areas present on this Physical Volume. .TP .BR \-u ", " \-\-uuid Generate new random UUID for specified physical volumes. .TP .BR \-x ", " \-\-allocatable " {" \fIy | \fIn } Enable or disable allocation of physical extents on this physical volume. .SH Example Disallows the allocation of physical extents on this physical volume (possibly because of disk errors, or because it will be removed after freeing it: .sp .B pvchange -x n /dev/sdk1 .SH SEE ALSO .BR lvm (8), .BR pvcreate (8) lvm2-2.02.98/man/vgconvert.8.in0000640000175000017500000000232312037016272014776 0ustar blankblank.TH VGCONVERT 8 "LVM TOOLS #VERSION#" "Sistina Software UK" \" -*- nroff -*- .SH NAME vgconvert \- convert volume group metadata format .SH SYNOPSIS .B vgconvert .RB [ \-d | \-\-debug ] .RB [ \-h | \-\-help ] .RB [ \-t | \-\-test ] .RB [ \-v | \-\-verbose ] .RB [ \-\-labelsector ] .RB [ \-M | \-\-metadatatype .IR type ] .RB [ \-\-pvmetadatacopies .IR NumberOfCopies ] .RB [ \-\-metadatasize .IR size ] .RB [ \-\-version ] .I VolumeGroupName .RI [ VolumeGroupName ...] .SH DESCRIPTION vgconvert converts .I VolumeGroupName metadata from one format to another provided that the metadata fits into the same space. .SH OPTIONS See \fBlvm\fP(8) and \fBpvcreate\fP(8) for options. .SH Examples Convert volume group vg1 from LVM1 metadata format to the new LVM2 metadata format. .sp .B vgconvert \-M2 vg1 .SH RECOVERY Use \fBpvscan\fP(8) to see which PVs lost their metadata. Run \fBpvcreate\fP(8) with the \fB\-\-uuid\fP and \fB\-\-restorefile\fP options on each such PV to reformat it as it was, using the archive file that \fBvgconvert\fP(8) created at the start of the procedure. Finally run \fBvgcfgrestore\fP(8) with that archive file to restore the original metadata. .SH SEE ALSO .BR lvm (8), .BR pvcreate (8), .BR vgcfgrestore (8) lvm2-2.02.98/man/dmeventd.8.in0000640000175000017500000000303212037016272014565 0ustar blankblank.TH DMEVENTD 8 "DM TOOLS #VERSION#" "Red Hat Inc" \" -*- nroff -*- .SH NAME dmeventd \- Device-mapper event daemon .SH SYNOPSIS .B dmeventd .RB [ \-d " [" -d " [" -d ]]] .RB [ \-f ] .RB [ \-h ] .RB [ \-R ] .RB [ \-V ] .RB [ \-? ] .SH DESCRIPTION dmeventd is the event monitoring daemon for device-mapper devices. Library plugins can register and carry out actions triggered when particular events occur. .SH LVM PLUGINS .TP .I Mirror Attempts to handle device failure automatically. See \fBlvm.conf\fP(5). .TP .I Raid Attempts to handle device failure automatically. See \fBlvm.conf\fP(5). .TP .I Snapshot Monitors how full a snapshot is becoming and emits a warning to syslog when it exceeds 80% full. The warning is repeated when 85%, 90% and 95% of the snapshot is filled. See \fBlvm.conf\fP(5). .TP .I Thin Monitors how full a thin pool is becoming and emits a warning to syslog when it exceeds 80% full. The warning is repeated when 85%, 90% and 95% of the thin pool is filled. See \fBlvm.conf\fP(5). .SH OPTIONS .TP .B \-d Repeat from 1 to 3 times (-d, -dd, -ddd) to increase the detail of debug messages sent to syslog. Each extra d adds more debugging information. .TP .B \-f Don't fork, run in the foreground. .TP .BR \-h ", " \-? Show help information. .TP .B \-R Replace a running dmeventd instance. The running dmeventd must be version 2.02.77 or newer. The new dmeventd instance will obtain a list of devices and events to monitor from the currently running daemon. .TP .B \-V Show version of dmeventd. .SH SEE ALSO .BR lvm (8), .BR lvm.conf (5) lvm2-2.02.98/man/lvrename.8.in0000640000175000017500000000234412037016272014575 0ustar blankblank.TH LVRENAME 8 "LVM TOOLS #VERSION#" "Sistina Software UK" \" -*- nroff -*- .SH NAME lvrename \- rename a logical volume .SH SYNOPSIS .B lvrename .RB [ \-A | \-\-autobackup .RI { y | n }] .RB [ \-d | \-\-debug ] .RB [ \-h | \-\-help ] .RB [ \-t | \-\-test ] .RB [ \-v | \-\-verbose ] .RB [ \-\-version ] .RB [ \-f | \-\-force ] .RB [ \-\-noudevsync ] .RI { OldLogicalVolume { Name | Path } .IR NewLogicalVolume { Name | Path } | .I VolumeGroupName OldLogicalVolumeName NewLogicalVolumeName\fR} .SH DESCRIPTION lvrename renames an existing logical volume from .IR OldLogicalVolume { Name | Path } to .IR NewLogicalVolume { Name | Path }. .SH OPTIONS See \fBlvm\fP(8) for common options. .TP .BR \-\-noudevsync Disable udev synchronisation. The process will not wait for notification from udev. It 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. .SH EXAMPLE To rename lvold in volume group vg02 to lvnew: .sp .B lvrename /dev/vg02/lvold vg02/lvnew .sp An alternate syntax to rename this logical volume is: .sp .B lvrename vg02 lvold lvnew .sp .SH SEE ALSO .BR lvm (8), .BR lvchange (8), .BR vgcreate (8), .BR vgrename (8) lvm2-2.02.98/man/lvresize.8.in0000640000175000017500000001015712037016272014630 0ustar blankblank.TH LVRESIZE 8 "LVM TOOLS #VERSION#" "Sistina Software UK" \" -*- nroff -*- .SH NAME lvresize \- resize a logical volume .SH SYNOPSIS .B lvresize .RB [ \-\-alloc " " \fIAllocationPolicy ] .RB [ \-\-noudevsync ] .RB [ \-i | \-\-stripes " " \fIStripes .RB [ \-I | \-\-stripesize " " \fIStripeSize ]] .RB {[ \-l | \-\-extents .RI [ + | \- ] LogicalExtentsNumber [ % { VG | LV | PVS | FREE | ORIGIN "}] |" .RB [ \-L | \-\-size .RI [ + | \- ] LogicalVolumeSize [ bBsSkKmMgGtTpPeE ]} .RB [ \-f | \-\-force ] .RB [ \-n | \-\-nofsck ] .RB [ \-r | \-\-resizefs ] .IR LogicalVolume { Name | Path } .RI [ PhysicalVolumePath [ :PE [ -PE ]]...] .SH DESCRIPTION lvresize allows you to resize a logical volume. Be careful when reducing a logical volume's size, because data in the reduced part is lost!!! You should therefore ensure that any filesystem on the volume is shrunk first so that the extents that are to be removed are not in use. Resizing snapshot logical volumes (see .BR lvcreate (8) for information about creating snapshots) is supported as well. But to change the number of copies in a mirrored logical volume use .BR lvconvert (8). .SH OPTIONS See \fBlvm\fP(8) for common options. .TP .BR \-f ", " \-\-force Force resize without prompting even when it may cause data loss. .TP .BR \-n ", " \-\-nofsck Do not perform fsck before resizing filesystem when filesystem requires it. You may need to use \fB--force\fR to proceed with this option. .TP .BR \-r ", " \-\-resizefs Resize underlying filesystem together with the logical volume using \fBfsadm\fR(8). .TP .IR \fB\-l ", " \fB\-\-extents " [" + | - ] LogicalExtentsNumber [ % { VG | LV | PVS | FREE | ORIGIN }] Change or set the logical volume size in units of logical extents. With the \fI+\fP or \fI-\fP sign the value is added to or subtracted from the actual size of the logical volume and without it, the value is taken as an absolute one. The number can also be expressed as a percentage of the total space in the Volume Group with the suffix \fI%VG\fP, relative to the existing size of the Logical Volume with the suffix \fI%LV\fP, as a percentage of the remaining free space of the PhysicalVolumes on the command line with the suffix \fI%PVS\fP, as a percentage of the remaining free space in the Volume Group with the suffix \fI%FREE\fP, or (for a snapshot) as a percentage of the total space in the Origin Logical Volume with the suffix \fI%ORIGIN\fP. The resulting value is rounded downward for the substraction otherwise it is rounded upward. .TP .IR \fB\-L ", " \fB\-\-size " [" + | - ] LogicalVolumeSize [ bBsSkKmMgGtTpPeE ] Change or set the logical volume size in units of megabytes. A size suffix of \fIM\fP for megabytes, \fIG\fP for gigabytes, \fIT\fP for terabytes, \fIP\fP for petabytes or \fIE\fP for exabytes is optional. With the \fI+\fP or \fI-\fP sign the value is added or subtracted from the actual size of the logical volume and rounded to the full extent size and without it, the value is taken as an absolute one. .TP .BR \-i ", " \-\-stripes " " \fIStripes Gives the number of stripes to use when extending a Logical Volume. Defaults to whatever the last segment of the Logical Volume uses. Not applicable to LVs using the original metadata LVM format, which must use a single value throughout. .TP .BR \-I ", " \-\-stripesize " " \fIStripeSize Gives the number of kilobytes for the granularity of the stripes. Defaults to whatever the last segment of the Logical Volume uses. Not applicable to LVs using the original metadata LVM format, which must use a single value throughout. .br StripeSize must be 2^n (n = 2 to 9). .TP .B \-\-noudevsync Disable udev synchronisation. The process will not wait for notification from udev. It 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. .SH EXAMPLES .br Extend a logical volume vg1/lv1 by 16MB using physical extents /dev/sda:0-1 and /dev/sdb:0-1 for allocation of extents: .sp .B lvresize -L+16M vg1/lv1 /dev/sda:0-1 /dev/sdb:0-1 .SH SEE ALSO .BR fsadm (8), .BR lvm (8), .BR lvconvert (8), .BR lvcreate (8), .BR lvreduce (8), .BR lvchange (8) lvm2-2.02.98/man/pvremove.8.in0000640000175000017500000000165512037016272014633 0ustar blankblank.TH PVREMOVE 8 "LVM TOOLS #VERSION#" "Sistina Software UK" \" -*- nroff -*- .SH NAME pvremove \- remove a physical volume .SH SYNOPSIS .B pvremove .RB [ \-d | \-\-debug ] .RB [ \-h | \-\-help ] .RB [ \-t | \-\-test ] .RB [ \-v | \-\-verbose ] .RB [ \-\-version ] .RB [ \-f [ f ]| \-\-force .RB [ \-\-force ]] .RB [ \-y | \-\-yes ] .I PhysicalVolume .RI [ PhysicalVolume ...] .SH DESCRIPTION pvremove wipes the label on a device so that LVM will no longer recognise it as a physical volume. .SH OPTIONS See \fBlvm\fP(8) for common options. .TP .BR \-ff ", " \-\-force " " \-\-force Force the removal of a physical volume belonging to an existing volume group. Normally \fBvgreduce\fP(8) should be used instead of this command. You cannot remove a physical volume which in use by some active logical volume. .TP .BR \-y ", " \-\-yes Answer yes to all questions. .SH SEE ALSO .BR lvm (8), .BR pvcreate (8), .BR pvdisplay (8), .BR vgreduce (8) lvm2-2.02.98/man/vgimport.8.in0000640000175000017500000000130312037016272014625 0ustar blankblank.TH VGIMPORT 8 "LVM TOOLS #VERSION#" "Sistina Software UK" \" -*- nroff -*- .SH NAME vgimport \- make exported volume groups known to the system .SH SYNOPSIS .B vgimport .RB [ \-a | \-\-all ] .RB [ \-d | \-\-debug ] .RB [ \-h | \-? | \-\-help ] .RB [ \-v | \-\-verbose ] .I VolumeGroupName .RI [ VolumeGroupName ...] .SH DESCRIPTION vgimport allows you to make a Volume Group that was previously exported using .BR vgexport (8) known to the system again, perhaps after moving its Physical Volumes from a different machine. .SH OPTIONS See \fBlvm\fP(8) for common options. .TP .BR \-a ", " \-\-all Import all exported Volume Groups. .SH SEE ALSO .BR lvm (8), .BR pvscan (8), .BR vgexport (8), .BR vgscan (8) lvm2-2.02.98/man/lvextend.8.in0000640000175000017500000001020012037016272014603 0ustar blankblank.TH LVEXTEND 8 "LVM TOOLS #VERSION#" "Sistina Software UK" \" -*- nroff -*- .SH NAME lvextend \- extend the size of a logical volume .SH SYNOPSIS .B lvextend .RB [ \-\-alloc .IR AllocationPolicy ] .RB [ \-A | \-\-autobackup .RI { y | n }] .RB [ \-d | \-\-debug ] .RB [ \-h | \-? | \-\-help ] .RB [ \-\-noudevsync] .RB [ \-i | \-\-stripes .I Stripes .RB [ \-I | \-\-stripesize .IR StripeSize ]] .RB { \-l | \-\-extents .RI [ + ] LogicalExtentsNumber [ % { VG | LV | PVS | FREE | ORIGIN }] | .BR \-L | \-\-size .RI [ + ] LogicalVolumeSize [ bBsSkKmMgGtTpPeE ]} .RB [ \-f | \-\-force ] .RB [ \-n | \-\-nofsck ] .RB [ \-r | \-\-resizefs ] .RB [ \-t | \-\-test ] .RB [ \-v | \-\-verbose ] .I LogicalVolumePath .RI [ PhysicalVolumePath [ :PE [ -PE ]]...] .SH DESCRIPTION lvextend allows you to extend the size of a logical volume. Extension of snapshot logical volumes (see .BR lvcreate (8) for information to create snapshots) is supported as well. But to change the number of copies in a mirrored logical volume use .BR lvconvert (8). .SH OPTIONS See \fBlvm\fP(8) for common options. .TP .B \-\-noudevsync Disable udev synchronisation. The process will not wait for notification from udev. It 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. .TP .IR \fB\-l ", " \fB\-\-extents " [" + ] LogicalExtentsNumber [ % { VG | LV | PVS | FREE | ORIGIN }] Extend or set the logical volume size in units of logical extents. With the '\fI+\fP' sign the value is added to the actual size of the logical volume and without it, the value is taken as an absolute one. The number can also be expressed as a percentage of the total space in the Volume Group with the suffix \fI%VG\fP, relative to the existing size of the Logical Volume with the suffix \fI%LV\fP, of the remaining free space for the specified PhysicalVolume(s) with the suffix \fI%PVS\fP, as a percentage of the remaining free space in the Volume Group with the suffix \fI%FREE\fP, or (for a snapshot) as a percentage of the total space in the Origin Logical Volume with the suffix \fI%ORIGIN\fP. The resulting value is rounded upward. .TP .IR \fB\-L ", " \fB\-\-size " [" + ] LogicalVolumeSize [ bBsSkKmMgGtTpPeE ] Extend or set the logical volume size in units of megabytes. A size suffix of M for megabytes, G for gigabytes, T for terabytes, P for petabytes or E for exabytes is optional. With the + sign the value is added to the actual size of the logical volume and without it, the value is taken as an absolute one. .TP .BR \-i ", " \-\-stripes " " \fIStripes Gives the number of stripes for the extension. Not applicable to LVs using the original metadata LVM format, which must use a single value throughout. .TP .BR \-I ", " \-\-stripesize " " \fIStripeSize Gives the number of kilobytes for the granularity of the stripes. Not applicable to LVs using the original metadata LVM format, which must use a single value throughout. .br StripeSize must be 2^n (n = 2 to 9) .TP .BR \-f ", " \-\-force Proceed with size extension without prompting. .TP .BR \-n ", " \-\-nofsck Do not perform fsck before extending filesystem when filesystem requires it. You may need to use \fB\-\-force\fR to proceed with this option. .TP .BR \-r ", " \-\-resizefs Resize underlying filesystem together with the logical volume using \fBfsadm\fR(8). .SH Examples Extends the size of the logical volume "vg01/lvol10" by 54MiB on physical volume /dev/sdk3. This is only possible if /dev/sdk3 is a member of volume group vg01 and there are enough free physical extents in it: .sp .B lvextend -L +54 /dev/vg01/lvol10 /dev/sdk3 Extends the size of logical volume "vg01/lvol01" by the amount of free space on physical volume /dev/sdk3. This is equivalent to specifying "-l +100%PVS" on the command line: .sp .B lvextend /dev/vg01/lvol01 /dev/sdk3 Extends a logical volume "vg01/lvol01" by 16MiB using physical extents /dev/sda:8-9 and /dev/sdb:8-9 for allocation of extents: .sp .B lvextend -L+16M vg01/lvol01 /dev/sda:8-9 /dev/sdb:8-9 .SH SEE ALSO .BR fsadm (8), .BR lvm (8), .BR lvcreate (8), .BR lvconvert (8), .BR lvreduce (8), .BR lvresize (8), .BR lvchange (8) lvm2-2.02.98/man/lvcreate.8.in0000640000175000017500000003436712037016272014603 0ustar blankblank.TH LVCREATE 8 "LVM TOOLS #VERSION#" "Sistina Software UK" \" -*- nroff -*- .SH NAME lvcreate \- create a logical volume in an existing volume group .SH SYNOPSIS .B lvcreate .RB [ \-\-addtag .IR Tag ] .RB [ \-\-alloc .IR AllocationPolicy ] .RB [ \-a | \-\-activate .RI [ a | e | l ]{ y | n }] .RB [ \-A | \-\-autobackup .RI { y | n }] .RB [ \-C | \-\-contiguous .RI { y | n }] .RB [ \-d | \-\-debug ] .RB [ \-h | \-? | \-\-help ] .RB [ \-\-noudevsync ] .RB [ \-\-ignoremonitoring ] .RB [ \-\-monitor .RI { y | n }] .RB [ \-i | \-\-stripes .IR Stripes .RB [ \-I | \-\-stripesize .IR StripeSize ]] .RB {[ \-l | \-\-extents .IR LogicalExtentsNumber [ % { VG | PVS | FREE }] | .BR \-L | \-\-size .IR LogicalVolumeSize [ bBsSkKmMgGtTpPeE ]] | .BR \-V | \-\-virtualsize .IR VirtualSize [ bBsSkKmMgGtTpPeE ]} .RB [ \-M | \-\-persistent .RI { y | n }] .RB [ \-\-minor .IR minor ] .RB [ \-m | \-\-mirrors .IR Mirrors .RB [ \-\-nosync ] .RB [ \-\-mirrorlog .RI { disk | core | mirrored } | .BR \-\-corelog ] .RB [ \-R | \-\-regionsize .IR MirrorLogRegionSize ]] .RB [ \-n | \-\-name .IR LogicalVolume { Name | Path }] .RB [ \-p | \-\-permission .RI { r | rw }] .RB [ \-r | \-\-readahead .RI { ReadAheadSectors | auto | none }] .RB [ \-t | \-\-test ] .RB [ \-T | \-\-thin .RB [ \-c | \-\-chunksize .IR ChunkSize ] .RB [ \-\-discards .RI { ignore | nopassdown | passdown }] .RB [ \-\-poolmetadatasize .IR MetadataSize [ bBsSkKmMgG ]]] .RB [ \-\-thinpool .IR ThinPoolLogicalVolume { Name | Path }] .RB [ \-\-type .IR SegmentType ] .RB [ \-v | \-\-verbose ] .RB [ \-Z | \-\-zero .RI { y | n }] .IR VolumeGroup { Name | Path }[/ ThinPoolLogicalVolumeName ] .RI [ PhysicalVolumePath [ :PE [ -PE ]]...] .br .B lvcreate .RB [ \-l | \-\-extents .IR LogicalExtentsNumber [ % { VG | FREE | ORIGIN }] | .BR \-L | \-\-size .IR LogicalVolumeSize [ bBsSkKmMgGtTpPeE ]] .RB [ \-c | \-\-chunksize .IR ChunkSize ] .RB [ \-\-noudevsync ] .RB [ \-\-ignoremonitoring ] .RB [ \-\-monitor " {" \fIy | \fIn }] .RB [ \-n | \-\-name .IR SnapshotLogicalVolume { Name | Path }] .BR \-s | \-\-snapshot .RI {[ VolumeGroup { Name | Path }/] OriginalLogicalVolumeName .BR \-V | \-\-virtualsize .IR VirtualSize [ bBsSkKmMgGtTpPeE ]} .br .SH DESCRIPTION lvcreate creates a new logical volume in a volume group (see .BR vgcreate "(8), " vgchange (8)) by allocating logical extents from the free physical extent pool of that volume group. If there are not enough free physical extents then the volume group can be extended (see .BR vgextend (8)) with other physical volumes or by reducing existing logical volumes of this volume group in size (see .BR lvreduce (8)). If you specify one or more PhysicalVolumes, allocation of physical extents will be restricted to these volumes. .br .br The second form supports the creation of snapshot logical volumes which keep the contents of the original logical volume for backup purposes. .SH OPTIONS See .BR lvm (8) for common options. .TP .IR \fB\-a ", " \fB\-\-activate " {" y | ay | n | ey | en | ly | ln } Controls the availability of the Logical Volumes for immediate use after the command finishes running. By default, new Logical Volumes are activated (\fB-a\fIy\fR). If it is possible technically, \fB-a\fIn\fR will leave the new Logical Volume inactive. But for example, snapshots can only be created in the active state so \fB\-a\fIn\fR cannot be used with \fB\-\-snapshot\fP. Normally the \fB\-\-zero n\fP argument has to be supplied too because zeroing (the default behaviour) also requires activation. If autoactivation option is used (\fB\-a\fIay\fR), the logical volume is activated only if it matches an item in the activation/auto_activation_volume_list set in lvm.conf. For autoactivated logical volumes, \fB\-\-zero n\fP is always assumed and it can't be overridden. If clustered locking is enabled, \fB\-a\fIey\fR will activate exclusively on one node and \fB\-a\fIly\fR will activate only on the local node. .TP .BR \-c ", " \-\-chunksize " " \fIChunkSize Gives the size of chunk for snapshot and thin pool logical volumes. For snapshots the value must be power of 2 between 4KiB and 512KiB and the default value is 4. For thin pools the value must be between 64KiB and 1048576KiB and the default value starts with 64 and scales up to fit the pool metadata size within 128MB, if the poolmetadata size is not specified. Older dm thin pool target version (<1.4) requires the value to be power of 2. The newer version requires to be the multiple of 64KiB, however discard is not supported for non power of 2 values. Default unit is in kilobytes. .TP .BR \-C ", " \-\-contiguous " {" \fIy | \fIn } Sets or resets the contiguous allocation policy for logical volumes. Default is no contiguous allocation based on a next free principle. .TP .BR \-\-discards " {" \fIignore | \fInopassdown | \fIpassdown } Set discards behavior. Default is \fIpassdown\fP. .TP .BR \-i ", " \-\-stripes " " \fIStripes Gives the number of stripes. This is equal to the number of physical volumes to scatter the logical volume. .TP .BR \-I ", " \-\-stripesize " " \fIStripeSize Gives the number of kilobytes for the granularity of the stripes. .br StripeSize must be 2^n (n = 2 to 9) for metadata in LVM1 format. For metadata in LVM2 format, the stripe size may be a larger power of 2 but must not exceed the physical extent size. .TP .IR \fB\-l ", " \fB\-\-extents " " LogicalExtentsNumber [ % { VG | PVS | FREE | ORIGIN }] Gives the number of logical extents to allocate for the new logical volume. The number can also be expressed as a percentage of the total space in the Volume Group with the suffix \fI%VG\fR, as a percentage of the remaining free space in the Volume Group with the suffix \fI%FREE\fR, as a percentage of the remaining free space for the specified PhysicalVolume(s) with the suffix \fI%PVS\fR, or (for a snapshot) as a percentage of the total space in the Origin Logical Volume with the suffix \fI%ORIGIN\fR. .TP .IR \fB\-L ", " \fB\-\-size " " LogicalVolumeSize [ bBsSkKmMgGtTpPeE ] Gives the size to allocate for the new logical volume. A size suffix of \fIK\fR for kilobytes, \fIM\fR for megabytes, \fIG\fR for gigabytes, \fIT\fR for terabytes, \fIP\fR for petabytes or \fIE\fR for exabytes is optional. .br Default unit is megabytes. .TP .B \-\-minor \fIminor Set the minor number. .TP .IR \fB\-M ", " \fB\-\-persistent " {" y | n } Set to y to make the minor number specified persistent. .TP .BR \-m ", " \-\-mirrors " " \fIMirrors Creates a mirrored logical volume with Mirrors copies. For example, specifying "-m 1" would result in a mirror with two-sides; that is, a linear volume plus one copy. Specifying the optional argument --nosync will cause the creation of the mirror to skip the initial resynchronization. Any data written afterwards will be mirrored, but the original contents will not be copied. This is useful for skipping a potentially long and resource intensive initial sync of an empty device. The optional argument --mirrorlog specifies the type of log to be used. The default is disk, which is persistent and requires a small amount of storage space, usually on a separate device from the data being mirrored. Using core means the mirror is regenerated by copying the data from the first device again each time the device is activated, for example, after every reboot. Using "mirrored" will create a persistent log that is itself mirrored. The optional argument --corelog is equivalent to --mirrorlog core. .TP .IR \fB\-n ", " \fB\-\-name " " LogicalVolume { Name | Path } The name for the new logical volume. .br Without this option a default names of "lvol#" will be generated where # is the LVM internal number of the logical volume. .TP .B \-\-noudevsync Disable udev synchronisation. The process will not wait for notification from udev. It 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. .TP .BR \-\-monitor " {" \fIy | \fIn } Start or avoid monitoring a mirrored or snapshot logical volume with dmeventd, if it is installed. If a device used by a monitored mirror reports an I/O error, the failure is handled according to \fBmirror_image_fault_policy\fP and \fBmirror_log_fault_policy\fP set in \fBlvm.conf\fP. .TP .B \-\-ignoremonitoring Make no attempt to interact with dmeventd unless \-\-monitor is specified. .TP .BR \-p ", " \-\-permission " {" \fIr | \fIrw } Set access permissions to read only or read and write. .br Default is read and write. .TP .IR \fB\-\-poolmetadatasize " " MetadataSize [ bBsSkKmMgG ] Set the size of thin pool's metadata logical volume. Supported value is in range between 2MiB and 16GiB. Default value is (Pool_LV_size / Pool_LV_chunk_size * 64b). Default unit is megabytes. .TP .IR \fB\-r ", " \fB\-\-readahead " {" ReadAheadSectors | auto | none } Set read ahead sector count of this logical volume. For volume groups with metadata in lvm1 format, this must be a value between 2 and 120. The default value is "auto" which allows the kernel to choose a suitable value automatically. "None" is equivalent to specifying zero. .TP .BR \-R ", " \-\-regionsize " " \fIMirrorLogRegionSize A mirror is divided into regions of this size (in MB), and the mirror log uses this granularity to track which regions are in sync. .TP .IR \fB\-s ", " \fB\-\-snapshot " " OriginalLogicalVolume { Name | Path } Create a snapshot logical volume (or snapshot) for an existing, so called original logical volume (or origin). Snapshots provide a 'frozen image' of the contents of the origin while the origin can still be updated. They enable consistent backups and online recovery of removed/overwritten data/files. Thin snapshot is created when the origin is a thin volume and the size is not specified. Thin snapshot shares same blocks within the thin pool volume. The snapshot with the specified size does not need the same amount of storage the origin has. In a typical scenario, 15-20% might be enough. In case the snapshot runs out of storage, use .BR lvextend (8) to grow it. Shrinking a snapshot is supported by .BR lvreduce (8) as well. Run .BR lvdisplay (8) on the snapshot in order to check how much data is allocated to it. Note that a small amount of the space you allocate to the snapshot is used to track the locations of the chunks of data, so you should allocate slightly more space than you actually need and monitor the rate at which the snapshot data is growing so you can avoid running out of space. .TP .IR \fB\-T ", " \fB\-\-thin ", " \fB\-\-thinpool " " ThinPoolLogicalVolume { Name | Path } Creates thin pool or thin logical volume or both. Specifying the optional argument \fB\-\-size\fP will cause the creation of the thin pool logical volume. Specifying the optional argument \fB\-\-virtualsize\fP will cause the creation of the thin logical volume from given thin pool volume. Specifying both arguments will cause the creation of both thin pool and thin volume using this pool. Requires device mapper kernel driver for thin provisioning from kernel 3.2 or newer. .TP .B \-\-type \fISegmentType Create a logical volume that uses the specified segment type (e.g. "raid5", "mirror", "snapshot", "thin", "thin-pool"). Many segment types have a commandline switch alias that will enable their use (\fB\-s\fP is an alias for \fB\-\-type snapshot\fP). However, this argument must be used when no existing commandline switch alias is available for the desired type, as is the case with .IR error ", " zero ", " raid1 ", " raid4 ", " raid5 " or " raid6 . .TP .BR \-V ", " \-\-virtualsize " " \fIVirtualSize [ \fIbBsSkKmMgGtTpPeE ] Create a sparse device of the given size (in MB by default) using a snapshot or thinly provisioned device when thin pool is specified. Anything written to the device will be returned when reading from it. Reading from other areas of the device will return blocks of zeros. Virtual snapshot is implemented by creating a hidden virtual device of the requested size using the zero target. A suffix of _vorigin is used for this device. .TP .BR \-Z ", " \-\-zero " {" \fIy | \fIn } Controls zeroing of the first KB of data in the new logical volume. .br Default is yes. .br Volume will not be zeroed if read only flag is set. .br Snapshot volumes are zeroed always. .br Warning: trying to mount an unzeroed logical volume can cause the system to hang. .SH Examples Creates a striped logical volume with 3 stripes, a stripesize of 8KB and a size of 100MB in the volume group named vg00. The logical volume name will be chosen by lvcreate: .sp .B lvcreate \-i 3 \-I 8 \-L 100M vg00 Creates a mirror logical volume with 2 sides with a useable size of 500 MiB. This operation would require 3 devices (or option --alloc anywhere) - two for the mirror devices and one for the disk log: .sp .B lvcreate \-m1 \-L 500M vg00 Creates a mirror logical volume with 2 sides with a useable size of 500 MiB. This operation would require 2 devices - the log is "in-memory": .sp .B lvcreate \-m1 \-\-mirrorlog core \-L 500M vg00 Creates a snapshot logical volume named /dev/vg00/snap which has access to the contents of the original logical volume named /dev/vg00/lvol1 at snapshot logical volume creation time. If the original logical volume contains a file system, you can mount the snapshot logical volume on an arbitrary directory in order to access the contents of the filesystem to run a backup while the original filesystem continues to get updated: .sp .B lvcreate \-\-size 100m \-\-snapshot \-\-name snap /dev/vg00/lvol1 Creates a sparse device named /dev/vg1/sparse of size 1TiB with space for just under 100MiB of actual data on it: .sp .B lvcreate \-\-virtualsize 1T \-\-size 100M \-\-snapshot \-\-name sparse vg1 Creates a linear logical volume "vg00/lvol1" using physical extents /dev/sda:0-7 and /dev/sdb:0-7 for allocation of extents: .sp .B lvcreate \-L 64M -n lvol1 vg00 /dev/sda:0\-7 /dev/sdb:0\-7 Creates a 5GiB RAID5 logical volume "vg00/my_lv", with 3 stripes (plus a parity drive for a total of 4 devices) and a stripesize of 64KiB: .sp .B lvcreate \-\-type raid5 \-L 5G \-i 3 \-I 64 \-n my_lv vg00 Creates 100MiB pool logical volume for thin provisioning build with 2 stripes 64KiB and chunk size 128KiB together with 1TiB thin provisioned logical volume "vg00/thin_lv": .sp .B lvcreate \-i 2 \-I 64 \-c 256 \-L100M \-T vg00/pool \-V 1T \-\-name thin_lv .SH SEE ALSO .BR lvm (8), .BR vgcreate (8), .BR lvchange (8), .BR lvremove (8), .BR lvrename (8) .BR lvextend (8), .BR lvreduce (8), .BR lvdisplay (8), .BR lvscan (8) lvm2-2.02.98/man/pvmove.8.in0000640000175000017500000001206412037016272014300 0ustar blankblank.TH PVMOVE 8 "LVM TOOLS #VERSION#" "Sistina Software UK" \" -*- nroff -*- .SH NAME pvmove \- move physical extents .SH SYNOPSIS .B pvmove .RB [ \-\-abort ] .RB [ \-\-alloc .IR AllocationPolicy ] .RB [ \-b | \-\-background ] .RB [ \-d | \-\-debug ] .RB [ \-h | \-\-help ] .RB [ \-i | \-\-interval .IR Seconds ] .RB [ \-\-noudevsync ] .RB [ \-v | \-\-verbose ] .RB [ \-n | \-\-name .IR LogicalVolume ] .RI [ SourcePhysicalVolume [ :PE [ -PE ]...] .RI [ DestinationPhysicalVolume [ :PE [ -PE ]...]...]] .SH DESCRIPTION pvmove allows you to move the allocated physical extents (PEs) on .I SourcePhysicalVolume to one or more other physical volumes (PVs). You can optionally specify a source .I LogicalVolume in which case only extents used by that LV will be moved to free (or specified) extents on .IR DestinationPhysicalVolume (s). If no .I DestinationPhysicalVolume is specified, the normal allocation rules for the Volume Group are used. If pvmove gets interrupted for any reason (e.g. the machine crashes) then run pvmove again without any PhysicalVolume arguments to restart any moves that were in progress from the last checkpoint. Alternatively use \fBpvmove --abort\fP at any time to abort them at the last checkpoint. You can run more than one pvmove at once provided they are moving data off different SourcePhysicalVolumes, but additional pvmoves will ignore any Logical Volumes already in the process of being changed, so some data might not get moved. \fBpvmove\fP works as follows: 1. A temporary 'pvmove' Logical Volume is created to store details of all the data movements required. 2. Every Logical Volume in the Volume Group is searched for contiguous data that need moving according to the command line arguments. For each piece of data found, a new segment is added to the end of the pvmove LV. This segment takes the form of a temporary mirror to copy the data from the original location to a newly-allocated location. The original LV is updated to use the new temporary mirror segment in the pvmove LV instead of accessing the data directly. 3. The Volume Group metadata is updated on disk. 4. The first segment of the pvmove Logical Volume is activated and starts to mirror the first part of the data. Only one segment is mirrored at once as this is usually more efficient. 5. A daemon repeatedly checks progress at the specified time interval. When it detects that the first temporary mirror is in-sync, it breaks that mirror so that only the new location for that data gets used and writes a checkpoint into the Volume Group metadata on disk. Then it activates the mirror for the next segment of the pvmove LV. 6. When there are no more segments left to be mirrored, the temporary Logical Volume is removed and the Volume Group metadata is updated so that the Logical Volumes reflect the new data locations. Note that this new process cannot support the original LVM1 type of on-disk metadata. Metadata can be converted using \fBvgconvert\fP(8). N.B. The moving of mirrors, snapshots and their origins is not yet supported. .SH OPTIONS See \fBlvm\fP(8) for common options. .TP .B \-\-abort Abort any moves in progress. .TP .B \-\-noudevsync Disable udev synchronisation. The process will not wait for notification from udev. It 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. .TP .BR \-b ", " \-\-background Run the daemon in the background. .TP .BR \-i ", " \-\-interval " " \fISeconds Report progress as a percentage at regular intervals. .TP .BR \-n ", " \-\-name " " \fILogicalVolume Move only the extents belonging to .I LogicalVolume from .I SourcePhysicalVolume instead of all allocated extents to the destination physical volume(s). .SH Examples To move all Physical Extents that are used by simple Logical Volumes on /dev/sdb1 to free Physical Extents elsewhere in the Volume Group use: .sp .B pvmove /dev/sdb1 .P Any mirrors, snapshots and their origins are left unchanged. .P Additionally, a specific destination device /dev/sdc1 can be specified like this: .sp .B pvmove /dev/sdb1 /dev/sdc1 .P To perform the action only on extents belonging to the single Logical Volume lvol1 do this: .sp .B pvmove -n lvol1 /dev/sdb1 /dev/sdc1 .P Rather than moving the contents of the entire device, it is possible to move a range of Physical Extents - for example numbers 1000 to 1999 inclusive on /dev/sdb1 - like this: .sp .B pvmove /dev/sdb1:1000-1999 .P To move a range of Physical Extents to a specific location (which must have sufficent free extents) use the form: .sp .B pvmove /dev/sdb1:1000-1999 /dev/sdc1 .sp or .sp .B pvmove /dev/sdb1:1000-1999 /dev/sdc1:0-999 .P If the source and destination are on the same disk, the .B anywhere allocation policy would be needed, like this: .sp .B pvmove --alloc anywhere /dev/sdb1:1000-1999 /dev/sdb1:0-999 .P The part of a specific Logical Volume present within in a range of Physical Extents can also be picked out and moved, like this: .sp .B pvmove -n lvol1 /dev/sdb1:1000-1999 /dev/sdc1 .SH SEE ALSO .BR lvm (8), .BR vgconvert (8) .BR pvs (8) lvm2-2.02.98/man/lvmchange.8.in0000640000175000017500000000050512037016272014725 0ustar blankblank.TH LVMCHANGE 8 "LVM TOOLS #VERSION#" "Sistina Software UK" \" -*- nroff -*- .SH NAME lvmchange \- change attributes of the logical volume manager .SH SYNOPSIS .B lvmchange .SH DESCRIPTION lvmchange is not currently supported under LVM2, although \fBdmsetup\fP(8) has a \fBremove_all\fP command. .SH SEE ALSO .BR dmsetup (8) lvm2-2.02.98/man/lvs.8.in0000640000175000017500000001300712037016272013566 0ustar blankblank.TH LVS 8 "LVM TOOLS #VERSION#" "Sistina Software UK" \" -*- nroff -*- .SH NAME lvs \- report information about logical volumes .SH SYNOPSIS .B lvs .RB [ \-\-aligned ] .RB [ \-a | \-\-all ] .RB [ \-d | \-\-debug ] .RB [ \-h | \-? | \-\-help ] .RB [ \-\-ignorelockingfailure ] .RB [ \-\-nameprefixes ] .RB [ \-\-noheadings ] .RB [ \-\-nosuffix ] .RB [ \-o | \-\-options .RI [ + ] Field [, Field ]] .RB [ \-O | \-\-sort .RI [ + | \- ] Key1 [,[ + | \- ] Key2 [,...]]] .RB [ \-P | \-\-partial ] .RB [ \-\-rows ] .RB [ \-\-separator .IR Separator ] .RB [ \-\-segments ] .RB [ \-\-unbuffered ] .RB [ \-\-units .IR hHbBsSkKmMgGtTpPeE ] .RB [ \-\-unquoted ] .RB [ \-v | \-\-verbose ] .RB [ \-\-version ] .RI [ VolumeGroupName .RI [ VolumeGroupName ...]] .SH DESCRIPTION lvs produces formatted output about logical volumes. .SH OPTIONS See .BR lvm (8) for common options. .TP .B \-\-aligned Use with \fB\-\-separator\fP to align the output columns. .TP .B \-\-all Include information in the output about internal Logical Volumes that are components of normally-accessible Logical Volumes, such as mirrors, but which are not independently accessible (e.g. not mountable). The names of such Logical Volumes are enclosed within square brackets in the output. For example, after creating a mirror using .B lvcreate -m1 --mirrorlog disk , this option will reveal three internal Logical Volumes, with suffixes mimage_0, mimage_1, and mlog. .TP .B \-\-nameprefixes Add an "LVM2_" prefix plus the field name to the output. Useful with \fB\-\-noheadings\fP to produce a list of field=value pairs that can be used to set environment variables (for example, in .BR udev (7) rules). .TP .B \-\-noheadings Suppress the headings line that is normally the first line of output. Useful if grepping the output. .TP .B \-\-nosuffix Suppress the suffix on output sizes. Use with \fB\-\-units\fP (except h and H) if processing the output. .TP .BR \-o ", " \-\-options Comma-separated ordered list of columns. Precede the list with '\fI+\fP' to append to the default selection of columns instead of replacing it. .IP Use \fB\-o lv_all\fP to select all logical volume columns, and \fB\-o seg_all\fP to select all logical volume segment columns. .IP Use \fB\-o help\fP to view the full list of columns available. .IP Column names include: chunk_size, convert_lv, copy_percent, data_lv, devices, discards, lv_attr, lv_host, lv_kernel_major, lv_kernel_minor, lv_kernel_read_ahead, lv_major, lv_minor, lv_name, lv_path, lv_read_ahead, lv_size, lv_tags, lv_time, lv_uuid, metadata_lv, mirror_log, modules, move_pv, origin, origin_size, pool_lv, region_size, segtype, seg_count, seg_pe_ranges, seg_size, seg_start, seg_start_pe, seg_tags, snap_percent, stripes, stripe_size, thin_count, transaction_id, zero. .IP With \fB\-\-segments\fP, any "seg_" prefixes are optional; otherwise any "lv_" prefixes are optional. Columns mentioned in .BR vgs (8) can also be chosen. .IP The lv_attr bits are: .RS .IP 1 3 Volume type: (m)irrored, (M)irrored without initial sync, (o)rigin, (O)rigin with merging snapshot, (r)aid, (R)aid without initial sync, (s)napshot, merging (S)napshot, (p)vmove, (v)irtual, mirror or raid (i)mage, mirror or raid (I)mage out-of-sync, mirror (l)og device, under (c)onversion, thin (V)olume, (t)hin pool, (T)hin pool data, raid or thin pool m(e)tadata .IP 2 3 Permissions: (w)riteable, (r)ead-only, (R)ead-only activation of non-read-only volume .IP 3 3 Allocation policy: (a)nywhere, (c)ontiguous, (i)nherited, c(l)ing, (n)ormal This is capitalised if the volume is currently locked against allocation changes, for example during .BR pvmove (8). .IP 4 3 fixed (m)inor .IP 5 3 State: (a)ctive, (s)uspended, (I)nvalid snapshot, invalid (S)uspended snapshot, snapshot (m)erge failed, suspended snapshot (M)erge failed, mapped (d)evice present without tables, mapped device present with (i)nactive table .IP 6 3 device (o)pen .IP 7 3 Target type: (m)irror, (r)aid, (s)napshot, (t)hin, (u)nknown, (v)irtual. This groups logical volumes related to the same kernel target together. So, for example, mirror images, mirror logs as well as mirrors themselves appear as (m) if they use the original device-mapper mirror kernel driver; whereas the raid equivalents using the md raid kernel driver all appear as (r). Snapshots using the original device-mapper driver appear as (s); whereas snapshots of thin volumes using the new thin provisioning driver appear as (t). .IP 8 3 Newly-allocated data blocks are overwritten with blocks of (z)eroes before use. .IP 9 3 (p)artial: One or more of the Physical Volumes this Logical Volume uses is missing from the system. .RE .TP .BR \-O ", " \-\-sort Comma-separated ordered list of columns to sort by. Replaces the default selection. Precede any column with '\fI\-\fP' for a reverse sort on that column. .TP .B \-\-rows Output columns as rows. .TP .B \-\-segments Use default columns that emphasize segment information. .TP .B \-\-separator \fISeparator String to use to separate each column. Useful if grepping the output. .TP .B \-\-unbuffered Produce output immediately without sorting or aligning the columns properly. .TP .B \-\-units \fIhHbBsSkKmMgGtTpPeE All sizes are output in these units: (h)uman-readable, (b)ytes, (s)ectors, (k)ilobytes, (m)egabytes, (g)igabytes, (t)erabytes, (p)etabytes, (e)xabytes. Capitalise to use multiples of 1000 (S.I.) instead of 1024. Can also specify custom units e.g. \fB\-\-units 3M\fP .TP .B \-\-unquoted When used with \fB\-\-nameprefixes\fP, output values in the field=value pairs are not quoted. .SH SEE ALSO .BR lvm (8), .BR lvdisplay (8), .BR pvs (8), .BR vgs (8) lvm2-2.02.98/man/lvmetad.8.in0000640000175000017500000000270112037016272014415 0ustar blankblank.TH LVMETAD 8 "LVM TOOLS #VERSION#" "Red Hat Inc" \" -*- nroff -*- .SH NAME lvmetad \- LVM metadata cache daemon .SH SYNOPSIS .B lvmetad .RB [ \-l .RI {all|wire|debug} .RB ] .RB [ \-s .RI path .RB ] .RB [ \-f ] .RB [ \-h ] .RB [ \-V ] .RB [ \-? ] .SH DESCRIPTION lvmetad is a metadata caching daemon for LVM. The daemon receives notifications from udev rules (which must be installed for LVM to work correctly when lvmetad is in use). Through these notifications, lvmetad has an up-to-date and consistent image of the volume groups available in the system. By default, lvmetad, even if running, is not used by LVM. See \fBlvm.conf\fP(5). .SH OPTIONS .TP .BR \-l " {" \fIall | \fIwire | \fIdebug } Select the type of log messages to generate. Messages are logged by syslog. Additionally, when -f is given they are also sent to standard error. Since release 2.02.98, there are two classes of messages: wire and debug. Selecting 'all' supplies both and is equivalent to a comma-separated list -l wire,debug. Prior to release 2.02.98, repeating -d from 1 to 3 times, viz. -d, -dd, -ddd, increased the detail of messages. .TP .B \-f Don't fork, run in the foreground. .TP .BR \-h ", " \-? Show help information. .TP .B \-s \fIpath Path to the socket file to use. The option overrides both the built-in default (#DEFAULT_RUN_DIR#/lvmetad.socket) and the environment variable LVM_LVMETAD_SOCKET. .TP .B \-V Show version of dmeventd. .SH SEE ALSO .BR lvm (8), .BR lvm.conf (5) lvm2-2.02.98/man/pvresize.8.in0000640000175000017500000000267412037016272014641 0ustar blankblank.TH PVRESIZE 8 "LVM TOOLS #VERSION#" "Sistina Software UK" \" -*- nroff -*- .SH NAME pvresize \- resize a disk or partition in use by LVM2 .SH SYNOPSIS .B pvresize .RB [ \-d | \-\-debug ] .RB [ \-h | \-\-help ] .RB [ \-t | \-\-test ] .RB [ \-v | \-\-verbose ] .RB [ \-\-version ] .RB [ \-\-setphysicalvolumesize .IR size ] .I PhysicalVolume .RI [ PhysicalVolume ...] .SH DESCRIPTION pvresize resizes .I PhysicalVolume which may already be in a volume group and have active logical volumes allocated on it. .SH OPTIONS See \fBlvm\fP(8) for common options. .TP .BI \-\-setphysicalvolumesize " size" Overrides the automatically-detected size of the PV. Use with care, or prior to reducing the physical size of the device. .SH EXAMPLES Expand the PV on /dev/sda1 after enlarging the partition with fdisk: .sp .B pvresize /dev/sda1 .sp Shrink the PV on /dev/sda1 prior to shrinking the partition with fdisk (ensure that the PV size is appropriate for your intended new partition size): .sp .B pvresize \-\-setphysicalvolumesize 40G /dev/sda1 .sp .SH RESTRICTIONS pvresize will refuse to shrink .I PhysicalVolume if it has allocated extents after where its new end would be. In the future, it should relocate these elsewhere in the volume group if there is sufficient free space, like .B pvmove does. .sp .B pvresize won't currently work correctly on LVM1 volumes or PVs with extra metadata areas. .SH SEE ALSO .BR lvm (8), .BR pvmove (8), .BR lvresize (8), .BR fdisk (8) lvm2-2.02.98/man/lvm.8.in0000640000175000017500000003660312037016272013567 0ustar blankblank.TH LVM 8 "LVM TOOLS #VERSION#" "Sistina Software UK" \" -*- nroff -*- .SH NAME lvm \- LVM2 tools .SH SYNOPSIS .B lvm [command | file] .SH DESCRIPTION lvm provides the command-line tools for LVM2. A separate manual page describes each command in detail. .LP If \fBlvm\fP is invoked with no arguments it presents a readline prompt (assuming it was compiled with readline support). LVM commands may be entered interactively at this prompt with readline facilities including history and command name and option completion. Refer to \fBreadline\fP(3) for details. .LP If \fBlvm\fP is invoked with argv[0] set to the name of a specific LVM command (for example by using a hard or soft link) it acts as that command. .LP On invocation, \fBlvm\fP requires that only the standard file descriptors stdin, stdout and stderr are available. If others are found, they get closed and messages are issued warning about the leak. .LP Where commands take VG or LV names as arguments, the full path name is optional. An LV called "lvol0" in a VG called "vg0" can be specified as "vg0/lvol0". Where a list of VGs is required but is left empty, a list of all VGs will be substituted. Where a list of LVs is required but a VG is given, a list of all the LVs in that VG will be substituted. So \fBlvdisplay vg0\fP will display all the LVs in "vg0". Tags can also be used - see \fB\-\-addtag\fP below. .LP One advantage of using the built-in shell is that configuration information gets cached internally between commands. .LP A file containing a simple script with one command per line can also be given on the command line. The script can also be executed directly if the first line is #! followed by the absolute path of \fBlvm\fP. .SH BUILT-IN COMMANDS The following commands are built into lvm without links normally being created in the filesystem for them. .TP \fBdumpconfig\fP \(em Display the configuration information after loading \fBlvm.conf\fP(5) and any other configuration files. .TP \fBformats\fP \(em Display recognised metadata formats. .TP \fBhelp\fP \(em Display the help text. .TP \fBpvdata\fP \(em Not implemented in LVM2. .TP \fBsegtypes\fP \(em Display recognised Logical Volume segment types. .TP \fBversion\fP \(em Display version information. .LP .SH COMMANDS The following commands implement the core LVM functionality. .TP \fBpvchange\fP \(em Change attributes of a Physical Volume. .TP \fBpvck\fP \(em Check Physical Volume metadata. .TP \fBpvcreate\fP \(em Initialize a disk or partition for use by LVM. .TP \fBpvdisplay\fP \(em Display attributes of a Physical Volume. .TP \fBpvmove\fP \(em Move Physical Extents. .TP \fBpvremove\fP \(em Remove a Physical Volume. .TP \fBpvresize\fP \(em Resize a disk or partition in use by LVM2. .TP \fBpvs\fP \(em Report information about Physical Volumes. .TP \fBpvscan\fP \(em Scan all disks for Physical Volumes. .TP \fBvgcfgbackup\fP \(em Backup Volume Group descriptor area. .TP \fBvgcfgrestore\fP \(em Restore Volume Group descriptor area. .TP \fBvgchange\fP \(em Change attributes of a Volume Group. .TP \fBvgck\fP \(em Check Volume Group metadata. .TP \fBvgconvert\fP \(em Convert Volume Group metadata format. .TP \fBvgcreate\fP \(em Create a Volume Group. .TP \fBvgdisplay\fP \(em Display attributes of Volume Groups. .TP \fBvgexport\fP \(em Make volume Groups unknown to the system. .TP \fBvgextend\fP \(em Add Physical Volumes to a Volume Group. .TP \fBvgimport\fP \(em Make exported Volume Groups known to the system. .TP \fBvgimportclone\fP \(em Import and rename duplicated Volume Group (e.g. a hardware snapshot). .TP \fBvgmerge\fP \(em Merge two Volume Groups. .TP \fBvgmknodes\fP \(em Recreate Volume Group directory and Logical Volume special files .TP \fBvgreduce\fP \(em Reduce a Volume Group by removing one or more Physical Volumes. .TP \fBvgremove\fP \(em Remove a Volume Group. .TP \fBvgrename\fP \(em Rename a Volume Group. .TP \fBvgs\fP \(em Report information about Volume Groups. .TP \fBvgscan\fP \(em Scan all disks for Volume Groups and rebuild caches. .TP \fBvgsplit\fP \(em Split a Volume Group into two, moving any logical volumes from one Volume Group to another by moving entire Physical Volumes. .TP \fBlvchange\fP \(em Change attributes of a Logical Volume. .TP \fBlvconvert\fP \(em Convert a Logical Volume from linear to mirror or snapshot. .TP \fBlvcreate\fP \(em Create a Logical Volume in an existing Volume Group. .TP \fBlvdisplay\fP \(em Display attributes of a Logical Volume. .TP \fBlvextend\fP \(em Extend the size of a Logical Volume. .TP \fBlvmchange\fP \(em Change attributes of the Logical Volume Manager. .TP \fBlvmdiskscan\fP \(em Scan for all devices visible to LVM2. .TP \fBlvmdump\fP \(em Create lvm2 information dumps for diagnostic purposes. .TP \fBlvreduce\fP \(em Reduce the size of a Logical Volume. .TP \fBlvremove\fP \(em Remove a Logical Volume. .TP \fBlvrename\fP \(em Rename a Logical Volume. .TP \fBlvresize\fP \(em Resize a Logical Volume. .TP \fBlvs\fP \(em Report information about Logical Volumes. .TP \fBlvscan\fP \(em Scan (all disks) for Logical Volumes. .TP The following commands are not implemented in LVM2 but might be in the future: lvmsadc, lvmsar, pvdata. .SH OPTIONS The following options are available for many of the commands. They are implemented generically and documented here rather than repeated on individual manual pages. .TP .BR \-h ", " \-\-help Display the help text. .TP .B \-\-version Display version information. .TP .BR \-v ", " \-\-verbose Set verbose level. Repeat from 1 to 3 times to increase the detail of messages sent to stdout and stderr. Overrides config file setting. .TP .BR \-d ", " \-\-debug Set debug level. Repeat from 1 to 6 times to increase the detail of messages sent to the log file and/or syslog (if configured). Overrides config file setting. .TP .BR \-q ", " \-\-quiet Suppress output and log messages. Overrides \fB\-d\fP and \fB\-v\fP. .TP .BR \-t ", " \-\-test Run in test mode. Commands will not update metadata. This is implemented by disabling all metadata writing but nevertheless returning success to the calling function. This may lead to unusual error messages in multi-stage operations if a tool relies on reading back metadata it believes has changed but hasn't. .TP .BR \-\-driverloaded " {" \fIy | \fIn } Whether or not the device-mapper kernel driver is loaded. If you set this to \fIn\fP, no attempt will be made to contact the driver. .TP .BR \-A ", " \-\-autobackup " {" \fIy | \fIn } Whether or not to metadata should be backed up automatically after a change. You are strongly advised not to disable this! See \fBvgcfgbackup\fP(8). .TP .BR \-P ", " \-\-partial When set, the tools will do their best to provide access to Volume Groups that are only partially available (one or more Physical Volumes belonging to the Volume Group are missing from the system). Where part of a logical volume is missing, \fB/dev/ioerror\fP will be substituted, and you could use \fBdmsetup\fP(8) to set this up to return I/O errors when accessed, or create it as a large block device of nulls. Metadata may not be changed with this option. To insert a replacement Physical Volume of the same or large size use \fBpvcreate \-u\fP to set the uuid to match the original followed by \fBvgcfgrestore\fP(8). .TP .BR \-M ", " \-\-metadatatype " " \fIType Specifies which type of on-disk metadata to use, such as \fIlvm1\fP or \fIlvm2\fP, which can be abbreviated to \fI1\fP or \fI2\fP respectively. The default (\fIlvm2\fP) can be changed by setting \fBformat\fP in the \fBglobal\fP section of the config file. .TP .B \-\-ignorelockingfailure This lets you proceed with read-only metadata operations such as \fBlvchange \-ay\fP and \fBvgchange \-ay\fP even if the locking module fails. One use for this is in a system init script if the lock directory is mounted read-only when the script runs. .TP .B \-\-addtag \fITag Add the tag \fITag\fP to a PV, VG or LV. Supply this argument multiple times to add more than one tag at once. A tag is a word that can be used to group LVM2 objects of the same type together. Tags can be given on the command line in place of PV, VG or LV arguments. Tags should be prefixed with @ to avoid ambiguity. Each tag is expanded by replacing it with all objects possessing that tag which are of the type expected by its position on the command line. PVs can only possess tags while they are part of a Volume Group: PV tags are discarded if the PV is removed from the VG. As an example, you could tag some LVs as \fBdatabase\fP and others as \fBuserdata\fP and then activate the database ones with \fBlvchange \-ay @database\fP. Objects can possess multiple tags simultaneously. Only the new LVM2 metadata format supports tagging: objects using the LVM1 metadata format cannot be tagged because the on-disk format does not support it. Characters allowed in tags are: .B A-Z a-z 0-9 _ + . - and as of version 2.02.78 the following characters are also accepted: .B / = ! : # & .TP .B \-\-deltag \fITag Delete the tag \fITag\fP from a PV, VG or LV, if it's present. Supply this argument multiple times to remove more than one tag at once. .TP .B \-\-alloc \fIAllocationPolicy The allocation policy to use: .IR contiguous , .IR cling , .IR normal , .IR anywhere " or" .IR inherit . When a command needs to allocate Physical Extents from the Volume Group, the allocation policy controls how they are chosen. Each Volume Group and Logical Volume has an allocation policy defined. The default for a Volume Group is \fInormal\fP which applies common-sense rules such as not placing parallel stripes on the same Physical Volume. The default for a Logical Volume is \fIinherit\fP which applies the same policy as for the Volume Group. These policies can be changed using \fBlvchange\fP(8) and \fBvgchange\fP(8) or overridden on the command line of any command that performs allocation. The \fIcontiguous\fP policy requires that new Physical Extents be placed adjacent to existing Physical Extents. The \fIcling\fP policy places new Physical Extents on the same Physical Volume as existing Physical Extents in the same stripe of the Logical Volume. If there are sufficient free Physical Extents to satisfy an allocation request but \fInormal\fP doesn't use them, \fIanywhere\fP will - even if that reduces performance by placing two stripes on the same Physical Volume. .SH ENVIRONMENT VARIABLES .TP .B HOME Directory containing \fI.lvm_history\fP if the internal readline shell is invoked. .TP .B LVM_SYSTEM_DIR Directory containing \fBlvm.conf\fP(5) and other LVM system files. Defaults to "#DEFAULT_SYS_DIR#". .TP .B LVM_VG_NAME The Volume Group name that is assumed for any reference to a Logical Volume that doesn't specify a path. Not set by default. .SH VALID NAMES The following characters are valid for VG and LV names: .B a-z A-Z 0-9 + _ . - .LP VG and LV names cannot begin with a hyphen. There are also various reserved names that are used internally by lvm that can not be used as LV or VG names. A VG cannot be called anything that exists in /dev/ at the time of creation, nor can it be called '.' or '..'. A LV cannot be called '.' '..' 'snapshot' or 'pvmove'. The LV name may also not contain the strings '_mlog', '_mimage', '_rimage', '_tdata', '_tmeta'. .SH ALLOCATION When an operation needs to allocate Physical Extents for one or more Logical Volumes, the tools proceed as follows: First of all, they generate the complete set of unallocated Physical Extents in the Volume Group. If any ranges of Physical Extents are supplied at the end of the command line, only unallocated Physical Extents within those ranges on the specified Physical Volumes are considered. Then they try each allocation policy in turn, starting with the strictest policy (\fIcontiguous\fP) and ending with the allocation policy specified using \fB\-\-alloc\fP or set as the default for the particular Logical Volume or Volume Group concerned. For each policy, working from the lowest-numbered Logical Extent of the empty Logical Volume space that needs to be filled, they allocate as much space as possible according to the restrictions imposed by the policy. If more space is needed, they move on to the next policy. The restrictions are as follows: \fIContiguous\fP requires that the physical location of any Logical Extent that is not the first Logical Extent of a Logical Volume is adjacent to the physical location of the Logical Extent immediately preceding it. \fICling\fP requires that the Physical Volume used for any Logical Extent to be added to an existing Logical Volume is already in use by at least one Logical Extent earlier in that Logical Volume. If the configuration parameter allocation/cling_tag_list is defined, then two Physical Volumes are considered to match if any of the listed tags is present on both Physical Volumes. This allows groups of Physical Volumes with similar properties (such as their physical location) to be tagged and treated as equivalent for allocation purposes. When a Logical Volume is striped or mirrored, the above restrictions are applied independently to each stripe or mirror image (leg) that needs space. \fINormal\fP will not choose a Physical Extent that shares the same Physical Volume as a Logical Extent already allocated to a parallel Logical Volume (i.e. a different stripe or mirror image/leg) at the same offset within that parallel Logical Volume. When allocating a mirror log at the same time as Logical Volumes to hold the mirror data, Normal will first try to select different Physical Volumes for the log and the data. If that's not possible and the allocation/mirror_logs_require_separate_pvs configuration parameter is set to 0, it will then allow the log to share Physical Volume(s) with part of the data. When allocating thin pool metadata, similar considerations to those of a mirror log in the last paragraph apply based on the value of the allocation/thin_pool_metadata_require_separate_pvs configuration parameter. If you rely upon any layout behaviour beyond that documented here, be aware that it might change in future versions of the code. For example, if you supply on the command line two empty Physical Volumes that have an identical number of free Physical Extents available for allocation, the current code considers using each of them in the order they are listed, but there is no guarantee that future releases will maintain that property. If it is important to obtain a specific layout for a particular Logical Volume, then you should build it up through a sequence of \fBlvcreate\fP(8) and \fBlvconvert\fP(8) steps such that the restrictions described above applied to each step leave the tools no discretion over the layout. To view the way the allocation process currently works in any specific case, read the debug logging output, for example by adding \-vvvv to a command. .SH DIAGNOSTICS All tools return a status code of zero on success or non-zero on failure. .SH FILES .I #DEFAULT_SYS_DIR#/lvm.conf .br .I $HOME/.lvm_history .SH SEE ALSO .BR clvmd (8), .BR lvchange (8), .BR lvcreate (8), .BR lvdisplay (8), .BR lvextend (8), .BR lvmchange (8), .BR lvmdiskscan (8), .BR lvreduce (8), .BR lvremove (8), .BR lvrename (8), .BR lvresize (8), .BR lvs (8), .BR lvscan (8), .BR pvchange (8), .BR pvck (8), .BR pvcreate (8), .BR pvdisplay (8), .BR pvmove (8), .BR pvremove (8), .BR pvs (8), .BR pvscan (8), .BR vgcfgbackup (8), .BR vgchange (8), .BR vgck (8), .BR vgconvert (8), .BR vgcreate (8), .BR vgdisplay (8), .BR vgextend (8), .BR vgimport (8), .BR vgimportclone (8), .BR vgmerge (8), .BR vgmknodes (8), .BR vgreduce (8), .BR vgremove (8), .BR vgrename (8), .BR vgs (8), .BR vgscan (8), .BR vgsplit (8), .BR readline (3), .BR lvm.conf (5) lvm2-2.02.98/man/pvscan.8.in0000640000175000017500000000352612037016272014261 0ustar blankblank.TH PVSCAN 8 "LVM TOOLS #VERSION#" "Sistina Software UK" \" -*- nroff -*- .SH NAME pvscan \- scan all disks for physical volumes .SH SYNOPSIS .B pvscan .RB [ \-d | \-\-debug ] .RB [ \-h | \-\-help ] .RB [ \-v | \-\-verbose ] .RB [ \-\-version ] .RB [ \-\-ignorelockingfailure ] .RB [ \-e | \-\-exported ] .RB [ \-n | \-\-novolumegroup ] .RB [ \-s | \-\-short ] .RB [ \-u | \-\-uuid ] .BR .B pvscan .RB [ \-d | \-\-debug ] .RB [ \-h | \-\-help ] .B \-\-cache .RB [ \-a | \-\-activate " " \fIay ] .RB [ \-\-major .I major .B \-\-minor .I minor | .IR DevicePath ]... .SH DESCRIPTION pvscan scans all supported LVM block devices in the system for physical volumes. .SH OPTIONS See \fBlvm\fP(8) for common options. .TP .BR \-e ", " \-\-exported Only show physical volumes belonging to exported volume groups. .TP .BR \-n ", " \-\-novolumegroup Only show physical volumes not belonging to any volume group. .TP .BR \-s ", " \-\-short Short listing format. .TP .BR \-u ", " \-\-uuid Show UUIDs (Uniform Unique Identifiers) in addition to device special names. .TP .BR \-a ", " \-\-activate " " \fIay Together with the information already cached in lvmetad, automatically activate any logical volumes that become activatable after the scan done on one or more devices. The logical volume to autoactivate is matched against the activation/auto_activation_volume_list set in lvm.conf. Autoactivation is not yet supported on logical volumes that are part of partial or clustered volume groups. .TP .BR \-\-cache " [" \-\-major " " \fImajor " " \-\-minor " " \fIminor " | " \fIDevicePath " ]..." Scan one or more devices and instruct the lvmetad daemon to update its cached state accordingly. Called internally by udev rules. All devices listed explicitly are processed \fBregardless\fP of any device filters set in lvm.conf. .SH SEE ALSO .BR lvm (8), .BR pvcreate (8), .BR pvdisplay (8) lvm2-2.02.98/man/vgcreate.8.in0000640000175000017500000001344312037016272014566 0ustar blankblank.TH VGCREATE 8 "LVM TOOLS #VERSION#" "Sistina Software UK" \" -*- nroff -*- .SH NAME vgcreate \- create a volume group .SH SYNOPSIS .B vgcreate .RB [ \-\-addtag .IR Tag ] .RB [ \-\-alloc .IR AllocationPolicy ] .RB [ \-A | \-\-autobackup .RI { y | n }] .RB [ \-c | \-\-clustered .RI { y | n }] .RB [ \-d | \-\-debug ] .RB [ \-h | \-\-help ] .RB [ \-l | \-\-maxlogicalvolumes .IR MaxLogicalVolumes ] .RB [ -M | \-\-metadatatype .IR type ] .RB [ -p | \-\-maxphysicalvolumes .IR MaxPhysicalVolumes ] .RB [ \-\- [ vg ] metadatacopies .IR NumberOfCopies | unmanaged | all ] .RB [ \-s | \-\-physicalextentsize .IR PhysicalExtentSize [ bBsSkKmMgGtTpPeE ]] .RB [ \-t | \-\-test ] .RB [ \-v | \-\-verbose ] .RB [ \-\-version ] .RB [ "PHYSICAL DEVICE OPTIONS" ] .I VolumeGroupName PhysicalDevicePath .RI [ PhysicalDevicePath ...] .SH DESCRIPTION vgcreate creates a new volume group called .I VolumeGroupName using the block special device \fIPhysicalDevicePath\fP. .sp If \fIPhysicalDevicePath\fP was not previously configured for LVM with \fBpvcreate\fP(8), the device will be initialized with the same default values used with \fBpvcreate\fP(8). If non-default \fPpvcreate\fP values are desired, they may be given on the commandline with the same options as \fBpvcreate\fP(8). See .B PHYSICAL DEVICE OPTIONS for available options. Note that the restore-related options such as .BR \-\-restorefile ", " \-\-uuid " and " \-\-physicalvolumesize are not available. If a restore operation is needed, use \fBpvcreate\fP(8) and \fBvgcfgrestore\fP(8). .SH OPTIONS See \fBlvm\fP(8) for common options. .TP .BR \-c ", " \-\-clustered " {" \fIy | \fIn } If clustered locking is enabled, this defaults to \fBy\fP indicating that this Volume Group is shared with other nodes in the cluster. If the new Volume Group contains only local disks that are not visible on the other nodes, you must specify \fB\-\-clustered\ n\fP. If the cluster infrastructure is unavailable on a particular node at a particular time, you may still be able to use such Volume Groups. .TP .BR \-l ", " \-\-maxlogicalvolumes " " \fIMaxLogicalVolumes Sets the maximum number of logical volumes allowed in this volume group. The setting can be changed with \fBvgchange\fP(8). For volume groups with metadata in lvm1 format, the limit and default value is 255. If the metadata uses lvm2 format, the default value is 0 which removes this restriction: there is then no limit. .TP .BR \-p ", " \-\-maxphysicalvolumes " " \fIMaxPhysicalVolumes Sets the maximum number of physical volumes that can belong to this volume group. The setting can be changed with \fBvgchange\fP. For volume groups with metadata in lvm1 format, the limit and default value is 255. If the metadata uses lvm2 format, the value 0 removes this restriction: there is then no limit. If you have a large number of physical volumes in a volume group with metadata in lvm2 format, for tool performance reasons, you should consider some use of \fB\-\-pvmetadatacopies 0\fP as described in \fBpvcreate\fP(8), and/or use \fB\-\-vgmetadatacopies\fP. .TP .BR \-\- [ vg ] metadatacopies " " \fINumberOfCopies | \fIunmanaged | \fIall Sets the desired number of metadata copies in the volume group. If set to a non-zero value, LVM will automatically manage the 'metadataignore' flags on the physical volumes (see \fBpvcreate\fP(8) or \fBpvchange \-\-metadataignore\fP) in order to achieve \fINumberOfCopies\fP copies of metadata. If set to \fIunmanaged\fP, LVM will not automatically manage the 'metadataignore' flags. If set to \fIall\fP, LVM will first clear all of the 'metadataignore' flags on all metadata areas in the volume group, then set the value to \fIunmanaged\fP. The \fBvgmetadatacopies\fP option is useful for volume groups containing large numbers of physical volumes with metadata as it may be used to minimize metadata read and write overhead. The default value is \fIunmanaged\fP. .TP .BR \-s ", " \-\-physicalextentsize " " \fIPhysicalExtentSize [ \fIbBsSkKmMgGtTpPeE ] Sets the physical extent size on physical volumes of this volume group. A size suffix (k for kilobytes up to t for terabytes) is optional, megabytes is the default if no suffix is present. The default is 4 MiB and it must be at least 1 KiB and a power of 2. Once this value has been set, it is difficult to change it without recreating the volume group which would involve backing up and restoring data on any logical volumes. However, if no extents need moving for the new value to apply, it can be altered using \fBvgchange \-s\fP. If the volume group metadata uses lvm1 format, extents can vary in size from 8KiB to 16GiB and there is a limit of 65534 extents in each logical volume. The default of 4 MiB leads to a maximum logical volume size of around 256GiB. If the volume group metadata uses lvm2 format those restrictions do not apply, but having a large number of extents will slow down the tools but have no impact on I/O performance to the logical volume. The smallest PE is 1KiB The 2.4 kernel has a limitation of 2TiB per block device. .SH PHYSICAL DEVICE OPTIONS The following options are available for initializing physical devices in the volume group. These options are further described in the \fBpvcreate\fP(8) man page. .TP .BR \-f ", " \-\-force .TP .BR \-y ", " \-\-yes .TP .BR \-Z ", " \-\-zero " {" \fIy | \fIn } .TP .B \-\-labelsector \fIsector .TP .B \-\-metadatasize \fIsize .TP .B \-\-pvmetadatacopies \fIcopies .TP .B \-\-dataalignment \fIalignment .TP .B \-\-dataalignmentoffset \fIalignment_offset .SH Examples Creates a volume group named "test_vg" using physical volumes "/dev/sdk1" and "/dev/sdl1" with default physical extent size of 4MiB: .sp .B vgcreate test_vg /dev/sdk1 /dev/sdl1 .SH SEE ALSO .BR lvm (8), .BR pvdisplay (8), .BR pvcreate (8), .BR vgdisplay (8), .BR vgextend (8), .BR vgreduce (8), .BR lvcreate (8), .BR lvdisplay (8), .BR lvextend (8), .BR lvreduce (8) lvm2-2.02.98/man/vgcfgrestore.8.in0000640000175000017500000000342712037016272015467 0ustar blankblank.TH VGCFGRESTORE 8 "LVM TOOLS #VERSION#" "Sistina Software UK" \" -*- nroff -*- .SH NAME vgcfgrestore \- restore volume group descriptor area .SH SYNOPSIS .B vgcfgrestore .RB [ \-d | \-\-debug ] .RB [ \-f | \-\-file .RI < filename >] .RB [ \-l [ l ]| \-\-list ] .RB [ \-h | \-\-help ] .RB [ \-M | \-\-metadatatype .IR 1 | 2 ] .RB [ \-t | \-\-test ] .RB [ \-v | \-\-verbose ] .RI \fIVolumeGroupName\fP .SH DESCRIPTION vgcfgrestore allows you to restore the metadata of \fIVolumeGroupName\fP from a text backup file produced by \fBvgcfgbackup\fP. You can specify a backup file with \fB\-\-file\fP. If no backup file is specified, the most recent one is used. Use \fB\-\-list\fP for a list of the available backup and archive files of \fIVolumeGroupName\fP. .SH OPTIONS See \fBlvm\fP(8) for common options. .TP .BR \-l ", " \-\-list\fP List files pertaining to \fIVolumeGroupName\fP List metadata backup and archive files pertaining to \fIVolumeGroupName\fP. May be used with the \fB\-f\fP option. Does not restore \fIVolumeGroupName\fP. .TP .BR \-f ", " \-\-file " " \fIfilename Name of LVM metadata backup file Specifies a metadata backup or archive file to be used for restoring VolumeGroupName. Often this file has been created with \fBvgcfgbackup\fP. .SH REPLACING PHYSICAL VOLUMES \fBvgdisplay \-\-partial \-\-verbose\fP will show you the UUIDs and sizes of any PVs that are no longer present. If a PV in the VG is lost and you wish to substitute another of the same size, use \fBpvcreate \-\-restorefile filename \-\-uuid uuid\fP (plus additional arguments as appropriate) to initialise it with the same UUID as the missing PV. Repeat for all other missing PVs in the VG. Then use \fBvgcfgrestore \-\-file filename\fP to restore the volume group's metadata. .SH SEE ALSO .BR lvm (8), .BR vgcreate (8) lvm2-2.02.98/man/vgs.8.in0000640000175000017500000000657212037016272013572 0ustar blankblank.TH VGS 8 "LVM TOOLS #VERSION#" "Sistina Software UK" \" -*- nroff -*- .SH NAME vgs \- report information about volume groups .SH SYNOPSIS .B vgs .RB [ \-a | \-\-all ] .RB [ \-\-aligned ] .RB [ \-d | \-\-debug ] .RB [ \-h | \-? | \-\-help ] .RB [ \-\-ignorelockingfailure ] .RB [ \-\-nameprefixes ] .RB [ \-\-noheadings ] .RB [ \-\-nosuffix ] .RB [ \-o | \-\-options .RI [ + ] Field1 [ ,Field2 ...]] .RB [ \-O | \-\-sort .RI [ + | \- ] Key1 [ , [ + | \- ] Key2 ...]] .RB [ \-P | \-\-partial ] .RB [ \-\-rows ] .RB [ \-\-separator .IR Separator ] .RB [ \-\-unbuffered ] .RB [ \-\-units .IR hHbBsSkKmMgGtTpPeE ] .RB [ \-\-unquoted ] .RB [ \-v | \-\-verbose ] .RB [ \-\-version ] .RI [ VolumeGroupName .RI [ VolumeGroupName ...]] .SH DESCRIPTION vgs produces formatted output about volume groups. .SH OPTIONS See \fBlvm\fP(8) for common options. .TP .B \-\-all List all volume groups. Equivalent to not specifying any volume groups. .TP .B \-\-aligned Use with \fB\-\-separator\fP to align the output columns. .TP .B \-\-nameprefixes Add an "LVM2_" prefix plus the field name to the output. Useful with \fB\-\-noheadings\fP to produce a list of field=value pairs that can be used to set environment variables (for example, in \fBudev\fP(7) rules). .TP .B \-\-noheadings Suppress the headings line that is normally the first line of output. Useful if grepping the output. .TP .B \-\-nosuffix Suppress the suffix on output sizes. Use with \fB\-\-units\fP (except h and H) if processing the output. .TP .BR \-o ", " \-\-options Comma-separated ordered list of columns. Precede the list with '+' to append to the default selection of columns. .IP Use \fB\-o vg_all\fP to select all volume group columns. .IP Use \fB\-o help\fP to view the full list of columns available. .IP Column names include: vg_fmt, vg_uuid, vg_name, vg_attr, vg_size, vg_free, vg_sysid, vg_extent_size, vg_extent_count, vg_free_count, max_lv, max_pv, pv_count, lv_count, snap_count, vg_seqno, vg_tags, vg_mda_count, vg_mda_free, and vg_mda_size, vg_mda_used_count. .IP Any "vg_" prefixes are optional. Columns mentioned in either \fBpvs\fP(8) or \fBlvs\fP(8) can also be chosen, but columns cannot be taken from both at the same time. .IP The vg_attr bits are: .RS .IP 1 3 Permissions: (w)riteable, (r)ead-only .IP 2 3 Resi(z)eable .IP 3 3 E(x)ported .IP 4 3 (p)artial: one or more physical volumes belonging to the volume group are missing from the system .IP 5 3 Allocation policy: (c)ontiguous, c(l)ing, (n)ormal, (a)nywhere, (i)nherited .IP 6 3 (c)lustered .RE .TP .BR \-O ", " \-\-sort Comma-separated ordered list of columns to sort by. Replaces the default selection. Precede any column with '\fI\-\fP' for a reverse sort on that column. .TP .B \-\-rows Output columns as rows. .TP .B \-\-separator \fISeparator String to use to separate each column. Useful if grepping the output. .TP .B \-\-unbuffered Produce output immediately without sorting or aligning the columns properly. .TP .B \-\-units \fIhHbBsSkKmMgGtTpPeE All sizes are output in these units: (h)uman-readable, (b)ytes, (s)ectors, (k)ilobytes, (m)egabytes, (g)igabytes, (t)erabytes, (p)etabytes, (e)xabytes. Capitalise to use multiples of 1000 (S.I.) instead of 1024. Can also specify custom units e.g. \-\-units 3M .TP .B \-\-unquoted When used with \fB\-\-nameprefixes\fP, output values in the field=value pairs are not quoted. .SH SEE ALSO .BR lvm (8), .BR vgdisplay (8), .BR pvs (8), .BR lvs (8) lvm2-2.02.98/man/lvm.conf.5.in0000640000175000017500000006015112037016272014503 0ustar blankblank.TH LVM.CONF 5 "LVM TOOLS #VERSION#" "Sistina Software UK" \" -*- nroff -*- .SH NAME lvm.conf \- Configuration file for LVM2 .SH SYNOPSIS .B #DEFAULT_SYS_DIR#/lvm.conf .SH DESCRIPTION lvm.conf is loaded during the initialisation phase of \fBlvm\fP(8). This file can in turn lead to other files being loaded - settings read in later override earlier settings. File timestamps are checked between commands and if any have changed, all the files are reloaded. .LP Use \fBlvm dumpconfig\fP to check what settings are in use. .SH SYNTAX .LP This section describes the configuration file syntax. .LP Whitespace is not significant unless it is within quotes. This provides a wide choice of acceptable indentation styles. Comments begin with # and continue to the end of the line. They are treated as whitespace. .LP Here is an informal grammar: .TP .BR file " = " value * .br A configuration file consists of a set of values. .TP .BR value " = " section " | " assignment .br A value can either be a new section, or an assignment. .TP .BR section " = " identifier " '" { "' " value "* '" } ' .br A section is groups associated values together. .br It is denoted by a name and delimited by curly brackets. .br e.g. backup { .br ... .br } .TP .BR assignment " = " identifier " '" = "' ( " array " | " type " )" .br An assignment associates a type with an identifier. .br e.g. max_archives = 42 .br .TP .BR array " = '" [ "' ( " type " '" , "')* " type " '" ] "' | '" [ "' '" ] ' .br Inhomogeneous arrays are supported. .br Elements must be separated by commas. .br An empty array is acceptable. .TP .BR type " = " integer " | " float " | " string .BR integer " = [0-9]*" .br .BR float " = [0-9]*'" . '[0-9]* .br .B string \fR= '\fB"\fR'.*'\fB"\fR' .IP Strings must be enclosed in double quotes. .SH SECTIONS .LP The sections that may be present in the file are: .TP \fBdevices\fP \(em Device settings .IP \fBdir\fP \(em Directory in which to create volume group device nodes. Defaults to "/dev". Commands also accept this as a prefix on volume group names. .IP \fBscan\fP \(em List of directories to scan recursively for LVM physical volumes. Devices in directories outside this hierarchy will be ignored. Defaults to "/dev". .IP \fBpreferred_names\fP \(em List of patterns compared in turn against all the pathnames referencing the same device in in the scanned directories. The pathname that matches the earliest pattern in the list is the one used in any output. As an example, if device-mapper multipathing is used, the following will select multipath device names: .br \fBdevices { preferred_names = [ "^/dev/mapper/mpath" ] }\fP .IP \fBfilter\fP \(em List of patterns to apply to devices found by a scan. Patterns are regular expressions delimited by any character and preceded by \fBa\fP (for accept) or \fBr\fP (for reject). The list is traversed in order, and the first regex that matches determines if the device will be accepted or rejected (ignored). Devices that don't match any patterns are accepted. If you want to reject patterns that don't match, end the list with "r/.*/". If there are several names for the same device (e.g. symbolic links in /dev), if the first matching pattern in the list for any of the names is an \fBa\fP pattern, the device is accepted; otherwise if the first matching pattern in the list for any of the names is an \fBr\fP pattern it is rejected; otherwise it is accepted. As an example, to ignore /dev/cdrom you could use: .br \fBdevices { filter=["r|cdrom|"] }\fP .IP \fBcache_dir\fP \(em Persistent filter cache file directory. Defaults to "#DEFAULT_CACHE_DIR#". .IP \fBwrite_cache_state\fP \(em Set to 0 to disable the writing out of the persistent filter cache file when \fBlvm\fP exits. Defaults to 1. .IP \fBtypes\fP \(em List of pairs of additional acceptable block device types found in /proc/devices together with maximum (non-zero) number of partitions (normally 16). By default, LVM2 supports ide, sd, md, loop, dasd, dac960, nbd, ida, cciss, ubd, ataraid, drbd, power2, i2o_block and iseries/vd. Block devices with major numbers of different types are ignored by LVM2. Example: \fBtypes = ["fd", 16]\fP. To create physical volumes on device-mapper volumes created outside LVM2, perhaps encrypted ones from \fBcryptsetup\fP, you'll need \fBtypes = ["device-mapper", 16]\fP. But if you do this, be careful to avoid recursion within LVM2. The figure for number of partitions is not currently used in LVM2 - and might never be. .IP \fBsysfs_scan\fP \(em If set to 1 and your kernel supports sysfs and it is mounted, sysfs will be used as a quick way of filtering out block devices that are not present. .IP \fBmd_component_detection\fP \(em If set to 1, LVM2 will ignore devices used as components of software RAID (md) devices by looking for md superblocks. This doesn't always work satisfactorily e.g. if a device has been reused without wiping the md superblocks first. .IP \fBmd_chunk_alignment\fP \(em If set to 1, and a Physical Volume is placed directly upon an md device, LVM2 will align its data blocks with the md device's stripe-width. .IP \fBdata_alignment_detection\fP \(em If set to 1, and your kernel provides topology information in sysfs for the Physical Volume, the start of data area will be aligned on a multiple of the ’minimum_io_size’ or ’optimal_io_size’ exposed in sysfs. minimum_io_size is the smallest request the device can perform without incurring a read-modify-write penalty (e.g. MD's chunk size). optimal_io_size is 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 both \fBmd_chunk_alignment\fP and \fBdata_alignment_detection\fP are enabled the result of \fBdata_alignment_detection\fP is used. .IP \fBdata_alignment\fP \(em Default alignment (in KB) of start of data area when creating a new Physical Volume using the \fBlvm2\fP format. If a Physical Volume is placed directly upon an md device and \fBmd_chunk_alignment\fP or \fBdata_alignment_detection\fP is enabled this parameter is ignored. Set to 0 to use the default alignment of 64KB or the page size, if larger. .IP \fBdata_alignment_offset_detection\fP \(em If set to 1, and your kernel provides topology information in sysfs for the Physical Volume, the start of the aligned data area of the Physical Volume will be shifted by the alignment_offset exposed in sysfs. .sp To see the location of the first Physical Extent of an existing Physical Volume use \fBpvs -o +pe_start\fP . It will be a multiple of the requested \fBdata_alignment\fP plus the alignment_offset from \fBdata_alignment_offset_detection\fP (if enabled) or the pvcreate commandline. .IP \fBdisable_after_error_count\fP \(em 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. .IP \fBpv_min_size\fP \(em Minimal size (in KB) of the block device which can be used as a PV. In clustered environment all nodes have to use the same value. Any value smaller than 512KB is ignored. Up to and include version 2.02.84 the default was 512KB. From 2.02.85 onwards it was changed to 2MB to avoid floppy drives by default. .IP \fBissue_discards\fP \(em Issue discards to a logical volumes's underlying physical volume(s) when the logical volume is no longer using the physical volumes' space (e.g. lvremove, lvreduce, etc). Discards inform the storage that a region is no longer in use. Storage that supports discards advertise the protocol specific way discards should be issued by the kernel (TRIM, UNMAP, or WRITE SAME with UNMAP bit set). Not all storage will support or benefit from discards but SSDs and thinly provisioned LUNs generally do. If set to 1, discards will only be issued if both the storage and kernel provide support. .IP .TP \fBallocation\fP \(em Space allocation policies .IP \fBcling_tag_list\fP \(em List of PV tags matched by the \fBcling\fP allocation policy. .IP When searching for free space to extend an LV, the \fBcling\fP 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. .IP The @ prefix for tags is required. Use the special tag "@*" as a wildcard to match any PV tag and so use all PV tags for this purpose. .IP For 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 and these two PV tags are selected for use with this allocation policy: .IP cling_tag_list = [ "@site1", "@site2" ] .TP \fBlog\fP \(em Default log settings .IP \fBfile\fP \(em Location of log file. If this entry is not present, no log file is written. .IP \fBoverwrite\fP \(em Set to 1 to overwrite the log file each time a tool is invoked. By default tools append messages to the log file. .IP \fBlevel\fP \(em Log level (0-9) of messages to write to the file. 9 is the most verbose; 0 should produce no output. .IP \fBverbose\fP \(em Default level (0-3) of messages sent to stdout or stderr. 3 is the most verbose; 0 should produce the least output. .IP \fBsilent\fP \(em Set to 1 to suppress all non-essential tool output. When set, display and reporting tools will still write the requested device properties to standard output, but messages confirming that something was or wasn't changed will be reduced to the 'verbose' level and not appear unless -v is supplied. .IP \fBsyslog\fP \(em Set to 1 (the default) to send log messages through syslog. Turn off by setting to 0. If you set to an integer greater than one, this is used - unvalidated - as the facility. The default is LOG_USER. See /usr/include/sys/syslog.h for safe facility values to use. For example, LOG_LOCAL0 might be 128. .IP \fBindent\fP \(em When set to 1 (the default) messages are indented according to their severity, two spaces per level. Set to 0 to turn off indentation. .IP \fBcommand_names\fP \(em When set to 1, the command name is used as a prefix for each message. Default is 0 (off). .IP \fBprefix\fP \(em Prefix used for all messages (after the command name). Default is two spaces. .IP \fBactivation\fP \(em Set to 1 to log messages while devices are suspended during activation. Only set this temporarily while debugging a problem because in low memory situations this setting can cause your machine to lock up. .TP \fBbackup\fP \(em Configuration for metadata backups. .IP \fBarchive_dir\fP \(em Directory used for automatic metadata archives. Backup copies of former metadata for each volume group are archived here. Defaults to "#DEFAULT_ARCHIVE_DIR#". .IP \fBbackup_dir\fP \(em Directory used for automatic metadata backups. A single backup copy of the current metadata for each volume group is stored here. Defaults to "#DEFAULT_BACKUP_DIR#". .IP \fBarchive\fP \(em Whether or not tools automatically archive existing metadata into \fBarchive_dir\fP before making changes to it. Default is 1 (automatic archives enabled). Set to 0 to disable. Disabling this might make metadata recovery difficult or impossible if something goes wrong. .IP \fBbackup\fP \(em Whether or not tools make an automatic backup into \fBbackup_dir\fP after changing metadata. Default is 1 (automatic backups enabled). Set to 0 to disable. Disabling this might make metadata recovery difficult or impossible if something goes wrong. .IP \fBretain_min\fP \(em Minimum number of archives to keep. Defaults to 10. .IP \fBretain_days\fP \(em Minimum number of days to keep archive files. Defaults to 30. .TP \fBshell\fP \(em LVM2 built-in readline shell settings .IP \fBhistory_size\fP \(em Maximum number of lines of shell history to retain (default 100) in $HOME/.lvm_history .TP \fBglobal\fP \(em Global settings .IP \fBtest\fP \(em If set to 1, run tools in test mode i.e. no changes to the on-disk metadata will get made. It's equivalent to having the -t option on every command. .IP \fBactivation\fP \(em Set to 0 to turn off all communication with the device-mapper driver. Useful if you want to manipulate logical volumes while device-mapper is not present in your kernel. .IP \fBproc\fP \(em Mount point of proc filesystem. Defaults to /proc. .IP \fBumask\fP \(em File creation mask for any files and directories created. Interpreted as octal if the first digit is zero. Defaults to 077. Use 022 to allow other users to read the files by default. .IP \fBformat\fP \(em The default value of \fB--metadatatype\fP used to determine which format of metadata to use when creating new physical volumes and volume groups. \fBlvm1\fP or \fBlvm2\fP. .IP \fBfallback_to_lvm1\fP \(em Set this to 1 if you need to be able to switch between 2.4 kernels using LVM1 and kernels including device-mapper. The LVM2 tools should be installed as normal and the LVM1 tools should be installed with a .lvm1 suffix e.g. vgscan.lvm1. If an LVM2 tool is then run but unable to communicate with device-mapper, it will automatically invoke the equivalent LVM1 version of the tool. Note that for LVM1 tools to manipulate physical volumes and volume groups created by LVM2 you must use \fB--metadataformat lvm1\fP when creating them. .IP \fBlibrary_dir\fP \(em A directory searched for LVM2's shared libraries ahead of the places \fBdlopen\fP (3) searches. .IP \fBformat_libraries\fP \(em A list of shared libraries to load that contain code to process different formats of metadata. For example, liblvm2formatpool.so is needed to read GFS pool metadata if LVM2 was configured \fB--with-pool=shared\fP. .IP \fBlocking_type\fP \(em What type of locking to use. 1 is the default, which use flocks on files in \fBlocking_dir\fP (see below) to avoid conflicting LVM2 commands running concurrently on a single machine. 0 disables locking and risks corrupting your metadata. If set to 2, the tools will load the external \fBlocking_library\fP (see below). If the tools were configured \fB--with-cluster=internal\fP (the default) then 3 means to use built-in cluster-wide locking. Type 4 enforces read-only metadata and forbids any operations that might want to modify Volume Group metadata. All changes to logical volumes and their states are communicated using locks. .IP \fBwait_for_locks\fP \(em When set to 1, the default, the tools wait if a lock request cannot be satisfied immediately. When set to 0, the operation is aborted instead. .IP \fBlocking_dir\fP \(em The directory LVM2 places its file locks if \fBlocking_type\fP is set to 1. The default is \fB/var/lock/lvm\fP. .IP \fBlocking_library\fP \(em The name of the external locking library to load if \fBlocking_type\fP is set to 2. The default is \fBliblvm2clusterlock.so\fP. If you need to write such a library, look at the lib/locking source code directory. .TP \fBtags\fP \(em Host tag settings .IP \fBhosttags\fP \(em If set to 1, create a host tag with the machine name. Setting this to 0 does nothing, neither creating nor destroying any tag. The machine name used is the nodename as returned by \fBuname\fP (2). .IP Additional host tags to be set can be listed here as subsections. The @ prefix for tags is optional. Each of these host tag subsections can contain a \fBhost_list\fP array of host names. If any one of these entries matches the machine name exactly then the host tag gets defined on this particular host, otherwise it doesn't. .IP After lvm.conf has been processed, LVM2 works through each host tag that has been defined in turn, and if there is a configuration file called lvm_\fB\fP.conf it attempts to load it. Any settings read in override settings found in earlier files. Any additional host tags defined get appended to the search list, so in turn they can lead to further configuration files being processed. Use \fBlvm dumpconfig\fP to check the result of config file processing. .IP The following example always sets host tags \fBtag1\fP and sets \fBtag2\fP on machines fs1 and fs2: .IP tags { tag1 { } tag2 { host_list = [ "fs1", "fs2" ] } } .IP These options are useful if you are replicating configuration files around a cluster. Use of \fBhosttags = 1\fP means every machine can have static and identical local configuration files yet use different settings and activate different logical volumes by default. See also \fBvolume_list\fP below and \fB--addtag\fP in \fBlvm\fP (8). .TP \fBactivation\fP \(em Settings affecting device-mapper activation .IP \fBmissing_stripe_filler\fP \(em When activating an incomplete logical volume in partial mode, this option dictates how the missing data is replaced. A value of "error" will cause activation to create error mappings for the missing data, meaning that read access to missing portions of the volume will result in I/O errors. You can instead also use a device path, and in that case this device will be used in place of missing stripes. However, note that using anything other than "error" with mirrored or snapshotted volumes is likely to result in data corruption. For instructions on how to create a device that always returns zeros, see \fBlvcreate\fP (8). .IP \fBmirror_region_size\fP \(em Unit size in KB for copy operations when mirroring. .IP \fBreadahead\fP \(em Used when there is no readahead value stored in the volume group metadata. Set to \fBnone\fP to disable readahead in these circumstances or \fBauto\fP to use the default value chosen by the kernel. .IP \fBreserved_memory\fP, \fBreserved_stack\fP \(em How many KB to reserve for LVM2 to use while logical volumes are suspended. If insufficient memory is reserved before suspension, there is a risk of machine deadlock. .IP \fBprocess_priority\fP \(em The nice value to use while devices are suspended. This is set to a high priority so that logical volumes are suspended (with I/O generated by other processes to those logical volumes getting queued) for the shortest possible time. .IP \fBvolume_list\fP \(em This acts as a filter through which all requests to activate a logical volume on this machine are passed. A logical volume is only activated if it matches an item in the list. Tags must be preceded by @ and are checked against all tags defined in the logical volume and volume group metadata for a match. @* is short-hand to check every tag set on the host machine (see \fBtags\fP above). Logical volume and volume groups can also be included in the list by name e.g. vg00, vg00/lvol1. .IP \fBauto_activation_volume_list\fP \(em This acts as a filter through which all requests to autoactivate a logical volume on this machine are passed. A logical volume is autoactivated if it matches an item in the list. Volumes must also pass the \fBvolume_list\fP filter, if present. Tags must be preceded by @ and are checked against all tags defined in the logical volume and volume group metadata for a match. @* is short-hand to check every tag set on the host machine (see \fBtags\fP above). Logical volume and volume groups can also be included in the list by name e.g. vg00, vg00/lvol1. .IP \fBread_only_volume_list\fP \(em This acts as a filter through which all requests to activate a logical volume on this machine are passed. A logical volume is activated in read-only mode (instead of read-write) if it matches an item in the list. Volumes must first pass the \fBvolume_list\fP filter, if present. Tags must be preceded by @ and are checked against all tags defined in the logical volume and volume group metadata for a match. @* is short-hand to check every tag set on the host machine (see \fBtags\fP above). Logical volume and volume groups can also be included in the list by name e.g. vg00, vg00/lvol1. .TP \fBmetadata\fP \(em Advanced metadata settings .IP \fBpvmetadatacopies\fP \(em When creating a physical volume using the LVM2 metadata format, this is the default number of copies of metadata to store on each physical volume. Currently it can be set to 0, 1 or 2. The default is 1. If set to 2, one copy is placed at the beginning of the disk and the other is placed at the end. It can be overridden on the command line with \fB--pvmetadatacopies\fP (see \fBpvcreate\fP). If creating a volume group with just one physical volume, it's a good idea to have 2 copies. If creating a large volume group with many physical volumes, you may decide that 3 copies of the metadata is sufficient, i.e. setting it to 1 on three of the physical volumes, and 0 on the rest. Every volume group must contain at least one physical volume with at least 1 copy of the metadata (unless using the text files described below). The disadvantage of having lots of copies is that every time the tools access the volume group, every copy of the metadata has to be accessed, and this slows down the tools. .IP \fBpvmetadatasize\fP \(em Approximate number of sectors to set aside for each copy of the metadata. Volume groups with large numbers of physical or logical volumes, or volumes groups containing complex logical volume structures will need additional space for their metadata. The metadata areas are treated as circular buffers, so unused space becomes filled with an archive of the most recent previous versions of the metadata. .IP \fBpvmetadataignore\fP When creating a physical volume using the LVM2 metadata format, this states whether metadata areas should be ignored. The default is "n". If metadata areas on a physical volume are ignored, LVM will not not store metadata in the metadata areas present on newly created Physical Volumes. The option can be overridden on the command line with \fB--metadataignore\fP (See \fBpvcreate\fP and \fBpvchange\fP). Metadata areas cannot be created or extended after Logical Volumes have been allocated on the device. If you do not want to store metadata on this device, it is still wise always to allocate a metadata area (use a non-zero value for \fB--pvmetadatacopies\fP) in case you need it in the future and to use this option to instruct LVM2 to ignore it. .IP \fBvgmetadatacopies\fP \(em When creating a volume group using the LVM2 metadata format, this is the default number of copies of metadata desired across all the physical volumes in the volume group. If set to a non-zero value, LVM will automatically set or clear the metadataignore flag on the physical volumes (see \fBpvcreate\fP and \fBpvchange\fP \fB--metadataignore\fP) in order to achieve the desired number of metadata copies. An LVM command that adds or removes physical volumes (for example, \fBvgextend\fP, \fBvgreduce\fP, \fBvgsplit\fP, or \fBvgmerge\fP), may cause LVM to automatically set or clear the metadataignore flags. Also, if physical volumes go missing or reappear, or a new number of copies is explicitly set (see \fBvgchange --vgmetadatacopies\fP), LVM may adjust the metadataignore flags. Set \fBvgmetadatacopies\fP to 0 instructs LVM not to set or clear the metadataignore flags automatically. You may set a value larger than the sum of all metadata areas on all physical volumes. The value can be overridden on the command line with \fB--vgmetadatacopies\fP for various commands (for example, \fBvgcreate\fP and \fBvgchange\fP), and can be queryied with the \fBvg_mda_copies\fP field of \fBvgs\fP. This option is useful for volume groups containing large numbers of physical volumes with metadata as it may be used to minimize metadata read and write overhead. .IP \fBdirs\fP \(em List of directories holding live copies of LVM2 metadata as text files. These directories must not be on logical volumes. It is possible to use LVM2 with a couple of directories here, preferably on different (non-logical-volume) filesystems and with no other on-disk metadata, \fBpvmetadatacopies = 0\fP. Alternatively these directories can be in addition to the on-disk metadata areas. This feature was created during the development of the LVM2 metadata before the new on-disk metadata areas were designed and no longer gets tested. It is not supported under low-memory conditions, and it is important never to edit these metadata files unless you fully understand how things work: to make changes you should always use the tools as normal, or else vgcfgbackup, edit backup, vgcfgrestore. .SH FILES .I #DEFAULT_SYS_DIR#/lvm.conf .br .I #DEFAULT_ARCHIVE_DIR# .br .I #DEFAULT_BACKUP_DIR# .br .I #DEFAULT_CACHE_DIR#/.cache .br .I #DEFAULT_LOCK_DIR# .SH SEE ALSO .BR lvm (8), .BR umask (2), .BR uname (2), .BR dlopen (3), .BR syslog (3), .BR syslog.conf (5) lvm2-2.02.98/man/lvchange.8.in0000640000175000017500000001440612037016272014555 0ustar blankblank.TH LVCHANGE 8 "LVM TOOLS #VERSION#" "Sistina Software UK" \" -*- nroff -*- .SH NAME lvchange \- change attributes of a logical volume .SH SYNOPSIS .B lvchange .RB [ \-\-addtag .IR Tag ] .RB [ \-A | \-\-autobackup .RI { y | n }] .RB [ \-a | \-\-activate .RI [ a | e | l ]{ y | n }] .RB [ \-\-alloc .IR AllocationPolicy ] .RB [ \-C | \-\-contiguous .RI { y | n }] .RB [ \-d | \-\-debug ] .RB [ \-\-deltag .IR Tag ] .RB [ \-\-discards .RI { ignore | nopassdown | passdown }] .RB [ \-\-resync ] .RB [ \-h | \-? | \-\-help ] .RB [ \-\-ignorelockingfailure ] .RB [ \-\-ignoremonitoring ] .RB [ \-\-monitor .RI { y | n }] .RB [ \-\-poll .RI { y | n }] .RB [ \-\-sysinit ] .RB [ \-\-noudevsync ] .RB [ \-M | \-\-persistent .RI { y | n }] .RB [ \-\-minor .IR minor ] .RB [ \-P | \-\-partial ] .RB [ \-p | \-\-permission .RI { r | rw }] .RB [ \-r | \-\-readahead .RI { ReadAheadSectors | auto | none }] .RB [ \-\-refresh ] .RB [ \-t | \-\-test ] .RB [ \-v | \-\-verbose ] .RB [ \-Z | \-\-zero .RI { y | n }] .I LogicalVolumePath .RI [ LogicalVolumePath ...] .SH DESCRIPTION lvchange allows you to change the attributes of a logical volume including making them known to the kernel ready for use. .SH OPTIONS See \fBlvm\fP(8) for common options. .TP .BR \-a ", " \-\-activate " [" \fIa | \fIe | \fIl ]{ \fIy | \fIn } Controls the availability of the logical volumes for use. Communicates with the kernel device-mapper driver via libdevmapper to activate (\-ay) or deactivate (\-an) the logical volumes. If autoactivation option is used (\-aay), the logical volume is activated only if it matches an item in the activation/auto_activation_volume_list set in lvm.conf. Autoactivation is not yet supported for logical volumes that are part of partial or clustered volume groups. .IP If clustered locking is enabled, -aey will activate exclusively on one node and -aly will activate only on the local node. To deactivate only on the local node use -aln. Logical volumes with single-host snapshots are always activated exclusively because they can only be used on one node at once. .TP .BR \-C ", " \-\-contiguous " {" \fIy | \fIn } Tries to set or reset the contiguous allocation policy for logical volumes. It's only possible to change a non-contiguous logical volume's allocation policy to contiguous, if all of the allocated physical extents are already contiguous. .TP .BR \-\-discards " {" \fIignore | \fInopassdown | \fIpassdown } Set this to \fIignore\fP to ignore any discards received by a thin pool Logical Volume. Set to \fInopassdown\fP to process such discards within the thin pool itself and allow the no-longer-needed extents to be overwritten by new data. Set to \fIpassdown\fP (the default) to process them both within the thin pool itself and to pass them down the underlying device. .TP .B \-\-resync Forces the complete resynchronization of a mirror. In normal circumstances you should not need this option because synchronization happens automatically. Data is read from the primary mirror device and copied to the others, so this can take a considerable amount of time - and during this time you are without a complete redundant copy of your data. .TP .B \-\-minor \fIminor Set the minor number. .TP .BR \-\-monitor " {" \fIy | \fIn } Start or stop monitoring a mirrored or snapshot logical volume with dmeventd, if it is installed. If a device used by a monitored mirror reports an I/O error, the failure is handled according to \fBmirror_image_fault_policy\fP and \fBmirror_log_fault_policy\fP set in \fBlvm.conf\fP. .TP .BR \-\-poll " {" \fIy | \fIn } Without polling a logical volume's backgrounded transformation process will never complete. If there is an incomplete pvmove or lvconvert (for example, on rebooting after a crash), use \fB\-\-poll y\fP to restart the process from its last checkpoint. However, it may not be appropriate to immediately poll a logical volume when it is activated, use \fB\-\-poll n\fP to defer and then \fB\-\-poll y\fP to restart the process. .TP .B \-\-sysinit Indicates that \fBlvchange\fP(8) is being invoked from early system initialisation scripts (e.g. rc.sysinit or an initrd), before writeable filesystems are available. As such, some functionality needs to be disabled and this option acts as a shortcut which selects an appropriate set of options. Currently this is equivalent to using \fB\-\-ignorelockingfailure\fP, \fB\-\-ignoremonitoring\fP, \fB\-\-poll n\fP and setting \fBLVM_SUPPRESS_LOCKING_FAILURE_MESSAGES\fP environment variable. If \fB\-\-sysinit\fP is used in conjunction with lvmetad(8) enabled and running, autoactivation is preferred over manual activation via direct lvchange call. Logical volumes are autoactivated according to auto_activation_volume_list set in lvm.conf(5). .TP .B \-\-noudevsync Disable udev synchronisation. The process will not wait for notification from udev. It 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. .TP .B \-\-ignoremonitoring Make no attempt to interact with dmeventd unless \fB\-\-monitor\fP is specified. Do not use this if dmeventd is already monitoring a device. .TP .BR \-M ", " \-\-persistent " {" \fIy | \fIn } Set to y to make the minor number specified persistent. .TP .BR \-p ", " \-\-permission " {" \fIr | \fIrw } Change access permission to read-only or read/write. .TP .BR \-r ", " \-\-readahead " {" \fIReadAheadSectors | \fIauto | \fInone } Set read ahead sector count of this logical volume. For volume groups with metadata in lvm1 format, this must be a value between 2 and 120 sectors. The default value is "auto" which allows the kernel to choose a suitable value automatically. "None" is equivalent to specifying zero. .TP .B \-\-refresh If the logical volume is active, reload its metadata. This is not necessary in normal operation, but may be useful if something has gone wrong or if you're doing clustering manually without a clustered lock manager. .TP .BR \-Z ", " \-\-zero " {" \fIy | \fIn } Set zeroing mode for thin pool. Note: already provisioned blocks from pool in non-zero mode are not cleared in unwritten parts when setting zero to \fIy\fP. .SH Examples Changes the permission on volume lvol1 in volume group vg00 to be read-only: .sp .B lvchange -pr vg00/lvol1 .SH SEE ALSO .BR lvm (8), .BR lvcreate (8), .BR vgchange (8) lvm2-2.02.98/man/vgck.8.in0000640000175000017500000000071012037016272013711 0ustar blankblank.TH VGCK 8 "LVM TOOLS #VERSION#" "Sistina Software UK" \" -*- nroff -*- .SH NAME vgck \- check volume group metadata .SH SYNOPSIS .B vgck .RB [ \-d | \-\-debug ] .RB [ \-h | \-? | \-\-help ] .RB [ \-v | \-\-verbose ] .RI [ VolumeGroupName ...] .SH DESCRIPTION vgck checks LVM metadata for each named volume group for consistency. .SH OPTIONS See \fBlvm\fP(8) for common options. .SH SEE ALSO .BR lvm (8), .BR vgcreate (8), .BR vgchange (8), .BR vgscan (8) lvm2-2.02.98/man/lvmdump.8.in0000640000175000017500000000401512037016272014445 0ustar blankblank.TH LVMDUMP 8 "LVM TOOLS #VERSION#" "Red Hat, Inc." .SH NAME lvmdump - create lvm2 information dumps for diagnostic purposes .SH SYNOPSIS .B lvmdump .RB [ \-a ] .RB [ \-c ] .RB [ \-d .IR directory ] .RB [ \-h ] .RB [ \-m ] .SH DESCRIPTION lvmdump is a tool to dump various information concerning LVM2. By default, it creates a tarball suitable for submission along with a problem report. .PP The content of the tarball is as follows: .br - dmsetup info .br - table of currently running processes .br - recent entries from /var/log/messages (containing system messages) .br - complete lvm configuration and cache (content of /etc/lvm) .br - list of device nodes present under /dev .br - list of files present /sys/block .br - list of files present /sys/devices/virtual/block .br - if enabled with \-m, metadata dump will be also included .br - if enabled with \-a, debug output of vgscan, pvscan and list of all available volume groups, physical volumes and logical volumes will be included .br - if enabled with \-c, cluster status info .SH OPTIONS .TP .B \-a Advanced collection. \fBWARNING\fR: if lvm is already hung, then this script may hang as well if \fB\-a\fR is used. .TP .B \-c If clvmd is running, gather cluster data as well. .TP .B \-d \fIdirectory Dump into a directory instead of tarball By default, lvmdump will produce a single compressed tarball containing all the information. Using this option, it can be instructed to only produce the raw dump tree, rooted in \fIdirectory\fP. .TP .B \-h Print help message .TP .B \-m Gather LVM metadata from the PVs This option generates a 1:1 dump of the metadata area from all PVs visible to the system, which can cause the dump to increase in size considerably. However, the metadata dump may represent a valuable diagnostic resource. .SH ENVIRONMENT VARIABLES .TP \fBLVM_BINARY\fP The LVM2 binary to use. Defaults to "lvm". Sometimes you might need to set this to "/sbin/lvm.static", for example. .TP \fBDMSETUP_BINARY\fP The dmsetup binary to use. Defaults to "dmsetup". .PP .SH SEE ALSO .BR lvm (8) lvm2-2.02.98/unit-tests/0000750000175000017500000000000012037016273013627 5ustar blankblanklvm2-2.02.98/unit-tests/datastruct/0000750000175000017500000000000012037016273016005 5ustar blankblanklvm2-2.02.98/unit-tests/datastruct/TESTS0000640000175000017500000000004612037016273016633 0ustar blankblankbitset iteration:$TEST_TOOL ./bitset_tlvm2-2.02.98/unit-tests/datastruct/Makefile.in0000640000175000017500000000162212037016273020054 0ustar blankblank# # 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@ SOURCES=\ bitset_t.c TARGETS=\ bitset_t include $(top_builddir)/make.tmpl INCLUDES += -I$(top_srcdir)/libdm DM_DEPS = $(top_builddir)/libdm/libdevmapper.so DM_LIBS = -ldevmapper $(LIBS) bitset_t: bitset_t.o $(DM_DEPS) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ bitset_t.o $(DM_LIBS) lvm2-2.02.98/unit-tests/datastruct/bitset_t.c0000640000175000017500000000675612037016273020005 0ustar blankblank/* * 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 */ #include "libdevmapper.h" #include enum { NR_BITS = 137 }; static void test_get_next(struct dm_pool *mem) { int i, j, last, first; dm_bitset_t bs = dm_bitset_create(mem, NR_BITS); for (i = 0; i < NR_BITS; i++) assert(!dm_bit(bs, i)); for (i = 0, j = 1; i < NR_BITS; i += j, j++) dm_bit_set(bs, i); first = 1; for (i = 0, j = 1; i < NR_BITS; i += j, j++) { if (first) { last = dm_bit_get_first(bs); first = 0; } else last = dm_bit_get_next(bs, last); assert(last == i); } assert(dm_bit_get_next(bs, last) == -1); } static void bit_flip(dm_bitset_t bs, int bit) { int old = dm_bit(bs, bit); if (old) dm_bit_clear(bs, bit); else dm_bit_set(bs, bit); } static void test_equal(struct dm_pool *mem) { dm_bitset_t bs1 = dm_bitset_create(mem, NR_BITS); dm_bitset_t bs2 = dm_bitset_create(mem, NR_BITS); int i, j; for (i = 0, j = 1; i < NR_BITS; i += j, j++) { dm_bit_set(bs1, i); dm_bit_set(bs2, i); } assert(dm_bitset_equal(bs1, bs2)); assert(dm_bitset_equal(bs2, bs1)); for (i = 0; i < NR_BITS; i++) { bit_flip(bs1, i); assert(!dm_bitset_equal(bs1, bs2)); assert(!dm_bitset_equal(bs2, bs1)); assert(dm_bitset_equal(bs1, bs1)); /* comparing with self */ bit_flip(bs1, i); } } static void test_and(struct dm_pool *mem) { dm_bitset_t bs1 = dm_bitset_create(mem, NR_BITS); dm_bitset_t bs2 = dm_bitset_create(mem, NR_BITS); dm_bitset_t bs3 = dm_bitset_create(mem, NR_BITS); int i, j; for (i = 0, j = 1; i < NR_BITS; i += j, j++) { dm_bit_set(bs1, i); dm_bit_set(bs2, i); } dm_bit_and(bs3, bs1, bs2); assert(dm_bitset_equal(bs1, bs2)); assert(dm_bitset_equal(bs1, bs3)); assert(dm_bitset_equal(bs2, bs3)); dm_bit_clear_all(bs1); dm_bit_clear_all(bs2); for (i = 0; i < NR_BITS; i++) { if (i % 2) dm_bit_set(bs1, i); else dm_bit_set(bs2, i); } dm_bit_and(bs3, bs1, bs2); for (i = 0; i < NR_BITS; i++) assert(!dm_bit(bs3, i)); } int main(int argc, char **argv) { typedef void (*test_fn)(struct dm_pool *); static test_fn tests[] = { test_get_next, test_equal, test_and }; int i; for (i = 0; i < sizeof(tests) / sizeof(*tests); i++) { struct dm_pool *mem = dm_pool_create("bitset test", 1024); assert(mem); tests[i](mem); dm_pool_destroy(mem); } return 0; } lvm2-2.02.98/unit-tests/mm/0000750000175000017500000000000012037016273014240 5ustar blankblanklvm2-2.02.98/unit-tests/mm/TESTS0000640000175000017500000000011212037016273015060 0ustar blankblankvalgrind pool awareness:valgrind ./pool_valgrind_t 2>&1 | ./check_results lvm2-2.02.98/unit-tests/mm/check_results0000750000175000017500000000104512037016273017024 0ustar blankblank#!/usr/bin/env ruby1.9 require 'pp' patterns = [ /Invalid read of size 1/, /Invalid write of size 1/, /Invalid read of size 1/, /still reachable: [0-9,]+ bytes in 3 blocks/ ] lines = STDIN.readlines pp lines result = catch(:done) do patterns.each do |pat| loop do throw(:done, false) if lines.size == 0 line = lines.shift if line =~ pat STDERR.puts "matched #{pat}" break; end end end throw(:done, true) end exit(result ? 0 : 1) lvm2-2.02.98/unit-tests/mm/pool_valgrind_t.c0000640000175000017500000001131612037016273017571 0ustar blankblank#include "libdevmapper.h" #include /* * Checks that valgrind is picking up unallocated pool memory as * uninitialised, even if the chunk has been recycled. * * $ valgrind --track-origins=yes ./pool_valgrind_t * * ==7023== Memcheck, a memory error detector * ==7023== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al. * ==7023== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info * ==7023== Command: ./pool_valgrind_t * ==7023== * first branch worked (as expected) * ==7023== Conditional jump or move depends on uninitialised value(s) * ==7023== at 0x4009AC: main (in /home/ejt/work/lvm2/unit-tests/mm/pool_valgrind_t) * ==7023== Uninitialised value was created by a client request * ==7023== at 0x4E40CB8: dm_pool_free (in /home/ejt/work/lvm2/libdm/ioctl/libdevmapper.so.1.02) * ==7023== by 0x4009A8: main (in /home/ejt/work/lvm2/unit-tests/mm/pool_valgrind_t) * ==7023== * second branch worked (valgrind should have flagged this as an error) * ==7023== * ==7023== HEAP SUMMARY: * ==7023== in use at exit: 0 bytes in 0 blocks * ==7023== total heap usage: 2 allocs, 2 frees, 2,104 bytes allocated * ==7023== * ==7023== All heap blocks were freed -- no leaks are possible * ==7023== * ==7023== For counts of detected and suppressed errors, rerun with: -v * ==7023== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 4 from 4) */ #define COUNT 10 static void check_free() { int i; char *blocks[COUNT]; struct dm_pool *p = dm_pool_create("blah", 1024); for (i = 0; i < COUNT; i++) blocks[i] = dm_pool_alloc(p, 37); /* check we can access the last block */ blocks[COUNT - 1][0] = 'E'; if (blocks[COUNT - 1][0] == 'E') printf("first branch worked (as expected)\n"); dm_pool_free(p, blocks[5]); if (blocks[COUNT - 1][0] == 'E') printf("second branch worked (valgrind should have flagged this as an error)\n"); dm_pool_destroy(p); } /* Checks that freed chunks are marked NOACCESS */ static void check_free2() { struct dm_pool *p = dm_pool_create("", 900); /* 900 will get * rounded up to 1024, * 1024 would have got * rounded up to * 2048 */ char *data1, *data2; assert(p); data1 = dm_pool_alloc(p, 123); assert(data1); data1 = dm_pool_alloc(p, 1024); assert(data1); data2 = dm_pool_alloc(p, 123); assert(data2); data2[0] = 'A'; /* should work fine */ dm_pool_free(p, data1); /* * so now the first chunk is active, the second chunk has become * the free one. */ data2[0] = 'B'; /* should prompt an invalid write error */ dm_pool_destroy(p); } static void check_alignment() { /* * Pool always tries to allocate blocks with particular alignment. * So there are potentially small gaps between allocations. This * test checks that valgrind is spotting illegal accesses to these * gaps. */ int i, sum; struct dm_pool *p = dm_pool_create("blah", 1024); char *data1, *data2; char buffer[16]; data1 = dm_pool_alloc_aligned(p, 1, 4); assert(data1); data2 = dm_pool_alloc_aligned(p, 1, 4); assert(data1); snprintf(buffer, sizeof(buffer), "%c", *(data1 + 1)); /* invalid read size 1 */ dm_pool_destroy(p); } /* * Looking at the code I'm not sure allocations that are near the chunk * size are working. So this test is trying to exhibit a specific problem. */ static void check_allocation_near_chunk_size() { int i; char *data; struct dm_pool *p = dm_pool_create("", 900); /* * allocate a lot and then free everything so we know there * is a spare chunk. */ for (i = 0; i < 1000; i++) { data = dm_pool_alloc(p, 37); memset(data, 0, 37); assert(data); } dm_pool_empty(p); /* now we allocate something close to the chunk size ... */ data = dm_pool_alloc(p, 1020); assert(data); memset(data, 0, 1020); dm_pool_destroy(p); } /* FIXME: test the dbg_malloc at exit (this test should be in dbg_malloc) */ static void check_leak_detection() { int i; struct dm_pool *p = dm_pool_create("", 1024); for (i = 0; i < 10; i++) dm_pool_alloc(p, (i + 1) * 37); } /* we shouldn't get any errors from this one */ static void check_object_growth() { int i; struct dm_pool *p = dm_pool_create("", 32); char data[100] = { 0 }; void *obj; dm_pool_begin_object(p, 43); for (i = 1; i < 100; i++) dm_pool_grow_object(p, data, i); obj = dm_pool_end_object(p); dm_pool_destroy(p); } int main(int argc, char **argv) { check_free(); check_free2(); check_alignment(); check_allocation_near_chunk_size(); check_leak_detection(); check_object_growth(); return 0; } lvm2-2.02.98/unit-tests/mm/Makefile.in0000640000175000017500000000154412037016273016312 0ustar blankblank# # 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 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@ VPATH = @srcdir@ SOURCES=\ pool_valgrind_t.c TARGETS=\ pool_valgrind_t include $(top_builddir)/make.tmpl DM_LIBS = -ldevmapper $(LIBS) pool_valgrind_t: pool_valgrind_t.o $(CC) $(CFLAGS) -o $@ pool_valgrind_t.o $(LDFLAGS) $(DM_LIBS) lvm2-2.02.98/unit-tests/regex/0000750000175000017500000000000012037016273014741 5ustar blankblanklvm2-2.02.98/unit-tests/regex/random_regexes0000640000175000017500000000562012037016273017672 0ustar blankblank"(((a?)(([Ub]*)|z))((([qr]|X)+)([Qn]*)))+" "[HZejtuw]*" "((B|s)*)|(((([Fv]l)(N+))(([el]|C)(tJ)))?)" "((([Ma]?)|(t*))*)|((([cm]E)|(M?))|(([BE][EV])|([Qj][Mh])))" "(((([bw]*)|([IO]*))((zK)*))|(((pU)|(i|q))|((z?)|([HL]?))))*" "((([Pt]?)|[Tr])?)((Hq)*)" "[HOXcfgikosvwxz]" "[BCEFGHNPTUWfjlprsy]" "((((aD)*)|([Xo]+))+)(([HKn](([Eq]|[JQ])(I*)))*)" "([LNWYeghv]|e)*" "(((y(L*))*)|((([EP]+)(W+))*))*" "U*" "((((R+)(W|[Qr]))|([py]+))+)([LM]*)" "(([DOjx](D(b?)))|([Ke]*))*" "((([ls](c|[FT]))*)([JS]*))*" "((l?)|(([Gz]+)|(D*)))*" "[ABgjn]" "(((q|[dg])?)|([Uk]*))((([Fl]?)|([Ry]+))|(([IR]|c)|(T?)))" "((([an]|P)|[Jw])((a*)|(m*)))*" "((((R[ht])(h+))?)|(([pz](n?))+))+" "(((([Dc]b)([Sp][Ii]))|((k|F)*))|[Uiovz])*" "[Res]*" "[Zl]|a" "^[ANZdf]$" "[En]|(((Q+)(U+))([pt]*))" "[ADEIMQUWXZhklrsvz]" "(((S(y*))*)|(j*))*" "n*" "[NUau]*" "((((Z*)(D|[Nd]))|(([np]|B)+))|(([Xy][Fi])*))+" "((([EZ]?)|(d[HR]))*)((([Hg]|q)(P+))*)" "q" "((m*)|(p|B))|((((x?)|(t+))(([Sb][PX])(O|[HM])))+)" "((((A*)(z[RS]))*)|(((z+)(Q*))+))*" "(((M*)([Uu]*))+)|[Uk]" "[imv]" "[GLSchtw](([Yw]((F[Dd])|([Tw]+)))?)" "([MOZj]*)(S|[Wknr])" "((G|q)*)[BHKN]" "((((NW)|([Ao]?))|((l|[UV])+))+)|((i|(z*))*)" "((((Z+)|([IR]?))|(L*))|([JKQ]+))+" "([Bdin](S*))+" "[HLNSTp]*" "(((J*)([Bq]|[Yu]))*)|([Kv]*)" "(((([BJ]|[Zy])(wI))*)(y*))+" "(((hF)+)|(H*))*" "((([QU][Pj])([GQ]?))+)|[PWo]" "(((([cq][BX])?)|((f[DI])*))*)(([GM]*)[SVYr])" "(([Zt]*)|((qx)|(([BV]+)(f?))))*" "[ILWYhsx]*" "(([Uy]*)|[sv])|([NSc]*)" "((c*)|([JUfhy]?))+" "(((q*)([So]*))(((g[jq])(j?))+))*" "((b+)|(((T+)([fw]T))?))*" "((([DS]?)|([Th]|u))(Q*))*" "[FKLX]|((([fw](L?))(([gq]*)|(O?)))?)" "((([HZ]+)u)*)|[APWijn]" "(e*)|(((v?)|((J+)(Hb)))?)" "(e|((w+)f))*" "[BEHKPQVdelnqy]" "((((B|N)(s*))|[Rr])(((g?)|([rv]+))+))+" "(((s*)|(K*))([AP]G))*" "[CELTp]" "(([Fq]?)|([Al]+))*" "((((r?)|(y[jx]))|([mp]*))+)|((B(S*))*)" "((([Eq]+)|(Y[ds]))|(x|(i|[Ku])))[IJNrvy]" "((([NO]*)[Ix])+)([Jenq]+)" "(((([HP]*)(j|y))*)[Ylqvy])*" "[PTv]+" "[AINSZhpx]|([EOYZ]*)" "([ABCFQv]*)((([Zx]|h)+)|([ej]*))" "((([pr]*)|(([Dq]|p)|(H?)))?)([NRUXmoq]*)" "(([er]*)|([mx]*))(((nV)([am]?))+)" "[BHPRlpu]" "(((([Ah]|[tx])|(e|[uy]))?)((([fl]+)([Vz]|v))*))*" "[AGdm]" "(((K*)^(O*)$)|(B?))*" "((([Ks]|[Ka])*)|([FSTab]?))?" "(([kw]+)[ei])(([Hy]*)(([Mc]*)|(G|f)))" "((((e*)|(Zf))|(R|[nq]))((([Jz]v)([Rj]+))+))*" "(((a?)|(e?))(([Uc]*)(S+)))*" "((((E+)([MZ]?))+)|(((s|[Az])|z)*))?" "((((i[MO])*)|((LH)*))|(((BA)|([AI]+))|[Ug]))*" "[EGHILcho]*" "(((Z[vw])?)((z|g)+))(((H|U)([iv]Q))|([qw]?))" "(([ehmr]|((L[Uw])*))+)((a+)I)" "[EKNSWYagj](((v|[TX])|([Uk]+))*)" "(((R[Mo])|(O*))|([Fm]|([qw]*)))((m*)|((S|[Ki])?))" "((((kP)|c)?)((([do]+)|([Gi]?))*))*" "((^(B|W)$|([Ww]+))([no]*))|((([iv]?)|(M*))|((x|L)?))" "[AEGPRSbcfhsy]" "[Wbcf]|((([MO]?)|([NT]|m))(([Oo]?)([Wg]*)))" "(((YZ)*)[PQVei])*" "[GJKYt][AEGWdegmnt]" "^[CDEGJKNUVYZagkv]$" "([DPWbx]*)|(((q|B)|(P|u))((M[Bq])*))" "[FHIJRTVYZdiorsuvz]*" "([MWoqvz]*)|^(l*)" "(((I|[Rx])*)((X[Mf])([Xa]L)))([Ha]|([HY]*))" "(((l|[Sd])*)((([Ix]+)|([XY]?))(Z*)))+" lvm2-2.02.98/unit-tests/regex/nonprint_input0000640000175000017500000000003012037016273017744 0ustar blankblankfoo.bar foo€bar fooÂb € lvm2-2.02.98/unit-tests/regex/TESTS0000640000175000017500000000067212037016273015574 0ustar blankblankdfa matching:$TEST_TOOL ./matcher_t --fingerprint dev_patterns < devices.list > matcher_t.output && diff -u matcher_t.expected matcher_t.output dfa matching:$TEST_TOOL ./matcher_t --fingerprint random_regexes < /dev/null > matcher_t.output && diff -u matcher_t.expected2 matcher_t.output dfa with non-print regex chars:$TEST_TOOL ./matcher_t nonprint_regexes < nonprint_input > matcher_t.output && diff -u matcher_t.expected3 matcher_t.outputlvm2-2.02.98/unit-tests/regex/matcher_t.expected0000640000175000017500000000063412037016273020436 0ustar blankblankfingerprint: 352b6c4f /dev/loop/0 : loop/[0-9]+ /dev/loop/1 : loop/[0-9]+ /dev/loop/2 : loop/[0-9]+ /dev/loop/3 : loop/[0-9]+ /dev/loop/4 : loop/[0-9]+ /dev/loop/5 : loop/[0-9]+ /dev/loop/6 : loop/[0-9]+ /dev/loop/7 : loop/[0-9]+ /dev/hda1 : hd[a-d][0-5]+ /dev/hda2 : hd[a-d][0-5]+ /dev/hda3 : hd[a-d][0-5]+ /dev/hda4 : hd[a-d][0-5]+ /dev/hda5 : hd[a-d][0-5]+ /dev/hdb1 : hd[a-d][0-5]+ /dev/hdc1 : hd[a-d][0-5]+ lvm2-2.02.98/unit-tests/regex/devices.list0000640000175000017500000002573212037016273017272 0ustar blankblank/dev /dev/.devfsd /dev/cpu /dev/cpu/mtrr /dev/netlink /dev/netlink/route /dev/netlink/skip /dev/netlink/USERSOCK /dev/netlink/fwmonitor /dev/netlink/ARPD /dev/netlink/ROUTE6 /dev/netlink/IP6_FW /dev/netlink/tap0 /dev/netlink/tap1 /dev/netlink/tap2 /dev/netlink/tap3 /dev/netlink/tap4 /dev/netlink/tap5 /dev/netlink/tap6 /dev/netlink/tap7 /dev/netlink/tap8 /dev/netlink/tap9 /dev/netlink/tap10 /dev/netlink/tap11 /dev/netlink/tap12 /dev/netlink/tap13 /dev/netlink/tap14 /dev/netlink/tap15 /dev/shm /dev/mem /dev/kmem /dev/null /dev/port /dev/zero /dev/full /dev/random /dev/urandom /dev/tty /dev/console /dev/vc /dev/vc/1 /dev/vc/2 /dev/vc/3 /dev/vc/4 /dev/vc/5 /dev/vc/6 /dev/vc/7 /dev/vc/8 /dev/vc/9 /dev/vc/10 /dev/vc/11 /dev/vc/12 /dev/vc/13 /dev/vc/14 /dev/vc/15 /dev/vc/16 /dev/vc/17 /dev/vc/18 /dev/vc/19 /dev/vc/20 /dev/vc/21 /dev/vc/22 /dev/vc/23 /dev/vc/24 /dev/vc/25 /dev/vc/26 /dev/vc/27 /dev/vc/28 /dev/vc/29 /dev/vc/30 /dev/vc/31 /dev/vc/32 /dev/vc/33 /dev/vc/34 /dev/vc/35 /dev/vc/36 /dev/vc/37 /dev/vc/38 /dev/vc/39 /dev/vc/40 /dev/vc/41 /dev/vc/42 /dev/vc/43 /dev/vc/44 /dev/vc/45 /dev/vc/46 /dev/vc/47 /dev/vc/48 /dev/vc/49 /dev/vc/50 /dev/vc/51 /dev/vc/52 /dev/vc/53 /dev/vc/54 /dev/vc/55 /dev/vc/56 /dev/vc/57 /dev/vc/58 /dev/vc/59 /dev/vc/60 /dev/vc/61 /dev/vc/62 /dev/vc/63 /dev/vc/0 /dev/ptmx /dev/misc /dev/misc/psaux /dev/pty /dev/pty/m0 /dev/pty/m1 /dev/pty/m2 /dev/pty/m3 /dev/pty/m4 /dev/pty/m5 /dev/pty/m6 /dev/pty/m7 /dev/pty/m8 /dev/pty/m9 /dev/pty/m10 /dev/pty/m11 /dev/pty/m12 /dev/pty/m13 /dev/pty/m14 /dev/pty/m15 /dev/pty/m16 /dev/pty/m17 /dev/pty/m18 /dev/pty/m19 /dev/pty/m20 /dev/pty/m21 /dev/pty/m22 /dev/pty/m23 /dev/pty/m24 /dev/pty/m25 /dev/pty/m26 /dev/pty/m27 /dev/pty/m28 /dev/pty/m29 /dev/pty/m30 /dev/pty/m31 /dev/pty/m32 /dev/pty/m33 /dev/pty/m34 /dev/pty/m35 /dev/pty/m36 /dev/pty/m37 /dev/pty/m38 /dev/pty/m39 /dev/pty/m40 /dev/pty/m41 /dev/pty/m42 /dev/pty/m43 /dev/pty/m44 /dev/pty/m45 /dev/pty/m46 /dev/pty/m47 /dev/pty/m48 /dev/pty/m49 /dev/pty/m50 /dev/pty/m51 /dev/pty/m52 /dev/pty/m53 /dev/pty/m54 /dev/pty/m55 /dev/pty/m56 /dev/pty/m57 /dev/pty/m58 /dev/pty/m59 /dev/pty/m60 /dev/pty/m61 /dev/pty/m62 /dev/pty/m63 /dev/pty/m64 /dev/pty/m65 /dev/pty/m66 /dev/pty/m67 /dev/pty/m68 /dev/pty/m69 /dev/pty/m70 /dev/pty/m71 /dev/pty/m72 /dev/pty/m73 /dev/pty/m74 /dev/pty/m75 /dev/pty/m76 /dev/pty/m77 /dev/pty/m78 /dev/pty/m79 /dev/pty/m80 /dev/pty/m81 /dev/pty/m82 /dev/pty/m83 /dev/pty/m84 /dev/pty/m85 /dev/pty/m86 /dev/pty/m87 /dev/pty/m88 /dev/pty/m89 /dev/pty/m90 /dev/pty/m91 /dev/pty/m92 /dev/pty/m93 /dev/pty/m94 /dev/pty/m95 /dev/pty/m96 /dev/pty/m97 /dev/pty/m98 /dev/pty/m99 /dev/pty/m100 /dev/pty/m101 /dev/pty/m102 /dev/pty/m103 /dev/pty/m104 /dev/pty/m105 /dev/pty/m106 /dev/pty/m107 /dev/pty/m108 /dev/pty/m109 /dev/pty/m110 /dev/pty/m111 /dev/pty/m112 /dev/pty/m113 /dev/pty/m114 /dev/pty/m115 /dev/pty/m116 /dev/pty/m117 /dev/pty/m118 /dev/pty/m119 /dev/pty/m120 /dev/pty/m121 /dev/pty/m122 /dev/pty/m123 /dev/pty/m124 /dev/pty/m125 /dev/pty/m126 /dev/pty/m127 /dev/pty/m128 /dev/pty/m129 /dev/pty/m130 /dev/pty/m131 /dev/pty/m132 /dev/pty/m133 /dev/pty/m134 /dev/pty/m135 /dev/pty/m136 /dev/pty/m137 /dev/pty/m138 /dev/pty/m139 /dev/pty/m140 /dev/pty/m141 /dev/pty/m142 /dev/pty/m143 /dev/pty/m144 /dev/pty/m145 /dev/pty/m146 /dev/pty/m147 /dev/pty/m148 /dev/pty/m149 /dev/pty/m150 /dev/pty/m151 /dev/pty/m152 /dev/pty/m153 /dev/pty/m154 /dev/pty/m155 /dev/pty/m156 /dev/pty/m157 /dev/pty/m158 /dev/pty/m159 /dev/pty/m160 /dev/pty/m161 /dev/pty/m162 /dev/pty/m163 /dev/pty/m164 /dev/pty/m165 /dev/pty/m166 /dev/pty/m167 /dev/pty/m168 /dev/pty/m169 /dev/pty/m170 /dev/pty/m171 /dev/pty/m172 /dev/pty/m173 /dev/pty/m174 /dev/pty/m175 /dev/pty/m176 /dev/pty/m177 /dev/pty/m178 /dev/pty/m179 /dev/pty/m180 /dev/pty/m181 /dev/pty/m182 /dev/pty/m183 /dev/pty/m184 /dev/pty/m185 /dev/pty/m186 /dev/pty/m187 /dev/pty/m188 /dev/pty/m189 /dev/pty/m190 /dev/pty/m191 /dev/pty/m192 /dev/pty/m193 /dev/pty/m194 /dev/pty/m195 /dev/pty/m196 /dev/pty/m197 /dev/pty/m198 /dev/pty/m199 /dev/pty/m200 /dev/pty/m201 /dev/pty/m202 /dev/pty/m203 /dev/pty/m204 /dev/pty/m205 /dev/pty/m206 /dev/pty/m207 /dev/pty/m208 /dev/pty/m209 /dev/pty/m210 /dev/pty/m211 /dev/pty/m212 /dev/pty/m213 /dev/pty/m214 /dev/pty/m215 /dev/pty/m216 /dev/pty/m217 /dev/pty/m218 /dev/pty/m219 /dev/pty/m220 /dev/pty/m221 /dev/pty/m222 /dev/pty/m223 /dev/pty/m224 /dev/pty/m225 /dev/pty/m226 /dev/pty/m227 /dev/pty/m228 /dev/pty/m229 /dev/pty/m230 /dev/pty/m231 /dev/pty/m232 /dev/pty/m233 /dev/pty/m234 /dev/pty/m235 /dev/pty/m236 /dev/pty/m237 /dev/pty/m238 /dev/pty/m239 /dev/pty/m240 /dev/pty/m241 /dev/pty/m242 /dev/pty/m243 /dev/pty/m244 /dev/pty/m245 /dev/pty/m246 /dev/pty/m247 /dev/pty/m248 /dev/pty/m249 /dev/pty/m250 /dev/pty/m251 /dev/pty/m252 /dev/pty/m253 /dev/pty/m254 /dev/pty/m255 /dev/pts /dev/pts/0 /dev/pts/1 /dev/pts/2 /dev/pts/3 /dev/pts/4 /dev/pts/5 /dev/pts/6 /dev/pts/7 /dev/vcc /dev/vcc/0 /dev/vcc/a /dev/vcc/1 /dev/vcc/a1 /dev/vcc/2 /dev/vcc/a2 /dev/vcc/3 /dev/vcc/a3 /dev/vcc/5 /dev/vcc/a5 /dev/vcc/4 /dev/vcc/a4 /dev/vcc/6 /dev/vcc/a6 /dev/vcc/7 /dev/vcc/a7 /dev/tts /dev/tts/0 /dev/cua /dev/cua/0 /dev/ide /dev/ide/host0 /dev/ide/host0/bus0 /dev/ide/host0/bus0/target0 /dev/ide/host0/bus0/target0/lun0 /dev/ide/host0/bus0/target0/lun0/disc /dev/ide/host0/bus0/target0/lun0/part1 /dev/ide/host0/bus0/target0/lun0/part2 /dev/ide/host0/bus0/target0/lun0/part3 /dev/ide/host0/bus0/target0/lun0/part4 /dev/ide/host0/bus0/target0/lun0/part5 /dev/ide/host0/bus0/target0/lun0/part6 /dev/ide/host0/bus0/target0/lun0/part7 /dev/ide/host0/bus0/target0/lun0/part8 /dev/ide/host0/bus0/target1 /dev/ide/host0/bus0/target1/lun0 /dev/ide/host0/bus0/target1/lun0/disc /dev/ide/host0/bus0/target1/lun0/part1 /dev/ide/host0/bus1 /dev/ide/host0/bus1/target0 /dev/ide/host0/bus1/target0/lun0 /dev/ide/host0/bus1/target0/lun0/disc /dev/ide/host0/bus1/target0/lun0/part1 /dev/ide/host0/bus1/target1 /dev/ide/host0/bus1/target1/lun0 /dev/discs /dev/discs/disc0 /dev/discs/disc1 /dev/discs/disc2 /dev/floppy /dev/floppy/0u1440 /dev/floppy/0u1680 /dev/floppy/0u1722 /dev/floppy/0u1743 /dev/floppy/0u1760 /dev/floppy/0u1920 /dev/floppy/0u1840 /dev/floppy/0u1600 /dev/floppy/0u360 /dev/floppy/0u720 /dev/floppy/0u820 /dev/floppy/0u830 /dev/floppy/0u1040 /dev/floppy/0u1120 /dev/floppy/0u800 /dev/floppy/0 /dev/loop /dev/loop/0 /dev/loop/1 /dev/loop/2 /dev/loop/3 /dev/loop/4 /dev/loop/5 /dev/loop/6 /dev/loop/7 /dev/cdroms /dev/sound /dev/sound/dsp /dev/sound/dsp1 /dev/sound/mixer /dev/sound/midi /dev/usb /dev/root /dev/initctl /dev/xconsole /dev/fd /dev/stdin /dev/stdout /dev/stderr /dev/route /dev/skip /dev/USERSOCK /dev/fwmonitor /dev/ARPD /dev/ROUTE6 /dev/IP6_FW /dev/tap0 /dev/tap1 /dev/tap2 /dev/tap3 /dev/tap4 /dev/tap5 /dev/tap6 /dev/tap7 /dev/tap8 /dev/tap9 /dev/tap10 /dev/tap11 /dev/tap12 /dev/tap13 /dev/tap14 /dev/tap15 /dev/tty1 /dev/tty2 /dev/tty3 /dev/tty4 /dev/tty5 /dev/tty6 /dev/tty7 /dev/tty8 /dev/tty9 /dev/tty10 /dev/tty11 /dev/tty12 /dev/tty13 /dev/tty14 /dev/tty15 /dev/tty16 /dev/tty17 /dev/tty18 /dev/tty19 /dev/tty20 /dev/tty21 /dev/tty22 /dev/tty23 /dev/tty24 /dev/tty25 /dev/tty26 /dev/tty27 /dev/tty28 /dev/tty29 /dev/tty30 /dev/tty31 /dev/tty32 /dev/tty33 /dev/tty34 /dev/tty35 /dev/tty36 /dev/tty37 /dev/tty38 /dev/tty39 /dev/tty40 /dev/tty41 /dev/tty42 /dev/tty43 /dev/tty44 /dev/tty45 /dev/tty46 /dev/tty47 /dev/tty48 /dev/tty49 /dev/tty50 /dev/tty51 /dev/tty52 /dev/tty53 /dev/tty54 /dev/tty55 /dev/tty56 /dev/tty57 /dev/tty58 /dev/tty59 /dev/tty60 /dev/tty61 /dev/tty62 /dev/tty63 /dev/tty0 /dev/psaux /dev/ptyp0 /dev/ptyp1 /dev/ptyp2 /dev/ptyp3 /dev/ptyp4 /dev/ptyp5 /dev/ptyp6 /dev/ptyp7 /dev/ptyp8 /dev/ptyp9 /dev/ptypa /dev/ptypb /dev/ptypc /dev/ptypd /dev/ptype /dev/ptypf /dev/ptyq0 /dev/ptyq1 /dev/ptyq2 /dev/ptyq3 /dev/ptyq4 /dev/ptyq5 /dev/ptyq6 /dev/ptyq7 /dev/ptyq8 /dev/ptyq9 /dev/ptyqa /dev/ptyqb /dev/ptyqc /dev/ptyqd /dev/ptyqe /dev/ptyqf /dev/ptyr0 /dev/ptyr1 /dev/ptyr2 /dev/ptyr3 /dev/ptyr4 /dev/ptyr5 /dev/ptyr6 /dev/ptyr7 /dev/ptyr8 /dev/ptyr9 /dev/ptyra /dev/ptyrb /dev/ptyrc /dev/ptyrd /dev/ptyre /dev/ptyrf /dev/ptys0 /dev/ptys1 /dev/ptys2 /dev/ptys3 /dev/ptys4 /dev/ptys5 /dev/ptys6 /dev/ptys7 /dev/ptys8 /dev/ptys9 /dev/ptysa /dev/ptysb /dev/ptysc /dev/ptysd /dev/ptyse /dev/ptysf /dev/ptyt0 /dev/ptyt1 /dev/ptyt2 /dev/ptyt3 /dev/ptyt4 /dev/ptyt5 /dev/ptyt6 /dev/ptyt7 /dev/ptyt8 /dev/ptyt9 /dev/ptyta /dev/ptytb /dev/ptytc /dev/ptytd /dev/ptyte /dev/ptytf /dev/ptyu0 /dev/ptyu1 /dev/ptyu2 /dev/ptyu3 /dev/ptyu4 /dev/ptyu5 /dev/ptyu6 /dev/ptyu7 /dev/ptyu8 /dev/ptyu9 /dev/ptyua /dev/ptyub /dev/ptyuc /dev/ptyud /dev/ptyue /dev/ptyuf /dev/ptyv0 /dev/ptyv1 /dev/ptyv2 /dev/ptyv3 /dev/ptyv4 /dev/ptyv5 /dev/ptyv6 /dev/ptyv7 /dev/ptyv8 /dev/ptyv9 /dev/ptyva /dev/ptyvb /dev/ptyvc /dev/ptyvd /dev/ptyve /dev/ptyvf /dev/ptyw0 /dev/ptyw1 /dev/ptyw2 /dev/ptyw3 /dev/ptyw4 /dev/ptyw5 /dev/ptyw6 /dev/ptyw7 /dev/ptyw8 /dev/ptyw9 /dev/ptywa /dev/ptywb /dev/ptywc /dev/ptywd /dev/ptywe /dev/ptywf /dev/ptyx0 /dev/ptyx1 /dev/ptyx2 /dev/ptyx3 /dev/ptyx4 /dev/ptyx5 /dev/ptyx6 /dev/ptyx7 /dev/ptyx8 /dev/ptyx9 /dev/ptyxa /dev/ptyxb /dev/ptyxc /dev/ptyxd /dev/ptyxe /dev/ptyxf /dev/ptyy0 /dev/ptyy1 /dev/ptyy2 /dev/ptyy3 /dev/ptyy4 /dev/ptyy5 /dev/ptyy6 /dev/ptyy7 /dev/ptyy8 /dev/ptyy9 /dev/ptyya /dev/ptyyb /dev/ptyyc /dev/ptyyd /dev/ptyye /dev/ptyyf /dev/ptyz0 /dev/ptyz1 /dev/ptyz2 /dev/ptyz3 /dev/ptyz4 /dev/ptyz5 /dev/ptyz6 /dev/ptyz7 /dev/ptyz8 /dev/ptyz9 /dev/ptyza /dev/ptyzb /dev/ptyzc /dev/ptyzd /dev/ptyze /dev/ptyzf /dev/ptya0 /dev/ptya1 /dev/ptya2 /dev/ptya3 /dev/ptya4 /dev/ptya5 /dev/ptya6 /dev/ptya7 /dev/ptya8 /dev/ptya9 /dev/ptyaa /dev/ptyab /dev/ptyac /dev/ptyad /dev/ptyae /dev/ptyaf /dev/ptyb0 /dev/ptyb1 /dev/ptyb2 /dev/ptyb3 /dev/ptyb4 /dev/ptyb5 /dev/ptyb6 /dev/ptyb7 /dev/ptyb8 /dev/ptyb9 /dev/ptyba /dev/ptybb /dev/ptybc /dev/ptybd /dev/ptybe /dev/ptybf /dev/ptyc0 /dev/ptyc1 /dev/ptyc2 /dev/ptyc3 /dev/ptyc4 /dev/ptyc5 /dev/ptyc6 /dev/ptyc7 /dev/ptyc8 /dev/ptyc9 /dev/ptyca /dev/ptycb /dev/ptycc /dev/ptycd /dev/ptyce /dev/ptycf /dev/ptyd0 /dev/ptyd1 /dev/ptyd2 /dev/ptyd3 /dev/ptyd4 /dev/ptyd5 /dev/ptyd6 /dev/ptyd7 /dev/ptyd8 /dev/ptyd9 /dev/ptyda /dev/ptydb /dev/ptydc /dev/ptydd /dev/ptyde /dev/ptydf /dev/ptye0 /dev/ptye1 /dev/ptye2 /dev/ptye3 /dev/ptye4 /dev/ptye5 /dev/ptye6 /dev/ptye7 /dev/ptye8 /dev/ptye9 /dev/ptyea /dev/ptyeb /dev/ptyec /dev/ptyed /dev/ptyee /dev/ptyef /dev/vcs /dev/vcsa /dev/vcs1 /dev/vcsa1 /dev/ttyS0 /dev/cua0 /dev/hda /dev/hda1 /dev/hda2 /dev/hda3 /dev/hda4 /dev/hda5 /dev/hda6 /dev/hda7 /dev/hda8 /dev/hdb /dev/hdb1 /dev/hdc /dev/hdc1 /dev/fd0u1440 /dev/fd0u1680 /dev/fd0u1722 /dev/fd0u1743 /dev/fd0u1760 /dev/fd0u1920 /dev/fd0u1840 /dev/fd0u1600 /dev/fd0u360 /dev/fd0u720 /dev/fd0u820 /dev/fd0u830 /dev/fd0u1040 /dev/fd0u1120 /dev/fd0u800 /dev/fd0 /dev/loop0 /dev/loop1 /dev/loop2 /dev/loop3 /dev/loop4 /dev/loop5 /dev/loop6 /dev/loop7 /dev/dsp /dev/dsp1 /dev/mixer /dev/midi /dev/lvm /dev/vg0 /dev/vg0/group /dev/vg0/packages /dev/vg0/photos /dev/vg0/music /dev/log /dev/MAKEDEV /dev/printer /dev/vcs2 /dev/vcsa2 /dev/vcs3 /dev/vcsa3 /dev/vcs5 /dev/vcsa5 /dev/vcs4 /dev/vcsa4 /dev/vcs6 /dev/vcsa6 /dev/nvidia0 /dev/nvidia1 /dev/nvidia2 /dev/nvidia3 /dev/nvidiactl /dev/vcs7 /dev/vcsa7 lvm2-2.02.98/unit-tests/regex/matcher_t.c0000640000175000017500000000625712037016273017066 0ustar blankblank/* * 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 */ #include "libdevmapper.h" #include "log.h" #include #include #include #include #include #include #include #include static int _read_spec(const char *file, char ***regex, int *nregex) { char buffer[1024], *start, *ptr; FILE *fp = fopen(file, "r"); int asize = 100; char **rx = dm_malloc(sizeof(*rx) * asize); int nr = 0; if (!fp) return 0; while (fgets(buffer, sizeof(buffer),fp)) { /* trim leading whitespace */ for (ptr = buffer; *ptr && isspace((int) *ptr); ptr++); if (!*ptr || *ptr == '#') continue; if (*ptr == '\"') { ptr++; start = ptr; while (*ptr && *ptr != '\"') { if (*ptr == '\\') ptr++; ptr++; } if (!*ptr) { fprintf(stderr, "Formatting error : " "No terminating quote\n"); return 0; } rx[nr] = dm_malloc((ptr - start) + 1); strncpy(rx[nr], start, ptr - start); rx[nr][ptr - start] = '\0'; nr++; } else { fprintf(stderr, "%s", ptr); fprintf(stderr, "Formatting error : \"\" " "\n"); return 0; } } *regex = rx; *nregex = nr; return 1; } static void _free_regex(char **regex, int nregex) { int i; for (i = 0; i < nregex; i++) dm_free(regex[i]); dm_free(regex); } static void _scan_input(struct dm_regex *m, char **regex) { char buffer[256], *ptr; int r; while (fgets(buffer, sizeof(buffer), stdin)) { if ((ptr = strchr(buffer, '\n'))) *ptr = '\0'; r = dm_regex_match(m, buffer); if (r >= 0) printf("%s : %s\n", buffer, regex[r]); } } int main(int argc, char **argv) { struct dm_pool *mem; struct dm_regex *scanner; char **regex; int nregex; int ret = 0; int want_finger_print = 0, i; const char *pattern_file = NULL; for (i = 1; i < argc; i++) if (!strcmp(argv[i], "--fingerprint")) want_finger_print = 1; else pattern_file = argv[i]; if (!pattern_file) { fprintf(stderr, "Usage : %s [--fingerprint] \n", argv[0]); exit(1); } dm_log_init_verbose(_LOG_DEBUG); if (!(mem = dm_pool_create("match_regex", 10 * 1024))) { fprintf(stderr, "Couldn't create pool\n"); ret = 2; goto err; } if (!_read_spec(pattern_file, ®ex, &nregex)) { fprintf(stderr, "Couldn't read the lex specification\n"); ret = 3; goto err; } if (!(scanner = dm_regex_create(mem, (const char **)regex, nregex))) { fprintf(stderr, "Couldn't build the lexer\n"); ret = 4; goto err; } if (want_finger_print) printf("fingerprint: %x\n", dm_regex_fingerprint(scanner)); _scan_input(scanner, regex); _free_regex(regex, nregex); err: dm_pool_destroy(mem); return ret; } lvm2-2.02.98/unit-tests/regex/matcher_t.expected30000640000175000017500000000004012037016273020510 0ustar blankblankfoo€bar : € fooÂb : fooÂb € : € lvm2-2.02.98/unit-tests/regex/nonprint_regexes0000640000175000017500000000002612037016273020254 0ustar blankblank"foo€bar" "fooÂb" "€" lvm2-2.02.98/unit-tests/regex/Makefile.in0000640000175000017500000000200512037016273017004 0ustar blankblank# # 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@ SOURCES=\ parse_t.c \ matcher_t.c TARGETS=\ parse_t \ matcher_t include $(top_builddir)/make.tmpl INCLUDES += -I$(top_srcdir)/libdm DM_DEPS = $(top_builddir)/libdm/libdevmapper.so DM_LIBS = -ldevmapper $(LIBS) parse_t: parse_t.o $(DM_DEPS) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ parse_t.o $(DM_LIBS) matcher_t: matcher_t.o $(DM_DEPS) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ matcher_t.o $(DM_LIBS) lvm2-2.02.98/unit-tests/regex/parse_t.c0000640000175000017500000000426012037016273016545 0ustar blankblank/* * 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 */ /* hack - using unexported internal function */ #define DEBUG #include "regex/parse_rx.c" #include #include static void _pretty_print(struct rx_node *rx, int depth) { int i; for (i = 0; i < depth; i++) printf(" "); /* display info about the node */ switch (rx->type) { case CAT: printf("Cat"); break; case OR: printf("Or"); break; case STAR: printf("Star"); break; case PLUS: printf("Plus"); break; case QUEST: printf("Quest"); break; case CHARSET: printf("Charset : "); for (i = 0; i < 256; i++) { if (dm_bit(rx->charset, i) && isprint(i)) printf("%c", (char) i); } break; default: printf("Unknown type"); } printf("\n"); if (rx->left) _pretty_print(rx->left, depth + 1); if (rx->right) _pretty_print(rx->right, depth + 1); } int main(int argc, char **argv) { struct dm_pool *mem; struct rx_node *rx; int regex_print = 0; int show_nodes = 0; int regex_arg = 1; if (argc == 3 && !strcmp(argv[1], "-r")) { regex_print++; regex_arg++; argc--; } if (argc == 3 && !strcmp(argv[1], "-R")) { regex_print++; show_nodes++; regex_arg++; argc--; } if (argc != 2) { fprintf(stderr, "Usage : %s [-r] \n", argv[0]); exit(0); } dm_log_init_verbose(_LOG_DEBUG); if (!(mem = dm_pool_create("parse_regex", 1024))) { fprintf(stderr, "Couldn't create pool\n"); exit(1); } if (!(rx = rx_parse_str(mem, argv[regex_arg]))) { dm_pool_destroy(mem); fprintf(stderr, "Couldn't parse regex\n"); exit(1); } if (regex_print) _regex_print(rx, 0, show_nodes); else _pretty_print(rx, 0); dm_pool_destroy(mem); return 0; } lvm2-2.02.98/unit-tests/regex/dev_patterns0000640000175000017500000000003612037016273017362 0ustar blankblank"loop/[0-9]+" "hd[a-d][0-5]+" lvm2-2.02.98/unit-tests/regex/matcher_t.expected20000640000175000017500000000002612037016273020513 0ustar blankblankfingerprint: eed8ceb8 lvm2-2.02.98/tools/0000750000175000017500000000000012037016273012650 5ustar blankblanklvm2-2.02.98/tools/.exported_symbols0000640000175000017500000000000012037016273016242 0ustar blankblanklvm2-2.02.98/tools/pvresize.c0000640000175000017500000001063212037016273014666 0ustar blankblank/* * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. * Copyright (C) 2005 Zak Kipling. 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 "tools.h" #include "metadata.h" struct pvresize_params { uint64_t new_size; unsigned done; unsigned total; }; static int _pv_resize_single(struct cmd_context *cmd, struct volume_group *vg, struct physical_volume *pv, const uint64_t new_size) { struct pv_list *pvl; uint64_t size = 0; int r = 0; const char *pv_name = pv_dev_name(pv); const char *vg_name = pv_vg_name(pv); struct volume_group *old_vg = vg; int vg_needs_pv_write = 0; if (is_orphan_vg(vg_name)) { if (!lock_vol(cmd, vg_name, LCK_VG_WRITE)) { log_error("Can't get lock for orphans"); return 0; } if (!(pv = pv_read(cmd, pv_name, 1, 0))) { unlock_vg(cmd, vg_name); log_error("Unable to read PV \"%s\"", pv_name); return 0; } } else { vg = vg_read_for_update(cmd, vg_name, NULL, 0); if (vg_read_error(vg)) { release_vg(vg); log_error("Unable to read volume group \"%s\".", vg_name); return 0; } if (!(pvl = find_pv_in_vg(vg, pv_name))) { log_error("Unable to find \"%s\" in volume group \"%s\"", pv_name, vg->name); goto out; } pv = pvl->pv; if (!archive(vg)) goto out; } if (!(pv->fmt->features & FMT_RESIZE_PV)) { log_error("Physical volume %s format does not support resizing.", pv_name); goto out; } /* Get new size */ if (!dev_get_size(pv_dev(pv), &size)) { log_error("%s: Couldn't get size.", pv_name); goto out; } if (new_size) { if (new_size > size) log_warn("WARNING: %s: Overriding real size. " "You could lose data.", pv_name); log_verbose("%s: Pretending size is %" PRIu64 " not %" PRIu64 " sectors.", pv_name, new_size, pv_size(pv)); size = new_size; } log_verbose("Resizing volume \"%s\" to %" PRIu64 " sectors.", pv_name, pv_size(pv)); if (!pv_resize(pv, vg, size)) goto_out; log_verbose("Updating physical volume \"%s\"", pv_name); /* Write PV label only if this an orphan PV or it has 2nd mda. */ if ((is_orphan_vg(vg_name) || (vg_needs_pv_write = (fid_get_mda_indexed(vg->fid, (const char *) &pv->id, ID_LEN, 1) != NULL))) && !pv_write(cmd, pv, 1)) { log_error("Failed to store physical volume \"%s\"", pv_name); goto out; } if (!is_orphan_vg(vg_name)) { if (!vg_write(vg) || !vg_commit(vg)) { log_error("Failed to store physical volume \"%s\" in " "volume group \"%s\"", pv_name, vg_name); goto out; } backup(vg); } log_print_unless_silent("Physical volume \"%s\" changed", pv_name); r = 1; out: if (!r && vg_needs_pv_write) log_error("Use pvcreate and vgcfgrestore " "to repair from archived metadata."); unlock_vg(cmd, vg_name); if (is_orphan_vg(vg_name)) free_pv_fid(pv); if (!old_vg) release_vg(vg); return r; } static int _pvresize_single(struct cmd_context *cmd, struct volume_group *vg, struct physical_volume *pv, void *handle) { struct pvresize_params *params = (struct pvresize_params *) handle; params->total++; if (!_pv_resize_single(cmd, vg, pv, params->new_size)) { stack; return ECMD_FAILED; } params->done++; return ECMD_PROCESSED; } int pvresize(struct cmd_context *cmd, int argc, char **argv) { struct pvresize_params params; int ret; if (!argc) { log_error("Please supply physical volume(s)"); return EINVALID_CMD_LINE; } if (arg_sign_value(cmd, physicalvolumesize_ARG, SIGN_NONE) == SIGN_MINUS) { log_error("Physical volume size may not be negative"); return 0; } params.new_size = arg_uint64_value(cmd, physicalvolumesize_ARG, UINT64_C(0)); params.done = 0; params.total = 0; ret = process_each_pv(cmd, argc, argv, NULL, READ_FOR_UPDATE, 0, ¶ms, _pvresize_single); log_print_unless_silent("%d physical volume(s) resized / %d physical volume(s) " "not resized", params.done, params.total - params.done); return ret; } lvm2-2.02.98/tools/vgmknodes.c0000640000175000017500000000222712037016273015015 0ustar blankblank/* * 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 */ #include "tools.h" static int _vgmknodes_single(struct cmd_context *cmd, struct logical_volume *lv, void *handle __attribute__((unused))) { if (arg_count(cmd, refresh_ARG) && lv_is_visible(lv)) if (!lv_refresh(cmd, lv)) { stack; return ECMD_FAILED; } if (!lv_mknodes(cmd, lv)) { stack; return ECMD_FAILED; } return ECMD_PROCESSED; } int vgmknodes(struct cmd_context *cmd, int argc, char **argv) { if (!lv_mknodes(cmd, NULL)) { stack; return ECMD_FAILED; } return process_each_lv(cmd, argc, argv, LCK_VG_READ, NULL, &_vgmknodes_single); } lvm2-2.02.98/tools/lvm.c0000640000175000017500000001235612037016273013622 0ustar blankblank/* * 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 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 "tools.h" #include "lvm2cmdline.h" int main(int argc, char **argv) { return lvm2_main(argc, argv); } #ifdef READLINE_SUPPORT # include # include # ifndef HAVE_RL_COMPLETION_MATCHES # define rl_completion_matches(a, b) completion_matches((char *)a, b) # endif static struct cmdline_context *_cmdline; /* List matching commands */ static char *_list_cmds(const char *text, int state) { static int i = 0; static size_t len = 0; /* Initialise if this is a new completion attempt */ if (!state) { i = 0; len = strlen(text); } while (i < _cmdline->num_commands) if (!strncmp(text, _cmdline->commands[i++].name, len)) return strdup(_cmdline->commands[i - 1].name); return NULL; } /* List matching arguments */ static char *_list_args(const char *text, int state) { static int match_no = 0; static size_t len = 0; static struct command *com; /* Initialise if this is a new completion attempt */ if (!state) { char *s = rl_line_buffer; int j; match_no = 0; com = NULL; len = strlen(text); /* Find start of first word in line buffer */ while (isspace(*s)) s++; /* Look for word in list of commands */ for (j = 0; j < _cmdline->num_commands; j++) { const char *p; char *q = s; p = _cmdline->commands[j].name; while (*p == *q) { p++; q++; } if ((!*p) && *q == ' ') { com = _cmdline->commands + j; break; } } } if (!com) return NULL; /* Short form arguments */ if (len < 3) { while (match_no < com->num_args) { char s[3]; char c; if (!(c = (_cmdline->arg_props + com->valid_args[match_no++])->short_arg)) continue; sprintf(s, "-%c", c); if (!strncmp(text, s, len)) return strdup(s); } } /* Long form arguments */ if (match_no < com->num_args) match_no = com->num_args; while (match_no - com->num_args < com->num_args) { const char *l; l = (_cmdline->arg_props + com->valid_args[match_no++ - com->num_args])->long_arg; if (*(l + 2) && !strncmp(text, l, len)) return strdup(l); } return NULL; } /* Custom completion function */ static char **_completion(const char *text, int start_pos, int end_pos __attribute__((unused))) { char **match_list = NULL; int p = 0; while (isspace((int) *(rl_line_buffer + p))) p++; /* First word should be one of our commands */ if (start_pos == p) match_list = rl_completion_matches(text, _list_cmds); else if (*text == '-') match_list = rl_completion_matches(text, _list_args); /* else other args */ /* No further completion */ rl_attempted_completion_over = 1; return match_list; } static int _hist_file(char *buffer, size_t size) { char *e = getenv("HOME"); if (dm_snprintf(buffer, size, "%s/.lvm_history", e) < 0) { log_error("$HOME/.lvm_history: path too long"); return 0; } return 1; } static void _read_history(struct cmd_context *cmd) { char hist_file[PATH_MAX]; if (!_hist_file(hist_file, sizeof(hist_file))) return; if (read_history(hist_file)) log_very_verbose("Couldn't read history from %s.", hist_file); stifle_history(find_config_tree_int(cmd, "shell/history_size", DEFAULT_MAX_HISTORY)); } static void _write_history(void) { char hist_file[PATH_MAX]; if (!_hist_file(hist_file, sizeof(hist_file))) return; if (write_history(hist_file)) log_very_verbose("Couldn't write history to %s.", hist_file); } int lvm_shell(struct cmd_context *cmd, struct cmdline_context *cmdline) { int argc, ret; char *input = NULL, *args[MAX_ARGS], **argv; rl_readline_name = "lvm"; rl_attempted_completion_function = (CPPFunction *) _completion; _read_history(cmd); _cmdline = cmdline; _cmdline->interactive = 1; while (1) { free(input); input = readline("lvm> "); /* EOF */ if (!input) { /* readline sends prompt to stdout */ printf("\n"); break; } /* empty line */ if (!*input) continue; add_history(input); argv = args; if (lvm_split(input, &argc, argv, MAX_ARGS) == MAX_ARGS) { log_error("Too many arguments, sorry."); continue; } if (!argc) continue; if (!strcmp(argv[0], "lvm")) { argv++; argc--; } if (!argc) continue; if (!strcmp(argv[0], "quit") || !strcmp(argv[0], "exit")) { remove_history(history_length - 1); log_error("Exiting."); break; } ret = lvm_run_command(cmd, argc, argv); if (ret == ENO_SUCH_CMD) log_error("No such command '%s'. Try 'help'.", argv[0]); if ((ret != ECMD_PROCESSED) && !error_message_produced()) { log_debug(INTERNAL_ERROR "Failed command did not use log_error"); log_error("Command failed with status code %d.", ret); } _write_history(); } free(input); return 0; } #endif /* READLINE_SUPPORT */ lvm2-2.02.98/tools/vgextend.c0000640000175000017500000000750212037016273014645 0ustar blankblank/* * 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 */ #include "tools.h" static int _restore_pv(struct volume_group *vg, char *pv_name) { struct pv_list *pvl = NULL; pvl = find_pv_in_vg(vg, pv_name); if (!pvl) { log_warn("WARNING: PV %s not found in VG %s", pv_name, vg->name); return 0; } if (!(pvl->pv->status & MISSING_PV)) { log_warn("WARNING: PV %s was not missing in VG %s", pv_name, vg->name); return 0; } if (!pvl->pv->dev) { log_warn("WARNING: The PV %s is still missing.", pv_name); return 0; } pvl->pv->status &= ~MISSING_PV; return 1; } int vgextend(struct cmd_context *cmd, int argc, char **argv) { const char *vg_name; struct volume_group *vg = NULL; int r = ECMD_FAILED; struct pvcreate_params pp; int fixed = 0, i = 0; if (!argc) { log_error("Please enter volume group name and " "physical volume(s)"); return EINVALID_CMD_LINE; } vg_name = skip_dev_dir(cmd, argv[0], NULL); argc--; argv++; if (arg_count(cmd, metadatacopies_ARG)) { log_error("Invalid option --metadatacopies, " "use --pvmetadatacopies instead."); return EINVALID_CMD_LINE; } pvcreate_params_set_defaults(&pp); if (!pvcreate_params_validate(cmd, argc, argv, &pp)) { return EINVALID_CMD_LINE; } /* * It is always ok to add new PVs to a VG - even if there are * missing PVs. No LVs are affected by this operation, but * repair processes - particularly for RAID segtypes - can * be facilitated. */ cmd->handles_missing_pvs = 1; log_verbose("Checking for volume group \"%s\"", vg_name); vg = vg_read_for_update(cmd, vg_name, NULL, 0); if (vg_read_error(vg)) { release_vg(vg); stack; return ECMD_FAILED; } if (!archive(vg)) goto_bad; if (arg_count(cmd, restoremissing_ARG)) { for (i = 0; i < argc; ++i) { if (_restore_pv(vg, argv[i])) ++ fixed; } if (!fixed) { log_error("No PV has been restored."); goto_bad; } } else { /* no --restore, normal vgextend */ if (!lock_vol(cmd, VG_ORPHANS, LCK_VG_WRITE)) { log_error("Can't get lock for orphan PVs"); unlock_and_release_vg(cmd, vg, vg_name); return ECMD_FAILED; } if (arg_count(cmd, metadataignore_ARG) && (vg_mda_copies(vg) != VGMETADATACOPIES_UNMANAGED) && (pp.force == PROMPT) && yes_no_prompt("Override preferred number of copies " "of VG %s metadata? [y/n]: ", vg_name) == 'n') { log_error("Volume group %s not changed", vg_name); goto_bad; } /* extend vg */ if (!vg_extend(vg, argc, (const char* const*)argv, &pp)) goto_bad; if (arg_count(cmd, metadataignore_ARG) && (vg_mda_copies(vg) != VGMETADATACOPIES_UNMANAGED) && (vg_mda_copies(vg) != vg_mda_used_count(vg))) { log_warn("WARNING: Changing preferred number of copies of VG %s " "metadata from %"PRIu32" to %"PRIu32, vg_name, vg_mda_copies(vg), vg_mda_used_count(vg)); vg_set_mda_copies(vg, vg_mda_used_count(vg)); } /* ret > 0 */ log_verbose("Volume group \"%s\" will be extended by %d new " "physical volumes", vg_name, argc); } /* store vg on disk(s) */ if (!vg_write(vg) || !vg_commit(vg)) goto_bad; backup(vg); log_print_unless_silent("Volume group \"%s\" successfully extended", vg_name); r = ECMD_PROCESSED; bad: if (!arg_count(cmd, restoremissing_ARG)) unlock_vg(cmd, VG_ORPHANS); unlock_and_release_vg(cmd, vg, vg_name); return r; } lvm2-2.02.98/tools/lvremove.c0000640000175000017500000000255712037016273014665 0ustar blankblank/* * 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 "tools.h" static int lvremove_single(struct cmd_context *cmd, struct logical_volume *lv, void *handle __attribute__((unused))) { struct logical_volume *origin; /* * If this is a sparse device, remove its origin too. */ if (lv_is_cow(lv) && lv_is_virtual_origin(origin = origin_from_cow(lv))) lv = origin; if (!lv_remove_with_dependencies(cmd, lv, (force_t) arg_count(cmd, force_ARG), 0)) { stack; return ECMD_FAILED; } return ECMD_PROCESSED; } int lvremove(struct cmd_context *cmd, int argc, char **argv) { if (!argc) { log_error("Please enter one or more logical volume paths"); return EINVALID_CMD_LINE; } cmd->handles_missing_pvs = 1; return process_each_lv(cmd, argc, argv, READ_FOR_UPDATE, NULL, &lvremove_single); } lvm2-2.02.98/tools/lvm2cmd.c0000640000175000017500000000137612037016273014370 0ustar blankblank/* * Copyright (C) 2006-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 "lvm2cmdline.h" #include "lvm2cmd.h" void *lvm2_init(void) { return cmdlib_lvm2_init(0); } int lvm_shell(struct cmd_context *cmd __attribute__((unused)), struct cmdline_context *cmdline __attribute__((unused))) { return 0; } lvm2-2.02.98/tools/lvreduce.c0000640000175000017500000000130312037016273014623 0ustar blankblank/* * 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 */ #include "tools.h" int lvreduce(struct cmd_context *cmd, int argc, char **argv) { return lvresize(cmd, argc, argv); } lvm2-2.02.98/tools/polldaemon.h0000640000175000017500000000440412037016273015156 0ustar blankblank/* * Copyright (C) 2003-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_TOOL_POLLDAEMON_H #define _LVM_TOOL_POLLDAEMON_H #include "metadata-exported.h" typedef enum { PROGRESS_CHECK_FAILED = 0, PROGRESS_UNFINISHED = 1, PROGRESS_FINISHED_SEGMENT = 2, PROGRESS_FINISHED_ALL = 3 } progress_t; struct daemon_parms; struct poll_functions { const char *(*get_copy_name_from_lv) (struct logical_volume *lv); struct volume_group *(*get_copy_vg) (struct cmd_context *cmd, const char *name, const char *uuid); struct logical_volume *(*get_copy_lv) (struct cmd_context *cmd, struct volume_group *vg, const char *name, const char *uuid, uint64_t lv_type); progress_t (*poll_progress)(struct cmd_context *cmd, struct logical_volume *lv, const char *name, struct daemon_parms *parms); int (*update_metadata) (struct cmd_context *cmd, struct volume_group *vg, struct logical_volume *lv, struct dm_list *lvs_changed, unsigned flags); int (*finish_copy) (struct cmd_context *cmd, struct volume_group *vg, struct logical_volume *lv, struct dm_list *lvs_changed); }; struct daemon_parms { unsigned interval; unsigned wait_before_testing; unsigned aborting; unsigned background; unsigned outstanding_count; unsigned progress_display; const char *progress_title; uint64_t lv_type; struct poll_functions *poll_fns; }; int poll_daemon(struct cmd_context *cmd, const char *name, const char *uuid, unsigned background, uint64_t lv_type, struct poll_functions *poll_fns, const char *progress_title); progress_t poll_mirror_progress(struct cmd_context *cmd, struct logical_volume *lv, const char *name, struct daemon_parms *parms); #endif lvm2-2.02.98/tools/vgimport.c0000640000175000017500000000352612037016273014672 0ustar blankblank/* * 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 */ #include "tools.h" static int vgimport_single(struct cmd_context *cmd __attribute__((unused)), const char *vg_name, struct volume_group *vg, void *handle __attribute__((unused))) { struct pv_list *pvl; struct physical_volume *pv; if (!vg_is_exported(vg)) { log_error("Volume group \"%s\" is not exported", vg_name); goto bad; } if (vg_status(vg) & PARTIAL_VG) { log_error("Volume group \"%s\" is partially missing", vg_name); goto bad; } if (!archive(vg)) goto_bad; vg->status &= ~EXPORTED_VG; dm_list_iterate_items(pvl, &vg->pvs) { pv = pvl->pv; pv->status &= ~EXPORTED_VG; } if (!vg_write(vg) || !vg_commit(vg)) goto_bad; backup(vg); log_print_unless_silent("Volume group \"%s\" successfully imported", vg->name); return ECMD_PROCESSED; bad: return ECMD_FAILED; } int vgimport(struct cmd_context *cmd, int argc, char **argv) { if (!argc && !arg_count(cmd, all_ARG)) { log_error("Please supply volume groups or use -a for all."); return ECMD_FAILED; } if (argc && arg_count(cmd, all_ARG)) { log_error("No arguments permitted when using -a for all."); return ECMD_FAILED; } return process_each_vg(cmd, argc, argv, READ_FOR_UPDATE | READ_ALLOW_EXPORTED, NULL, &vgimport_single); } lvm2-2.02.98/tools/lvmcmdline.c0000640000175000017500000010442012037016273015150 0ustar blankblank/* * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU 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 "tools.h" #include "lvm2cmdline.h" #include "label.h" #include "lvm-version.h" #include "stub.h" #include "last-path-component.h" #include #include #include #include #include #include #ifdef HAVE_GETOPTLONG # include # define GETOPTLONG_FN(a, b, c, d, e) getopt_long((a), (b), (c), (d), (e)) # define OPTIND_INIT 0 #else struct option { }; extern int optind; extern char *optarg; # define GETOPTLONG_FN(a, b, c, d, e) getopt((a), (b), (c)) # define OPTIND_INIT 1 #endif /* * Table of valid switches */ static struct arg_props _arg_props[ARG_COUNT + 1] = { #define arg(a, b, c, d, e) {b, "", "--" c, d, e}, #include "args.h" #undef arg }; static struct cmdline_context _cmdline; /* Command line args */ unsigned arg_count(const struct cmd_context *cmd, int a) { return cmd->arg_values[a].count; } unsigned grouped_arg_count(const struct arg_values *av, int a) { return av[a].count; } unsigned arg_is_set(const struct cmd_context *cmd, int a) { return arg_count(cmd, a) ? 1 : 0; } unsigned grouped_arg_is_set(const struct arg_values *av, int a) { return grouped_arg_count(av, a) ? 1 : 0; } const char *arg_value(struct cmd_context *cmd, int a) { return cmd->arg_values[a].value; } const char *arg_str_value(struct cmd_context *cmd, int a, const char *def) { return arg_count(cmd, a) ? cmd->arg_values[a].value : def; } const char *grouped_arg_str_value(const struct arg_values *av, int a, const char *def) { return grouped_arg_count(av, a) ? av[a].value : def; } int32_t grouped_arg_int_value(const struct arg_values *av, int a, const int32_t def) { return grouped_arg_count(av, a) ? av[a].i_value : def; } int32_t first_grouped_arg_int_value(struct cmd_context *cmd, int a, const int32_t def) { struct arg_value_group_list *current_group; struct arg_values *av; dm_list_iterate_items(current_group, &cmd->arg_value_groups) { av = current_group->arg_values; if (grouped_arg_count(av, a)) return grouped_arg_int_value(av, a, def); } return def; } int32_t arg_int_value(struct cmd_context *cmd, int a, const int32_t def) { return (_cmdline.arg_props[a].flags & ARG_GROUPABLE) ? first_grouped_arg_int_value(cmd, a, def) : (arg_count(cmd, a) ? cmd->arg_values[a].i_value : def); } uint32_t arg_uint_value(struct cmd_context *cmd, int a, const uint32_t def) { return arg_count(cmd, a) ? cmd->arg_values[a].ui_value : def; } int64_t arg_int64_value(struct cmd_context *cmd, int a, const int64_t def) { return arg_count(cmd, a) ? cmd->arg_values[a].i64_value : def; } uint64_t arg_uint64_value(struct cmd_context *cmd, int a, const uint64_t def) { return arg_count(cmd, a) ? cmd->arg_values[a].ui64_value : def; } /* No longer used. const void *arg_ptr_value(struct cmd_context *cmd, int a, const void *def) { return arg_count(cmd, a) ? cmd->arg_values[a].ptr : def; } */ sign_t arg_sign_value(struct cmd_context *cmd, int a, const sign_t def) { return arg_count(cmd, a) ? cmd->arg_values[a].sign : def; } percent_type_t arg_percent_value(struct cmd_context *cmd, int a, const percent_type_t def) { return arg_count(cmd, a) ? cmd->arg_values[a].percent : def; } int arg_count_increment(struct cmd_context *cmd, int a) { return cmd->arg_values[a].count++; } int yes_no_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { av->sign = SIGN_NONE; av->percent = PERCENT_NONE; if (!strcmp(av->value, "y")) { av->i_value = 1; av->ui_value = 1; } else if (!strcmp(av->value, "n")) { av->i_value = 0; av->ui_value = 0; } else return 0; return 1; } int activation_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { av->sign = SIGN_NONE; av->percent = PERCENT_NONE; if (!strcmp(av->value, "e") || !strcmp(av->value, "ey") || !strcmp(av->value, "ye")) { av->i_value = CHANGE_AE; av->ui_value = CHANGE_AE; } else if (!strcmp(av->value, "y")) { av->i_value = CHANGE_AY; av->ui_value = CHANGE_AY; } else if (!strcmp(av->value, "a") || !strcmp(av->value, "ay") || !strcmp(av->value, "ya")) { av->i_value = CHANGE_AAY; av->ui_value = CHANGE_AAY; } else if (!strcmp(av->value, "n") || !strcmp(av->value, "en") || !strcmp(av->value, "ne")) { av->i_value = CHANGE_AN; av->ui_value = CHANGE_AN; } else if (!strcmp(av->value, "ln") || !strcmp(av->value, "nl")) { av->i_value = CHANGE_ALN; av->ui_value = CHANGE_ALN; } else if (!strcmp(av->value, "ly") || !strcmp(av->value, "yl")) { av->i_value = CHANGE_ALY; av->ui_value = CHANGE_ALY; } else return 0; return 1; } int discards_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { thin_discards_t discards; if (!get_pool_discards(av->value, &discards)) return_0; av->i_value = discards; av->ui_value = discards; return 1; } int metadatatype_arg(struct cmd_context *cmd, struct arg_values *av) { return get_format_by_name(cmd, av->value) ? 1 : 0; } static int _get_int_arg(struct arg_values *av, char **ptr) { char *val; long v; av->percent = PERCENT_NONE; val = av->value; switch (*val) { case '+': av->sign = SIGN_PLUS; val++; break; case '-': av->sign = SIGN_MINUS; val++; break; default: av->sign = SIGN_NONE; } if (!isdigit(*val)) return 0; v = strtol(val, ptr, 10); if (*ptr == val) return 0; av->i_value = (int32_t) v; av->ui_value = (uint32_t) v; av->i64_value = (int64_t) v; av->ui64_value = (uint64_t) v; return 1; } /* Size stored in sectors */ static int _size_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av, int factor) { char *ptr; int i; static const char *suffixes = "kmgtpebs"; char *val; double v; uint64_t v_tmp, adjustment; av->percent = PERCENT_NONE; val = av->value; switch (*val) { case '+': av->sign = SIGN_PLUS; val++; break; case '-': av->sign = SIGN_MINUS; val++; break; default: av->sign = SIGN_NONE; } if (!isdigit(*val)) return 0; v = strtod(val, &ptr); if (ptr == val) return 0; if (*ptr) { for (i = strlen(suffixes) - 1; i >= 0; i--) if (suffixes[i] == tolower((int) *ptr)) break; if (i < 0) { return 0; } else if (i == 7) { /* v is already in sectors */ ; } else if (i == 6) { /* bytes */ v_tmp = (uint64_t) v; adjustment = v_tmp % 512; if (adjustment) { v_tmp += (512 - adjustment); log_error("Size is not a multiple of 512. " "Try using %"PRIu64" or %"PRIu64".", v_tmp - 512, v_tmp); return 0; } v /= 512; } else { /* all other units: kmgtpe */ while (i-- > 0) v *= 1024; v *= 2; } } else v *= factor; av->i_value = (int32_t) v; av->ui_value = (uint32_t) v; av->i64_value = (int64_t) v; av->ui64_value = (uint64_t) v; return 1; } int size_kb_arg(struct cmd_context *cmd, struct arg_values *av) { return _size_arg(cmd, av, 2); } int size_mb_arg(struct cmd_context *cmd, struct arg_values *av) { return _size_arg(cmd, av, 2048); } int int_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { char *ptr; if (!_get_int_arg(av, &ptr) || (*ptr) || (av->sign == SIGN_MINUS)) return 0; return 1; } int int_arg_with_sign(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { char *ptr; if (!_get_int_arg(av, &ptr) || (*ptr)) return 0; return 1; } int int_arg_with_sign_and_percent(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { char *ptr; if (!_get_int_arg(av, &ptr)) return 0; if (!*ptr) return 1; if (*ptr++ != '%') return 0; if (!strcasecmp(ptr, "V") || !strcasecmp(ptr, "VG")) av->percent = PERCENT_VG; else if (!strcasecmp(ptr, "L") || !strcasecmp(ptr, "LV")) av->percent = PERCENT_LV; else if (!strcasecmp(ptr, "P") || !strcasecmp(ptr, "PV") || !strcasecmp(ptr, "PVS")) av->percent = PERCENT_PVS; else if (!strcasecmp(ptr, "F") || !strcasecmp(ptr, "FR") || !strcasecmp(ptr, "FREE")) av->percent = PERCENT_FREE; else if (!strcasecmp(ptr, "O") || !strcasecmp(ptr, "OR") || !strcasecmp(ptr, "ORIGIN")) av->percent = PERCENT_ORIGIN; else return 0; return 1; } int string_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av __attribute__((unused))) { return 1; } int tag_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { char *pos = av->value; if (*pos == '@') pos++; if (!validate_tag(pos)) return 0; av->value = pos; return 1; } int permission_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { av->sign = SIGN_NONE; if ((!strcmp(av->value, "rw")) || (!strcmp(av->value, "wr"))) av->ui_value = LVM_READ | LVM_WRITE; else if (!strcmp(av->value, "r")) av->ui_value = LVM_READ; else return 0; return 1; } int alloc_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { alloc_policy_t alloc; av->sign = SIGN_NONE; alloc = get_alloc_from_string(av->value); if (alloc == ALLOC_INVALID) return 0; av->ui_value = (uint32_t) alloc; return 1; } int segtype_arg(struct cmd_context *cmd, struct arg_values *av) { return get_segtype_from_string(cmd, av->value) ? 1 : 0; } /* * Positive integer, zero or "auto". */ int readahead_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { if (!strcasecmp(av->value, "auto")) { av->ui_value = DM_READ_AHEAD_AUTO; return 1; } if (!strcasecmp(av->value, "none")) { av->ui_value = DM_READ_AHEAD_NONE; return 1; } if (!_size_arg(cmd, av, 1)) return 0; if (av->sign == SIGN_MINUS) return 0; return 1; } /* * Non-zero, positive integer, "all", or "unmanaged" */ int metadatacopies_arg(struct cmd_context *cmd, struct arg_values *av) { if (!strncmp(cmd->command->name, "vg", 2)) { if (!strcasecmp(av->value, "all")) { av->ui_value = VGMETADATACOPIES_ALL; return 1; } if (!strcasecmp(av->value, "unmanaged")) { av->ui_value = VGMETADATACOPIES_UNMANAGED; return 1; } } return int_arg(cmd, av); } int major_minor_valid(const struct cmd_context *cmd, const struct format_type *fmt, int32_t major, int32_t minor) { if (!strncmp(cmd->kernel_vsn, "2.4.", 4) || (fmt->features & FMT_RESTRICTED_LVIDS)) { if (major < 0 || major > 255) { log_error("Major number outside range 0-255"); return 0; } if (minor < 0 || minor > 255) { log_error("Minor number outside range 0-255"); return 0; } } else { /* 12 bits for major number */ if (major < 0 || major > 4095) { log_error("Major number outside range 0-4095"); return 0; } /* 20 bits for minor number */ if (minor < 0 || minor > 1048575) { log_error("Minor number outside range 0-1048575"); return 0; } } return 1; } static void __alloc(int size) { if (!(_cmdline.commands = dm_realloc(_cmdline.commands, sizeof(*_cmdline.commands) * size))) { log_fatal("Couldn't allocate memory."); exit(ECMD_FAILED); } _cmdline.commands_size = size; } static void _alloc_command(void) { if (!_cmdline.commands_size) __alloc(32); if (_cmdline.commands_size <= _cmdline.num_commands) __alloc(2 * _cmdline.commands_size); } static void _create_new_command(const char *name, command_fn command, unsigned flags, const char *desc, const char *usagestr, int nargs, int *args) { struct command *nc; _alloc_command(); nc = _cmdline.commands + _cmdline.num_commands++; nc->name = name; nc->desc = desc; nc->usage = usagestr; nc->fn = command; nc->flags = flags; nc->num_args = nargs; nc->valid_args = args; } static void _register_command(const char *name, command_fn fn, const char *desc, unsigned flags, const char *usagestr, ...) { int nargs = 0, i; int *args; va_list ap; /* count how many arguments we have */ va_start(ap, usagestr); while (va_arg(ap, int) >= 0) nargs++; va_end(ap); /* allocate space for them */ if (!(args = dm_malloc(sizeof(*args) * nargs))) { log_fatal("Out of memory."); exit(ECMD_FAILED); } /* fill them in */ va_start(ap, usagestr); for (i = 0; i < nargs; i++) args[i] = va_arg(ap, int); va_end(ap); /* enter the command in the register */ _create_new_command(name, fn, flags, desc, usagestr, nargs, args); } void lvm_register_commands(void) { #define xx(a, b, c, d...) _register_command(# a, a, b, c, ## d, \ driverloaded_ARG, \ debug_ARG, help_ARG, help2_ARG, \ version_ARG, verbose_ARG, \ quiet_ARG, config_ARG, -1); #include "commands.h" #undef xx } static struct command *_find_command(const char *name) { int i; const char *base; base = last_path_component(name); for (i = 0; i < _cmdline.num_commands; i++) { if (!strcmp(base, _cmdline.commands[i].name)) break; } if (i >= _cmdline.num_commands) return 0; return _cmdline.commands + i; } static void _short_usage(const char *name) { log_error("Run `%s --help' for more information.", name); } static int _usage(const char *name) { struct command *com = _find_command(name); if (!com) { log_print("%s: no such command.", name); return 0; } log_print("%s: %s\n\n%s", com->name, com->desc, com->usage); return 1; } /* * Sets up the short and long argument. If there * is no short argument then the index of the * argument in the the_args array is set as the * long opt value. Yuck. Of course this means we * can't have more than 'a' long arguments. */ static void _add_getopt_arg(int arg, char **ptr, struct option **o) { struct arg_props *a = _cmdline.arg_props + arg; if (a->short_arg) { *(*ptr)++ = a->short_arg; if (a->fn) *(*ptr)++ = ':'; } #ifdef HAVE_GETOPTLONG if (*(a->long_arg + 2)) { (*o)->name = a->long_arg + 2; (*o)->has_arg = a->fn ? 1 : 0; (*o)->flag = NULL; if (a->short_arg) (*o)->val = a->short_arg; else (*o)->val = arg + 128; (*o)++; } #endif } static int _find_arg(struct command *com, int opt) { struct arg_props *a; int i, arg; for (i = 0; i < com->num_args; i++) { arg = com->valid_args[i]; a = _cmdline.arg_props + arg; /* * opt should equal either the * short arg, or the index into * the_args. */ if ((a->short_arg && (opt == a->short_arg)) || (!a->short_arg && (opt == (arg + 128)))) return arg; } return -1; } static int _process_command_line(struct cmd_context *cmd, int *argc, char ***argv) { int i, opt, arg; char str[((ARG_COUNT + 1) * 2) + 1], *ptr = str; struct option opts[ARG_COUNT + 1], *o = opts; struct arg_props *a; struct arg_values *av; struct arg_value_group_list *current_group = NULL; if (!(cmd->arg_values = dm_pool_zalloc(cmd->mem, sizeof(*cmd->arg_values) * ARG_COUNT))) { log_fatal("Unable to allocate memory for command line arguments."); return 0; } /* fill in the short and long opts */ for (i = 0; i < cmd->command->num_args; i++) _add_getopt_arg(cmd->command->valid_args[i], &ptr, &o); *ptr = '\0'; memset(o, 0, sizeof(*o)); /* initialise getopt_long & scan for command line switches */ optarg = 0; optind = OPTIND_INIT; while ((opt = GETOPTLONG_FN(*argc, *argv, str, opts, NULL)) >= 0) { if (opt == '?') return 0; if ((arg = _find_arg(cmd->command, opt)) < 0) { log_fatal("Unrecognised option."); return 0; } a = _cmdline.arg_props + arg; av = &cmd->arg_values[arg]; if (a->flags & ARG_GROUPABLE) { /* Start a new group of arguments the first time or if a non-countable argument is repeated. */ if (!current_group || (current_group->arg_values[arg].count && !(a->flags & ARG_COUNTABLE))) { /* FIXME Reduce size including only groupable args */ if (!(current_group = dm_pool_zalloc(cmd->mem, sizeof(struct arg_value_group_list) + sizeof(*cmd->arg_values) * ARG_COUNT))) { log_fatal("Unable to allocate memory for command line arguments."); return 0; } dm_list_add(&cmd->arg_value_groups, ¤t_group->list); } /* Maintain total argument count as well as count within each group */ av->count++; av = ¤t_group->arg_values[arg]; } if (av->count && !(a->flags & ARG_COUNTABLE)) { log_error("Option%s%c%s%s may not be repeated.", a->short_arg ? " -" : "", a->short_arg ? : ' ', (a->short_arg && a->long_arg) ? "/" : "", a->long_arg ? : ""); return 0; } if (a->fn) { if (!optarg) { log_error("Option requires argument."); return 0; } av->value = optarg; if (!a->fn(cmd, av)) { log_error("Invalid argument for %s: %s", a->long_arg, optarg); return 0; } } av->count++; } *argc -= optind; *argv += optind; return 1; } static int _merge_synonym(struct cmd_context *cmd, int oldarg, int newarg) { const struct arg_values *old; struct arg_values *new; if (arg_count(cmd, oldarg) && arg_count(cmd, newarg)) { log_error("%s and %s are synonyms. Please only supply one.", _cmdline.arg_props[oldarg].long_arg, _cmdline.arg_props[newarg].long_arg); return 0; } if (!arg_count(cmd, oldarg)) return 1; old = cmd->arg_values + oldarg; new = cmd->arg_values + newarg; new->count = old->count; new->value = old->value; new->i_value = old->i_value; new->ui_value = old->ui_value; new->i64_value = old->i64_value; new->ui64_value = old->ui64_value; new->sign = old->sign; return 1; } int version(struct cmd_context *cmd __attribute__((unused)), int argc __attribute__((unused)), char **argv __attribute__((unused))) { char vsn[80]; log_print("LVM version: %s", LVM_VERSION); if (library_version(vsn, sizeof(vsn))) log_print("Library version: %s", vsn); if (driver_version(vsn, sizeof(vsn))) log_print("Driver version: %s", vsn); return ECMD_PROCESSED; } static int _get_settings(struct cmd_context *cmd) { cmd->current_settings = cmd->default_settings; if (arg_count(cmd, debug_ARG)) cmd->current_settings.debug = _LOG_FATAL + (arg_count(cmd, debug_ARG) - 1); if (arg_count(cmd, verbose_ARG)) cmd->current_settings.verbose = arg_count(cmd, verbose_ARG); if (arg_count(cmd, quiet_ARG)) { cmd->current_settings.debug = 0; cmd->current_settings.verbose = 0; } if (arg_count(cmd, quiet_ARG) > 1) cmd->current_settings.silent = 1; if (arg_count(cmd, test_ARG)) cmd->current_settings.test = arg_count(cmd, test_ARG); if (arg_count(cmd, driverloaded_ARG)) { cmd->current_settings.activation = arg_int_value(cmd, driverloaded_ARG, cmd->default_settings.activation); } cmd->current_settings.archive = arg_int_value(cmd, autobackup_ARG, cmd->current_settings.archive); cmd->current_settings.backup = arg_int_value(cmd, autobackup_ARG, cmd->current_settings.backup); cmd->current_settings.cache_vgmetadata = cmd->command->flags & CACHE_VGMETADATA ? 1 : 0; cmd->partial_activation = 0; if (arg_count(cmd, partial_ARG)) { cmd->partial_activation = 1; log_warn("PARTIAL MODE. Incomplete logical volumes will be processed."); } if (arg_count(cmd, ignorelockingfailure_ARG) || arg_count(cmd, sysinit_ARG)) init_ignorelockingfailure(1); else init_ignorelockingfailure(0); if (!arg_count(cmd, sysinit_ARG)) lvmetad_warning(); if (arg_count(cmd, nosuffix_ARG)) cmd->current_settings.suffix = 0; if (arg_count(cmd, units_ARG)) if (!(cmd->current_settings.unit_factor = units_to_bytes(arg_str_value(cmd, units_ARG, ""), &cmd->current_settings.unit_type))) { log_error("Invalid units specification"); return EINVALID_CMD_LINE; } if (arg_count(cmd, trustcache_ARG)) { if (arg_count(cmd, all_ARG)) { log_error("--trustcache is incompatible with --all"); return EINVALID_CMD_LINE; } init_trust_cache(1); log_warn("WARNING: Cache file of PVs will be trusted. " "New devices holding PVs may get ignored."); } else init_trust_cache(0); if (arg_count(cmd, noudevsync_ARG)) { cmd->current_settings.udev_sync = 0; cmd->current_settings.udev_fallback = 1; } /* Handle synonyms */ if (!_merge_synonym(cmd, resizable_ARG, resizeable_ARG) || !_merge_synonym(cmd, allocation_ARG, allocatable_ARG) || !_merge_synonym(cmd, allocation_ARG, resizeable_ARG) || !_merge_synonym(cmd, virtualoriginsize_ARG, virtualsize_ARG) || !_merge_synonym(cmd, available_ARG, activate_ARG)) return EINVALID_CMD_LINE; if ((!strncmp(cmd->command->name, "pv", 2) && !_merge_synonym(cmd, metadatacopies_ARG, pvmetadatacopies_ARG)) || (!strncmp(cmd->command->name, "vg", 2) && !_merge_synonym(cmd, metadatacopies_ARG, vgmetadatacopies_ARG))) return EINVALID_CMD_LINE; /* Zero indicates success */ return 0; } static int _process_common_commands(struct cmd_context *cmd) { if (arg_count(cmd, help_ARG) || arg_count(cmd, help2_ARG)) { _usage(cmd->command->name); return ECMD_PROCESSED; } if (arg_count(cmd, version_ARG)) { return version(cmd, 0, (char **) NULL); } /* Zero indicates it's OK to continue processing this command */ return 0; } static void _display_help(void) { int i; log_error("Available lvm commands:"); log_error("Use 'lvm help ' for more information"); log_error(" "); for (i = 0; i < _cmdline.num_commands; i++) { struct command *com = _cmdline.commands + i; log_error("%-16.16s%s", com->name, com->desc); } } int help(struct cmd_context *cmd __attribute__((unused)), int argc, char **argv) { int ret = ECMD_PROCESSED; if (!argc) _display_help(); else { int i; for (i = 0; i < argc; i++) if (!_usage(argv[i])) ret = EINVALID_CMD_LINE; } return ret; } static void _apply_settings(struct cmd_context *cmd) { init_debug(cmd->current_settings.debug); init_verbose(cmd->current_settings.verbose + VERBOSE_BASE_LEVEL); init_silent(cmd->current_settings.silent); init_test(cmd->current_settings.test); init_full_scan_done(0); init_mirror_in_sync(0); init_dmeventd_monitor(DEFAULT_DMEVENTD_MONITOR); init_msg_prefix(cmd->default_settings.msg_prefix); init_cmd_name(cmd->default_settings.cmd_name); archive_enable(cmd, cmd->current_settings.archive); backup_enable(cmd, cmd->current_settings.backup); set_activation(cmd->current_settings.activation); cmd->fmt = get_format_by_name(cmd, arg_str_value(cmd, metadatatype_ARG, cmd->current_settings.fmt_name)); cmd->handles_missing_pvs = 0; } static const char *_copy_command_line(struct cmd_context *cmd, int argc, char **argv) { int i, space; /* * Build up the complete command line, used as a * description for backups. */ if (!dm_pool_begin_object(cmd->mem, 128)) goto_bad; for (i = 0; i < argc; i++) { space = strchr(argv[i], ' ') ? 1 : 0; if (space && !dm_pool_grow_object(cmd->mem, "'", 1)) goto_bad; if (!dm_pool_grow_object(cmd->mem, argv[i], strlen(argv[i]))) goto_bad; if (space && !dm_pool_grow_object(cmd->mem, "'", 1)) goto_bad; if (i < (argc - 1)) if (!dm_pool_grow_object(cmd->mem, " ", 1)) goto_bad; } /* * Terminate. */ if (!dm_pool_grow_object(cmd->mem, "\0", 1)) goto_bad; return dm_pool_end_object(cmd->mem); bad: log_error("Couldn't copy command line."); dm_pool_abandon_object(cmd->mem); return NULL; } int lvm_run_command(struct cmd_context *cmd, int argc, char **argv) { int ret = 0; int locking_type; int monitoring; struct dm_config_tree *old_cft; init_error_message_produced(0); /* each command should start out with sigint flag cleared */ sigint_clear(); if (!(cmd->cmd_line = _copy_command_line(cmd, argc, argv))) { stack; return ECMD_FAILED; } log_debug("Parsing: %s", cmd->cmd_line); if (!(cmd->command = _find_command(argv[0]))) return ENO_SUCH_CMD; if (!_process_command_line(cmd, &argc, &argv)) { log_error("Error during parsing of command line."); return EINVALID_CMD_LINE; } set_cmd_name(cmd->command->name); if (arg_count(cmd, config_ARG)) if (override_config_tree_from_string(cmd, arg_str_value(cmd, config_ARG, ""))) { ret = EINVALID_CMD_LINE; goto_out; } if (arg_count(cmd, config_ARG) || !cmd->config_valid || config_files_changed(cmd)) { /* Reinitialise various settings inc. logging, filters */ if (!refresh_toolcontext(cmd)) { old_cft = remove_overridden_config_tree(cmd); if (old_cft) dm_config_destroy(old_cft); log_error("Updated config file invalid. Aborting."); return ECMD_FAILED; } } if ((ret = _get_settings(cmd))) goto_out; _apply_settings(cmd); if (!get_activation_monitoring_mode(cmd, &monitoring)) goto_out; init_dmeventd_monitor(monitoring); log_debug("Processing: %s", cmd->cmd_line); #ifdef O_DIRECT_SUPPORT log_debug("O_DIRECT will be used"); #endif if ((ret = _process_common_commands(cmd))) { if (ret != ECMD_PROCESSED) stack; goto out; } if (cmd->metadata_read_only && !(cmd->command->flags & PERMITTED_READ_ONLY)) { log_error("%s: Command not permitted while global/metadata_read_only " "is set.", cmd->cmd_line); goto out; } if (arg_count(cmd, nolocking_ARG)) locking_type = 0; else locking_type = -1; if (!init_locking(locking_type, cmd, arg_count(cmd, sysinit_ARG))) { ret = ECMD_FAILED; goto out; } ret = cmd->command->fn(cmd, argc, argv); fin_locking(); out: if (test_mode()) { log_verbose("Test mode: Wiping internal cache"); lvmcache_destroy(cmd, 1); } if ((old_cft = remove_overridden_config_tree(cmd))) { dm_config_destroy(old_cft); /* Move this? */ if (!refresh_toolcontext(cmd)) stack; } /* FIXME Move this? */ cmd->current_settings = cmd->default_settings; _apply_settings(cmd); if (ret == EINVALID_CMD_LINE && !_cmdline.interactive) _short_usage(cmd->command->name); log_debug("Completed: %s", cmd->cmd_line); /* * free off any memory the command used. */ dm_list_init(&cmd->arg_value_groups); dm_pool_empty(cmd->mem); reset_lvm_errno(1); reset_log_duplicated(); return ret; } int lvm_return_code(int ret) { return (ret == ECMD_PROCESSED ? 0 : ret); } int lvm_split(char *str, int *argc, char **argv, int max) { char *b = str, *e; *argc = 0; while (*b) { while (*b && isspace(*b)) b++; if ((!*b) || (*b == '#')) break; e = b; while (*e && !isspace(*e)) e++; argv[(*argc)++] = b; if (!*e) break; *e++ = '\0'; b = e; if (*argc == max) break; } return *argc; } /* Make sure we have always valid filedescriptors 0,1,2 */ static int _check_standard_fds(void) { int err = is_valid_fd(STDERR_FILENO); if (!is_valid_fd(STDIN_FILENO) && !(stdin = fopen(_PATH_DEVNULL, "r"))) { if (err) perror("stdin stream open"); else printf("stdin stream open: %s\n", strerror(errno)); return 0; } if (!is_valid_fd(STDOUT_FILENO) && !(stdout = fopen(_PATH_DEVNULL, "w"))) { if (err) perror("stdout stream open"); /* else no stdout */ return 0; } if (!is_valid_fd(STDERR_FILENO) && !(stderr = fopen(_PATH_DEVNULL, "w"))) { printf("stderr stream open: %s\n", strerror(errno)); return 0; } return 1; } static const char *_get_cmdline(pid_t pid) { static char _proc_cmdline[32]; char buf[256]; int fd, n = 0; snprintf(buf, sizeof(buf), DEFAULT_PROC_DIR "/%u/cmdline", pid); /* FIXME Use generic read code. */ if ((fd = open(buf, O_RDONLY)) >= 0) { if ((n = read(fd, _proc_cmdline, sizeof(_proc_cmdline) - 1)) < 0) { log_sys_error("read", buf); n = 0; } if (close(fd)) log_sys_error("close", buf); } _proc_cmdline[n] = '\0'; return _proc_cmdline; } static const char *_get_filename(int fd) { static char filename[PATH_MAX]; char buf[32]; /* Assumes short DEFAULT_PROC_DIR */ int size; snprintf(buf, sizeof(buf), DEFAULT_PROC_DIR "/self/fd/%u", fd); if ((size = readlink(buf, filename, sizeof(filename) - 1)) == -1) filename[0] = '\0'; else filename[size] = '\0'; return filename; } static void _close_descriptor(int fd, unsigned suppress_warnings, const char *command, pid_t ppid, const char *parent_cmdline) { int r; const char *filename; /* Ignore bad file descriptors */ if (!is_valid_fd(fd)) return; if (!suppress_warnings) filename = _get_filename(fd); r = close(fd); if (suppress_warnings) return; if (!r) fprintf(stderr, "File descriptor %d (%s) leaked on " "%s invocation.", fd, filename, command); else if (errno == EBADF) return; else fprintf(stderr, "Close failed on stray file descriptor " "%d (%s): %s", fd, filename, strerror(errno)); fprintf(stderr, " Parent PID %" PRIpid_t ": %s\n", ppid, parent_cmdline); } static int _close_stray_fds(const char *command) { #ifndef VALGRIND_POOL struct rlimit rlim; int fd; unsigned suppress_warnings = 0; pid_t ppid = getppid(); const char *parent_cmdline = _get_cmdline(ppid); static const char _fd_dir[] = DEFAULT_PROC_DIR "/self/fd"; struct dirent *dirent; DIR *d; if (getenv("LVM_SUPPRESS_FD_WARNINGS")) suppress_warnings = 1; if (!(d = opendir(_fd_dir))) { if (errno != ENOENT) { log_sys_error("opendir", _fd_dir); return 0; /* broken system */ } /* Path does not exist, use the old way */ if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) { log_sys_error("getrlimit", "RLIMIT_NOFILE"); return 1; } for (fd = 3; fd < (int)rlim.rlim_cur; fd++) _close_descriptor(fd, suppress_warnings, command, ppid, parent_cmdline); return 1; } while ((dirent = readdir(d))) { fd = atoi(dirent->d_name); if (fd > 2 && fd != dirfd(d)) _close_descriptor(fd, suppress_warnings, command, ppid, parent_cmdline); } if (closedir(d)) log_sys_error("closedir", _fd_dir); #endif return 1; } struct cmd_context *init_lvm(void) { struct cmd_context *cmd; if (!udev_init_library_context()) stack; if (!(cmd = create_toolcontext(0, NULL, 1, 0))) { udev_fin_library_context(); return_NULL; } _cmdline.arg_props = &_arg_props[0]; if (stored_errno()) { destroy_toolcontext(cmd); udev_fin_library_context(); return_NULL; } return cmd; } static void _fin_commands(void) { int i; for (i = 0; i < _cmdline.num_commands; i++) dm_free(_cmdline.commands[i].valid_args); dm_free(_cmdline.commands); _cmdline.commands = NULL; _cmdline.num_commands = 0; _cmdline.commands_size = 0; } void lvm_fin(struct cmd_context *cmd) { _fin_commands(); destroy_toolcontext(cmd); udev_fin_library_context(); } static int _run_script(struct cmd_context *cmd, int argc, char **argv) { FILE *script; char buffer[CMD_LEN]; int ret = 0; int magic_number = 0; char *script_file = argv[0]; if ((script = fopen(script_file, "r")) == NULL) return ENO_SUCH_CMD; while (fgets(buffer, sizeof(buffer), script) != NULL) { if (!magic_number) { if (buffer[0] == '#' && buffer[1] == '!') magic_number = 1; else { ret = ENO_SUCH_CMD; break; } } if ((strlen(buffer) == sizeof(buffer) - 1) && (buffer[sizeof(buffer) - 1] - 2 != '\n')) { buffer[50] = '\0'; log_error("Line too long (max 255) beginning: %s", buffer); ret = EINVALID_CMD_LINE; break; } if (lvm_split(buffer, &argc, argv, MAX_ARGS) == MAX_ARGS) { buffer[50] = '\0'; log_error("Too many arguments: %s", buffer); ret = EINVALID_CMD_LINE; break; } if (!argc) continue; if (!strcmp(argv[0], "quit") || !strcmp(argv[0], "exit")) break; ret = lvm_run_command(cmd, argc, argv); if (ret != ECMD_PROCESSED) { if (!error_message_produced()) { log_debug(INTERNAL_ERROR "Failed command did not use log_error"); log_error("Command failed with status code %d.", ret); } break; } } if (fclose(script)) log_sys_error("fclose", script_file); return ret; } /* * Determine whether we should fall back and exec the equivalent LVM1 tool */ static int _lvm1_fallback(struct cmd_context *cmd) { char vsn[80]; int dm_present; if (!find_config_tree_int(cmd, "global/fallback_to_lvm1", DEFAULT_FALLBACK_TO_LVM1) || strncmp(cmd->kernel_vsn, "2.4.", 4)) return 0; log_suppress(1); dm_present = driver_version(vsn, sizeof(vsn)); log_suppress(0); if (dm_present || !lvm1_present(cmd)) return 0; return 1; } static void _exec_lvm1_command(char **argv) { char path[PATH_MAX]; if (dm_snprintf(path, sizeof(path), "%s.lvm1", argv[0]) < 0) { log_error("Failed to create LVM1 tool pathname"); return; } execvp(path, argv); log_sys_error("execvp", path); } static void _nonroot_warning(void) { if (getuid() || geteuid()) log_warn("WARNING: Running as a non-root user. Functionality may be unavailable."); } int lvm2_main(int argc, char **argv) { const char *base; int ret, alias = 0; struct cmd_context *cmd; base = last_path_component(argv[0]); if (strcmp(base, "lvm") && strcmp(base, "lvm.static") && strcmp(base, "initrd-lvm")) alias = 1; if (!_check_standard_fds()) return -1; if (!_close_stray_fds(base)) return -1; if (is_static() && strcmp(base, "lvm.static") && path_exists(LVM_SHARED_PATH) && !getenv("LVM_DID_EXEC")) { if (setenv("LVM_DID_EXEC", base, 1)) log_sys_error("setenv", "LVM_DID_EXEC"); if (execvp(LVM_SHARED_PATH, argv) == -1) log_sys_error("execvp", "LVM_SHARED_PATH"); if (unsetenv("LVM_DID_EXEC")) log_sys_error("unsetenv", "LVM_DID_EXEC"); } /* "version" command is simple enough so it doesn't need any complex init */ if (!alias && argc > 1 && !strcmp(argv[1], "version")) return lvm_return_code(version(NULL, argc, argv)); if (!(cmd = init_lvm())) return -1; cmd->argv = argv; lvm_register_commands(); if (_lvm1_fallback(cmd)) { /* Attempt to run equivalent LVM1 tool instead */ if (!alias) { argv++; argc--; } if (!argc) { log_error("Falling back to LVM1 tools, but no " "command specified."); ret = ECMD_FAILED; goto out; } _exec_lvm1_command(argv); ret = ECMD_FAILED; goto out; } #ifdef READLINE_SUPPORT if (!alias && argc == 1) { _nonroot_warning(); ret = lvm_shell(cmd, &_cmdline); goto out; } #endif if (!alias) { if (argc < 2) { log_fatal("Please supply an LVM command."); _display_help(); ret = EINVALID_CMD_LINE; goto out; } argc--; argv++; } _nonroot_warning(); ret = lvm_run_command(cmd, argc, argv); if ((ret == ENO_SUCH_CMD) && (!alias)) ret = _run_script(cmd, argc, argv); if (ret == ENO_SUCH_CMD) log_error("No such command. Try 'help'."); if ((ret != ECMD_PROCESSED) && !error_message_produced()) { log_debug(INTERNAL_ERROR "Failed command did not use log_error"); log_error("Command failed with status code %d.", ret); } out: lvm_fin(cmd); return lvm_return_code(ret); } lvm2-2.02.98/tools/pvcreate.c0000640000175000017500000000706512037016273014636 0ustar blankblank/* * 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 */ #include "tools.h" #include "metadata-exported.h" /* * Intial sanity checking of recovery-related command-line arguments. * These args are: --restorefile, --uuid, and --physicalvolumesize * * Output arguments: * pp: structure allocated by caller, fields written / validated here */ static int pvcreate_restore_params_validate(struct cmd_context *cmd, int argc, char **argv, struct pvcreate_params *pp) { const char *uuid = NULL; struct volume_group *vg; struct pv_list *existing_pvl; if (arg_count(cmd, restorefile_ARG) && !arg_count(cmd, uuidstr_ARG)) { log_error("--uuid is required with --restorefile"); return 0; } if (!arg_count(cmd, restorefile_ARG) && arg_count(cmd, uuidstr_ARG)) { if (!arg_count(cmd, norestorefile_ARG) && find_config_tree_bool(cmd, "devices/require_restorefile_with_uuid", DEFAULT_REQUIRE_RESTOREFILE_WITH_UUID)) { log_error("--restorefile is required with --uuid"); return 0; } } if (arg_count(cmd, uuidstr_ARG) && argc != 1) { log_error("Can only set uuid on one volume at once"); return 0; } if (arg_count(cmd, uuidstr_ARG)) { uuid = arg_str_value(cmd, uuidstr_ARG, ""); if (!id_read_format(&pp->id, uuid)) return 0; pp->idp = &pp->id; lvmcache_seed_infos_from_lvmetad(cmd); /* need to check for UUID dups */ } if (arg_count(cmd, restorefile_ARG)) { pp->restorefile = arg_str_value(cmd, restorefile_ARG, ""); /* The uuid won't already exist */ if (!(vg = backup_read_vg(cmd, NULL, pp->restorefile))) { log_error("Unable to read volume group from %s", pp->restorefile); return 0; } if (!(existing_pvl = find_pv_in_vg_by_uuid(vg, pp->idp))) { log_error("Can't find uuid %s in backup file %s", uuid, pp->restorefile); return 0; } pp->pe_start = pv_pe_start(existing_pvl->pv); pp->extent_size = pv_pe_size(existing_pvl->pv); pp->extent_count = pv_pe_count(existing_pvl->pv); release_vg(vg); } if (arg_sign_value(cmd, physicalvolumesize_ARG, SIGN_NONE) == SIGN_MINUS) { log_error("Physical volume size may not be negative"); return 0; } pp->size = arg_uint64_value(cmd, physicalvolumesize_ARG, UINT64_C(0)); if (arg_count(cmd, restorefile_ARG) || arg_count(cmd, uuidstr_ARG)) pp->zero = 0; return 1; } int pvcreate(struct cmd_context *cmd, int argc, char **argv) { int i; int ret = ECMD_PROCESSED; struct pvcreate_params pp; struct physical_volume *pv; pvcreate_params_set_defaults(&pp); if (!pvcreate_restore_params_validate(cmd, argc, argv, &pp)) { return EINVALID_CMD_LINE; } if (!pvcreate_params_validate(cmd, argc, argv, &pp)) { return EINVALID_CMD_LINE; } for (i = 0; i < argc; i++) { if (!lock_vol(cmd, VG_ORPHANS, LCK_VG_WRITE)) { log_error("Can't get lock for orphan PVs"); return ECMD_FAILED; } dm_unescape_colons_and_at_signs(argv[i], NULL, NULL); if (!(pv = pvcreate_single(cmd, argv[i], &pp, 1))) { stack; ret = ECMD_FAILED; } unlock_vg(cmd, VG_ORPHANS); if (sigint_caught()) return ret; } return ret; } lvm2-2.02.98/tools/vgchange.c0000640000175000017500000003767612037016273014622 0ustar blankblank/* * 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 "tools.h" /* * Increments *count by the number of _new_ monitored devices. */ static int _monitor_lvs_in_vg(struct cmd_context *cmd, struct volume_group *vg, int reg, int *count) { struct lv_list *lvl; struct logical_volume *lv; struct lvinfo info; int r = 1; dm_list_iterate_items(lvl, &vg->lvs) { lv = lvl->lv; if (!lv_info(cmd, lv, lv_is_thin_pool(lv) ? 1 : 0, &info, 0, 0) || !info.exists) continue; /* * FIXME: Need to consider all cases... PVMOVE, etc */ if (lv->status & PVMOVE) continue; if (!monitor_dev_for_events(cmd, lv, 0, reg)) { r = 0; continue; } else (*count)++; } return r; } static int _poll_lvs_in_vg(struct cmd_context *cmd, struct volume_group *vg) { struct lv_list *lvl; struct logical_volume *lv; struct lvinfo info; int lv_active; int count = 0; dm_list_iterate_items(lvl, &vg->lvs) { lv = lvl->lv; if (!lv_info(cmd, lv, 0, &info, 0, 0)) lv_active = 0; else lv_active = info.exists; if (lv_active && (lv->status & (PVMOVE|CONVERTING|MERGING))) { lv_spawn_background_polling(cmd, lv); count++; } } /* * returns the number of polled devices * - there is no way to know if lv is already being polled */ return count; } static int _activate_lvs_in_vg(struct cmd_context *cmd, struct volume_group *vg, activation_change_t activate) { struct lv_list *lvl; struct logical_volume *lv; int count = 0, expected_count = 0; sigint_allow(); dm_list_iterate_items(lvl, &vg->lvs) { if (sigint_caught()) return_0; lv = lvl->lv; if (!lv_is_visible(lv)) continue; /* If LV is sparse, activate origin instead */ if (lv_is_cow(lv) && lv_is_virtual_origin(origin_from_cow(lv))) lv = origin_from_cow(lv); /* Only request activation of snapshot origin devices */ if ((lv->status & SNAPSHOT) || lv_is_cow(lv)) continue; /* Only request activation of mirror LV */ if ((lv->status & MIRROR_IMAGE) || (lv->status & MIRROR_LOG)) continue; /* Only request activation of the first replicator-dev LV */ /* Avoids retry with all heads in case of failure */ if (lv_is_replicator_dev(lv) && (lv != first_replicator_dev(lv))) continue; /* Can't deactivate a pvmove LV */ /* FIXME There needs to be a controlled way of doing this */ if (((activate == CHANGE_AN) || (activate == CHANGE_ALN)) && ((lv->status & PVMOVE) )) continue; /* * If the LV is active exclusive remotely, * then ignore it here */ if (lv_is_active_exclusive_remotely(lv)) { log_verbose("%s/%s is exclusively active on" " a remote node", vg->name, lv->name); continue; } if (activate == CHANGE_AAY && !lv_passes_auto_activation_filter(cmd, lv)) continue; expected_count++; if (activate == CHANGE_AN) { if (!deactivate_lv(cmd, lv)) { stack; continue; } } else if (activate == CHANGE_ALN) { if (!deactivate_lv_local(cmd, lv)) { stack; continue; } } else if ((activate == CHANGE_AE) || lv_is_origin(lv) || lv_is_thin_type(lv)) { /* FIXME: duplicated test code with lvchange */ if (!activate_lv_excl(cmd, lv)) { stack; continue; } } else if (activate == CHANGE_AAY || activate == CHANGE_ALY) { if (!activate_lv_local(cmd, lv)) { stack; continue; } } else if (!activate_lv(cmd, lv)) { stack; continue; } if (background_polling() && activate != CHANGE_AN && activate != CHANGE_ALN && (lv->status & (PVMOVE|CONVERTING|MERGING))) lv_spawn_background_polling(cmd, lv); count++; } sigint_restore(); if (expected_count) log_verbose("%s %d logical volumes in volume group %s", (activate == CHANGE_AN || activate == CHANGE_ALN)? "Deactivated" : "Activated", count, vg->name); return (expected_count != count) ? 0 : 1; } static int _vgchange_monitoring(struct cmd_context *cmd, struct volume_group *vg) { int r = 1; int monitored = 0; if (lvs_in_vg_activated(vg) && dmeventd_monitor_mode() != DMEVENTD_MONITOR_IGNORE) { if (!_monitor_lvs_in_vg(cmd, vg, dmeventd_monitor_mode(), &monitored)) r = 0; log_print_unless_silent("%d logical volume(s) in volume group " "\"%s\" %smonitored", monitored, vg->name, (dmeventd_monitor_mode()) ? "" : "un"); } return r; } static int _vgchange_background_polling(struct cmd_context *cmd, struct volume_group *vg) { int polled; if (lvs_in_vg_activated(vg) && background_polling()) { polled = _poll_lvs_in_vg(cmd, vg); if (polled) log_print_unless_silent("Background polling started for %d logical volume(s) " "in volume group \"%s\"", polled, vg->name); } return 1; } int vgchange_activate(struct cmd_context *cmd, struct volume_group *vg, activation_change_t activate) { int lv_open, active, monitored = 0, r = 1, do_activate = 1; if ((activate == CHANGE_AN) || (activate == CHANGE_ALN)) do_activate = 0; /* * Safe, since we never write out new metadata here. Required for * partial activation to work. */ cmd->handles_missing_pvs = 1; /* FIXME: Force argument to deactivate them? */ if (!do_activate && (lv_open = lvs_in_vg_opened(vg))) { log_error("Can't deactivate volume group \"%s\" with %d open " "logical volume(s)", vg->name, lv_open); return 0; } /* FIXME Move into library where clvmd can use it */ if (do_activate) check_current_backup(vg); if (do_activate && (active = lvs_in_vg_activated(vg))) { log_verbose("%d logical volume(s) in volume group \"%s\" " "already active", active, vg->name); if (dmeventd_monitor_mode() != DMEVENTD_MONITOR_IGNORE) { if (!_monitor_lvs_in_vg(cmd, vg, dmeventd_monitor_mode(), &monitored)) r = 0; log_verbose("%d existing logical volume(s) in volume " "group \"%s\" %smonitored", monitored, vg->name, dmeventd_monitor_mode() ? "" : "un"); } } if (!_activate_lvs_in_vg(cmd, vg, activate)) r = 0; /* Print message only if there was not found a missing VG */ if (!vg->cmd_missing_vgs) log_print_unless_silent("%d logical volume(s) in volume group \"%s\" now active", lvs_in_vg_activated(vg), vg->name); return r; } static int _vgchange_refresh(struct cmd_context *cmd, struct volume_group *vg) { log_verbose("Refreshing volume group \"%s\"", vg->name); if (!vg_refresh_visible(cmd, vg)) { stack; return 0; } return 1; } static int _vgchange_alloc(struct cmd_context *cmd, struct volume_group *vg) { alloc_policy_t alloc; alloc = (alloc_policy_t) arg_uint_value(cmd, alloc_ARG, ALLOC_NORMAL); /* FIXME: make consistent with vg_set_alloc_policy() */ if (alloc == vg->alloc) { log_error("Volume group allocation policy is already %s", get_alloc_string(vg->alloc)); return 0; } if (!vg_set_alloc_policy(vg, alloc)) return_0; return 1; } static int _vgchange_resizeable(struct cmd_context *cmd, struct volume_group *vg) { int resizeable = !strcmp(arg_str_value(cmd, resizeable_ARG, "n"), "y"); if (resizeable && vg_is_resizeable(vg)) { log_error("Volume group \"%s\" is already resizeable", vg->name); return 0; } if (!resizeable && !vg_is_resizeable(vg)) { log_error("Volume group \"%s\" is already not resizeable", vg->name); return 0; } if (resizeable) vg->status |= RESIZEABLE_VG; else vg->status &= ~RESIZEABLE_VG; return 1; } static int _vgchange_clustered(struct cmd_context *cmd, struct volume_group *vg) { int clustered = !strcmp(arg_str_value(cmd, clustered_ARG, "n"), "y"); if (clustered && (vg_is_clustered(vg))) { log_error("Volume group \"%s\" is already clustered", vg->name); return 0; } if (!clustered && !(vg_is_clustered(vg))) { log_error("Volume group \"%s\" is already not clustered", vg->name); return 0; } if (!vg_set_clustered(vg, clustered)) return_0; return 1; } static int _vgchange_logicalvolume(struct cmd_context *cmd, struct volume_group *vg) { uint32_t max_lv = arg_uint_value(cmd, logicalvolume_ARG, 0); if (!vg_set_max_lv(vg, max_lv)) return_0; return 1; } static int _vgchange_physicalvolumes(struct cmd_context *cmd, struct volume_group *vg) { uint32_t max_pv = arg_uint_value(cmd, maxphysicalvolumes_ARG, 0); if (!vg_set_max_pv(vg, max_pv)) return_0; return 1; } static int _vgchange_pesize(struct cmd_context *cmd, struct volume_group *vg) { uint32_t extent_size; if (arg_uint64_value(cmd, physicalextentsize_ARG, 0) > MAX_EXTENT_SIZE) { log_error("Physical extent size cannot be larger than %s", display_size(cmd, (uint64_t) MAX_EXTENT_SIZE)); return 1; } extent_size = arg_uint_value(cmd, physicalextentsize_ARG, 0); /* FIXME: remove check - redundant with vg_change_pesize */ if (extent_size == vg->extent_size) { log_error("Physical extent size of VG %s is already %s", vg->name, display_size(cmd, (uint64_t) extent_size)); return 1; } if (!vg_set_extent_size(vg, extent_size)) return_0; return 1; } static int _vgchange_addtag(struct cmd_context *cmd, struct volume_group *vg) { return change_tag(cmd, vg, NULL, NULL, addtag_ARG); } static int _vgchange_deltag(struct cmd_context *cmd, struct volume_group *vg) { return change_tag(cmd, vg, NULL, NULL, deltag_ARG); } static int _vgchange_uuid(struct cmd_context *cmd __attribute__((unused)), struct volume_group *vg) { struct lv_list *lvl; if (lvs_in_vg_activated(vg)) { log_error("Volume group has active logical volumes"); return 0; } if (!id_create(&vg->id)) { log_error("Failed to generate new random UUID for VG %s.", vg->name); return 0; } dm_list_iterate_items(lvl, &vg->lvs) { memcpy(&lvl->lv->lvid, &vg->id, sizeof(vg->id)); } return 1; } static int _vgchange_metadata_copies(struct cmd_context *cmd, struct volume_group *vg) { uint32_t mda_copies = arg_uint_value(cmd, vgmetadatacopies_ARG, DEFAULT_VGMETADATACOPIES); if (mda_copies == vg_mda_copies(vg)) { if (vg_mda_copies(vg) == VGMETADATACOPIES_UNMANAGED) log_error("Number of metadata copies for VG %s is already unmanaged.", vg->name); else log_error("Number of metadata copies for VG %s is already %" PRIu32, vg->name, mda_copies); return 1; } if (!vg_set_mda_copies(vg, mda_copies)) return_0; return 1; } static int vgchange_single(struct cmd_context *cmd, const char *vg_name, struct volume_group *vg, void *handle __attribute__((unused))) { int archived = 0; int i; static struct { int arg; int (*fn)(struct cmd_context *cmd, struct volume_group *vg); } _vgchange_args[] = { { logicalvolume_ARG, &_vgchange_logicalvolume }, { maxphysicalvolumes_ARG, &_vgchange_physicalvolumes }, { resizeable_ARG, &_vgchange_resizeable }, { deltag_ARG, &_vgchange_deltag }, { addtag_ARG, &_vgchange_addtag }, { physicalextentsize_ARG, &_vgchange_pesize }, { uuid_ARG, &_vgchange_uuid }, { alloc_ARG, &_vgchange_alloc }, { clustered_ARG, &_vgchange_clustered }, { vgmetadatacopies_ARG, &_vgchange_metadata_copies }, { -1, NULL }, }; if (vg_is_exported(vg)) { log_error("Volume group \"%s\" is exported", vg_name); return ECMD_FAILED; } /* * FIXME: DEFAULT_BACKGROUND_POLLING should be "unspecified". * If --poll is explicitly provided use it; otherwise polling * should only be started if the LV is not already active. So: * 1) change the activation code to say if the LV was actually activated * 2) make polling of an LV tightly coupled with LV activation * * Do not initiate any polling if --sysinit option is used. */ init_background_polling(arg_count(cmd, sysinit_ARG) ? 0 : arg_int_value(cmd, poll_ARG, DEFAULT_BACKGROUND_POLLING)); for (i = 0; _vgchange_args[i].arg >= 0; i++) { if (arg_count(cmd, _vgchange_args[i].arg)) { if (!archived && !archive(vg)) { stack; return ECMD_FAILED; } archived = 1; if (!_vgchange_args[i].fn(cmd, vg)) { stack; return ECMD_FAILED; } } } if (archived) { if (!vg_write(vg) || !vg_commit(vg)) { stack; return ECMD_FAILED; } backup(vg); log_print_unless_silent("Volume group \"%s\" successfully changed", vg->name); } if (arg_count(cmd, activate_ARG)) { if (!vgchange_activate(cmd, vg, (activation_change_t) arg_uint_value(cmd, activate_ARG, CHANGE_AY))) return ECMD_FAILED; } if (arg_count(cmd, refresh_ARG)) { /* refreshes the visible LVs (which starts polling) */ if (!_vgchange_refresh(cmd, vg)) return ECMD_FAILED; } if (!arg_count(cmd, activate_ARG) && !arg_count(cmd, refresh_ARG) && arg_count(cmd, monitor_ARG)) { /* -ay* will have already done monitoring changes */ if (!_vgchange_monitoring(cmd, vg)) return ECMD_FAILED; } if (!arg_count(cmd, refresh_ARG) && background_polling()) if (!_vgchange_background_polling(cmd, vg)) return ECMD_FAILED; return ECMD_PROCESSED; } int vgchange(struct cmd_context *cmd, int argc, char **argv) { /* Update commands that can be combined */ int update_partial_safe = arg_count(cmd, deltag_ARG) || arg_count(cmd, addtag_ARG); int update_partial_unsafe = arg_count(cmd, logicalvolume_ARG) || arg_count(cmd, maxphysicalvolumes_ARG) || arg_count(cmd, resizeable_ARG) || arg_count(cmd, uuid_ARG) || arg_count(cmd, physicalextentsize_ARG) || arg_count(cmd, clustered_ARG) || arg_count(cmd, alloc_ARG) || arg_count(cmd, vgmetadatacopies_ARG); int update = update_partial_safe || update_partial_unsafe; if (!update && !arg_count(cmd, activate_ARG) && !arg_count(cmd, monitor_ARG) && !arg_count(cmd, poll_ARG) && !arg_count(cmd, refresh_ARG)) { log_error("Need 1 or more of -a, -c, -l, -p, -s, -x, " "--refresh, --uuid, --alloc, --addtag, --deltag, " "--monitor, --poll, --vgmetadatacopies or " "--metadatacopies"); return EINVALID_CMD_LINE; } if (arg_count(cmd, activate_ARG) && arg_count(cmd, refresh_ARG)) { log_error("Only one of -a and --refresh permitted."); return EINVALID_CMD_LINE; } if ((arg_count(cmd, ignorelockingfailure_ARG) || arg_count(cmd, sysinit_ARG)) && update) { log_error("Only -a permitted with --ignorelockingfailure and --sysinit"); return EINVALID_CMD_LINE; } if (arg_count(cmd, activate_ARG) && (arg_count(cmd, monitor_ARG) || arg_count(cmd, poll_ARG))) { int activate = arg_uint_value(cmd, activate_ARG, 0); if (activate == CHANGE_AN || activate == CHANGE_ALN) { log_error("Only -ay* allowed with --monitor or --poll."); return EINVALID_CMD_LINE; } } if (arg_count(cmd, poll_ARG) && arg_count(cmd, sysinit_ARG)) { log_error("Only one of --poll and --sysinit permitted."); return EINVALID_CMD_LINE; } if (arg_count(cmd, activate_ARG) == 1 && arg_count(cmd, autobackup_ARG)) { log_error("-A option not necessary with -a option"); return EINVALID_CMD_LINE; } if (arg_count(cmd, maxphysicalvolumes_ARG) && arg_sign_value(cmd, maxphysicalvolumes_ARG, SIGN_NONE) == SIGN_MINUS) { log_error("MaxPhysicalVolumes may not be negative"); return EINVALID_CMD_LINE; } if (arg_count(cmd, physicalextentsize_ARG) && arg_sign_value(cmd, physicalextentsize_ARG, SIGN_NONE) == SIGN_MINUS) { log_error("Physical extent size may not be negative"); return EINVALID_CMD_LINE; } if (arg_count(cmd, sysinit_ARG) && lvmetad_active() && arg_uint_value(cmd, activate_ARG, 0) == CHANGE_AAY) { log_warn("lvmetad is active while using --sysinit -a ay, " "skipping manual activation"); return ECMD_PROCESSED; } if (!update || !update_partial_unsafe) cmd->handles_missing_pvs = 1; return process_each_vg(cmd, argc, argv, update ? READ_FOR_UPDATE : 0, NULL, &vgchange_single); } lvm2-2.02.98/tools/pvmove.c0000640000175000017500000004341312037016273014336 0ustar blankblank/* * Copyright (C) 2003-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 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 "tools.h" #include "polldaemon.h" #include "display.h" #define PVMOVE_FIRST_TIME 0x00000001 /* Called for first time */ #define PVMOVE_EXCLUSIVE 0x00000002 /* Require exclusive LV */ static int _pvmove_target_present(struct cmd_context *cmd, int clustered) { const struct segment_type *segtype; unsigned attr = 0; int found = 1; static int _clustered_found = -1; if (clustered && _clustered_found >= 0) return _clustered_found; if (!(segtype = get_segtype_from_string(cmd, "mirror"))) return_0; if (activation() && segtype->ops->target_present && !segtype->ops->target_present(cmd, NULL, clustered ? &attr : NULL)) found = 0; if (activation() && clustered) { if (found && (attr & MIRROR_LOG_CLUSTERED)) _clustered_found = found = 1; else _clustered_found = found = 0; } return found; } static unsigned _pvmove_is_exclusive(struct cmd_context *cmd, struct volume_group *vg) { if (vg_is_clustered(vg)) if (!_pvmove_target_present(cmd, 1)) return 1; return 0; } /* Allow /dev/vgname/lvname, vgname/lvname or lvname */ static const char *_extract_lvname(struct cmd_context *cmd, const char *vgname, const char *arg) { const char *lvname; /* Is an lvname supplied directly? */ if (!strchr(arg, '/')) return arg; lvname = skip_dev_dir(cmd, arg, NULL); while (*lvname == '/') lvname++; if (!strchr(lvname, '/')) { log_error("--name takes a logical volume name"); return NULL; } if (strncmp(vgname, lvname, strlen(vgname)) || (lvname += strlen(vgname), *lvname != '/')) { log_error("Named LV and old PV must be in the same VG"); return NULL; } while (*lvname == '/') lvname++; if (!*lvname) { log_error("Incomplete LV name supplied with --name"); return NULL; } return lvname; } static struct volume_group *_get_vg(struct cmd_context *cmd, const char *vgname) { dev_close_all(); return vg_read_for_update(cmd, vgname, NULL, 0); } /* Create list of PVs for allocation of replacement extents */ static struct dm_list *_get_allocatable_pvs(struct cmd_context *cmd, int argc, char **argv, struct volume_group *vg, struct physical_volume *pv, alloc_policy_t alloc) { struct dm_list *allocatable_pvs, *pvht, *pvh; struct pv_list *pvl; if (argc) allocatable_pvs = create_pv_list(cmd->mem, vg, argc, argv, 1); else allocatable_pvs = clone_pv_list(cmd->mem, &vg->pvs); if (!allocatable_pvs) return_NULL; dm_list_iterate_safe(pvh, pvht, allocatable_pvs) { pvl = dm_list_item(pvh, struct pv_list); /* Don't allocate onto the PV we're clearing! */ if ((alloc != ALLOC_ANYWHERE) && (pvl->pv->dev == pv_dev(pv))) { dm_list_del(&pvl->list); continue; } /* Remove PV if full */ if (pvl->pv->pe_count == pvl->pv->pe_alloc_count) dm_list_del(&pvl->list); } if (dm_list_empty(allocatable_pvs)) { log_error("No extents available for allocation"); return NULL; } return allocatable_pvs; } /* * Replace any LV segments on given PV with temporary mirror. * Returns list of LVs changed. */ static int _insert_pvmove_mirrors(struct cmd_context *cmd, struct logical_volume *lv_mirr, struct dm_list *source_pvl, struct logical_volume *lv, struct dm_list *lvs_changed) { struct pv_list *pvl; uint32_t prev_le_count; /* Only 1 PV may feature in source_pvl */ pvl = dm_list_item(source_pvl->n, struct pv_list); prev_le_count = lv_mirr->le_count; if (!insert_layer_for_segments_on_pv(cmd, lv, lv_mirr, PVMOVE, pvl, lvs_changed)) return_0; /* check if layer was inserted */ if (lv_mirr->le_count - prev_le_count) { lv->status |= LOCKED; log_verbose("Moving %u extents of logical volume %s/%s", lv_mirr->le_count - prev_le_count, lv->vg->name, lv->name); } return 1; } /* Create new LV with mirror segments for the required copies */ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd, struct volume_group *vg, struct dm_list *source_pvl, const char *lv_name, struct dm_list *allocatable_pvs, alloc_policy_t alloc, struct dm_list **lvs_changed, unsigned *exclusive) { struct logical_volume *lv_mirr, *lv; struct lv_list *lvl; uint32_t log_count = 0; int lv_found = 0; int lv_skipped = 0; int lv_active_count = 0; int lv_exclusive_count = 0; /* FIXME Cope with non-contiguous => splitting existing segments */ if (!(lv_mirr = lv_create_empty("pvmove%d", NULL, LVM_READ | LVM_WRITE, ALLOC_CONTIGUOUS, vg))) { log_error("Creation of temporary pvmove LV failed"); return NULL; } lv_mirr->status |= (PVMOVE | LOCKED); if (!(*lvs_changed = dm_pool_alloc(cmd->mem, sizeof(**lvs_changed)))) { log_error("lvs_changed list struct allocation failed"); return NULL; } dm_list_init(*lvs_changed); /* Find segments to be moved and set up mirrors */ dm_list_iterate_items(lvl, &vg->lvs) { lv = lvl->lv; if (lv == lv_mirr) continue; if (lv_name) { if (strcmp(lv->name, lv_name)) continue; lv_found = 1; } if (lv_is_origin(lv) || lv_is_cow(lv)) { lv_skipped = 1; log_print_unless_silent("Skipping snapshot-related LV %s", lv->name); continue; } if (lv->status & MIRRORED) { lv_skipped = 1; log_print_unless_silent("Skipping mirror LV %s", lv->name); continue; } if (lv->status & MIRROR_LOG) { lv_skipped = 1; log_print_unless_silent("Skipping mirror log LV %s", lv->name); continue; } if (lv->status & MIRROR_IMAGE) { lv_skipped = 1; log_print_unless_silent("Skipping mirror image LV %s", lv->name); continue; } if (lv->status & LOCKED) { lv_skipped = 1; log_print_unless_silent("Skipping locked LV %s", lv->name); continue; } if (vg_is_clustered(vg) && lv_is_active_exclusive_remotely(lv)) { lv_skipped = 1; log_print_unless_silent("Skipping LV %s which is activated " "exclusively on remote node.", lv->name); continue; } if (vg_is_clustered(vg)) { if (lv_is_active_exclusive_locally(lv)) lv_exclusive_count++; else if (lv_is_active(lv)) lv_active_count++; } if (!_insert_pvmove_mirrors(cmd, lv_mirr, source_pvl, lv, *lvs_changed)) return_NULL; } if (lv_name && !lv_found) { log_error("Logical volume %s not found.", lv_name); return NULL; } /* Is temporary mirror empty? */ if (!lv_mirr->le_count) { if (lv_skipped) log_error("All data on source PV skipped. " "It contains locked, hidden or " "non-top level LVs only."); log_error("No data to move for %s", vg->name); return NULL; } if (vg_is_clustered(vg) && lv_active_count && *exclusive) { log_error("Cannot move in clustered VG %s, " "clustered mirror (cmirror) not detected " "and LVs are activated non-exclusively.", vg->name); return NULL; } if (vg_is_clustered(vg) && lv_exclusive_count) { if (lv_active_count) { log_error("Cannot move in clustered VG %s " "if some LVs are activated " "exclusively while others don't.", vg->name); return NULL; } *exclusive = 1; } if (!lv_add_mirrors(cmd, lv_mirr, 1, 1, 0, 0, log_count, allocatable_pvs, alloc, MIRROR_BY_SEG)) { log_error("Failed to convert pvmove LV to mirrored"); return_NULL; } if (!split_parent_segments_for_layer(cmd, lv_mirr)) { log_error("Failed to split segments being moved"); return_NULL; } return lv_mirr; } static int _activate_lv(struct cmd_context *cmd, struct logical_volume *lv_mirr, unsigned exclusive) { int r = 0; if (exclusive || lv_is_active_exclusive(lv_mirr)) r = activate_lv_excl(cmd, lv_mirr); else r = activate_lv(cmd, lv_mirr); if (!r) stack; return r; } static int _detach_pvmove_mirror(struct cmd_context *cmd, struct logical_volume *lv_mirr) { struct dm_list lvs_completed; struct lv_list *lvl; /* Update metadata to remove mirror segments and break dependencies */ dm_list_init(&lvs_completed); if (!lv_remove_mirrors(cmd, lv_mirr, 1, 0, NULL, NULL, PVMOVE) || !remove_layers_for_segments_all(cmd, lv_mirr, PVMOVE, &lvs_completed)) { return 0; } dm_list_iterate_items(lvl, &lvs_completed) /* FIXME Assumes only one pvmove at a time! */ lvl->lv->status &= ~LOCKED; return 1; } static int _suspend_lvs(struct cmd_context *cmd, unsigned first_time, struct logical_volume *lv_mirr, struct dm_list *lvs_changed, struct volume_group *vg_to_revert) { /* * Suspend lvs_changed the first time. * Suspend mirrors on subsequent calls. */ if (first_time) { if (!suspend_lvs(cmd, lvs_changed, vg_to_revert)) return_0; } else if (!suspend_lv(cmd, lv_mirr)) { if (vg_to_revert) vg_revert(vg_to_revert); return_0; } return 1; } static int _resume_lvs(struct cmd_context *cmd, unsigned first_time, struct logical_volume *lv_mirr, struct dm_list *lvs_changed) { /* * Suspend lvs_changed the first time. * Suspend mirrors on subsequent calls. */ if (first_time) { if (!resume_lvs(cmd, lvs_changed)) { log_error("Unable to resume logical volumes"); return 0; } } else if (!resume_lv(cmd, lv_mirr)) { log_error("Unable to reactivate logical volume \"%s\"", lv_mirr->name); return 0; } return 1; } /* * Called to set up initial pvmove LV and to advance the mirror * to successive sections of it. * (Not called after the last section completes.) */ static int _update_metadata(struct cmd_context *cmd, struct volume_group *vg, struct logical_volume *lv_mirr, struct dm_list *lvs_changed, unsigned flags) { unsigned exclusive = (flags & PVMOVE_EXCLUSIVE) ? 1 : 0; unsigned first_time = (flags & PVMOVE_FIRST_TIME) ? 1 : 0; int r = 0; log_verbose("Updating volume group metadata"); if (!vg_write(vg)) { log_error("ABORTING: Volume group metadata update failed."); return 0; } if (!_suspend_lvs(cmd, first_time, lv_mirr, lvs_changed, vg)) { log_error("ABORTING: Temporary pvmove mirror %s failed.", first_time ? "activation" : "reload"); /* FIXME Add a recovery path for first time too. */ if (!first_time && !revert_lv(cmd, lv_mirr)) stack; return 0; } /* Commit on-disk metadata */ if (!vg_commit(vg)) { log_error("ABORTING: Volume group metadata update failed."); if (!_resume_lvs(cmd, first_time, lv_mirr, lvs_changed)) stack; if (!first_time && !revert_lv(cmd, lv_mirr)) stack; return 0; } /* Activate the temporary mirror LV */ /* Only the first mirror segment gets activated as a mirror */ /* FIXME: Add option to use a log */ if (first_time) { if (!exclusive && _pvmove_is_exclusive(cmd, vg)) exclusive = 1; if (!_activate_lv(cmd, lv_mirr, exclusive)) { if (test_mode()) { r = 1; goto out; } /* * FIXME Run --abort internally here. */ log_error("ABORTING: Temporary pvmove mirror activation failed. Run pvmove --abort."); goto_out; } } r = 1; out: if (!_resume_lvs(cmd, first_time, lv_mirr, lvs_changed)) r = 0; if (r) backup(vg); return r; } static int _set_up_pvmove(struct cmd_context *cmd, const char *pv_name, int argc, char **argv) { const char *lv_name = NULL; char *pv_name_arg; struct volume_group *vg; struct dm_list *source_pvl; struct dm_list *allocatable_pvs; alloc_policy_t alloc; struct dm_list *lvs_changed; struct physical_volume *pv; struct logical_volume *lv_mirr; unsigned flags = PVMOVE_FIRST_TIME; unsigned exclusive; int r = ECMD_FAILED; pv_name_arg = argv[0]; argc--; argv++; /* Find PV (in VG) */ if (!(pv = find_pv_by_name(cmd, pv_name))) { stack; return EINVALID_CMD_LINE; } if (arg_count(cmd, name_ARG)) { if (!(lv_name = _extract_lvname(cmd, pv_vg_name(pv), arg_value(cmd, name_ARG)))) { stack; free_pv_fid(pv); return EINVALID_CMD_LINE; } if (!validate_name(lv_name)) { log_error("Logical volume name %s is invalid", lv_name); free_pv_fid(pv); return EINVALID_CMD_LINE; } } /* Read VG */ log_verbose("Finding volume group \"%s\"", pv_vg_name(pv)); vg = _get_vg(cmd, pv_vg_name(pv)); if (vg_read_error(vg)) { release_vg(vg); stack; return ECMD_FAILED; } exclusive = _pvmove_is_exclusive(cmd, vg); if ((lv_mirr = find_pvmove_lv(vg, pv_dev(pv), PVMOVE))) { log_print_unless_silent("Detected pvmove in progress for %s", pv_name); if (argc || lv_name) log_error("Ignoring remaining command line arguments"); if (!(lvs_changed = lvs_using_lv(cmd, vg, lv_mirr))) { log_error("ABORTING: Failed to generate list of moving LVs"); goto out; } /* Ensure mirror LV is active */ if (!_activate_lv(cmd, lv_mirr, exclusive)) { log_error("ABORTING: Temporary mirror activation failed."); goto out; } flags &= ~PVMOVE_FIRST_TIME; } else { /* Determine PE ranges to be moved */ if (!(source_pvl = create_pv_list(cmd->mem, vg, 1, &pv_name_arg, 0))) goto_out; alloc = (alloc_policy_t) arg_uint_value(cmd, alloc_ARG, ALLOC_INHERIT); if (alloc == ALLOC_INHERIT) alloc = vg->alloc; /* Get PVs we can use for allocation */ if (!(allocatable_pvs = _get_allocatable_pvs(cmd, argc, argv, vg, pv, alloc))) goto_out; if (!archive(vg)) goto_out; if (!(lv_mirr = _set_up_pvmove_lv(cmd, vg, source_pvl, lv_name, allocatable_pvs, alloc, &lvs_changed, &exclusive))) goto_out; } /* Lock lvs_changed and activate (with old metadata) */ if (!activate_lvs(cmd, lvs_changed, exclusive)) goto_out; /* FIXME Presence of a mirror once set PVMOVE - now remove associated logic */ /* init_pvmove(1); */ /* vg->status |= PVMOVE; */ if (flags & PVMOVE_FIRST_TIME) { if (exclusive) flags |= PVMOVE_EXCLUSIVE; if (!_update_metadata (cmd, vg, lv_mirr, lvs_changed, flags)) goto_out; } /* LVs are all in status LOCKED */ r = ECMD_PROCESSED; out: free_pv_fid(pv); unlock_and_release_vg(cmd, vg, pv_vg_name(pv)); return r; } static int _finish_pvmove(struct cmd_context *cmd, struct volume_group *vg, struct logical_volume *lv_mirr, struct dm_list *lvs_changed) { int r = 1; if (!dm_list_empty(lvs_changed) && (!_detach_pvmove_mirror(cmd, lv_mirr) || !replace_lv_with_error_segment(lv_mirr))) { log_error("ABORTING: Removal of temporary mirror failed"); return 0; } /* Store metadata without dependencies on mirror segments */ if (!vg_write(vg)) { log_error("ABORTING: Failed to write new data locations " "to disk."); return 0; } /* Suspend LVs changed (implicitly suspends lv_mirr) */ if (!suspend_lvs(cmd, lvs_changed, vg)) { log_error("ABORTING: Locking LVs to remove temporary mirror failed"); if (!revert_lv(cmd, lv_mirr)) stack; return 0; } /* Store metadata without dependencies on mirror segments */ if (!vg_commit(vg)) { log_error("ABORTING: Failed to write new data locations " "to disk."); if (!revert_lv(cmd, lv_mirr)) stack; if (!revert_lvs(cmd, lvs_changed)) stack; return 0; } /* Release mirror LV. (No pending I/O because it's been suspended.) */ if (!resume_lv(cmd, lv_mirr)) { log_error("Unable to reactivate logical volume \"%s\"", lv_mirr->name); r = 0; } /* Unsuspend LVs */ if (!resume_lvs(cmd, lvs_changed)) stack; /* Deactivate mirror LV */ if (!deactivate_lv(cmd, lv_mirr)) { log_error("ABORTING: Unable to deactivate temporary logical " "volume \"%s\"", lv_mirr->name); r = 0; } log_verbose("Removing temporary pvmove LV"); if (!lv_remove(lv_mirr)) { log_error("ABORTING: Removal of temporary pvmove LV failed"); return 0; } /* Store it on disks */ log_verbose("Writing out final volume group after pvmove"); if (!vg_write(vg) || !vg_commit(vg)) { log_error("ABORTING: Failed to write new data locations " "to disk."); return 0; } /* FIXME backup positioning */ backup(vg); return r; } static struct volume_group *_get_move_vg(struct cmd_context *cmd, const char *name, const char *uuid __attribute__((unused))) { struct physical_volume *pv; struct volume_group *vg; /* Reread all metadata in case it got changed */ if (!(pv = find_pv_by_name(cmd, name))) { log_error("ABORTING: Can't reread PV %s", name); /* What more could we do here? */ return NULL; } vg = _get_vg(cmd, pv_vg_name(pv)); free_pv_fid(pv); return vg; } static struct poll_functions _pvmove_fns = { .get_copy_name_from_lv = get_pvmove_pvname_from_lv_mirr, .get_copy_vg = _get_move_vg, .get_copy_lv = find_pvmove_lv_from_pvname, .poll_progress = poll_mirror_progress, .update_metadata = _update_metadata, .finish_copy = _finish_pvmove, }; int pvmove_poll(struct cmd_context *cmd, const char *pv_name, unsigned background) { if (test_mode()) return ECMD_PROCESSED; return poll_daemon(cmd, pv_name, NULL, background, PVMOVE, &_pvmove_fns, "Moved"); } int pvmove(struct cmd_context *cmd, int argc, char **argv) { char *pv_name = NULL; char *colon; int ret; /* dm raid1 target must be present in every case */ if (!_pvmove_target_present(cmd, 0)) { log_error("Required device-mapper target(s) not " "detected in your kernel"); return ECMD_FAILED; } if (argc) { if (!(pv_name = dm_pool_strdup(cmd->mem, argv[0]))) { log_error("Failed to clone PV name"); return ECMD_FAILED; } dm_unescape_colons_and_at_signs(pv_name, &colon, NULL); /* Drop any PE lists from PV name */ if (colon) *colon = '\0'; if (!arg_count(cmd, abort_ARG) && (ret = _set_up_pvmove(cmd, pv_name, argc, argv)) != ECMD_PROCESSED) { stack; return ret; } } return pvmove_poll(cmd, pv_name, arg_is_set(cmd, background_ARG)); } lvm2-2.02.98/tools/lvrename.c0000640000175000017500000000742612037016273014637 0ustar blankblank/* * 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 "tools.h" #include "lvm-types.h" /* * lvrename command implementation. * Check arguments and call lv_rename() to execute the request. */ int lvrename(struct cmd_context *cmd, int argc, char **argv) { size_t maxlen; char *lv_name_old, *lv_name_new; const char *vg_name, *vg_name_new, *vg_name_old; char *st; int r = ECMD_FAILED; struct volume_group *vg = NULL; struct lv_list *lvl; if (argc == 3) { vg_name = skip_dev_dir(cmd, argv[0], NULL); lv_name_old = argv[1]; lv_name_new = argv[2]; if (strchr(lv_name_old, '/') && (vg_name_old = extract_vgname(cmd, lv_name_old)) && strcmp(vg_name_old, vg_name)) { log_error("Please use a single volume group name " "(\"%s\" or \"%s\")", vg_name, vg_name_old); return EINVALID_CMD_LINE; } } else if (argc == 2) { lv_name_old = argv[0]; lv_name_new = argv[1]; vg_name = extract_vgname(cmd, lv_name_old); } else { log_error("Old and new logical volume names required"); return EINVALID_CMD_LINE; } if (!validate_name(vg_name)) { log_error("Please provide a valid volume group name"); return EINVALID_CMD_LINE; } if (strchr(lv_name_new, '/') && (vg_name_new = extract_vgname(cmd, lv_name_new)) && strcmp(vg_name, vg_name_new)) { log_error("Logical volume names must " "have the same volume group (\"%s\" or \"%s\")", vg_name, vg_name_new); return EINVALID_CMD_LINE; } if ((st = strrchr(lv_name_old, '/'))) lv_name_old = st + 1; if ((st = strrchr(lv_name_new, '/'))) lv_name_new = st + 1; /* Check sanity of new name */ maxlen = NAME_LEN - strlen(vg_name) - strlen(cmd->dev_dir) - 3; if (strlen(lv_name_new) > maxlen) { log_error("New logical volume path exceeds maximum length " "of %" PRIsize_t "!", maxlen); return ECMD_FAILED; } if (!*lv_name_new) { log_error("New logical volume name may not be blank"); return ECMD_FAILED; } if (!apply_lvname_restrictions(lv_name_new)) { stack; return ECMD_FAILED; } if (!validate_name(lv_name_new)) { log_error("New logical volume name \"%s\" is invalid", lv_name_new); return EINVALID_CMD_LINE; } if (!strcmp(lv_name_old, lv_name_new)) { log_error("Old and new logical volume names must differ"); return EINVALID_CMD_LINE; } log_verbose("Checking for existing volume group \"%s\"", vg_name); vg = vg_read_for_update(cmd, vg_name, NULL, 0); if (vg_read_error(vg)) { release_vg(vg); stack; return ECMD_FAILED; } if (!(lvl = find_lv_in_vg(vg, lv_name_old))) { log_error("Existing logical volume \"%s\" not found in " "volume group \"%s\"", lv_name_old, vg_name); goto error; } if (lvl->lv->status & (RAID_IMAGE | RAID_META)) { log_error("Cannot rename a RAID %s directly", (lvl->lv->status & RAID_IMAGE) ? "image" : "metadata area"); r = ECMD_FAILED; goto error; } if (lv_is_raid_with_tracking(lvl->lv)) { log_error("Cannot rename %s while it is tracking a split image", lvl->lv->name); r = ECMD_FAILED; goto error; } if (!lv_rename(cmd, lvl->lv, lv_name_new)) goto error; log_print_unless_silent("Renamed \"%s\" to \"%s\" in volume group \"%s\"", lv_name_old, lv_name_new, vg_name); r = ECMD_PROCESSED; error: unlock_and_release_vg(cmd, vg, vg_name); return r; } lvm2-2.02.98/tools/lvm2cmd.h0000640000175000017500000000406212037016273014370 0ustar blankblank/* * Copyright (C) 2003-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_CMDLIB_H #define _LVM_CMDLIB_H #ifdef __cplusplus extern "C" { #endif #ifndef _LVM_LOG_H typedef void (*lvm2_log_fn_t) (int level, const char *file, int line, int dm_errno, const char *message); #endif #define LVM2_LOG_SUPPRESS 0 /* Logging levels */ #define LVM2_LOG_FATAL 2 #define LVM2_LOG_ERROR 3 #define LVM2_LOG_PRINT 4 #define LVM2_LOG_VERBOSE 5 #define LVM2_LOG_VERY_VERBOSE 6 #define LVM2_LOG_DEBUG 7 /* * Define external function to replace the built-in logging function. * It receives output line-by-line. * * level is the logging level (see above) * file & line refer to the source code where the message originates. */ void lvm2_log_fn(lvm2_log_fn_t log_fn); /* * Initialise library. * Returns a handle so repeated use of lvm2_run is more efficient. */ void *lvm2_init(void); /* * Disable any dmeventd calls that the library may otherwise do. Useful to avoid * recursive calls from dmeventd to itself. */ void lvm2_disable_dmeventd_monitoring(void *handle); /* * Set log level (as above) if using built-in logging function. * Default is LVM2_LOG_PRINT. Use LVM2_LOG_SUPPRESS to suppress output. */ void lvm2_log_level(void *handle, int level); /* * Run an LVM2 command. * Use NULL handle if the call is a one-off and you don't want to bother * calling lvm2_init/lvm2_exit. */ int lvm2_run(void *handle, const char *cmdline); /* Release handle */ void lvm2_exit(void *handle); #ifdef __cplusplus } #endif #endif lvm2-2.02.98/tools/tools.h0000640000175000017500000001412012037016273014160 0ustar blankblank/* * 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_TOOLS_H #define _LVM_TOOLS_H #define _GNU_SOURCE #define _FILE_OFFSET_BITS 64 #include "configure.h" #include #include "libdevmapper.h" #include "lvm-types.h" #include "lvm-logging.h" #include "activate.h" #include "archiver.h" #include "lvmcache.h" #include "lvmetad.h" #include "config.h" #include "defaults.h" #include "dev-cache.h" #include "device.h" #include "display.h" #include "errors.h" #include "filter.h" #include "filter-composite.h" #include "filter-persistent.h" #include "filter-regex.h" #include "metadata-exported.h" #include "locking.h" #include "lvm-exec.h" #include "lvm-file.h" #include "lvm-string.h" #include "segtype.h" #include "str_list.h" #include "toolcontext.h" #include "toollib.h" #include #include #include #include #include #include #define CMD_LEN 256 #define MAX_ARGS 64 /* command functions */ typedef int (*command_fn) (struct cmd_context * cmd, int argc, char **argv); #define xx(a, b...) int a(struct cmd_context *cmd, int argc, char **argv); #include "commands.h" #undef xx /* define the enums for the command line switches */ enum { #define arg(a, b, c, d, e) a , #include "args.h" #undef arg }; typedef enum { SIGN_NONE = 0, SIGN_PLUS = 1, SIGN_MINUS = 2 } sign_t; typedef enum { PERCENT_NONE = 0, PERCENT_VG, PERCENT_FREE, PERCENT_LV, PERCENT_PVS, PERCENT_ORIGIN } percent_type_t; #define ARG_COUNTABLE 0x00000001 /* E.g. -vvvv */ #define ARG_GROUPABLE 0x00000002 /* E.g. --addtag */ struct arg_values { unsigned count; char *value; int32_t i_value; uint32_t ui_value; int64_t i64_value; uint64_t ui64_value; sign_t sign; percent_type_t percent; /* void *ptr; // Currently not used. */ }; /* a global table of possible arguments */ struct arg_props { const char short_arg; char _padding[7]; const char *long_arg; int (*fn) (struct cmd_context *cmd, struct arg_values *av); uint32_t flags; }; struct arg_value_group_list { struct dm_list list; struct arg_values arg_values[0]; }; #define CACHE_VGMETADATA 0x00000001 #define PERMITTED_READ_ONLY 0x00000002 /* a register of the lvm commands */ struct command { const char *name; const char *desc; const char *usage; command_fn fn; unsigned flags; int num_args; int *valid_args; }; void usage(const char *name); /* the argument verify/normalise functions */ int yes_no_arg(struct cmd_context *cmd, struct arg_values *av); int activation_arg(struct cmd_context *cmd, struct arg_values *av); int discards_arg(struct cmd_context *cmd, struct arg_values *av); int size_kb_arg(struct cmd_context *cmd, struct arg_values *av); int size_mb_arg(struct cmd_context *cmd, struct arg_values *av); int int_arg(struct cmd_context *cmd, struct arg_values *av); int int_arg_with_sign(struct cmd_context *cmd, struct arg_values *av); int int_arg_with_sign_and_percent(struct cmd_context *cmd, struct arg_values *av); int major_arg(struct cmd_context *cmd, struct arg_values *av); int minor_arg(struct cmd_context *cmd, struct arg_values *av); int string_arg(struct cmd_context *cmd, struct arg_values *av); int tag_arg(struct cmd_context *cmd, struct arg_values *av); int permission_arg(struct cmd_context *cmd, struct arg_values *av); int metadatatype_arg(struct cmd_context *cmd, struct arg_values *av); int units_arg(struct cmd_context *cmd, struct arg_values *av); int segtype_arg(struct cmd_context *cmd, struct arg_values *av); int alloc_arg(struct cmd_context *cmd, struct arg_values *av); int readahead_arg(struct cmd_context *cmd, struct arg_values *av); int metadatacopies_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av); int major_minor_valid(const struct cmd_context * cmd, const struct format_type *fmt, int32_t major, int32_t minor); /* we use the enums to access the switches */ unsigned arg_count(const struct cmd_context *cmd, int a); unsigned arg_is_set(const struct cmd_context *cmd, int a); const char *arg_value(struct cmd_context *cmd, int a); const char *arg_str_value(struct cmd_context *cmd, int a, const char *def); int32_t arg_int_value(struct cmd_context *cmd, int a, const int32_t def); int32_t first_grouped_arg_int_value(struct cmd_context *cmd, int a, const int32_t def); uint32_t arg_uint_value(struct cmd_context *cmd, int a, const uint32_t def); int64_t arg_int64_value(struct cmd_context *cmd, int a, const int64_t def); uint64_t arg_uint64_value(struct cmd_context *cmd, int a, const uint64_t def); const void *arg_ptr_value(struct cmd_context *cmd, int a, const void *def); sign_t arg_sign_value(struct cmd_context *cmd, int a, const sign_t def); percent_type_t arg_percent_value(struct cmd_context *cmd, int a, const percent_type_t def); int arg_count_increment(struct cmd_context *cmd, int a); unsigned grouped_arg_count(const struct arg_values *av, int a); unsigned grouped_arg_is_set(const struct arg_values *av, int a); const char *grouped_arg_str_value(const struct arg_values *av, int a, const char *def); int32_t grouped_arg_int_value(const struct arg_values *av, int a, const int32_t def); const char *command_name(struct cmd_context *cmd); int pvmove_poll(struct cmd_context *cmd, const char *pv, unsigned background); int lvconvert_poll(struct cmd_context *cmd, struct logical_volume *lv, unsigned background); int mirror_remove_missing(struct cmd_context *cmd, struct logical_volume *lv, int force); uint32_t percent_of_extents(uint32_t percents, uint32_t count, int roundup); int vgchange_activate(struct cmd_context *cmd, struct volume_group *vg, activation_change_t activate); #endif lvm2-2.02.98/tools/lvmchange.c0000640000175000017500000000152412037016273014763 0ustar blankblank/* * Copyright (C) 2001-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 */ #include "tools.h" int lvmchange(struct cmd_context *cmd __attribute__((unused)), int argc __attribute__((unused)), char **argv __attribute__((unused))) { log_error("With LVM2 and the device mapper, this program is obsolete."); return ECMD_FAILED; } lvm2-2.02.98/tools/vgmerge.c0000640000175000017500000001117512037016273014456 0ustar blankblank/* * 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 */ #include "tools.h" static struct volume_group *_vgmerge_vg_read(struct cmd_context *cmd, const char *vg_name) { struct volume_group *vg; log_verbose("Checking for volume group \"%s\"", vg_name); vg = vg_read_for_update(cmd, vg_name, NULL, 0); if (vg_read_error(vg)) { release_vg(vg); return NULL; } return vg; } static int _vgmerge_single(struct cmd_context *cmd, const char *vg_name_to, const char *vg_name_from) { struct pv_list *pvl, *tpvl; struct volume_group *vg_to, *vg_from; struct lv_list *lvl1, *lvl2; int r = ECMD_FAILED; int lock_vg_from_first = 0; if (!strcmp(vg_name_to, vg_name_from)) { log_error("Duplicate volume group name \"%s\"", vg_name_from); return ECMD_FAILED; } if (strcmp(vg_name_to, vg_name_from) > 0) lock_vg_from_first = 1; if (lock_vg_from_first) { vg_from = _vgmerge_vg_read(cmd, vg_name_from); if (!vg_from) { stack; return ECMD_FAILED; } vg_to = _vgmerge_vg_read(cmd, vg_name_to); if (!vg_to) { stack; unlock_and_release_vg(cmd, vg_from, vg_name_from); return ECMD_FAILED; } } else { vg_to = _vgmerge_vg_read(cmd, vg_name_to); if (!vg_to) { stack; return ECMD_FAILED; } vg_from = _vgmerge_vg_read(cmd, vg_name_from); if (!vg_from) { stack; unlock_and_release_vg(cmd, vg_to, vg_name_to); return ECMD_FAILED; } } if (!vgs_are_compatible(cmd, vg_from, vg_to)) goto_bad; /* FIXME List arg: vg_show_with_pv_and_lv(vg_to); */ if (!archive(vg_from) || !archive(vg_to)) goto_bad; if (!drop_cached_metadata(vg_from)) stack; /* Merge volume groups */ dm_list_iterate_items_safe(pvl, tpvl, &vg_from->pvs) { del_pvl_from_vgs(vg_from, pvl); add_pvl_to_vgs(vg_to, pvl); pvl->pv->vg_name = dm_pool_strdup(cmd->mem, vg_to->name); } /* Fix up LVIDs */ dm_list_iterate_items(lvl1, &vg_to->lvs) { union lvid *lvid1 = &lvl1->lv->lvid; char uuid[64] __attribute__((aligned(8))); dm_list_iterate_items(lvl2, &vg_from->lvs) { union lvid *lvid2 = &lvl2->lv->lvid; if (id_equal(&lvid1->id[1], &lvid2->id[1])) { if (!id_create(&lvid2->id[1])) { log_error("Failed to generate new " "random LVID for %s", lvl2->lv->name); goto bad; } if (!id_write_format(&lvid2->id[1], uuid, sizeof(uuid))) goto_bad; log_verbose("Changed LVID for %s to %s", lvl2->lv->name, uuid); } } } dm_list_iterate_items(lvl1, &vg_from->lvs) { lvl1->lv->vg = vg_to; } while (!dm_list_empty(&vg_from->lvs)) { struct dm_list *lvh = vg_from->lvs.n; dm_list_move(&vg_to->lvs, lvh); } while (!dm_list_empty(&vg_from->fid->metadata_areas_in_use)) { struct dm_list *mdah = vg_from->fid->metadata_areas_in_use.n; dm_list_move(&vg_to->fid->metadata_areas_in_use, mdah); } while (!dm_list_empty(&vg_from->fid->metadata_areas_ignored)) { struct dm_list *mdah = vg_from->fid->metadata_areas_ignored.n; dm_list_move(&vg_to->fid->metadata_areas_ignored, mdah); } vg_to->extent_count += vg_from->extent_count; vg_to->free_count += vg_from->free_count; /* store it on disks */ log_verbose("Writing out updated volume group"); if (!vg_write(vg_to) || !vg_commit(vg_to)) goto_bad; /* FIXME Remove /dev/vgfrom */ backup(vg_to); log_print_unless_silent("Volume group \"%s\" successfully merged into \"%s\"", vg_from->name, vg_to->name); r = ECMD_PROCESSED; bad: /* * Note: as vg_to is referencing moved elements from vg_from * the order of release_vg calls is mandatory. */ unlock_and_release_vg(cmd, vg_to, vg_name_to); unlock_and_release_vg(cmd, vg_from, vg_name_from); return r; } int vgmerge(struct cmd_context *cmd, int argc, char **argv) { const char *vg_name_to, *vg_name_from; int opt = 0; int ret = 0, ret_max = 0; if (argc < 2) { log_error("Please enter 2 or more volume groups to merge"); return EINVALID_CMD_LINE; } vg_name_to = skip_dev_dir(cmd, argv[0], NULL); argc--; argv++; for (; opt < argc; opt++) { vg_name_from = skip_dev_dir(cmd, argv[opt], NULL); ret = _vgmerge_single(cmd, vg_name_to, vg_name_from); if (ret > ret_max) ret_max = ret; } return ret_max; } lvm2-2.02.98/tools/dmsetup.c0000640000175000017500000026427412037016273014515 0ustar blankblank/* * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved. * Copyright (C) 2005-2007 NEC Corporation * * This file is part of the device-mapper userspace tools. * * It includes tree drawing code based on pstree: http://psmisc.sourceforge.net/ * * 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 */ #define _GNU_SOURCE #define _FILE_OFFSET_BITS 64 #include "configure.h" #include "dm-logging.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef UDEV_SYNC_SUPPORT # include # include # include # include #endif /* FIXME Unused so far */ #undef HAVE_SYS_STATVFS_H #ifdef HAVE_SYS_STATVFS_H # include #endif #ifdef HAVE_SYS_IOCTL_H # include #endif #if HAVE_TERMIOS_H # include #endif #ifdef HAVE_GETOPTLONG # include # define GETOPTLONG_FN(a, b, c, d, e) getopt_long((a), (b), (c), (d), (e)) # define OPTIND_INIT 0 #else struct option { }; extern int optind; extern char *optarg; # define GETOPTLONG_FN(a, b, c, d, e) getopt((a), (b), (c)) # define OPTIND_INIT 1 #endif #ifndef TEMP_FAILURE_RETRY # define TEMP_FAILURE_RETRY(expression) \ (__extension__ \ ({ long int __result; \ do __result = (long int) (expression); \ while (__result == -1L && errno == EINTR); \ __result; })) #endif #ifdef linux # include "kdev_t.h" #else # define MAJOR(x) major((x)) # define MINOR(x) minor((x)) # define MKDEV(x,y) makedev((x),(y)) #endif #define LINE_SIZE 4096 #define ARGS_MAX 256 #define LOOP_TABLE_SIZE (PATH_MAX + 255) #define DEFAULT_DM_DEV_DIR "/dev/" #define DM_DEV_DIR_ENV_VAR_NAME "DM_DEV_DIR" #define DM_UDEV_COOKIE_ENV_VAR_NAME "DM_UDEV_COOKIE" /* FIXME Should be imported */ #ifndef DM_MAX_TYPE_NAME # define DM_MAX_TYPE_NAME 16 #endif /* FIXME Should be elsewhere */ #define SECTOR_SHIFT 9L #define err(msg, x...) fprintf(stderr, msg "\n", ##x) /* * We have only very simple switches ATM. */ enum { READ_ONLY = 0, ADD_NODE_ON_CREATE_ARG, ADD_NODE_ON_RESUME_ARG, CHECKS_ARG, COLS_ARG, EXEC_ARG, FORCE_ARG, GID_ARG, HELP_ARG, INACTIVE_ARG, MANGLENAME_ARG, MAJOR_ARG, MINOR_ARG, MODE_ARG, NAMEPREFIXES_ARG, NOFLUSH_ARG, NOHEADINGS_ARG, NOLOCKFS_ARG, NOOPENCOUNT_ARG, NOTABLE_ARG, UDEVCOOKIE_ARG, NOUDEVRULES_ARG, NOUDEVSYNC_ARG, OPTIONS_ARG, READAHEAD_ARG, RETRY_ARG, ROWS_ARG, SEPARATOR_ARG, SETUUID_ARG, SHOWKEYS_ARG, SORT_ARG, TABLE_ARG, TARGET_ARG, TREE_ARG, UID_ARG, UNBUFFERED_ARG, UNQUOTED_ARG, UUID_ARG, VERBOSE_ARG, VERIFYUDEV_ARG, VERSION_ARG, YES_ARG, NUM_SWITCHES }; typedef enum { DR_TASK = 1, DR_INFO = 2, DR_DEPS = 4, DR_TREE = 8, /* Complete dependency tree required */ DR_NAME = 16 } report_type_t; typedef enum { DN_DEVNO, /* Major and minor number pair */ DN_BLK, /* Block device name (e.g. dm-0) */ DN_MAP /* Map name (for dm devices only, equal to DN_BLK otherwise) */ } dev_name_t; static int _switches[NUM_SWITCHES]; static int _int_args[NUM_SWITCHES]; static char *_string_args[NUM_SWITCHES]; static int _num_devices; static char *_uuid; static char *_table; static char *_target; static char *_command; static uint32_t _read_ahead_flags; static uint32_t _udev_cookie; static int _udev_only; static struct dm_tree *_dtree; static struct dm_report *_report; static report_type_t _report_type; static dev_name_t _dev_name_type; /* * Commands */ struct command; #define CMD_ARGS const struct command *cmd, int argc, char **argv, struct dm_names *names, int multiple_devices typedef int (*command_fn) (CMD_ARGS); struct command { const char *name; const char *help; int min_args; int max_args; int repeatable_cmd; /* Repeat to process device list? */ command_fn fn; }; static int _parse_line(struct dm_task *dmt, char *buffer, const char *file, int line) { char ttype[LINE_SIZE], *ptr, *comment; unsigned long long start, size; int n; /* trim trailing space */ for (ptr = buffer + strlen(buffer) - 1; ptr >= buffer; ptr--) if (!isspace((int) *ptr)) break; ptr++; *ptr = '\0'; /* trim leading space */ for (ptr = buffer; *ptr && isspace((int) *ptr); ptr++) ; if (!*ptr || *ptr == '#') return 1; if (sscanf(ptr, "%llu %llu %s %n", &start, &size, ttype, &n) < 3) { err("Invalid format on line %d of table %s", line, file); return 0; } ptr += n; if ((comment = strchr(ptr, (int) '#'))) *comment = '\0'; if (!dm_task_add_target(dmt, start, size, ttype, ptr)) return 0; return 1; } static int _parse_file(struct dm_task *dmt, const char *file) { char *buffer = NULL; size_t buffer_size = 0; FILE *fp; int r = 0, line = 0; /* one-line table on cmdline */ if (_table) return _parse_line(dmt, _table, "", ++line); /* OK for empty stdin */ if (file) { if (!(fp = fopen(file, "r"))) { err("Couldn't open '%s' for reading", file); return 0; } } else fp = stdin; #ifndef HAVE_GETLINE buffer_size = LINE_SIZE; if (!(buffer = dm_malloc(buffer_size))) { err("Failed to malloc line buffer."); return 0; } while (fgets(buffer, (int) buffer_size, fp)) #else while (getline(&buffer, &buffer_size, fp) > 0) #endif if (!_parse_line(dmt, buffer, file ? : "on stdin", ++line)) goto out; r = 1; out: memset(buffer, 0, buffer_size); #ifndef HAVE_GETLINE dm_free(buffer); #else free(buffer); #endif if (file && fclose(fp)) fprintf(stderr, "%s: fclose failed: %s", file, strerror(errno)); return r; } struct dm_split_name { char *subsystem; char *vg_name; char *lv_name; char *lv_layer; }; struct dmsetup_report_obj { struct dm_task *task; struct dm_info *info; struct dm_task *deps_task; struct dm_tree_node *tree_node; struct dm_split_name *split_name; }; static struct dm_task *_get_deps_task(int major, int minor) { struct dm_task *dmt; struct dm_info info; if (!(dmt = dm_task_create(DM_DEVICE_DEPS))) return NULL; if (!dm_task_set_major(dmt, major) || !dm_task_set_minor(dmt, minor)) goto err; if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt)) goto err; if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt)) goto err; if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt)) goto err; if (!dm_task_run(dmt)) goto err; if (!dm_task_get_info(dmt, &info)) goto err; if (!info.exists) goto err; return dmt; err: dm_task_destroy(dmt); return NULL; } static char *_extract_uuid_prefix(const char *uuid, const int separator) { char *ptr = NULL; char *uuid_prefix = NULL; size_t len; if (uuid) ptr = strchr(uuid, separator); len = ptr ? ptr - uuid : 0; if (!(uuid_prefix = dm_malloc(len + 1))) { log_error("Failed to allocate memory to extract uuid prefix."); return NULL; } if (uuid) memcpy(uuid_prefix, uuid, len); uuid_prefix[len] = '\0'; return uuid_prefix; } static struct dm_split_name *_get_split_name(const char *uuid, const char *name, int separator) { struct dm_split_name *split_name; if (!(split_name = dm_malloc(sizeof(*split_name)))) { log_error("Failed to allocate memory to split device name " "into components."); return NULL; } if (!(split_name->subsystem = _extract_uuid_prefix(uuid, separator))) { dm_free(split_name); return_NULL; } split_name->vg_name = split_name->lv_name = split_name->lv_layer = (char *) ""; if (!strcmp(split_name->subsystem, "LVM") && (!(split_name->vg_name = dm_strdup(name)) || !dm_split_lvm_name(NULL, NULL, &split_name->vg_name, &split_name->lv_name, &split_name->lv_layer))) log_error("Failed to allocate memory to split LVM name " "into components."); return split_name; } static void _destroy_split_name(struct dm_split_name *split_name) { /* * lv_name and lv_layer are allocated within the same block * of memory as vg_name so don't need to be freed separately. */ if (!strcmp(split_name->subsystem, "LVM")) dm_free(split_name->vg_name); dm_free(split_name->subsystem); dm_free(split_name); } static int _display_info_cols(struct dm_task *dmt, struct dm_info *info) { struct dmsetup_report_obj obj; int r = 0; if (!info->exists) { fprintf(stderr, "Device does not exist.\n"); return 0; } obj.task = dmt; obj.info = info; obj.deps_task = NULL; obj.split_name = NULL; if (_report_type & DR_TREE) if (!(obj.tree_node = dm_tree_find_node(_dtree, info->major, info->minor))) { log_error("Cannot find node %d:%d.", info->major, info->minor); goto out; } if (_report_type & DR_DEPS) if (!(obj.deps_task = _get_deps_task(info->major, info->minor))) { log_error("Cannot get deps for %d:%d.", info->major, info->minor); goto out; } if (_report_type & DR_NAME) if (!(obj.split_name = _get_split_name(dm_task_get_uuid(dmt), dm_task_get_name(dmt), '-'))) goto_out; if (!dm_report_object(_report, &obj)) goto_out; r = 1; out: if (obj.deps_task) dm_task_destroy(obj.deps_task); if (obj.split_name) _destroy_split_name(obj.split_name); return r; } static void _display_info_long(struct dm_task *dmt, struct dm_info *info) { const char *uuid; uint32_t read_ahead; if (!info->exists) { printf("Device does not exist.\n"); return; } printf("Name: %s\n", dm_task_get_name(dmt)); printf("State: %s%s\n", info->suspended ? "SUSPENDED" : "ACTIVE", info->read_only ? " (READ-ONLY)" : ""); /* FIXME Old value is being printed when it's being changed. */ if (dm_task_get_read_ahead(dmt, &read_ahead)) printf("Read Ahead: %" PRIu32 "\n", read_ahead); if (!info->live_table && !info->inactive_table) printf("Tables present: None\n"); else printf("Tables present: %s%s%s\n", info->live_table ? "LIVE" : "", info->live_table && info->inactive_table ? " & " : "", info->inactive_table ? "INACTIVE" : ""); if (info->open_count != -1) printf("Open count: %d\n", info->open_count); printf("Event number: %" PRIu32 "\n", info->event_nr); printf("Major, minor: %d, %d\n", info->major, info->minor); if (info->target_count != -1) printf("Number of targets: %d\n", info->target_count); if ((uuid = dm_task_get_uuid(dmt)) && *uuid) printf("UUID: %s\n", uuid); printf("\n"); } static int _display_info(struct dm_task *dmt) { struct dm_info info; if (!dm_task_get_info(dmt, &info)) return 0; if (!_switches[COLS_ARG]) _display_info_long(dmt, &info); else /* FIXME return code */ _display_info_cols(dmt, &info); return info.exists ? 1 : 0; } static int _set_task_device(struct dm_task *dmt, const char *name, int optional) { if (name) { if (!dm_task_set_name(dmt, name)) return 0; } else if (_switches[UUID_ARG]) { if (!dm_task_set_uuid(dmt, _uuid)) return 0; } else if (_switches[MAJOR_ARG] && _switches[MINOR_ARG]) { if (!dm_task_set_major(dmt, _int_args[MAJOR_ARG]) || !dm_task_set_minor(dmt, _int_args[MINOR_ARG])) return 0; } else if (!optional) { fprintf(stderr, "No device specified.\n"); return 0; } return 1; } static int _set_task_add_node(struct dm_task *dmt) { if (!dm_task_set_add_node(dmt, DEFAULT_DM_ADD_NODE)) return 0; if (_switches[ADD_NODE_ON_RESUME_ARG] && !dm_task_set_add_node(dmt, DM_ADD_NODE_ON_RESUME)) return 0; if (_switches[ADD_NODE_ON_CREATE_ARG] && !dm_task_set_add_node(dmt, DM_ADD_NODE_ON_CREATE)) return 0; return 1; } static int _load(CMD_ARGS) { int r = 0; struct dm_task *dmt; const char *file = NULL; const char *name = NULL; if (_switches[NOTABLE_ARG]) { err("--notable only available when creating new device\n"); return 0; } if (!_switches[UUID_ARG] && !_switches[MAJOR_ARG]) { if (argc == 1) { err("Please specify device.\n"); return 0; } name = argv[1]; argc--; argv++; } else if (argc > 2) { err("Too many command line arguments.\n"); return 0; } if (argc == 2) file = argv[1]; if (!(dmt = dm_task_create(DM_DEVICE_RELOAD))) return 0; if (!_set_task_device(dmt, name, 0)) goto out; if (!_switches[NOTABLE_ARG] && !_parse_file(dmt, file)) goto out; if (_switches[READ_ONLY] && !dm_task_set_ro(dmt)) goto out; if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt)) goto out; if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt)) goto out; if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt)) goto out; if (!dm_task_run(dmt)) goto out; r = 1; if (_switches[VERBOSE_ARG]) r = _display_info(dmt); out: dm_task_destroy(dmt); return r; } static int _create(CMD_ARGS) { int r = 0; struct dm_task *dmt; const char *file = NULL; uint32_t cookie = 0; uint16_t udev_flags = 0; if (argc == 3) file = argv[2]; if (!(dmt = dm_task_create(DM_DEVICE_CREATE))) return 0; if (!dm_task_set_name(dmt, argv[1])) goto out; if (_switches[UUID_ARG] && !dm_task_set_uuid(dmt, _uuid)) goto out; if (!_switches[NOTABLE_ARG] && !_parse_file(dmt, file)) goto out; if (_switches[READ_ONLY] && !dm_task_set_ro(dmt)) goto out; if (_switches[MAJOR_ARG] && !dm_task_set_major(dmt, _int_args[MAJOR_ARG])) goto out; if (_switches[MINOR_ARG] && !dm_task_set_minor(dmt, _int_args[MINOR_ARG])) goto out; if (_switches[UID_ARG] && !dm_task_set_uid(dmt, _int_args[UID_ARG])) goto out; if (_switches[GID_ARG] && !dm_task_set_gid(dmt, _int_args[GID_ARG])) goto out; if (_switches[MODE_ARG] && !dm_task_set_mode(dmt, _int_args[MODE_ARG])) goto out; if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt)) goto out; if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt)) goto out; if (_switches[READAHEAD_ARG] && !dm_task_set_read_ahead(dmt, _int_args[READAHEAD_ARG], _read_ahead_flags)) goto out; if (_switches[NOTABLE_ARG]) dm_udev_set_sync_support(0); if (_switches[NOUDEVRULES_ARG]) udev_flags |= DM_UDEV_DISABLE_DM_RULES_FLAG | DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG; if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt)) goto out; if (!_set_task_add_node(dmt)) goto out; if (_udev_cookie) cookie = _udev_cookie; if (_udev_only) udev_flags |= DM_UDEV_DISABLE_LIBRARY_FALLBACK; if (!dm_task_set_cookie(dmt, &cookie, udev_flags) || !dm_task_run(dmt)) goto out; r = 1; out: if (!_udev_cookie) (void) dm_udev_wait(cookie); if (r && _switches[VERBOSE_ARG]) r = _display_info(dmt); dm_task_destroy(dmt); return r; } static int _do_rename(const char *name, const char *new_name, const char *new_uuid) { int r = 0; struct dm_task *dmt; uint32_t cookie = 0; uint16_t udev_flags = 0; if (!(dmt = dm_task_create(DM_DEVICE_RENAME))) return 0; /* FIXME Kernel doesn't support uuid or device number here yet */ if (!_set_task_device(dmt, name, 0)) goto out; if (new_uuid) { if (!dm_task_set_newuuid(dmt, new_uuid)) goto out; } else if (!new_name || !dm_task_set_newname(dmt, new_name)) goto out; if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt)) goto out; if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt)) goto out; if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt)) goto out; if (_switches[NOUDEVRULES_ARG]) udev_flags |= DM_UDEV_DISABLE_DM_RULES_FLAG | DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG; if (_udev_cookie) cookie = _udev_cookie; if (_udev_only) udev_flags |= DM_UDEV_DISABLE_LIBRARY_FALLBACK; if (!dm_task_set_cookie(dmt, &cookie, udev_flags) || !dm_task_run(dmt)) goto out; r = 1; out: if (!_udev_cookie) (void) dm_udev_wait(cookie); dm_task_destroy(dmt); return r; } static int _rename(CMD_ARGS) { const char *name = (argc == 3) ? argv[1] : NULL; return _switches[SETUUID_ARG] ? _do_rename(name, NULL, argv[argc - 1]) : _do_rename(name, argv[argc - 1], NULL); } static int _message(CMD_ARGS) { int r = 0, i; size_t sz = 1; struct dm_task *dmt; char *str; if (!(dmt = dm_task_create(DM_DEVICE_TARGET_MSG))) return 0; if (_switches[UUID_ARG] || _switches[MAJOR_ARG]) { if (!_set_task_device(dmt, NULL, 0)) goto out; } else { if (!_set_task_device(dmt, argv[1], 0)) goto out; argc--; argv++; } if (!dm_task_set_sector(dmt, (uint64_t) atoll(argv[1]))) goto out; argc -= 2; argv += 2; if (argc <= 0) err("No message supplied.\n"); for (i = 0; i < argc; i++) sz += strlen(argv[i]) + 1; if (!(str = dm_zalloc(sz))) { err("message string allocation failed"); goto out; } for (i = 0; i < argc; i++) { if (i) strcat(str, " "); strcat(str, argv[i]); } i = dm_task_set_message(dmt, str); dm_free(str); if (!i) goto out; if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt)) goto out; if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt)) goto out; if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt)) goto out; if (!dm_task_run(dmt)) goto out; r = 1; out: dm_task_destroy(dmt); return r; } static int _setgeometry(CMD_ARGS) { int r = 0; struct dm_task *dmt; if (!(dmt = dm_task_create(DM_DEVICE_SET_GEOMETRY))) return 0; if (_switches[UUID_ARG] || _switches[MAJOR_ARG]) { if (!_set_task_device(dmt, NULL, 0)) goto out; } else { if (!_set_task_device(dmt, argv[1], 0)) goto out; argc--; argv++; } if (!dm_task_set_geometry(dmt, argv[1], argv[2], argv[3], argv[4])) goto out; if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt)) goto out; if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt)) goto out; if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt)) goto out; /* run the task */ if (!dm_task_run(dmt)) goto out; r = 1; out: dm_task_destroy(dmt); return r; } static int _splitname(CMD_ARGS) { struct dmsetup_report_obj obj; int r = 1; obj.task = NULL; obj.info = NULL; obj.deps_task = NULL; obj.tree_node = NULL; if (!(obj.split_name = _get_split_name((argc == 3) ? argv[2] : "LVM", argv[1], '\0'))) return_0; r = dm_report_object(_report, &obj); _destroy_split_name(obj.split_name); return r; } static uint32_t _get_cookie_value(const char *str_value) { unsigned long int value; char *p; if (!(value = strtoul(str_value, &p, 0)) || *p || (value == ULONG_MAX && errno == ERANGE) || value > 0xFFFFFFFF) { err("Incorrect cookie value"); return 0; } else return (uint32_t) value; } static int _udevflags(CMD_ARGS) { uint32_t cookie; uint16_t flags; int i; static const char *dm_flag_names[] = {"DISABLE_DM_RULES", "DISABLE_SUBSYSTEM_RULES", "DISABLE_DISK_RULES", "DISABLE_OTHER_RULES", "LOW_PRIORITY", "DISABLE_LIBRARY_FALLBACK", "PRIMARY_SOURCE", 0}; if (!(cookie = _get_cookie_value(argv[1]))) return 0; flags = cookie >> DM_UDEV_FLAGS_SHIFT; for (i = 0; i < DM_UDEV_FLAGS_SHIFT; i++) if (1 << i & flags) { if (i < DM_UDEV_FLAGS_SHIFT / 2 && dm_flag_names[i]) printf("DM_UDEV_%s_FLAG='1'\n", dm_flag_names[i]); else if (i < DM_UDEV_FLAGS_SHIFT / 2) /* * This is just a fallback. Each new DM flag * should have its symbolic name assigned. */ printf("DM_UDEV_FLAG%d='1'\n", i); else /* * We can't assign symbolic names to subsystem * flags. Their semantics vary based on the * subsystem that is currently used. */ printf("DM_SUBSYSTEM_UDEV_FLAG%d='1'\n", i - DM_UDEV_FLAGS_SHIFT / 2); } return 1; } static int _udevcomplete(CMD_ARGS) { uint32_t cookie; if (!(cookie = _get_cookie_value(argv[1]))) return 0; /* * Strip flags from the cookie and use cookie magic instead. * If the cookie has non-zero prefix and the base is zero then * this one carries flags to control udev rules only and it is * not meant to be for notification. Return with success in this * situation. */ if (!(cookie &= ~DM_UDEV_FLAGS_MASK)) return 1; cookie |= DM_COOKIE_MAGIC << DM_UDEV_FLAGS_SHIFT; return dm_udev_complete(cookie); } #ifndef UDEV_SYNC_SUPPORT static const char _cmd_not_supported[] = "Command not supported. Recompile with \"--enable-udev_sync\" to enable."; static int _udevcreatecookie(CMD_ARGS) { log_error(_cmd_not_supported); return 0; } static int _udevreleasecookie(CMD_ARGS) { log_error(_cmd_not_supported); return 0; } static int _udevcomplete_all(CMD_ARGS) { log_error(_cmd_not_supported); return 0; } static int _udevcookies(CMD_ARGS) { log_error(_cmd_not_supported); return 0; } #else /* UDEV_SYNC_SUPPORT */ static int _set_up_udev_support(const char *dev_dir) { int dirs_diff; const char *env; size_t len = strlen(dev_dir), udev_dir_len = strlen(DM_UDEV_DEV_DIR); if (_switches[NOUDEVSYNC_ARG]) dm_udev_set_sync_support(0); if (!_udev_cookie) { env = getenv(DM_UDEV_COOKIE_ENV_VAR_NAME); if (env && *env && (_udev_cookie = _get_cookie_value(env))) log_debug("Using udev transaction 0x%08" PRIX32 " defined by %s environment variable.", _udev_cookie, DM_UDEV_COOKIE_ENV_VAR_NAME); } else if (_switches[UDEVCOOKIE_ARG]) log_debug("Using udev transaction 0x%08" PRIX32 " defined by --udevcookie option.", _udev_cookie); /* * Normally, there's always a fallback action by libdevmapper if udev * has not done its job correctly, e.g. the nodes were not created. * If using udev transactions by specifying existing cookie value, * we need to disable node creation by libdevmapper completely, * disabling any fallback actions, since any synchronisation happens * at the end of the transaction only. We need to do this to prevent * races between udev and libdevmapper but only in case udev "dev path" * is the same as "dev path" used by libdevmapper. */ /* * DM_UDEV_DEV_DIR always has '/' at its end. * If the dev_dir does not have it, be sure * to make the right comparison without the '/' char! */ if (dev_dir[len - 1] != '/') udev_dir_len--; dirs_diff = udev_dir_len != len || strncmp(DM_UDEV_DEV_DIR, dev_dir, len); _udev_only = !dirs_diff && (_udev_cookie || !_switches[VERIFYUDEV_ARG]); if (dirs_diff) { log_debug("The path %s used for creating device nodes that is " "set via DM_DEV_DIR environment variable differs from " "the path %s that is used by udev. All warnings " "about udev not working correctly while processing " "particular nodes will be suppressed. These nodes " "and symlinks will be managed in each directory " "separately.", dev_dir, DM_UDEV_DEV_DIR); dm_udev_set_checking(0); } return 1; } static int _udevcreatecookie(CMD_ARGS) { uint32_t cookie; if (!dm_udev_create_cookie(&cookie)) return 0; if (cookie) printf("0x%08" PRIX32 "\n", cookie); return 1; } static int _udevreleasecookie(CMD_ARGS) { if (argv[1] && !(_udev_cookie = _get_cookie_value(argv[1]))) return 0; if (!_udev_cookie) { log_error("No udev transaction cookie given."); return 0; } return dm_udev_wait(_udev_cookie); } __attribute__((format(printf, 1, 2))) static char _yes_no_prompt(const char *prompt, ...) { int c = 0, ret = 0; va_list ap; do { if (c == '\n' || !c) { va_start(ap, prompt); vprintf(prompt, ap); va_end(ap); } if ((c = getchar()) == EOF) { ret = 'n'; break; } c = tolower(c); if ((c == 'y') || (c == 'n')) ret = c; } while (!ret || c != '\n'); if (c != '\n') printf("\n"); return ret; } static int _udevcomplete_all(CMD_ARGS) { int max_id, id, sid; struct seminfo sinfo; struct semid_ds sdata; int counter = 0; int skipped = 0; unsigned age = 0; time_t t; if (argc == 2 && (sscanf(argv[1], "%i", &age) != 1)) { log_error("Failed to read age_in_minutes parameter."); return 0; } if (!_switches[YES_ARG]) { log_warn("This operation will destroy all semaphores %s%.0d%swith keys " "that have a prefix %" PRIu16 " (0x%" PRIx16 ").", age ? "older than " : "", age, age ? " minutes " : "", DM_COOKIE_MAGIC, DM_COOKIE_MAGIC); if (_yes_no_prompt("Do you really want to continue? [y/n]: ") == 'n') { log_print("Semaphores with keys prefixed by %" PRIu16 " (0x%" PRIx16 ") NOT destroyed.", DM_COOKIE_MAGIC, DM_COOKIE_MAGIC); return 1; } } if ((max_id = semctl(0, 0, SEM_INFO, &sinfo)) < 0) { log_sys_error("semctl", "SEM_INFO"); return 0; } for (id = 0; id <= max_id; id++) { if ((sid = semctl(id, 0, SEM_STAT, &sdata)) < 0) continue; if (sdata.sem_perm.__key >> 16 == DM_COOKIE_MAGIC) { t = time(NULL); if (sdata.sem_ctime + age * 60 > t || sdata.sem_otime + age * 60 > t) { skipped++; continue; } if (semctl(sid, 0, IPC_RMID, 0) < 0) { log_error("Could not cleanup notification semaphore " "with semid %d and cookie value " "%" PRIu32 " (0x%" PRIx32 ")", sid, sdata.sem_perm.__key, sdata.sem_perm.__key); continue; } counter++; } } log_print("%d semaphores with keys prefixed by " "%" PRIu16 " (0x%" PRIx16 ") destroyed. %d skipped.", counter, DM_COOKIE_MAGIC, DM_COOKIE_MAGIC, skipped); return 1; } static int _udevcookies(CMD_ARGS) { int max_id, id, sid; struct seminfo sinfo; struct semid_ds sdata; int val; char otime_str[26], ctime_str[26]; char *otimes, *ctimes; if ((max_id = semctl(0, 0, SEM_INFO, &sinfo)) < 0) { log_sys_error("sem_ctl", "SEM_INFO"); return 0; } printf("Cookie Semid Value Last semop time Last change time\n"); for (id = 0; id <= max_id; id++) { if ((sid = semctl(id, 0, SEM_STAT, &sdata)) < 0) continue; if (sdata.sem_perm.__key >> 16 == DM_COOKIE_MAGIC) { if ((val = semctl(sid, 0, GETVAL)) < 0) { log_error("semid %d: sem_ctl failed for " "cookie 0x%" PRIx32 ": %s", sid, sdata.sem_perm.__key, strerror(errno)); continue; } if ((otimes = ctime_r((const time_t *) &sdata.sem_otime, (char *)&otime_str))) otime_str[strlen(otimes)-1] = '\0'; if ((ctimes = ctime_r((const time_t *) &sdata.sem_ctime, (char *)&ctime_str))) ctime_str[strlen(ctimes)-1] = '\0'; printf("0x%-10x %-10d %-10d %s %s\n", sdata.sem_perm.__key, sid, val, otimes ? : "unknown", ctimes? : "unknown"); } } return 1; } #endif /* UDEV_SYNC_SUPPORT */ static int _version(CMD_ARGS) { char version[80]; if (dm_get_library_version(version, sizeof(version))) printf("Library version: %s\n", version); if (!dm_driver_version(version, sizeof(version))) return 0; printf("Driver version: %s\n", version); return 1; } static int _simple(int task, const char *name, uint32_t event_nr, int display) { uint32_t cookie = 0; uint16_t udev_flags = 0; int udev_wait_flag = task == DM_DEVICE_RESUME || task == DM_DEVICE_REMOVE; int r = 0; struct dm_task *dmt; if (!(dmt = dm_task_create(task))) return 0; if (!_set_task_device(dmt, name, 0)) goto out; if (event_nr && !dm_task_set_event_nr(dmt, event_nr)) goto out; if (_switches[NOFLUSH_ARG] && !dm_task_no_flush(dmt)) goto out; if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt)) goto out; if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt)) goto out; if (_switches[NOLOCKFS_ARG] && !dm_task_skip_lockfs(dmt)) goto out; if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt)) goto out; /* FIXME: needs to coperate with udev */ if (!_set_task_add_node(dmt)) goto out; if (_switches[READAHEAD_ARG] && !dm_task_set_read_ahead(dmt, _int_args[READAHEAD_ARG], _read_ahead_flags)) goto out; if (_switches[NOUDEVRULES_ARG]) udev_flags |= DM_UDEV_DISABLE_DM_RULES_FLAG | DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG; if (_udev_cookie) cookie = _udev_cookie; if (_udev_only) udev_flags |= DM_UDEV_DISABLE_LIBRARY_FALLBACK; if (udev_wait_flag && !dm_task_set_cookie(dmt, &cookie, udev_flags)) goto out; if (_switches[RETRY_ARG] && task == DM_DEVICE_REMOVE) dm_task_retry_remove(dmt); r = dm_task_run(dmt); out: if (!_udev_cookie && udev_wait_flag) (void) dm_udev_wait(cookie); if (r && display && _switches[VERBOSE_ARG]) r = _display_info(dmt); dm_task_destroy(dmt); return r; } static int _suspend(CMD_ARGS) { return _simple(DM_DEVICE_SUSPEND, argc > 1 ? argv[1] : NULL, 0, 1); } static int _resume(CMD_ARGS) { return _simple(DM_DEVICE_RESUME, argc > 1 ? argv[1] : NULL, 0, 1); } static int _clear(CMD_ARGS) { return _simple(DM_DEVICE_CLEAR, argc > 1 ? argv[1] : NULL, 0, 1); } static int _wait(CMD_ARGS) { const char *name = NULL; if (!_switches[UUID_ARG] && !_switches[MAJOR_ARG]) { if (argc == 1) { err("No device specified."); return 0; } name = argv[1]; argc--, argv++; } return _simple(DM_DEVICE_WAITEVENT, name, (argc > 1) ? (uint32_t) atoi(argv[argc - 1]) : 0, 1); } static int _process_all(const struct command *cmd, int argc, char **argv, int silent, int (*fn) (CMD_ARGS)) { int r = 1; struct dm_names *names; unsigned next = 0; struct dm_task *dmt; if (!(dmt = dm_task_create(DM_DEVICE_LIST))) return 0; if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt)) goto out; if (!dm_task_run(dmt)) { r = 0; goto out; } if (!(names = dm_task_get_names(dmt))) { r = 0; goto out; } if (!names->dev) { if (!silent) printf("No devices found\n"); goto out; } do { names = (struct dm_names *)((char *) names + next); if (!fn(cmd, argc, argv, names, 1)) r = 0; next = names->next; } while (next); out: dm_task_destroy(dmt); return r; } static uint64_t _get_device_size(const char *name) { uint64_t start, length, size = UINT64_C(0); struct dm_info info; char *target_type, *params; struct dm_task *dmt; void *next = NULL; if (!(dmt = dm_task_create(DM_DEVICE_TABLE))) return 0; if (!_set_task_device(dmt, name, 0)) goto out; if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt)) goto out; if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt)) goto out; if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt)) goto out; if (!dm_task_run(dmt)) goto out; if (!dm_task_get_info(dmt, &info) || !info.exists) goto out; do { next = dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms); size += length; } while (next); out: dm_task_destroy(dmt); return size; } static int _error_device(CMD_ARGS) { struct dm_task *dmt; const char *name; uint64_t size; int r = 0; name = names ? names->name : argv[1]; size = _get_device_size(name); if (!(dmt = dm_task_create(DM_DEVICE_RELOAD))) return 0; if (!_set_task_device(dmt, name, 0)) goto error; if (!dm_task_add_target(dmt, UINT64_C(0), size, "error", "")) goto error; if (_switches[READ_ONLY] && !dm_task_set_ro(dmt)) goto error; if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt)) goto error; if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt)) goto error; if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt)) goto error; if (!dm_task_run(dmt)) goto error; if (!_simple(DM_DEVICE_RESUME, name, 0, 0)) { _simple(DM_DEVICE_CLEAR, name, 0, 0); goto error; } r = 1; error: dm_task_destroy(dmt); return r; } static int _remove(CMD_ARGS) { if (_switches[FORCE_ARG] && argc > 1) (void) _error_device(cmd, argc, argv, NULL, 0); return _simple(DM_DEVICE_REMOVE, argc > 1 ? argv[1] : NULL, 0, 0); } static int _count_devices(CMD_ARGS) { _num_devices++; return 1; } static int _remove_all(CMD_ARGS) { int r; /* Remove all closed devices */ r = _simple(DM_DEVICE_REMOVE_ALL, "", 0, 0) | dm_mknodes(NULL); if (!_switches[FORCE_ARG]) return r; _num_devices = 0; r |= _process_all(cmd, argc, argv, 1, _count_devices); /* No devices left? */ if (!_num_devices) return r; r |= _process_all(cmd, argc, argv, 1, _error_device); r |= _simple(DM_DEVICE_REMOVE_ALL, "", 0, 0) | dm_mknodes(NULL); _num_devices = 0; r |= _process_all(cmd, argc, argv, 1, _count_devices); if (!_num_devices) return r; fprintf(stderr, "Unable to remove %d device(s).\n", _num_devices); return r; } static void _display_dev(struct dm_task *dmt, const char *name) { struct dm_info info; if (dm_task_get_info(dmt, &info)) printf("%s\t(%u, %u)\n", name, info.major, info.minor); } static int _mknodes(CMD_ARGS) { return dm_mknodes(argc > 1 ? argv[1] : NULL); } static int _exec_command(const char *name) { int n; static char path[PATH_MAX]; static char *args[ARGS_MAX + 1]; static int argc = 0; char *c; pid_t pid; if (argc < 0) return 0; if (!dm_mknodes(name)) return 0; n = snprintf(path, sizeof(path), "%s/%s", dm_dir(), name); if (n < 0 || n > (int) sizeof(path) - 1) return 0; if (!argc) { c = _command; while (argc < ARGS_MAX) { while (*c && isspace(*c)) c++; if (!*c) break; args[argc++] = c; while (*c && !isspace(*c)) c++; if (*c) *c++ = '\0'; } if (!argc) { argc = -1; return 0; } if (argc == ARGS_MAX) { err("Too many args to --exec\n"); argc = -1; return 0; } args[argc++] = path; args[argc] = NULL; } if (!(pid = fork())) { execvp(args[0], args); _exit(127); } else if (pid < (pid_t) 0) return 0; TEMP_FAILURE_RETRY(waitpid(pid, NULL, 0)); return 1; } static int _status(CMD_ARGS) { int r = 0; struct dm_task *dmt; void *next = NULL; uint64_t start, length; char *target_type = NULL; char *params, *c; int cmdno; const char *name = NULL; int matched = 0; int ls_only = 0; struct dm_info info; if (names) name = names->name; else { if (argc == 1 && !_switches[UUID_ARG] && !_switches[MAJOR_ARG]) return _process_all(cmd, argc, argv, 0, _status); name = argv[1]; } if (!strcmp(cmd->name, "table")) cmdno = DM_DEVICE_TABLE; else cmdno = DM_DEVICE_STATUS; if (!strcmp(cmd->name, "ls")) ls_only = 1; if (!(dmt = dm_task_create(cmdno))) return 0; if (!_set_task_device(dmt, name, 0)) goto out; if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt)) goto out; if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt)) goto out; if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt)) goto out; if (_switches[NOFLUSH_ARG] && !dm_task_no_flush(dmt)) goto out; if (!dm_task_run(dmt)) goto out; if (!dm_task_get_info(dmt, &info) || !info.exists) goto out; if (!name) name = dm_task_get_name(dmt); /* Fetch targets and print 'em */ do { next = dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms); /* Skip if target type doesn't match */ if (_switches[TARGET_ARG] && (!target_type || strcmp(target_type, _target))) continue; if (ls_only) { if (!_switches[EXEC_ARG] || !_command || _switches[VERBOSE_ARG]) _display_dev(dmt, name); next = NULL; } else if (!_switches[EXEC_ARG] || !_command || _switches[VERBOSE_ARG]) { if (!matched && _switches[VERBOSE_ARG]) _display_info(dmt); if (multiple_devices && !_switches[VERBOSE_ARG]) printf("%s: ", name); if (target_type) { /* Suppress encryption key */ if (!_switches[SHOWKEYS_ARG] && cmdno == DM_DEVICE_TABLE && !strcmp(target_type, "crypt")) { c = params; while (*c && *c != ' ') c++; if (*c) c++; while (*c && *c != ' ') *c++ = '0'; } printf("%" PRIu64 " %" PRIu64 " %s %s", start, length, target_type, params); } printf("\n"); } matched = 1; } while (next); if (multiple_devices && _switches[VERBOSE_ARG] && matched && !ls_only) printf("\n"); if (matched && _switches[EXEC_ARG] && _command && !_exec_command(name)) goto out; r = 1; out: dm_task_destroy(dmt); return r; } /* Show target names and their version numbers */ static int _targets(CMD_ARGS) { int r = 0; struct dm_task *dmt; struct dm_versions *target; struct dm_versions *last_target; if (!(dmt = dm_task_create(DM_DEVICE_LIST_VERSIONS))) return 0; if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt)) goto out; if (!dm_task_run(dmt)) goto out; target = dm_task_get_versions(dmt); /* Fetch targets and print 'em */ do { last_target = target; printf("%-16s v%d.%d.%d\n", target->name, target->version[0], target->version[1], target->version[2]); target = (struct dm_versions *)((char *) target + target->next); } while (last_target != target); r = 1; out: dm_task_destroy(dmt); return r; } static int _info(CMD_ARGS) { int r = 0; struct dm_task *dmt; char *name = NULL; if (names) name = names->name; else { if (argc == 1 && !_switches[UUID_ARG] && !_switches[MAJOR_ARG]) return _process_all(cmd, argc, argv, 0, _info); name = argv[1]; } if (!(dmt = dm_task_create(DM_DEVICE_INFO))) return 0; if (!_set_task_device(dmt, name, 0)) goto out; if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt)) goto out; if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt)) goto out; if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt)) goto out; if (!dm_task_run(dmt)) goto out; r = _display_info(dmt); out: dm_task_destroy(dmt); return r; } static int _deps(CMD_ARGS) { int r = 0; uint32_t i; struct dm_deps *deps; struct dm_task *dmt; struct dm_info info; char *name = NULL; char dev_name[PATH_MAX]; int major, minor; if (names) name = names->name; else { if (argc == 1 && !_switches[UUID_ARG] && !_switches[MAJOR_ARG]) return _process_all(cmd, argc, argv, 0, _deps); name = argv[1]; } if (!(dmt = dm_task_create(DM_DEVICE_DEPS))) return 0; if (!_set_task_device(dmt, name, 0)) goto out; if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt)) goto out; if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt)) goto out; if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt)) goto out; if (!dm_task_run(dmt)) goto out; if (!dm_task_get_info(dmt, &info)) goto out; if (!(deps = dm_task_get_deps(dmt))) goto out; if (!info.exists) { printf("Device does not exist.\n"); r = 1; goto out; } if (_switches[VERBOSE_ARG]) _display_info(dmt); if (multiple_devices && !_switches[VERBOSE_ARG]) printf("%s: ", name); printf("%d dependencies\t:", deps->count); for (i = 0; i < deps->count; i++) { major = (int) MAJOR(deps->device[i]); minor = (int) MINOR(deps->device[i]); if ((_dev_name_type == DN_BLK || _dev_name_type == DN_MAP) && dm_device_get_name(major, minor, _dev_name_type == DN_BLK, dev_name, PATH_MAX)) printf(" (%s)", dev_name); else printf(" (%d, %d)", major, minor); } printf("\n"); if (multiple_devices && _switches[VERBOSE_ARG]) printf("\n"); r = 1; out: dm_task_destroy(dmt); return r; } static int _display_name(CMD_ARGS) { char dev_name[PATH_MAX]; if (!names) return 1; if ((_dev_name_type == DN_BLK || _dev_name_type == DN_MAP) && dm_device_get_name((int) MAJOR(names->dev), (int) MINOR(names->dev), _dev_name_type == DN_BLK, dev_name, PATH_MAX)) printf("%s\t(%s)\n", names->name, dev_name); else printf("%s\t(%d:%d)\n", names->name, (int) MAJOR(names->dev), (int) MINOR(names->dev)); return 1; } /* * Tree drawing code */ enum { TR_DEVICE=0, /* display device major:minor number */ TR_BLKDEVNAME, /* display device kernel name */ TR_TABLE, TR_STATUS, TR_ACTIVE, TR_RW, TR_OPENCOUNT, TR_UUID, TR_COMPACT, TR_TRUNCATE, TR_BOTTOMUP, NUM_TREEMODE, }; static int _tree_switches[NUM_TREEMODE]; #define TR_PRINT_ATTRIBUTE ( _tree_switches[TR_ACTIVE] || \ _tree_switches[TR_RW] || \ _tree_switches[TR_OPENCOUNT] || \ _tree_switches[TR_UUID] ) #define TR_PRINT_TARGETS ( _tree_switches[TR_TABLE] || \ _tree_switches[TR_STATUS] ) /* Compact - fewer newlines */ #define TR_PRINT_COMPACT (_tree_switches[TR_COMPACT] && \ !TR_PRINT_ATTRIBUTE && \ !TR_PRINT_TARGETS) /* FIXME Get rid of this */ #define MAX_DEPTH 100 /* Drawing character definition from pstree */ /* [pstree comment] UTF-8 defines by Johan Myreen, updated by Ben Winslow */ #define UTF_V "\342\224\202" /* U+2502, Vertical line drawing char */ #define UTF_VR "\342\224\234" /* U+251C, Vertical and right */ #define UTF_H "\342\224\200" /* U+2500, Horizontal */ #define UTF_UR "\342\224\224" /* U+2514, Up and right */ #define UTF_HD "\342\224\254" /* U+252C, Horizontal and down */ #define VT_BEG "\033(0\017" /* use graphic chars */ #define VT_END "\033(B" /* back to normal char set */ #define VT_V "x" /* see UTF definitions above */ #define VT_VR "t" #define VT_H "q" #define VT_UR "m" #define VT_HD "w" static struct { const char *empty_2; /* */ const char *branch_2; /* |- */ const char *vert_2; /* | */ const char *last_2; /* `- */ const char *single_3; /* --- */ const char *first_3; /* -+- */ } _tsym_ascii = { " ", "|-", "| ", "`-", "---", "-+-" }, _tsym_utf = { " ", UTF_VR UTF_H, UTF_V " ", UTF_UR UTF_H, UTF_H UTF_H UTF_H, UTF_H UTF_HD UTF_H }, _tsym_vt100 = { " ", VT_BEG VT_VR VT_H VT_END, VT_BEG VT_V VT_END " ", VT_BEG VT_UR VT_H VT_END, VT_BEG VT_H VT_H VT_H VT_END, VT_BEG VT_H VT_HD VT_H VT_END }, *_tsym = &_tsym_ascii; /* * Tree drawing functions. */ /* FIXME Get rid of these statics - use dynamic struct */ /* FIXME Explain what these vars are for */ static int _tree_width[MAX_DEPTH], _tree_more[MAX_DEPTH]; static int _termwidth = 80; /* Maximum output width */ static int _cur_x = 1; /* Current horizontal output position */ static char _last_char = 0; static void _out_char(const unsigned c) { /* Only first UTF-8 char counts */ _cur_x += ((c & 0xc0) != 0x80); if (!_tree_switches[TR_TRUNCATE]) { putchar((int) c); return; } /* Truncation? */ if (_cur_x <= _termwidth) putchar((int) c); if (_cur_x == _termwidth + 1 && ((c & 0xc0) != 0x80)) { if (_last_char || (c & 0x80)) { putchar('.'); putchar('.'); putchar('.'); } else { _last_char = c; _cur_x--; } } } static void _out_string(const char *str) { while (*str) _out_char((unsigned char) *str++); } /* non-negative integers only */ static unsigned _out_int(unsigned num) { unsigned digits = 0; unsigned divi; if (!num) { _out_char('0'); return 1; } /* non zero case */ for (divi = 1; num / divi; divi *= 10) digits++; for (divi /= 10; divi; divi /= 10) _out_char('0' + (num / divi) % 10); return digits; } static void _out_newline(void) { if (_last_char && _cur_x == _termwidth) putchar(_last_char); _last_char = 0; putchar('\n'); _cur_x = 1; } static void _out_prefix(unsigned depth) { unsigned x, d; for (d = 0; d < depth; d++) { for (x = _tree_width[d] + 1; x > 0; x--) _out_char(' '); _out_string(d == depth - 1 ? !_tree_more[depth] ? _tsym->last_2 : _tsym->branch_2 : _tree_more[d + 1] ? _tsym->vert_2 : _tsym->empty_2); } } /* * Display tree */ static void _display_tree_attributes(struct dm_tree_node *node) { int attr = 0; const char *uuid; const struct dm_info *info; uuid = dm_tree_node_get_uuid(node); info = dm_tree_node_get_info(node); if (!info->exists) return; if (_tree_switches[TR_ACTIVE]) { _out_string(attr++ ? ", " : " ["); _out_string(info->suspended ? "SUSPENDED" : "ACTIVE"); } if (_tree_switches[TR_RW]) { _out_string(attr++ ? ", " : " ["); _out_string(info->read_only ? "RO" : "RW"); } if (_tree_switches[TR_OPENCOUNT]) { _out_string(attr++ ? ", " : " ["); (void) _out_int((unsigned) info->open_count); } if (_tree_switches[TR_UUID]) { _out_string(attr++ ? ", " : " ["); _out_string(uuid && *uuid ? uuid : ""); } if (attr) _out_char(']'); } /* FIXME Display table or status line. (Disallow both?) */ static void _display_tree_targets(struct dm_tree_node *node, unsigned depth) { } static void _display_tree_node(struct dm_tree_node *node, unsigned depth, unsigned first_child __attribute__((unused)), unsigned last_child, unsigned has_children) { int offset; const char *name; const struct dm_info *info; int first_on_line = 0; char dev_name[PATH_MAX]; /* Sub-tree for targets has 2 more depth */ if (depth + 2 > MAX_DEPTH) return; name = dm_tree_node_get_name(node); if ((!name || !*name) && (!_tree_switches[TR_DEVICE] && !_tree_switches[TR_BLKDEVNAME])) return; /* Indicate whether there are more nodes at this depth */ _tree_more[depth] = !last_child; _tree_width[depth] = 0; if (_cur_x == 1) first_on_line = 1; if (!TR_PRINT_COMPACT || first_on_line) _out_prefix(depth); /* Remember the starting point for compact */ offset = _cur_x; if (TR_PRINT_COMPACT && !first_on_line) _out_string(_tree_more[depth] ? _tsym->first_3 : _tsym->single_3); /* display node */ if (name) _out_string(name); info = dm_tree_node_get_info(node); if (_tree_switches[TR_BLKDEVNAME] && dm_device_get_name(info->major, info->minor, 1, dev_name, PATH_MAX)) { _out_string(name ? " <" : "<"); _out_string(dev_name); _out_char('>'); } if (_tree_switches[TR_DEVICE]) { _out_string(name ? " (" : "("); (void) _out_int(info->major); _out_char(':'); (void) _out_int(info->minor); _out_char(')'); } /* display additional info */ if (TR_PRINT_ATTRIBUTE) _display_tree_attributes(node); if (TR_PRINT_COMPACT) _tree_width[depth] = _cur_x - offset; if (!TR_PRINT_COMPACT || !has_children) _out_newline(); if (TR_PRINT_TARGETS) { _tree_more[depth + 1] = has_children; _display_tree_targets(node, depth + 2); } } /* * Walk the dependency tree */ static void _display_tree_walk_children(struct dm_tree_node *node, unsigned depth) { struct dm_tree_node *child, *next_child; void *handle = NULL; uint32_t inverted = _tree_switches[TR_BOTTOMUP]; unsigned first_child = 1; unsigned has_children; next_child = dm_tree_next_child(&handle, node, inverted); while ((child = next_child)) { next_child = dm_tree_next_child(&handle, node, inverted); has_children = dm_tree_node_num_children(child, inverted) ? 1 : 0; _display_tree_node(child, depth, first_child, next_child ? 0U : 1U, has_children); if (has_children) _display_tree_walk_children(child, depth + 1); first_child = 0; } } static int _add_dep(CMD_ARGS) { if (names && !dm_tree_add_dev(_dtree, (unsigned) MAJOR(names->dev), (unsigned) MINOR(names->dev))) return 0; return 1; } /* * Create and walk dependency tree */ static int _build_whole_deptree(const struct command *cmd) { if (_dtree) return 1; if (!(_dtree = dm_tree_create())) return 0; if (!_process_all(cmd, 0, NULL, 0, _add_dep)) return 0; return 1; } static int _display_tree(CMD_ARGS) { if (!_build_whole_deptree(cmd)) return 0; _display_tree_walk_children(dm_tree_find_node(_dtree, 0, 0), 0); return 1; } /* * Report device information */ /* dm specific display functions */ static int _int32_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { const int32_t value = *(const int32_t *)data; return dm_report_field_int32(rh, field, &value); } static int _uint32_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { const uint32_t value = *(const int32_t *)data; return dm_report_field_uint32(rh, field, &value); } static int _dm_name_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { const char *name = dm_task_get_name((const struct dm_task *) data); return dm_report_field_string(rh, field, &name); } static int _dm_mangled_name_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { char *name; int r = 0; if ((name = dm_task_get_name_mangled((const struct dm_task *) data))) { r = dm_report_field_string(rh, field, (const char * const *) &name); dm_free(name); } return r; } static int _dm_unmangled_name_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { char *name; int r = 0; if ((name = dm_task_get_name_unmangled((const struct dm_task *) data))) { r = dm_report_field_string(rh, field, (const char * const *) &name); dm_free(name); } return r; } static int _dm_uuid_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { const char *uuid = dm_task_get_uuid((const struct dm_task *) data); if (!uuid || !*uuid) uuid = ""; return dm_report_field_string(rh, field, &uuid); } static int _dm_mangled_uuid_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { char *uuid; int r = 0; if ((uuid = dm_task_get_uuid_mangled((const struct dm_task *) data))) { r = dm_report_field_string(rh, field, (const char * const *) &uuid); dm_free(uuid); } return r; } static int _dm_unmangled_uuid_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { char *uuid; int r = 0; if ((uuid = dm_task_get_uuid_unmangled((const struct dm_task *) data))) { r = dm_report_field_string(rh, field, (const char * const *) &uuid); dm_free(uuid); } return r; } static int _dm_read_ahead_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { uint32_t value; if (!dm_task_get_read_ahead((const struct dm_task *) data, &value)) value = 0; return dm_report_field_uint32(rh, field, &value); } static int _dm_blk_name_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { char dev_name[PATH_MAX]; const char *s = dev_name; const struct dm_info *info = data; if (!dm_device_get_name(info->major, info->minor, 1, dev_name, PATH_MAX)) { log_error("Could not resolve block device name for %d:%d.", info->major, info->minor); return 0; } return dm_report_field_string(rh, field, &s); } static int _dm_info_status_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { char buf[5]; const char *s = buf; const struct dm_info *info = data; buf[0] = info->live_table ? 'L' : '-'; buf[1] = info->inactive_table ? 'I' : '-'; buf[2] = info->suspended ? 's' : '-'; buf[3] = info->read_only ? 'r' : 'w'; buf[4] = '\0'; return dm_report_field_string(rh, field, &s); } static int _dm_info_table_loaded_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { const struct dm_info *info = data; if (info->live_table) { if (info->inactive_table) dm_report_field_set_value(field, "Both", NULL); else dm_report_field_set_value(field, "Live", NULL); return 1; } if (info->inactive_table) dm_report_field_set_value(field, "Inactive", NULL); else dm_report_field_set_value(field, "None", NULL); return 1; } static int _dm_info_suspended_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { const struct dm_info *info = data; if (info->suspended) dm_report_field_set_value(field, "Suspended", NULL); else dm_report_field_set_value(field, "Active", NULL); return 1; } static int _dm_info_read_only_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { const struct dm_info *info = data; if (info->read_only) dm_report_field_set_value(field, "Read-only", NULL); else dm_report_field_set_value(field, "Writeable", NULL); return 1; } static int _dm_info_devno_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { char buf[PATH_MAX], *repstr; const struct dm_info *info = data; if (!dm_pool_begin_object(mem, 8)) { log_error("dm_pool_begin_object failed"); return 0; } if (private) { if (!dm_device_get_name(info->major, info->minor, 1, buf, PATH_MAX)) goto out_abandon; } else { if (dm_snprintf(buf, sizeof(buf), "%d:%d", info->major, info->minor) < 0) { log_error("dm_pool_alloc failed"); goto out_abandon; } } if (!dm_pool_grow_object(mem, buf, strlen(buf) + 1)) { log_error("dm_pool_grow_object failed"); goto out_abandon; } repstr = dm_pool_end_object(mem); dm_report_field_set_value(field, repstr, repstr); return 1; out_abandon: dm_pool_abandon_object(mem); return 0; } static int _dm_tree_names(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private, unsigned inverted) { const struct dm_tree_node *node = data; struct dm_tree_node *parent; void *t = NULL; const char *name; int first_node = 1; char *repstr; if (!dm_pool_begin_object(mem, 16)) { log_error("dm_pool_begin_object failed"); return 0; } while ((parent = dm_tree_next_child(&t, node, inverted))) { name = dm_tree_node_get_name(parent); if (!name || !*name) continue; if (!first_node && !dm_pool_grow_object(mem, ",", 1)) { log_error("dm_pool_grow_object failed"); goto out_abandon; } if (!dm_pool_grow_object(mem, name, 0)) { log_error("dm_pool_grow_object failed"); goto out_abandon; } if (first_node) first_node = 0; } if (!dm_pool_grow_object(mem, "\0", 1)) { log_error("dm_pool_grow_object failed"); goto out_abandon; } repstr = dm_pool_end_object(mem); dm_report_field_set_value(field, repstr, repstr); return 1; out_abandon: dm_pool_abandon_object(mem); return 0; } static int _dm_deps_names_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { return _dm_tree_names(rh, mem, field, data, private, 0); } static int _dm_tree_parents_names_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { return _dm_tree_names(rh, mem, field, data, private, 1); } static int _dm_tree_parents_devs_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { const struct dm_tree_node *node = data; struct dm_tree_node *parent; void *t = NULL; const struct dm_info *info; int first_node = 1; char buf[DM_MAX_TYPE_NAME], *repstr; if (!dm_pool_begin_object(mem, 16)) { log_error("dm_pool_begin_object failed"); return 0; } while ((parent = dm_tree_next_child(&t, node, 1))) { info = dm_tree_node_get_info(parent); if (!info->major && !info->minor) continue; if (!first_node && !dm_pool_grow_object(mem, ",", 1)) { log_error("dm_pool_grow_object failed"); goto out_abandon; } if (dm_snprintf(buf, sizeof(buf), "%d:%d", info->major, info->minor) < 0) { log_error("dm_snprintf failed"); goto out_abandon; } if (!dm_pool_grow_object(mem, buf, 0)) { log_error("dm_pool_grow_object failed"); goto out_abandon; } if (first_node) first_node = 0; } if (!dm_pool_grow_object(mem, "\0", 1)) { log_error("dm_pool_grow_object failed"); goto out_abandon; } repstr = dm_pool_end_object(mem); dm_report_field_set_value(field, repstr, repstr); return 1; out_abandon: dm_pool_abandon_object(mem); return 0; } static int _dm_tree_parents_count_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { const struct dm_tree_node *node = data; int num_parent = dm_tree_node_num_children(node, 1); return dm_report_field_int(rh, field, &num_parent); } static int _dm_deps_disp_common(struct dm_report *rh, struct dm_pool*mem, struct dm_report_field *field, const void *data, void *private, int disp_blk_dev_names) { const struct dm_deps *deps = data; char buf[PATH_MAX], *repstr; int major, minor; unsigned i; if (!dm_pool_begin_object(mem, 16)) { log_error("dm_pool_begin_object failed"); return 0; } for (i = 0; i < deps->count; i++) { major = (int) MAJOR(deps->device[i]); minor = (int) MINOR(deps->device[i]); if (disp_blk_dev_names) { if (!dm_device_get_name(major, minor, 1, buf, PATH_MAX)) { log_error("Could not resolve block device " "name for %d:%d.", major, minor); goto out_abandon; } } else if (dm_snprintf(buf, sizeof(buf), "%d:%d", major, minor) < 0) { log_error("dm_snprintf failed"); goto out_abandon; } if (!dm_pool_grow_object(mem, buf, 0)) { log_error("dm_pool_grow_object failed"); goto out_abandon; } if (i + 1 < deps->count && !dm_pool_grow_object(mem, ",", 1)) { log_error("dm_pool_grow_object failed"); goto out_abandon; } } if (!dm_pool_grow_object(mem, "\0", 1)) { log_error("dm_pool_grow_object failed"); goto out_abandon; } repstr = dm_pool_end_object(mem); dm_report_field_set_value(field, repstr, repstr); return 1; out_abandon: dm_pool_abandon_object(mem); return 0; } static int _dm_deps_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { return _dm_deps_disp_common(rh, mem, field, data, private, 0); } static int _dm_deps_blk_names_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { return _dm_deps_disp_common(rh, mem, field, data, private, 1); } static int _dm_subsystem_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { return dm_report_field_string(rh, field, (const char *const *) data); } static int _dm_vg_name_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { return dm_report_field_string(rh, field, (const char *const *) data); } static int _dm_lv_name_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { return dm_report_field_string(rh, field, (const char *const *) data); } static int _dm_lv_layer_name_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { return dm_report_field_string(rh, field, (const char *const *) data); } static void *_task_get_obj(void *obj) { return ((struct dmsetup_report_obj *)obj)->task; } static void *_info_get_obj(void *obj) { return ((struct dmsetup_report_obj *)obj)->info; } static void *_deps_get_obj(void *obj) { return dm_task_get_deps(((struct dmsetup_report_obj *)obj)->deps_task); } static void *_tree_get_obj(void *obj) { return ((struct dmsetup_report_obj *)obj)->tree_node; } static void *_split_name_get_obj(void *obj) { return ((struct dmsetup_report_obj *)obj)->split_name; } static const struct dm_report_object_type _report_types[] = { { DR_TASK, "Mapped Device Name", "", _task_get_obj }, { DR_INFO, "Mapped Device Information", "", _info_get_obj }, { DR_DEPS, "Mapped Device Relationship Information", "", _deps_get_obj }, { DR_TREE, "Mapped Device Relationship Information", "", _tree_get_obj }, { DR_NAME, "Mapped Device Name Components", "", _split_name_get_obj }, { 0, "", "", NULL }, }; /* Column definitions */ #define OFFSET_OF(strct, field) (((char*)&((struct strct*)0)->field) - (char*)0) #define STR (DM_REPORT_FIELD_TYPE_STRING) #define NUM (DM_REPORT_FIELD_TYPE_NUMBER) #define FIELD_O(type, strct, sorttype, head, field, width, func, id, desc) {DR_ ## type, sorttype, OFFSET_OF(strct, field), width, id, head, &_ ## func ## _disp, desc}, #define FIELD_F(type, sorttype, head, width, func, id, desc) {DR_ ## type, sorttype, 0, width, id, head, &_ ## func ## _disp, desc}, static const struct dm_report_field_type _report_fields[] = { /* *INDENT-OFF* */ FIELD_F(TASK, STR, "Name", 16, dm_name, "name", "Name of mapped device.") FIELD_F(TASK, STR, "MangledName", 16, dm_mangled_name, "mangled_name", "Mangled name of mapped device.") FIELD_F(TASK, STR, "UnmangledName", 16, dm_unmangled_name, "unmangled_name", "Unmangled name of mapped device.") FIELD_F(TASK, STR, "UUID", 32, dm_uuid, "uuid", "Unique (optional) identifier for mapped device.") FIELD_F(TASK, STR, "MangledUUID", 32, dm_mangled_uuid, "mangled_uuid", "Mangled unique (optional) identifier for mapped device.") FIELD_F(TASK, STR, "UnmangledUUID", 32, dm_unmangled_uuid, "unmangled_uuid", "Unmangled unique (optional) identifier for mapped device.") /* FIXME Next one should be INFO */ FIELD_F(TASK, NUM, "RAhead", 6, dm_read_ahead, "read_ahead", "Read ahead in sectors.") FIELD_F(INFO, STR, "BlkDevName", 16, dm_blk_name, "blkdevname", "Name of block device.") FIELD_F(INFO, STR, "Stat", 4, dm_info_status, "attr", "(L)ive, (I)nactive, (s)uspended, (r)ead-only, read-(w)rite.") FIELD_F(INFO, STR, "Tables", 6, dm_info_table_loaded, "tables_loaded", "Which of the live and inactive table slots are filled.") FIELD_F(INFO, STR, "Suspended", 9, dm_info_suspended, "suspended", "Whether the device is suspended.") FIELD_F(INFO, STR, "Read-only", 9, dm_info_read_only, "readonly", "Whether the device is read-only or writeable.") FIELD_F(INFO, STR, "DevNo", 5, dm_info_devno, "devno", "Device major and minor numbers") FIELD_O(INFO, dm_info, NUM, "Maj", major, 3, int32, "major", "Block device major number.") FIELD_O(INFO, dm_info, NUM, "Min", minor, 3, int32, "minor", "Block device minor number.") FIELD_O(INFO, dm_info, NUM, "Open", open_count, 4, int32, "open", "Number of references to open device, if requested.") FIELD_O(INFO, dm_info, NUM, "Targ", target_count, 4, int32, "segments", "Number of segments in live table, if present.") FIELD_O(INFO, dm_info, NUM, "Event", event_nr, 6, uint32, "events", "Number of most recent event.") FIELD_O(DEPS, dm_deps, NUM, "#Devs", count, 5, int32, "device_count", "Number of devices used by this one.") FIELD_F(TREE, STR, "DevNamesUsed", 16, dm_deps_names, "devs_used", "List of names of mapped devices used by this one.") FIELD_F(DEPS, STR, "DevNosUsed", 16, dm_deps, "devnos_used", "List of device numbers of devices used by this one.") FIELD_F(DEPS, STR, "BlkDevNamesUsed", 16, dm_deps_blk_names, "blkdevs_used", "List of names of block devices used by this one.") FIELD_F(TREE, NUM, "#Refs", 5, dm_tree_parents_count, "device_ref_count", "Number of mapped devices referencing this one.") FIELD_F(TREE, STR, "RefNames", 8, dm_tree_parents_names, "names_using_dev", "List of names of mapped devices using this one.") FIELD_F(TREE, STR, "RefDevNos", 9, dm_tree_parents_devs, "devnos_using_dev", "List of device numbers of mapped devices using this one.") FIELD_O(NAME, dm_split_name, STR, "Subsys", subsystem, 6, dm_subsystem, "subsystem", "Userspace subsystem responsible for this device.") FIELD_O(NAME, dm_split_name, STR, "VG", vg_name, 4, dm_vg_name, "vg_name", "LVM Volume Group name.") FIELD_O(NAME, dm_split_name, STR, "LV", lv_name, 4, dm_lv_name, "lv_name", "LVM Logical Volume name.") FIELD_O(NAME, dm_split_name, STR, "LVLayer", lv_layer, 7, dm_lv_layer_name, "lv_layer", "LVM device layer.") {0, 0, 0, 0, "", "", NULL, NULL}, /* *INDENT-ON* */ }; #undef STR #undef NUM #undef FIELD_O #undef FIELD_F static const char *default_report_options = "name,major,minor,attr,open,segments,events,uuid"; static const char *splitname_report_options = "vg_name,lv_name,lv_layer"; static int _report_init(const struct command *cmd) { char *options = (char *) default_report_options; const char *keys = ""; const char *separator = " "; int aligned = 1, headings = 1, buffered = 1, field_prefixes = 0; int quoted = 1, columns_as_rows = 0; uint32_t flags = 0; size_t len = 0; int r = 0; if (cmd && !strcmp(cmd->name, "splitname")) options = (char *) splitname_report_options; /* emulate old dmsetup behaviour */ if (_switches[NOHEADINGS_ARG]) { separator = ":"; aligned = 0; headings = 0; } if (_switches[UNBUFFERED_ARG]) buffered = 0; if (_switches[ROWS_ARG]) columns_as_rows = 1; if (_switches[UNQUOTED_ARG]) quoted = 0; if (_switches[NAMEPREFIXES_ARG]) { aligned = 0; field_prefixes = 1; } if (_switches[OPTIONS_ARG] && _string_args[OPTIONS_ARG]) { if (*_string_args[OPTIONS_ARG] != '+') options = _string_args[OPTIONS_ARG]; else { len = strlen(default_report_options) + strlen(_string_args[OPTIONS_ARG]) + 1; if (!(options = dm_malloc(len))) { err("Failed to allocate option string."); return 0; } if (dm_snprintf(options, len, "%s,%s", default_report_options, &_string_args[OPTIONS_ARG][1]) < 0) { err("snprintf failed"); goto out; } } } if (_switches[SORT_ARG] && _string_args[SORT_ARG]) { keys = _string_args[SORT_ARG]; buffered = 1; if (cmd && (!strcmp(cmd->name, "status") || !strcmp(cmd->name, "table"))) { err("--sort is not yet supported with status and table"); goto out; } } if (_switches[SEPARATOR_ARG] && _string_args[SEPARATOR_ARG]) { separator = _string_args[SEPARATOR_ARG]; aligned = 0; } if (aligned) flags |= DM_REPORT_OUTPUT_ALIGNED; if (buffered) flags |= DM_REPORT_OUTPUT_BUFFERED; if (headings) flags |= DM_REPORT_OUTPUT_HEADINGS; if (field_prefixes) flags |= DM_REPORT_OUTPUT_FIELD_NAME_PREFIX; if (!quoted) flags |= DM_REPORT_OUTPUT_FIELD_UNQUOTED; if (columns_as_rows) flags |= DM_REPORT_OUTPUT_COLUMNS_AS_ROWS; if (!(_report = dm_report_init(&_report_type, _report_types, _report_fields, options, separator, flags, keys, NULL))) goto out; if ((_report_type & DR_TREE) && !_build_whole_deptree(cmd)) { err("Internal device dependency tree creation failed."); goto out; } if (field_prefixes) dm_report_set_output_field_name_prefix(_report, "dm_"); r = 1; out: if (!strcasecmp(options, "help") || !strcmp(options, "?")) r = 1; if (len) dm_free(options); return r; } /* * List devices */ static int _ls(CMD_ARGS) { if ((_switches[TARGET_ARG] && _target) || (_switches[EXEC_ARG] && _command)) return _status(cmd, argc, argv, NULL, 0); else if ((_switches[TREE_ARG])) return _display_tree(cmd, 0, NULL, NULL, 0); else return _process_all(cmd, argc, argv, 0, _display_name); } static int _mangle(CMD_ARGS) { const char *name, *uuid; char *new_name = NULL, *new_uuid = NULL; struct dm_task *dmt; struct dm_info info; int r = 0; int target_format; if (names) name = names->name; else { if (argc == 1 && !_switches[UUID_ARG] && !_switches[MAJOR_ARG]) return _process_all(cmd, argc, argv, 0, _mangle); name = argv[1]; } if (!(dmt = dm_task_create(DM_DEVICE_STATUS))) return 0; if (!(_set_task_device(dmt, name, 0))) goto out; if (!_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt)) goto out; if (!dm_task_run(dmt)) goto out; if (!dm_task_get_info(dmt, &info) || !info.exists) goto out; uuid = dm_task_get_uuid(dmt); target_format = _switches[MANGLENAME_ARG] ? _int_args[MANGLENAME_ARG] : DEFAULT_DM_NAME_MANGLING; if (target_format == DM_STRING_MANGLING_AUTO) { if (strstr(name, "\\x5cx")) { log_error("The name \"%s\" seems to be mangled more than once. " "Manual intervention required to rename the device.", name); goto out; } if (strstr(uuid, "\\x5cx")) { log_error("The UUID \"%s\" seems to be mangled more than once. " "Manual intervention required to correct the device UUID.", uuid); goto out; } } if (target_format == DM_STRING_MANGLING_NONE) { if (!(new_name = dm_task_get_name_unmangled(dmt))) goto out; if (!(new_uuid = dm_task_get_uuid_unmangled(dmt))) goto out; } else { if (!(new_name = dm_task_get_name_mangled(dmt))) goto out; if (!(new_uuid = dm_task_get_uuid_mangled(dmt))) goto out; } /* We can't rename the UUID, the device must be reactivated manually. */ if (strcmp(uuid, new_uuid)) { log_error("%s: %s: UUID in incorrect form. ", name, uuid); log_error("Unable to change device UUID. The device must be deactivated first."); r = 0; goto out; } /* Nothing to do if the name is in correct form already. */ if (!strcmp(name, new_name)) { log_print("%s: %s: name %salready in correct form", name, *uuid ? uuid : "[no UUID]", *uuid ? "and UUID " : ""); r = 1; goto out; } else log_print("%s: renaming to %s", name, new_name); /* Rename to correct form of the name. */ r = _do_rename(name, new_name, NULL); out: dm_free(new_name); dm_free(new_uuid); dm_task_destroy(dmt); return r; } static int _help(CMD_ARGS); /* * Dispatch table */ static struct command _commands[] = { {"help", "[-c|-C|--columns]", 0, 0, 0, _help}, {"create", " [-j|--major -m|--minor ]\n" "\t [-U|--uid ] [-G|--gid ] [-M|--mode ]\n" "\t [-u|uuid ] [{--addnodeonresume|--addnodeoncreate}]\n" "\t [--notable | --table
| ]", 1, 2,0, _create}, {"remove", "[-f|--force] ", 0, -1, 1, _remove}, {"remove_all", "[-f|--force]", 0, 0, 0, _remove_all}, {"suspend", "[--noflush] ", 0, -1, 1, _suspend}, {"resume", " [{--addnodeonresume|--addnodeoncreate}]", 0, -1, 1, _resume}, {"load", " []", 0, 2, 0, _load}, {"clear", "", 0, -1, 1, _clear}, {"reload", " []", 0, 2, 0, _load}, {"wipe_table", "", 0, -1, 1, _error_device}, {"rename", " [--setuuid] ", 1, 2, 0, _rename}, {"message", " ", 2, -1, 0, _message}, {"ls", "[--target ] [--exec ] [-o options] [--tree]", 0, 0, 0, _ls}, {"info", "[]", 0, -1, 1, _info}, {"deps", "[-o options] []", 0, -1, 1, _deps}, {"status", "[] [--noflush] [--target ]", 0, -1, 1, _status}, {"table", "[] [--target ] [--showkeys]", 0, -1, 1, _status}, {"wait", " [] [--noflush]", 0, 2, 0, _wait}, {"mknodes", "[]", 0, -1, 1, _mknodes}, {"mangle", "[]", 0, -1, 1, _mangle}, {"udevcreatecookie", "", 0, 0, 0, _udevcreatecookie}, {"udevreleasecookie", "[]", 0, 1, 0, _udevreleasecookie}, {"udevflags", "", 1, 1, 0, _udevflags}, {"udevcomplete", "", 1, 1, 0, _udevcomplete}, {"udevcomplete_all", "", 0, 1, 0, _udevcomplete_all}, {"udevcookies", "", 0, 0, 0, _udevcookies}, {"targets", "", 0, 0, 0, _targets}, {"version", "", 0, 0, 0, _version}, {"setgeometry", " ", 5, 5, 0, _setgeometry}, {"splitname", " []", 1, 2, 0, _splitname}, {NULL, NULL, 0, 0, 0, NULL} }; static void _usage(FILE *out) { int i; fprintf(out, "Usage:\n\n"); fprintf(out, "dmsetup [--version] [-h|--help [-c|-C|--columns]]\n" " [--checks] [--manglename ] [-v|--verbose [-v|--verbose ...]]\n" " [-r|--readonly] [--noopencount] [--nolockfs] [--inactive]\n" " [--udevcookie [cookie]] [--noudevrules] [--noudevsync] [--verifyudev]\n" " [-y|--yes] [--readahead [+]|auto|none] [--retry]\n" " [-c|-C|--columns] [-o ] [-O|--sort ]\n" " [--nameprefixes] [--noheadings] [--separator ]\n\n"); for (i = 0; _commands[i].name; i++) fprintf(out, "\t%s %s\n", _commands[i].name, _commands[i].help); fprintf(out, "\n may be device name or -u or " "-j -m \n"); fprintf(out, " is one of 'none', 'auto' and 'hex'.\n"); fprintf(out, " are comma-separated. Use 'help -c' for list.\n"); fprintf(out, "Table_file contents may be supplied on stdin.\n"); fprintf(out, "Options are: devno, devname, blkdevname.\n"); fprintf(out, "Tree specific options are: ascii, utf, vt100; compact, inverted, notrunc;\n" " blkdevname, [no]device, active, open, rw and uuid.\n"); fprintf(out, "\n"); } static void _losetup_usage(FILE *out) { fprintf(out, "Usage:\n\n"); fprintf(out, "losetup [-d|-a] [-e encryption] " "[-o offset] [-f|loop_device] [file]\n\n"); } static int _help(CMD_ARGS) { _usage(stderr); if (_switches[COLS_ARG]) { _switches[OPTIONS_ARG] = 1; _string_args[OPTIONS_ARG] = (char *) "help"; _switches[SORT_ARG] = 0; if (_report) { dm_report_free(_report); _report = NULL; } (void) _report_init(cmd); } return 1; } static struct command *_find_command(const char *name) { int i; for (i = 0; _commands[i].name; i++) if (!strcmp(_commands[i].name, name)) return _commands + i; return NULL; } static int _process_tree_options(const char *options) { const char *s, *end; struct winsize winsz; size_t len; /* Symbol set default */ if (!strcmp(nl_langinfo(CODESET), "UTF-8")) _tsym = &_tsym_utf; else _tsym = &_tsym_ascii; /* Default */ _tree_switches[TR_DEVICE] = 1; _tree_switches[TR_TRUNCATE] = 1; /* parse */ for (s = options; s && *s; s++) { len = 0; for (end = s; *end && *end != ','; end++, len++) ; if (!strncmp(s, "device", len)) _tree_switches[TR_DEVICE] = 1; else if (!strncmp(s, "blkdevname", len)) _tree_switches[TR_BLKDEVNAME] = 1; else if (!strncmp(s, "nodevice", len)) _tree_switches[TR_DEVICE] = 0; else if (!strncmp(s, "status", len)) _tree_switches[TR_STATUS] = 1; else if (!strncmp(s, "table", len)) _tree_switches[TR_TABLE] = 1; else if (!strncmp(s, "active", len)) _tree_switches[TR_ACTIVE] = 1; else if (!strncmp(s, "open", len)) _tree_switches[TR_OPENCOUNT] = 1; else if (!strncmp(s, "uuid", len)) _tree_switches[TR_UUID] = 1; else if (!strncmp(s, "rw", len)) _tree_switches[TR_RW] = 1; else if (!strncmp(s, "utf", len)) _tsym = &_tsym_utf; else if (!strncmp(s, "vt100", len)) _tsym = &_tsym_vt100; else if (!strncmp(s, "ascii", len)) _tsym = &_tsym_ascii; else if (!strncmp(s, "inverted", len)) _tree_switches[TR_BOTTOMUP] = 1; else if (!strncmp(s, "compact", len)) _tree_switches[TR_COMPACT] = 1; else if (!strncmp(s, "notrunc", len)) _tree_switches[TR_TRUNCATE] = 0; else { fprintf(stderr, "Tree options not recognised: %s\n", s); return 0; } if (!*end) break; s = end; } /* Truncation doesn't work well with vt100 drawing char */ if (_tsym != &_tsym_vt100) if (ioctl(1, (unsigned long) TIOCGWINSZ, &winsz) >= 0 && winsz.ws_col > 3) _termwidth = winsz.ws_col - 3; return 1; } /* * Returns the full absolute path, or NULL if the path could * not be resolved. */ static char *_get_abspath(const char *path) { char *_path; #ifdef HAVE_CANONICALIZE_FILE_NAME _path = canonicalize_file_name(path); #else /* FIXME Provide alternative */ log_error(INTERNAL_ERROR "Unimplemented _get_abspath."); _path = NULL; #endif return _path; } static char *parse_loop_device_name(const char *dev, const char *dev_dir) { char *buf; char *device = NULL; if (!(buf = dm_malloc(PATH_MAX))) return NULL; if (dev[0] == '/') { if (!(device = _get_abspath(dev))) goto error; if (strncmp(device, dev_dir, strlen(dev_dir))) goto error; /* If dev_dir does not end in a slash, ensure that the following byte in the device string is "/". */ if (dev_dir[strlen(dev_dir) - 1] != '/' && device[strlen(dev_dir)] != '/') goto error; strncpy(buf, strrchr(device, '/') + 1, PATH_MAX - 1); buf[PATH_MAX - 1] = '\0'; dm_free(device); } else { /* check for device number */ if (!strncmp(dev, "loop", strlen("loop"))) strncpy(buf, dev, (size_t) PATH_MAX); else goto error; } return buf; error: dm_free(device); dm_free(buf); return NULL; } /* * create a table for a mapped device using the loop target. */ static int _loop_table(char *table, size_t tlen, char *file, char *dev __attribute__((unused)), off_t off) { struct stat fbuf; off_t size, sectors; int fd = -1; #ifdef HAVE_SYS_STATVFS_H struct statvfs fsbuf; off_t blksize; #endif if (!_switches[READ_ONLY]) fd = open(file, O_RDWR); if (fd < 0) { _switches[READ_ONLY]++; fd = open(file, O_RDONLY); } if (fd < 0) goto error; if (fstat(fd, &fbuf)) goto error; size = (fbuf.st_size - off); sectors = size >> SECTOR_SHIFT; if (_switches[VERBOSE_ARG]) fprintf(stderr, "losetup: set loop size to %llukB " "(%llu sectors)\n", (long long unsigned) sectors >> 1, (long long unsigned) sectors); #ifdef HAVE_SYS_STATVFS_H if (fstatvfs(fd, &fsbuf)) goto error; /* FIXME Fragment size currently unused */ blksize = fsbuf.f_frsize; #endif if (close(fd)) log_sys_error("close", file); if (dm_snprintf(table, tlen, "%llu %llu loop %s %llu\n", 0ULL, (long long unsigned)sectors, file, (long long unsigned)off) < 0) return 0; if (_switches[VERBOSE_ARG] > 1) fprintf(stderr, "Table: %s\n", table); return 1; error: if (fd > -1 && close(fd)) log_sys_error("close", file); return 0; } static int _process_losetup_switches(const char *base, int *argc, char ***argv, const char *dev_dir) { int c; int encrypt_loop = 0, delete = 0, find = 0, show_all = 0; char *device_name = NULL; char *loop_file = NULL; off_t offset = 0; #ifdef HAVE_GETOPTLONG static struct option long_options[] = { {0, 0, 0, 0} }; #endif optarg = 0; optind = OPTIND_INIT; while ((c = GETOPTLONG_FN(*argc, *argv, "ade:fo:v", long_options, NULL)) != -1 ) { if (c == ':' || c == '?') return 0; if (c == 'a') show_all++; if (c == 'd') delete++; if (c == 'e') encrypt_loop++; if (c == 'f') find++; if (c == 'o') offset = atoi(optarg); if (c == 'v') _switches[VERBOSE_ARG]++; } *argv += optind ; *argc -= optind ; if (encrypt_loop){ fprintf(stderr, "%s: Sorry, cryptoloop is not yet implemented " "in this version.\n", base); return 0; } if (show_all) { fprintf(stderr, "%s: Sorry, show all is not yet implemented " "in this version.\n", base); return 0; } if (find) { fprintf(stderr, "%s: Sorry, find is not yet implemented " "in this version.\n", base); if (!*argc) return 0; } if (!*argc) { fprintf(stderr, "%s: Please specify loop_device.\n", base); _losetup_usage(stderr); return 0; } if (!(device_name = parse_loop_device_name((*argv)[0], dev_dir))) { fprintf(stderr, "%s: Could not parse loop_device %s\n", base, (*argv)[0]); _losetup_usage(stderr); return 0; } if (delete) { *argc = 2; (*argv)[1] = device_name; (*argv)[0] = (char *) "remove"; return 1; } if (*argc != 2) { fprintf(stderr, "%s: Too few arguments\n", base); _losetup_usage(stderr); dm_free(device_name); return 0; } /* FIXME move these to make them available to native dmsetup */ if (!(loop_file = _get_abspath((*argv)[(find) ? 0 : 1]))) { fprintf(stderr, "%s: Could not parse loop file name %s\n", base, (*argv)[1]); _losetup_usage(stderr); dm_free(device_name); return 0; } _table = dm_malloc(LOOP_TABLE_SIZE); if (!_table || !_loop_table(_table, (size_t) LOOP_TABLE_SIZE, loop_file, device_name, offset)) { fprintf(stderr, "Could not build device-mapper table for %s\n", (*argv)[0]); dm_free(device_name); return 0; } _switches[TABLE_ARG]++; (*argv)[0] = (char *) "create"; (*argv)[1] = device_name ; return 1; } static int _process_options(const char *options) { const char *s, *end; size_t len; /* Tree options are processed separately. */ if (_switches[TREE_ARG]) return _process_tree_options(_string_args[OPTIONS_ARG]); /* Column options are processed separately by _report_init (called later). */ if (_switches[COLS_ARG]) return 1; /* No options specified. */ if (!_switches[OPTIONS_ARG]) return 1; /* Set defaults. */ _dev_name_type = DN_DEVNO; /* Parse. */ for (s = options; s && *s; s++) { len = 0; for (end = s; *end && *end != ','; end++, len++) ; if (!strncmp(s, "devno", len)) _dev_name_type = DN_DEVNO; else if (!strncmp(s, "blkdevname", len)) _dev_name_type = DN_BLK; else if (!strncmp(s, "devname", len)) _dev_name_type = DN_MAP; else { fprintf(stderr, "Option not recognised: %s\n", s); return 0; } if (!*end) break; s = end; } return 1; } static int _process_switches(int *argc, char ***argv, const char *dev_dir) { const char *base; char *namebase, *s; static int ind; int c, r; #ifdef HAVE_GETOPTLONG static struct option long_options[] = { {"readonly", 0, &ind, READ_ONLY}, {"checks", 0, &ind, CHECKS_ARG}, {"columns", 0, &ind, COLS_ARG}, {"exec", 1, &ind, EXEC_ARG}, {"force", 0, &ind, FORCE_ARG}, {"gid", 1, &ind, GID_ARG}, {"help", 0, &ind, HELP_ARG}, {"inactive", 0, &ind, INACTIVE_ARG}, {"manglename", 1, &ind, MANGLENAME_ARG}, {"major", 1, &ind, MAJOR_ARG}, {"minor", 1, &ind, MINOR_ARG}, {"mode", 1, &ind, MODE_ARG}, {"nameprefixes", 0, &ind, NAMEPREFIXES_ARG}, {"noflush", 0, &ind, NOFLUSH_ARG}, {"noheadings", 0, &ind, NOHEADINGS_ARG}, {"nolockfs", 0, &ind, NOLOCKFS_ARG}, {"noopencount", 0, &ind, NOOPENCOUNT_ARG}, {"notable", 0, &ind, NOTABLE_ARG}, {"udevcookie", 1, &ind, UDEVCOOKIE_ARG}, {"noudevrules", 0, &ind, NOUDEVRULES_ARG}, {"noudevsync", 0, &ind, NOUDEVSYNC_ARG}, {"options", 1, &ind, OPTIONS_ARG}, {"readahead", 1, &ind, READAHEAD_ARG}, {"retry", 0, &ind, RETRY_ARG}, {"rows", 0, &ind, ROWS_ARG}, {"separator", 1, &ind, SEPARATOR_ARG}, {"setuuid", 0, &ind, SETUUID_ARG}, {"showkeys", 0, &ind, SHOWKEYS_ARG}, {"sort", 1, &ind, SORT_ARG}, {"table", 1, &ind, TABLE_ARG}, {"target", 1, &ind, TARGET_ARG}, {"tree", 0, &ind, TREE_ARG}, {"uid", 1, &ind, UID_ARG}, {"uuid", 1, &ind, UUID_ARG}, {"unbuffered", 0, &ind, UNBUFFERED_ARG}, {"unquoted", 0, &ind, UNQUOTED_ARG}, {"verbose", 1, &ind, VERBOSE_ARG}, {"verifyudev", 0, &ind, VERIFYUDEV_ARG}, {"version", 0, &ind, VERSION_ARG}, {"yes", 0, &ind, YES_ARG}, {"addnodeonresume", 0, &ind, ADD_NODE_ON_RESUME_ARG}, {"addnodeoncreate", 0, &ind, ADD_NODE_ON_CREATE_ARG}, {0, 0, 0, 0} }; #else struct option long_options; #endif /* * Zero all the index counts. */ memset(&_switches, 0, sizeof(_switches)); memset(&_int_args, 0, sizeof(_int_args)); _read_ahead_flags = 0; if (!(namebase = strdup((*argv)[0]))) { fprintf(stderr, "Failed to duplicate name.\n"); return 0; } base = dm_basename(namebase); if (!strcmp(base, "devmap_name")) { free(namebase); _switches[COLS_ARG]++; _switches[NOHEADINGS_ARG]++; _switches[OPTIONS_ARG]++; _switches[MAJOR_ARG]++; _switches[MINOR_ARG]++; _string_args[OPTIONS_ARG] = (char *) "name"; if (*argc == 3) { _int_args[MAJOR_ARG] = atoi((*argv)[1]); _int_args[MINOR_ARG] = atoi((*argv)[2]); *argc -= 2; *argv += 2; } else if ((*argc == 2) && (2 == sscanf((*argv)[1], "%i:%i", &_int_args[MAJOR_ARG], &_int_args[MINOR_ARG]))) { *argc -= 1; *argv += 1; } else { fprintf(stderr, "Usage: devmap_name \n"); return 0; } (*argv)[0] = (char *) "info"; return 1; } if (!strcmp(base, "losetup") || !strcmp(base, "dmlosetup")){ r = _process_losetup_switches(base, argc, argv, dev_dir); free(namebase); return r; } free(namebase); optarg = 0; optind = OPTIND_INIT; while ((ind = -1, c = GETOPTLONG_FN(*argc, *argv, "cCfG:hj:m:M:no:O:ru:U:vy", long_options, NULL)) != -1) { if (c == ':' || c == '?') return 0; if (c == 'h' || ind == HELP_ARG) _switches[HELP_ARG]++; if (c == 'c' || c == 'C' || ind == COLS_ARG) _switches[COLS_ARG]++; if (c == 'f' || ind == FORCE_ARG) _switches[FORCE_ARG]++; if (c == 'r' || ind == READ_ONLY) _switches[READ_ONLY]++; if (c == 'j' || ind == MAJOR_ARG) { _switches[MAJOR_ARG]++; _int_args[MAJOR_ARG] = atoi(optarg); } if (c == 'm' || ind == MINOR_ARG) { _switches[MINOR_ARG]++; _int_args[MINOR_ARG] = atoi(optarg); } if (c == 'n' || ind == NOTABLE_ARG) _switches[NOTABLE_ARG]++; if (c == 'o' || ind == OPTIONS_ARG) { _switches[OPTIONS_ARG]++; _string_args[OPTIONS_ARG] = optarg; } if (ind == SEPARATOR_ARG) { _switches[SEPARATOR_ARG]++; _string_args[SEPARATOR_ARG] = optarg; } if (c == 'O' || ind == SORT_ARG) { _switches[SORT_ARG]++; _string_args[SORT_ARG] = optarg; } if (c == 'v' || ind == VERBOSE_ARG) _switches[VERBOSE_ARG]++; if (c == 'u' || ind == UUID_ARG) { _switches[UUID_ARG]++; _uuid = optarg; } if (c == 'y' || ind == YES_ARG) _switches[YES_ARG]++; if (ind == ADD_NODE_ON_RESUME_ARG) _switches[ADD_NODE_ON_RESUME_ARG]++; if (ind == ADD_NODE_ON_CREATE_ARG) _switches[ADD_NODE_ON_CREATE_ARG]++; if (ind == CHECKS_ARG) _switches[CHECKS_ARG]++; if (ind == UDEVCOOKIE_ARG) { _switches[UDEVCOOKIE_ARG]++; _udev_cookie = _get_cookie_value(optarg); } if (ind == NOUDEVRULES_ARG) _switches[NOUDEVRULES_ARG]++; if (ind == NOUDEVSYNC_ARG) _switches[NOUDEVSYNC_ARG]++; if (ind == VERIFYUDEV_ARG) _switches[VERIFYUDEV_ARG]++; if (c == 'G' || ind == GID_ARG) { _switches[GID_ARG]++; _int_args[GID_ARG] = atoi(optarg); } if (c == 'U' || ind == UID_ARG) { _switches[UID_ARG]++; _int_args[UID_ARG] = atoi(optarg); } if (c == 'M' || ind == MODE_ARG) { _switches[MODE_ARG]++; /* FIXME Accept modes as per chmod */ _int_args[MODE_ARG] = (int) strtol(optarg, NULL, 8); } if (ind == EXEC_ARG) { _switches[EXEC_ARG]++; _command = optarg; } if (ind == TARGET_ARG) { _switches[TARGET_ARG]++; _target = optarg; } if (ind == INACTIVE_ARG) _switches[INACTIVE_ARG]++; if ((ind == MANGLENAME_ARG)) { _switches[MANGLENAME_ARG]++; if (!strcasecmp(optarg, "none")) _int_args[MANGLENAME_ARG] = DM_STRING_MANGLING_NONE; else if (!strcasecmp(optarg, "auto")) _int_args[MANGLENAME_ARG] = DM_STRING_MANGLING_AUTO; else if (!strcasecmp(optarg, "hex")) _int_args[MANGLENAME_ARG] = DM_STRING_MANGLING_HEX; else { log_error("Unknown name mangling mode"); return 0; } dm_set_name_mangling_mode((dm_string_mangling_t) _int_args[MANGLENAME_ARG]); } if (ind == NAMEPREFIXES_ARG) _switches[NAMEPREFIXES_ARG]++; if (ind == NOFLUSH_ARG) _switches[NOFLUSH_ARG]++; if (ind == NOHEADINGS_ARG) _switches[NOHEADINGS_ARG]++; if (ind == NOLOCKFS_ARG) _switches[NOLOCKFS_ARG]++; if (ind == NOOPENCOUNT_ARG) _switches[NOOPENCOUNT_ARG]++; if (ind == READAHEAD_ARG) { _switches[READAHEAD_ARG]++; if (!strcasecmp(optarg, "auto")) _int_args[READAHEAD_ARG] = DM_READ_AHEAD_AUTO; else if (!strcasecmp(optarg, "none")) _int_args[READAHEAD_ARG] = DM_READ_AHEAD_NONE; else { for (s = optarg; isspace(*s); s++) ; if (*s == '+') _read_ahead_flags = DM_READ_AHEAD_MINIMUM_FLAG; _int_args[READAHEAD_ARG] = atoi(optarg); if (_int_args[READAHEAD_ARG] < -1) { log_error("Negative read ahead value " "(%d) is not understood.", _int_args[READAHEAD_ARG]); return 0; } } } if (ind == RETRY_ARG) _switches[RETRY_ARG]++; if (ind == ROWS_ARG) _switches[ROWS_ARG]++; if (ind == SETUUID_ARG) _switches[SETUUID_ARG]++; if (ind == SHOWKEYS_ARG) _switches[SHOWKEYS_ARG]++; if (ind == TABLE_ARG) { _switches[TABLE_ARG]++; if (!(_table = dm_strdup(optarg))) { log_error("Could not allocate memory for table string."); return 0; } } if (ind == TREE_ARG) _switches[TREE_ARG]++; if (ind == UNQUOTED_ARG) _switches[UNQUOTED_ARG]++; if (ind == VERSION_ARG) _switches[VERSION_ARG]++; } if (_switches[VERBOSE_ARG] > 1) dm_log_init_verbose(_switches[VERBOSE_ARG] - 1); if ((_switches[MAJOR_ARG] && !_switches[MINOR_ARG]) || (!_switches[MAJOR_ARG] && _switches[MINOR_ARG])) { fprintf(stderr, "Please specify both major number and " "minor number.\n"); return 0; } if (!_process_options(_string_args[OPTIONS_ARG])) return 0; if (_switches[TABLE_ARG] && _switches[NOTABLE_ARG]) { fprintf(stderr, "--table and --notable are incompatible.\n"); return 0; } if (_switches[ADD_NODE_ON_RESUME_ARG] && _switches[ADD_NODE_ON_CREATE_ARG]) { fprintf(stderr, "--addnodeonresume and --addnodeoncreate are incompatible.\n"); return 0; } *argv += optind; *argc -= optind; return 1; } int main(int argc, char **argv) { int r = 1; const char *dev_dir; const struct command *cmd; int multiple_devices; (void) setlocale(LC_ALL, ""); dev_dir = getenv (DM_DEV_DIR_ENV_VAR_NAME); if (dev_dir && *dev_dir) { if (!dm_set_dev_dir(dev_dir)) { fprintf(stderr, "Invalid DM_DEV_DIR environment variable value.\n"); goto out; } } else dev_dir = DEFAULT_DM_DEV_DIR; if (!_process_switches(&argc, &argv, dev_dir)) { fprintf(stderr, "Couldn't process command line.\n"); goto out; } if (_switches[HELP_ARG]) { cmd = _find_command("help"); goto doit; } if (_switches[VERSION_ARG]) { cmd = _find_command("version"); goto doit; } if (argc == 0) { _usage(stderr); goto out; } if (!(cmd = _find_command(argv[0]))) { fprintf(stderr, "Unknown command\n"); _usage(stderr); goto out; } if (argc < cmd->min_args + 1 || (cmd->max_args >= 0 && argc > cmd->max_args + 1)) { fprintf(stderr, "Incorrect number of arguments\n"); _usage(stderr); goto out; } if (!_switches[COLS_ARG] && !strcmp(cmd->name, "splitname")) _switches[COLS_ARG]++; if (!strcmp(cmd->name, "mangle")) dm_set_name_mangling_mode(DM_STRING_MANGLING_NONE); if (_switches[COLS_ARG]) { if (!_report_init(cmd)) goto out; if (!_report) { if (!strcmp(cmd->name, "info")) r = 0; /* info -c -o help */ goto out; } } #ifdef UDEV_SYNC_SUPPORT if (!_set_up_udev_support(dev_dir)) goto out; #endif doit: multiple_devices = (cmd->repeatable_cmd && argc != 2 && (argc != 1 || (!_switches[UUID_ARG] && !_switches[MAJOR_ARG]))); do { if (!cmd->fn(cmd, argc--, argv++, NULL, multiple_devices)) { fprintf(stderr, "Command failed\n"); goto out; } } while (cmd->repeatable_cmd && argc > 1); r = 0; out: if (_report) { dm_report_output(_report); dm_report_free(_report); } if (_dtree) dm_tree_free(_dtree); dm_free(_table); return r; } lvm2-2.02.98/tools/vgscan.c0000640000175000017500000000361612037016273014304 0ustar blankblank/* * 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 */ #include "tools.h" static int vgscan_single(struct cmd_context *cmd, const char *vg_name, struct volume_group *vg, void *handle __attribute__((unused))) { log_print_unless_silent("Found %svolume group \"%s\" using metadata type %s", vg_is_exported(vg) ? "exported " : "", vg_name, vg->fid->fmt->name); check_current_backup(vg); return ECMD_PROCESSED; } int vgscan(struct cmd_context *cmd, int argc, char **argv) { int maxret, ret; if (argc) { log_error("Too many parameters on command line"); return EINVALID_CMD_LINE; } if (!lock_vol(cmd, VG_GLOBAL, LCK_VG_WRITE)) { log_error("Unable to obtain global lock."); return ECMD_FAILED; } if (cmd->filter->wipe) cmd->filter->wipe(cmd->filter); lvmcache_destroy(cmd, 1); if (arg_count(cmd, cache_ARG)) { if (lvmetad_active()) { if (!lvmetad_pvscan_all_devs(cmd, NULL)) return ECMD_FAILED; } else { log_error("Cannot proceed since lvmetad is not active."); unlock_vg(cmd, VG_GLOBAL); return ECMD_FAILED; } } log_print_unless_silent("Reading all physical volumes. This may take a while..."); maxret = process_each_vg(cmd, argc, argv, 0, NULL, &vgscan_single); if (arg_count(cmd, mknodes_ARG)) { ret = vgmknodes(cmd, argc, argv); if (ret > maxret) maxret = ret; } unlock_vg(cmd, VG_GLOBAL); return maxret; } lvm2-2.02.98/tools/formats.c0000640000175000017500000000141112037016273014465 0ustar blankblank/* * 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 */ #include "tools.h" int formats(struct cmd_context *cmd, int argc __attribute__((unused)), char **argv __attribute__((unused))) { display_formats(cmd); return ECMD_PROCESSED; } lvm2-2.02.98/tools/lvresize.c0000640000175000017500000005774312037016273014700 0ustar blankblank/* * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU 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 "tools.h" #define SIZE_BUF 128 struct lvresize_params { const char *vg_name; const char *lv_name; uint32_t stripes; uint32_t stripe_size; uint32_t mirrors; const struct segment_type *segtype; /* size */ uint32_t extents; uint64_t size; sign_t sign; percent_type_t percent; enum { LV_ANY = 0, LV_REDUCE = 1, LV_EXTEND = 2 } resize; int resizefs; int nofsck; int argc; char **argv; }; static int _validate_stripesize(struct cmd_context *cmd, const struct volume_group *vg, struct lvresize_params *lp) { if (arg_sign_value(cmd, stripesize_ARG, SIGN_NONE) == SIGN_MINUS) { log_error("Stripesize may not be negative."); return 0; } if (arg_uint64_value(cmd, stripesize_ARG, 0) > STRIPE_SIZE_LIMIT * 2) { log_error("Stripe size cannot be larger than %s", display_size(cmd, (uint64_t) STRIPE_SIZE_LIMIT)); return 0; } if (!(vg->fid->fmt->features & FMT_SEGMENTS)) log_warn("Varied stripesize not supported. Ignoring."); else if (arg_uint_value(cmd, stripesize_ARG, 0) > (uint64_t) vg->extent_size * 2) { log_error("Reducing stripe size %s to maximum, " "physical extent size %s", display_size(cmd, (uint64_t) arg_uint_value(cmd, stripesize_ARG, 0)), display_size(cmd, (uint64_t) vg->extent_size)); lp->stripe_size = vg->extent_size; } else lp->stripe_size = arg_uint_value(cmd, stripesize_ARG, 0); if (lp->stripe_size & (lp->stripe_size - 1)) { log_error("Stripe size must be power of 2"); return 0; } return 1; } static int _request_confirmation(struct cmd_context *cmd, const struct volume_group *vg, const struct logical_volume *lv, const struct lvresize_params *lp) { struct lvinfo info = { 0 }; if (!lv_info(cmd, lv, 0, &info, 1, 0) && driver_version(NULL, 0)) { log_error("lv_info failed: aborting"); return 0; } if (lp->resizefs) { if (!info.exists) { log_error("Logical volume %s must be activated " "before resizing filesystem", lp->lv_name); return 0; } return 1; } if (!info.exists) return 1; log_warn("WARNING: Reducing active%s logical volume to %s", info.open_count ? " and open" : "", display_size(cmd, (uint64_t) lp->extents * vg->extent_size)); log_warn("THIS MAY DESTROY YOUR DATA (filesystem etc.)"); if (!arg_count(cmd, force_ARG)) { if (yes_no_prompt("Do you really want to reduce %s? [y/n]: ", lp->lv_name) == 'n') { log_error("Logical volume %s NOT reduced", lp->lv_name); return 0; } if (sigint_caught()) return 0; } return 1; } enum fsadm_cmd_e { FSADM_CMD_CHECK, FSADM_CMD_RESIZE }; #define FSADM_CMD "fsadm" #define FSADM_CMD_MAX_ARGS 6 #define FSADM_CHECK_FAILS_FOR_MOUNTED 3 /* shell exist status code */ /* * FSADM_CMD --dry-run --verbose --force check lv_path * FSADM_CMD --dry-run --verbose --force resize lv_path size */ static int _fsadm_cmd(struct cmd_context *cmd, const struct volume_group *vg, const struct lvresize_params *lp, enum fsadm_cmd_e fcmd, int *status) { char lv_path[PATH_MAX]; char size_buf[SIZE_BUF]; const char *argv[FSADM_CMD_MAX_ARGS + 2]; unsigned i = 0; argv[i++] = FSADM_CMD; if (test_mode()) argv[i++] = "--dry-run"; if (verbose_level() >= _LOG_NOTICE) argv[i++] = "--verbose"; if (arg_count(cmd, force_ARG)) argv[i++] = "--force"; argv[i++] = (fcmd == FSADM_CMD_RESIZE) ? "resize" : "check"; if (status) *status = -1; if (dm_snprintf(lv_path, PATH_MAX, "%s%s/%s", cmd->dev_dir, lp->vg_name, lp->lv_name) < 0) { log_error("Couldn't create LV path for %s", lp->lv_name); return 0; } argv[i++] = lv_path; if (fcmd == FSADM_CMD_RESIZE) { if (dm_snprintf(size_buf, SIZE_BUF, "%" PRIu64 "K", (uint64_t) lp->extents * vg->extent_size / 2) < 0) { log_error("Couldn't generate new LV size string"); return 0; } argv[i++] = size_buf; } argv[i] = NULL; return exec_cmd(cmd, argv, status, 1); } static int _lvresize_params(struct cmd_context *cmd, int argc, char **argv, struct lvresize_params *lp) { const char *cmd_name; char *st; unsigned dev_dir_found = 0; int use_policy = arg_count(cmd, use_policies_ARG); lp->sign = SIGN_NONE; lp->resize = LV_ANY; cmd_name = command_name(cmd); if (!strcmp(cmd_name, "lvreduce")) lp->resize = LV_REDUCE; if (!strcmp(cmd_name, "lvextend")) lp->resize = LV_EXTEND; if (use_policy) { /* do nothing; _lvresize will handle --use-policies itself */ lp->extents = 0; lp->sign = SIGN_PLUS; lp->percent = PERCENT_LV; } else { /* * Allow omission of extents and size if the user has given us * one or more PVs. Most likely, the intent was "resize this * LV the best you can with these PVs" */ if ((arg_count(cmd, extents_ARG) + arg_count(cmd, size_ARG) == 0) && (argc >= 2)) { lp->extents = 100; lp->percent = PERCENT_PVS; lp->sign = SIGN_PLUS; } else if ((arg_count(cmd, extents_ARG) + arg_count(cmd, size_ARG) != 1)) { log_error("Please specify either size or extents but not " "both."); return 0; } if (arg_count(cmd, extents_ARG)) { lp->extents = arg_uint_value(cmd, extents_ARG, 0); lp->sign = arg_sign_value(cmd, extents_ARG, SIGN_NONE); lp->percent = arg_percent_value(cmd, extents_ARG, PERCENT_NONE); } /* Size returned in kilobyte units; held in sectors */ if (arg_count(cmd, size_ARG)) { lp->size = arg_uint64_value(cmd, size_ARG, 0); lp->sign = arg_sign_value(cmd, size_ARG, SIGN_NONE); lp->percent = PERCENT_NONE; } } if (lp->resize == LV_EXTEND && lp->sign == SIGN_MINUS) { log_error("Negative argument not permitted - use lvreduce"); return 0; } if (lp->resize == LV_REDUCE && lp->sign == SIGN_PLUS) { log_error("Positive sign not permitted - use lvextend"); return 0; } lp->resizefs = arg_is_set(cmd, resizefs_ARG); lp->nofsck = arg_is_set(cmd, nofsck_ARG); if (!argc) { log_error("Please provide the logical volume name"); return 0; } lp->lv_name = argv[0]; argv++; argc--; if (!(lp->lv_name = skip_dev_dir(cmd, lp->lv_name, &dev_dir_found)) || !(lp->vg_name = extract_vgname(cmd, lp->lv_name))) { log_error("Please provide a volume group name"); return 0; } if (!validate_name(lp->vg_name)) { log_error("Volume group name %s has invalid characters", lp->vg_name); return 0; } if ((st = strrchr(lp->lv_name, '/'))) lp->lv_name = st + 1; lp->argc = argc; lp->argv = argv; return 1; } static int _adjust_policy_params(struct cmd_context *cmd, struct logical_volume *lv, struct lvresize_params *lp) { percent_t percent; int policy_threshold, policy_amount; if (lv_is_thin_pool(lv)) { policy_threshold = find_config_tree_int(cmd, "activation/thin_pool_autoextend_threshold", DEFAULT_THIN_POOL_AUTOEXTEND_THRESHOLD) * PERCENT_1; policy_amount = find_config_tree_int(cmd, "activation/thin_pool_autoextend_percent", DEFAULT_THIN_POOL_AUTOEXTEND_PERCENT); if (!policy_amount && policy_threshold < PERCENT_100) return 0; } else { policy_threshold = find_config_tree_int(cmd, "activation/snapshot_autoextend_threshold", DEFAULT_SNAPSHOT_AUTOEXTEND_THRESHOLD) * PERCENT_1; policy_amount = find_config_tree_int(cmd, "activation/snapshot_autoextend_percent", DEFAULT_SNAPSHOT_AUTOEXTEND_PERCENT); } if (policy_threshold >= PERCENT_100) return 1; /* nothing to do */ if (lv_is_thin_pool(lv)) { if (!lv_thin_pool_percent(lv, 1, &percent)) return_0; if (percent > policy_threshold) { /* FIXME: metadata resize support missing */ log_error("Resize for %s/%s is not yet supported.", lp->vg_name, lp->lv_name); return ECMD_FAILED; } if (!lv_thin_pool_percent(lv, 0, &percent)) return_0; if (!(PERCENT_0 < percent && percent <= PERCENT_100) || percent <= policy_threshold) return 1; /* nothing to do */ } else { if (!lv_snapshot_percent(lv, &percent)) return_0; if (!(PERCENT_0 < percent && percent < PERCENT_100) || percent <= policy_threshold) return 1; /* nothing to do */ } lp->extents = policy_amount; return 1; } static uint32_t lvseg_get_stripes(struct lv_segment *seg, uint32_t *stripesize) { uint32_t s; struct lv_segment *seg_mirr; /* If segment mirrored, check if images are striped */ if (seg_is_mirrored(seg)) for (s = 0; s < seg->area_count; s++) { if (seg_type(seg, s) != AREA_LV) continue; seg_mirr = first_seg(seg_lv(seg, s)); if (seg_is_striped(seg_mirr)) { seg = seg_mirr; break; } } if (seg_is_striped(seg)) { *stripesize = seg->stripe_size; return seg->area_count; } *stripesize = 0; return 0; } static int _lvresize(struct cmd_context *cmd, struct volume_group *vg, struct lvresize_params *lp) { struct logical_volume *lv; struct lvinfo info; uint32_t stripesize_extents; uint32_t seg_stripes = 0, seg_stripesize = 0, seg_size; uint32_t seg_mirrors = 0; uint32_t extents_used; uint32_t size_rest; uint32_t pv_extent_count; alloc_policy_t alloc; struct logical_volume *lock_lv; struct lv_list *lvl; struct lv_segment *seg, *uninitialized_var(mirr_seg); uint32_t seg_extents; uint32_t sz, str; int status; struct dm_list *pvh = NULL; int use_policy = arg_count(cmd, use_policies_ARG); /* does LV exist? */ if (!(lvl = find_lv_in_vg(vg, lp->lv_name))) { log_error("Logical volume %s not found in volume group %s", lp->lv_name, lp->vg_name); return ECMD_FAILED; } if (lvl->lv->status & (RAID_IMAGE | RAID_META)) { log_error("Cannot resize a RAID %s directly", (lvl->lv->status & RAID_IMAGE) ? "image" : "metadata area"); return ECMD_FAILED; } if (lv_is_raid_with_tracking(lvl->lv)) { log_error("Cannot resize %s while it is tracking a split image", lvl->lv->name); return ECMD_FAILED; } if (arg_count(cmd, stripes_ARG)) { if (vg->fid->fmt->features & FMT_SEGMENTS) lp->stripes = arg_uint_value(cmd, stripes_ARG, 1); else log_warn("Varied striping not supported. Ignoring."); } if (arg_count(cmd, mirrors_ARG)) { if (vg->fid->fmt->features & FMT_SEGMENTS) lp->mirrors = arg_uint_value(cmd, mirrors_ARG, 1) + 1; else log_warn("Mirrors not supported. Ignoring."); if (arg_sign_value(cmd, mirrors_ARG, SIGN_NONE) == SIGN_MINUS) { log_error("Mirrors argument may not be negative"); return EINVALID_CMD_LINE; } } if (arg_count(cmd, stripesize_ARG) && !_validate_stripesize(cmd, vg, lp)) return EINVALID_CMD_LINE; lv = lvl->lv; if (use_policy) { if (!lv_is_cow(lv) && !lv_is_thin_pool(lv)) { log_error("Policy-based resize is supported only for snapshot and thin pool volumes."); return ECMD_FAILED; } if (!_adjust_policy_params(cmd, lv, lp)) return ECMD_FAILED; } if (!lv_is_visible(lv)) { log_error("Can't resize internal logical volume %s", lv->name); return ECMD_FAILED; } if (lv->status & LOCKED) { log_error("Can't resize locked LV %s", lv->name); return ECMD_FAILED; } if (lv->status & CONVERTING) { log_error("Can't resize %s while lvconvert in progress", lv->name); return ECMD_FAILED; } alloc = (alloc_policy_t) arg_uint_value(cmd, alloc_ARG, lv->alloc); /* * First adjust to an exact multiple of extent size. * When extending by a relative amount we round that amount up. * When reducing by a relative amount we remove at most that amount. * When changing to an absolute size, we round that size up. */ if (lp->size) { if (lp->size % vg->extent_size) { if (lp->sign == SIGN_MINUS) lp->size -= lp->size % vg->extent_size; else lp->size += vg->extent_size - (lp->size % vg->extent_size); log_print_unless_silent("Rounding size to boundary between physical extents: %s", display_size(cmd, lp->size)); } lp->extents = lp->size / vg->extent_size; } if (!(pvh = lp->argc ? create_pv_list(cmd->mem, vg, lp->argc, lp->argv, 1) : &vg->pvs)) { stack; return ECMD_FAILED; } switch(lp->percent) { case PERCENT_VG: lp->extents = percent_of_extents(lp->extents, vg->extent_count, (lp->sign != SIGN_MINUS)); break; case PERCENT_FREE: lp->extents = percent_of_extents(lp->extents, vg->free_count, (lp->sign != SIGN_MINUS)); break; case PERCENT_LV: lp->extents = percent_of_extents(lp->extents, lv->le_count, (lp->sign != SIGN_MINUS)); break; case PERCENT_PVS: if (lp->argc) { pv_extent_count = pv_list_extents_free(pvh); lp->extents = percent_of_extents(lp->extents, pv_extent_count, (lp->sign != SIGN_MINUS)); } else lp->extents = percent_of_extents(lp->extents, vg->extent_count, (lp->sign != SIGN_MINUS)); break; case PERCENT_ORIGIN: if (!lv_is_cow(lv)) { log_error("Specified LV does not have an origin LV."); return EINVALID_CMD_LINE; } lp->extents = percent_of_extents(lp->extents, origin_from_cow(lv)->le_count, (lp->sign != SIGN_MINUS)); break; case PERCENT_NONE: break; } if (lp->sign == SIGN_PLUS) { if (lp->extents >= (MAX_EXTENT_COUNT - lv->le_count)) { log_error("Unable to extend %s by %u extents, exceeds limit (%u).", lp->lv_name, lv->le_count, MAX_EXTENT_COUNT); return EINVALID_CMD_LINE; } lp->extents += lv->le_count; } if (lp->sign == SIGN_MINUS) { if (lp->extents >= lv->le_count) { log_error("Unable to reduce %s below 1 extent", lp->lv_name); return EINVALID_CMD_LINE; } lp->extents = lv->le_count - lp->extents; } if (!lp->extents) { log_error("New size of 0 not permitted"); return EINVALID_CMD_LINE; } if (lp->extents == lv->le_count) { if (use_policy) return ECMD_PROCESSED; /* Nothing to do. */ if (!lp->resizefs) { log_error("New size (%d extents) matches existing size " "(%d extents)", lp->extents, lv->le_count); return EINVALID_CMD_LINE; } lp->resize = LV_EXTEND; /* lets pretend zero size extension */ } seg_size = lp->extents - lv->le_count; /* Use segment type of last segment */ dm_list_iterate_items(seg, &lv->segments) { lp->segtype = seg->segtype; } /* FIXME Support LVs with mixed segment types */ if (lp->segtype != get_segtype_from_string(cmd, arg_str_value(cmd, type_ARG, lp->segtype->name))) { log_error("VolumeType does not match (%s)", lp->segtype->name); return EINVALID_CMD_LINE; } /* If extending, find mirrors of last segment */ if ((lp->extents > lv->le_count)) { /* * Has the user specified that they would like the additional * extents of a mirror not to have an initial sync? */ if (seg_is_mirrored(first_seg(lv)) && arg_count(cmd, nosync_ARG)) lv->status |= LV_NOTSYNCED; dm_list_iterate_back_items(mirr_seg, &lv->segments) { if (seg_is_mirrored(mirr_seg)) seg_mirrors = lv_mirror_count(mirr_seg->lv); else seg_mirrors = 0; break; } if (!arg_count(cmd, mirrors_ARG) && seg_mirrors) { log_print_unless_silent("Extending %" PRIu32 " mirror images.", seg_mirrors); lp->mirrors = seg_mirrors; } if ((arg_count(cmd, mirrors_ARG) || seg_mirrors) && (lp->mirrors != seg_mirrors)) { log_error("Cannot vary number of mirrors in LV yet."); return EINVALID_CMD_LINE; } if (seg_mirrors && !strcmp(mirr_seg->segtype->name, "raid10")) { lp->stripes = mirr_seg->area_count / seg_mirrors; lp->stripe_size = mirr_seg->stripe_size; } } /* If extending, find stripes, stripesize & size of last segment */ if ((lp->extents > lv->le_count) && !(lp->stripes == 1 || (lp->stripes > 1 && lp->stripe_size)) && strcmp(mirr_seg->segtype->name, "raid10")) { /* FIXME Don't assume mirror seg will always be AREA_LV */ /* FIXME We will need to support resize for metadata LV as well, * and data LV could be any type (i.e. mirror)) */ dm_list_iterate_items(seg, seg_mirrors ? &seg_lv(mirr_seg, 0)->segments : lv_is_thin_pool(lv) ? &seg_lv(first_seg(lv), 0)->segments : &lv->segments) { /* Allow through "striped" and RAID 4/5/6/10 */ if (!seg_is_striped(seg) && (!seg_is_raid(seg) || seg_is_mirrored(seg)) && strcmp(seg->segtype->name, "raid10")) continue; sz = seg->stripe_size; str = seg->area_count - lp->segtype->parity_devs; if ((seg_stripesize && seg_stripesize != sz && sz && !lp->stripe_size) || (seg_stripes && seg_stripes != str && !lp->stripes)) { log_error("Please specify number of " "stripes (-i) and stripesize (-I)"); return EINVALID_CMD_LINE; } seg_stripesize = sz; seg_stripes = str; } if (!lp->stripes) lp->stripes = seg_stripes; else if (seg_is_raid(first_seg(lv)) && (lp->stripes != seg_stripes)) { log_error("Unable to extend \"%s\" segment type with different number of stripes.", first_seg(lv)->segtype->ops->name(first_seg(lv))); return ECMD_FAILED; } if (!lp->stripe_size && lp->stripes > 1) { if (seg_stripesize) { log_print_unless_silent("Using stripesize of last segment %s", display_size(cmd, (uint64_t) seg_stripesize)); lp->stripe_size = seg_stripesize; } else { lp->stripe_size = find_config_tree_int(cmd, "metadata/stripesize", DEFAULT_STRIPESIZE) * 2; log_print_unless_silent("Using default stripesize %s", display_size(cmd, (uint64_t) lp->stripe_size)); } } } /* If reducing, find stripes, stripesize & size of last segment */ if (lp->extents < lv->le_count) { extents_used = 0; if (lp->stripes || lp->stripe_size || lp->mirrors) log_error("Ignoring stripes, stripesize and mirrors " "arguments when reducing"); dm_list_iterate_items(seg, &lv->segments) { seg_extents = seg->len; /* Check for underlying stripe sizes */ seg_stripes = lvseg_get_stripes(seg, &seg_stripesize); if (seg_is_mirrored(seg)) seg_mirrors = lv_mirror_count(seg->lv); else seg_mirrors = 0; if (lp->extents <= extents_used + seg_extents) break; extents_used += seg_extents; } seg_size = lp->extents - extents_used; lp->stripe_size = seg_stripesize; lp->stripes = seg_stripes; lp->mirrors = seg_mirrors; } if (lp->stripes > 1 && !lp->stripe_size) { log_error("Stripesize for striped segment should not be 0!"); return EINVALID_CMD_LINE; } if (lp->stripes > 1) { if (lp->stripe_size < STRIPE_SIZE_MIN) { log_error("Invalid stripe size %s", display_size(cmd, (uint64_t) lp->stripe_size)); return EINVALID_CMD_LINE; } if (!(stripesize_extents = lp->stripe_size / vg->extent_size)) stripesize_extents = 1; size_rest = seg_size % (lp->stripes * stripesize_extents); /* Round toward the original size. */ if (size_rest && ((lp->extents < lv->le_count) || !lp->percent || (vg->free_count >= (lp->extents - lv->le_count - size_rest + (lp->stripes * stripesize_extents))))) { log_print_unless_silent("Rounding size (%d extents) up to stripe " "boundary size for segment (%d extents)", lp->extents, lp->extents - size_rest + (lp->stripes * stripesize_extents)); lp->extents = lp->extents - size_rest + (lp->stripes * stripesize_extents); } else if (size_rest) { log_print_unless_silent("Rounding size (%d extents) down to stripe " "boundary size for segment (%d extents)", lp->extents, lp->extents - size_rest); lp->extents = lp->extents - size_rest; } } if (lp->extents < lv->le_count) { if (lp->resize == LV_EXTEND) { log_error("New size given (%d extents) not larger " "than existing size (%d extents)", lp->extents, lv->le_count); return EINVALID_CMD_LINE; } lp->resize = LV_REDUCE; } else if (lp->extents > lv->le_count) { if (lp->resize == LV_REDUCE) { log_error("New size given (%d extents) not less than " "existing size (%d extents)", lp->extents, lv->le_count); return EINVALID_CMD_LINE; } lp->resize = LV_EXTEND; } else if (lp->extents == lv->le_count) { if (use_policy) return ECMD_PROCESSED; /* Nothing to do. */ if (!lp->resizefs) { log_error("New size (%d extents) matches existing size " "(%d extents)", lp->extents, lv->le_count); return EINVALID_CMD_LINE; } lp->resize = LV_EXTEND; } if (lv_is_origin(lv)) { if (lp->resize == LV_REDUCE) { log_error("Snapshot origin volumes cannot be reduced " "in size yet."); return ECMD_FAILED; } if (lv_info(cmd, lv, 0, &info, 0, 0) && info.exists) { log_error("Snapshot origin volumes can be resized " "only while inactive: try lvchange -an"); return ECMD_FAILED; } } if (lv_is_thin_pool(lv)) { if (lp->resize == LV_REDUCE) { log_error("Thin pool volumes cannot be reduced in size yet."); return ECMD_FAILED; } if (lp->resizefs) { log_warn("Thin pool volumes do not have filesystem."); lp->resizefs = 0; } } if ((lp->resize == LV_REDUCE) && lp->argc) log_warn("Ignoring PVs on command line when reducing"); /* Request confirmation before operations that are often mistakes. */ if ((lp->resizefs || (lp->resize == LV_REDUCE)) && !_request_confirmation(cmd, vg, lv, lp)) { stack; return ECMD_FAILED; } if (lp->resizefs) { if (!lp->nofsck && !_fsadm_cmd(cmd, vg, lp, FSADM_CMD_CHECK, &status)) { if (status != FSADM_CHECK_FAILS_FOR_MOUNTED) { log_error("Filesystem check failed."); return ECMD_FAILED; } /* some filesystems supports online resize */ } if ((lp->resize == LV_REDUCE) && !_fsadm_cmd(cmd, vg, lp, FSADM_CMD_RESIZE, NULL)) { log_error("Filesystem resize failed."); return ECMD_FAILED; } } if (!archive(vg)) { stack; return ECMD_FAILED; } log_print_unless_silent("%sing logical volume %s to %s", (lp->resize == LV_REDUCE) ? "Reduc" : "Extend", lp->lv_name, display_size(cmd, (uint64_t) lp->extents * vg->extent_size)); if (lp->resize == LV_REDUCE) { if (!lv_reduce(lv, lv->le_count - lp->extents)) { stack; return ECMD_FAILED; } } else if ((lp->extents > lv->le_count) && /* Ensure we extend */ !lv_extend(lv, lp->segtype, lp->stripes, lp->stripe_size, lp->mirrors, first_seg(lv)->region_size, lp->extents - lv->le_count, NULL, pvh, alloc)) { stack; return ECMD_FAILED; } /* store vg on disk(s) */ if (!vg_write(vg)) { stack; return ECMD_FAILED; } /* If snapshot, must suspend all associated devices */ if (lv_is_cow(lv)) lock_lv = origin_from_cow(lv); else lock_lv = lv; if (!suspend_lv(cmd, lock_lv)) { log_error("Failed to suspend %s", lp->lv_name); vg_revert(vg); backup(vg); return ECMD_FAILED; } if (!vg_commit(vg)) { stack; if (!resume_lv(cmd, lock_lv)) stack; backup(vg); return ECMD_FAILED; } if (!resume_lv(cmd, lock_lv)) { log_error("Problem reactivating %s", lp->lv_name); backup(vg); return ECMD_FAILED; } backup(vg); /* * Update lvm pool metadata (drop messages) if the pool has been * resumed and do a pool active/deactivate in other case. * * Note: Active thin pool can be waiting for resize. * * FIXME: Activate only when thin volume is active */ if (lv_is_thin_pool(lv) && !update_pool_lv(lv, !lv_is_active(lv))) { stack; return ECMD_FAILED; } log_print_unless_silent("Logical volume %s successfully resized", lp->lv_name); if (lp->resizefs && (lp->resize == LV_EXTEND) && !_fsadm_cmd(cmd, vg, lp, FSADM_CMD_RESIZE, NULL)) { stack; return ECMD_FAILED; } return ECMD_PROCESSED; } int lvresize(struct cmd_context *cmd, int argc, char **argv) { struct lvresize_params lp = { 0 }; struct volume_group *vg; int r; if (!_lvresize_params(cmd, argc, argv, &lp)) return EINVALID_CMD_LINE; log_verbose("Finding volume group %s", lp.vg_name); vg = vg_read_for_update(cmd, lp.vg_name, NULL, 0); if (vg_read_error(vg)) { release_vg(vg); stack; return ECMD_FAILED; } if (!(r = _lvresize(cmd, vg, &lp))) stack; unlock_and_release_vg(cmd, vg, lp.vg_name); return r; } lvm2-2.02.98/tools/pvdisplay.c0000640000175000017500000000620512037016273015033 0ustar blankblank/* * 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 "tools.h" static int _pvdisplay_single(struct cmd_context *cmd, struct volume_group *vg, struct physical_volume *pv, void *handle) { struct pv_list *pvl; int ret = ECMD_PROCESSED; uint64_t size; struct volume_group *old_vg = vg; const char *pv_name = pv_dev_name(pv); const char *vg_name = NULL; if (!is_orphan(pv) && !vg) { vg_name = pv_vg_name(pv); vg = vg_read(cmd, vg_name, (char *)&pv->vgid, 0); if (vg_read_error(vg)) { log_error("Skipping volume group %s", vg_name); release_vg(vg); /* FIXME If CLUSTERED should return ECMD_PROCESSED here */ return ECMD_FAILED; } /* * Replace possibly incomplete PV structure with new one * allocated in vg_read_internal() path. */ if (!(pvl = find_pv_in_vg(vg, pv_name))) { log_error("Unable to find \"%s\" in volume group \"%s\"", pv_name, vg->name); ret = ECMD_FAILED; goto out; } pv = pvl->pv; } if (is_orphan(pv)) size = pv_size(pv); else size = (uint64_t)(pv_pe_count(pv) - pv_pe_alloc_count(pv)) * pv_pe_size(pv); if (arg_count(cmd, short_ARG)) { log_print("Device \"%s\" has a capacity of %s", pv_name, display_size(cmd, size)); goto out; } if (pv_status(pv) & EXPORTED_VG) log_print("Physical volume \"%s\" of volume group \"%s\" " "is exported", pv_name, pv_vg_name(pv)); if (is_orphan(pv)) log_print("\"%s\" is a new physical volume of \"%s\"", pv_name, display_size(cmd, size)); if (arg_count(cmd, colon_ARG)) { pvdisplay_colons(pv); goto out; } pvdisplay_full(cmd, pv, handle); if (arg_count(cmd, maps_ARG)) pvdisplay_segments(pv); out: if (vg_name) unlock_vg(cmd, vg_name); if (!old_vg) release_vg(vg); return ret; } int pvdisplay(struct cmd_context *cmd, int argc, char **argv) { if (arg_count(cmd, columns_ARG)) { if (arg_count(cmd, colon_ARG) || arg_count(cmd, maps_ARG) || arg_count(cmd, short_ARG)) { log_error("Incompatible options selected"); return EINVALID_CMD_LINE; } return pvs(cmd, argc, argv); } else if (arg_count(cmd, aligned_ARG) || arg_count(cmd, all_ARG) || arg_count(cmd, noheadings_ARG) || arg_count(cmd, options_ARG) || arg_count(cmd, separator_ARG) || arg_count(cmd, sort_ARG) || arg_count(cmd, unbuffered_ARG)) { log_error("Incompatible options selected"); return EINVALID_CMD_LINE; } if (arg_count(cmd, colon_ARG) && arg_count(cmd, maps_ARG)) { log_error("Option -v not allowed with option -c"); return EINVALID_CMD_LINE; } return process_each_pv(cmd, argc, argv, NULL, 0, 0, NULL, _pvdisplay_single); } lvm2-2.02.98/tools/lvscan.c0000640000175000017500000000432612037016273014310 0ustar blankblank/* * Copyright (C) 2001-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 */ #include "tools.h" static int lvscan_single(struct cmd_context *cmd, struct logical_volume *lv, void *handle __attribute__((unused))) { struct lvinfo info; int inkernel, snap_active = 1; struct lv_segment *snap_seg = NULL; percent_t snap_percent; /* fused, fsize; */ const char *active_str, *snapshot_str; if (!arg_count(cmd, all_ARG) && !lv_is_visible(lv)) return ECMD_PROCESSED; inkernel = lv_info(cmd, lv, 0, &info, 0, 0) && info.exists; if (lv_is_origin(lv)) { dm_list_iterate_items_gen(snap_seg, &lv->snapshot_segs, origin_list) { if (inkernel && (snap_active = lv_snapshot_percent(snap_seg->cow, &snap_percent))) if (snap_percent == PERCENT_INVALID) snap_active = 0; } snap_seg = NULL; } else if (lv_is_cow(lv)) { if (inkernel && (snap_active = lv_snapshot_percent(lv, &snap_percent))) if (snap_percent == PERCENT_INVALID) snap_active = 0; } /* FIXME Add -D arg to skip this! */ if (inkernel && snap_active) active_str = "ACTIVE "; else active_str = "inactive "; if (lv_is_origin(lv)) snapshot_str = "Original"; else if (lv_is_cow(lv)) snapshot_str = "Snapshot"; else snapshot_str = " "; log_print_unless_silent("%s%s '%s%s/%s' [%s] %s", active_str, snapshot_str, cmd->dev_dir, lv->vg->name, lv->name, display_size(cmd, lv->size), get_alloc_string(lv->alloc)); return ECMD_PROCESSED; } int lvscan(struct cmd_context *cmd, int argc, char **argv) { if (argc) { log_error("No additional command line arguments allowed"); return EINVALID_CMD_LINE; } return process_each_lv(cmd, argc, argv, 0, NULL, &lvscan_single); } lvm2-2.02.98/tools/polldaemon.c0000640000175000017500000002402512037016273015152 0ustar blankblank/* * Copyright (C) 2003-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 "tools.h" #include "polldaemon.h" #include "lvm2cmdline.h" #include #include static void _sigchld_handler(int sig __attribute__((unused))) { while (wait4(-1, NULL, WNOHANG | WUNTRACED, NULL) > 0) ; } /* * returns: * -1 if the fork failed * 0 if the parent * 1 if the child */ static int _become_daemon(struct cmd_context *cmd) { static const char devnull[] = "/dev/null"; int null_fd; pid_t pid; struct sigaction act = { {_sigchld_handler}, .sa_flags = SA_NOCLDSTOP, }; log_verbose("Forking background process"); sigaction(SIGCHLD, &act, NULL); sync_local_dev_names(cmd); /* Flush ops and reset dm cookie */ if ((pid = fork()) == -1) { log_error("fork failed: %s", strerror(errno)); return -1; } /* Parent */ if (pid > 0) return 0; /* Child */ if (setsid() == -1) log_error("Background process failed to setsid: %s", strerror(errno)); /* For poll debugging it's best to disable for compilation */ #if 1 if ((null_fd = open(devnull, O_RDWR)) == -1) { log_sys_error("open", devnull); _exit(ECMD_FAILED); } if ((dup2(null_fd, STDIN_FILENO) < 0) || /* reopen stdin */ (dup2(null_fd, STDOUT_FILENO) < 0) || /* reopen stdout */ (dup2(null_fd, STDERR_FILENO) < 0)) { /* reopen stderr */ log_sys_error("dup2", "redirect"); (void) close(null_fd); _exit(ECMD_FAILED); } if (null_fd > STDERR_FILENO) (void) close(null_fd); init_verbose(VERBOSE_BASE_LEVEL); #endif strncpy(*cmd->argv, "(lvm2)", strlen(*cmd->argv)); reset_locking(); if (!lvmcache_init()) /* FIXME Clean up properly here */ _exit(ECMD_FAILED); dev_close_all(); return 1; } progress_t poll_mirror_progress(struct cmd_context *cmd, struct logical_volume *lv, const char *name, struct daemon_parms *parms) { percent_t segment_percent = PERCENT_0, overall_percent = PERCENT_0; uint32_t event_nr = 0; if (!lv_is_mirrored(lv) || !lv_mirror_percent(cmd, lv, !parms->interval, &segment_percent, &event_nr) || (segment_percent == PERCENT_INVALID)) { log_error("ABORTING: Mirror percentage check failed."); return PROGRESS_CHECK_FAILED; } overall_percent = copy_percent(lv); if (parms->progress_display) log_print_unless_silent("%s: %s: %.1f%%", name, parms->progress_title, percent_to_float(overall_percent)); else log_verbose("%s: %s: %.1f%%", name, parms->progress_title, percent_to_float(overall_percent)); if (segment_percent != PERCENT_100) return PROGRESS_UNFINISHED; if (overall_percent == PERCENT_100) return PROGRESS_FINISHED_ALL; return PROGRESS_FINISHED_SEGMENT; } static int _check_lv_status(struct cmd_context *cmd, struct volume_group *vg, struct logical_volume *lv, const char *name, struct daemon_parms *parms, int *finished) { struct dm_list *lvs_changed; progress_t progress; /* By default, caller should not retry */ *finished = 1; if (parms->aborting) { if (!(lvs_changed = lvs_using_lv(cmd, vg, lv))) { log_error("Failed to generate list of copied LVs: " "can't abort."); return 0; } if (!parms->poll_fns->finish_copy(cmd, vg, lv, lvs_changed)) return_0; return 1; } progress = parms->poll_fns->poll_progress(cmd, lv, name, parms); if (progress == PROGRESS_CHECK_FAILED) return_0; if (progress == PROGRESS_UNFINISHED) { /* The only case the caller *should* try again later */ *finished = 0; return 1; } if (!(lvs_changed = lvs_using_lv(cmd, vg, lv))) { log_error("ABORTING: Failed to generate list of copied LVs"); return 0; } /* Finished? Or progress to next segment? */ if (progress == PROGRESS_FINISHED_ALL) { if (!parms->poll_fns->finish_copy(cmd, vg, lv, lvs_changed)) return_0; } else { if (parms->poll_fns->update_metadata && !parms->poll_fns->update_metadata(cmd, vg, lv, lvs_changed, 0)) { log_error("ABORTING: Segment progression failed."); parms->poll_fns->finish_copy(cmd, vg, lv, lvs_changed); return 0; } *finished = 0; /* Another segment */ } return 1; } static void _sleep_and_rescan_devices(struct daemon_parms *parms) { /* FIXME Use alarm for regular intervals instead */ if (parms->interval && !parms->aborting) { sleep(parms->interval); /* Devices might have changed while we slept */ init_full_scan_done(0); } } static int _wait_for_single_lv(struct cmd_context *cmd, const char *name, const char *uuid, struct daemon_parms *parms) { struct volume_group *vg; struct logical_volume *lv; int finished = 0; /* Poll for completion */ while (!finished) { if (parms->wait_before_testing) _sleep_and_rescan_devices(parms); /* Locks the (possibly renamed) VG again */ vg = parms->poll_fns->get_copy_vg(cmd, name, uuid); if (vg_read_error(vg)) { release_vg(vg); log_error("ABORTING: Can't reread VG for %s", name); /* What more could we do here? */ return 0; } lv = parms->poll_fns->get_copy_lv(cmd, vg, name, uuid, parms->lv_type); if (!lv && parms->lv_type == PVMOVE) { log_print_unless_silent("%s: no pvmove in progress - already finished or aborted.", name); unlock_and_release_vg(cmd, vg, vg->name); return 1; } if (!lv) { log_error("ABORTING: Can't find LV in %s for %s", vg->name, name); unlock_and_release_vg(cmd, vg, vg->name); return 0; } if (!_check_lv_status(cmd, vg, lv, name, parms, &finished)) { unlock_and_release_vg(cmd, vg, vg->name); return_0; } unlock_and_release_vg(cmd, vg, vg->name); /* * FIXME Sleeping after testing, while preferred, also works around * unreliable "finished" state checking in _percent_run. If the * above _check_lv_status is deferred until after the first sleep it * may be that a polldaemon will run without ever completing. * * This happens when one snapshot-merge polldaemon is racing with * another (polling the same LV). The first to see the LV status * reach the "finished" state will alter the LV that the other * polldaemon(s) are polling. These other polldaemon(s) can then * continue polling an LV that doesn't have a "status". */ if (!parms->wait_before_testing) _sleep_and_rescan_devices(parms); } return 1; } static int _poll_vg(struct cmd_context *cmd, const char *vgname, struct volume_group *vg, void *handle) { struct daemon_parms *parms = (struct daemon_parms *) handle; struct lv_list *lvl; struct logical_volume *lv; const char *name; int finished; if (!parms) { log_error(INTERNAL_ERROR "Handle is undefined."); return ECMD_FAILED; } dm_list_iterate_items(lvl, &vg->lvs) { lv = lvl->lv; if (!(lv->status & parms->lv_type)) continue; name = parms->poll_fns->get_copy_name_from_lv(lv); if (!name && !parms->aborting) continue; /* FIXME Need to do the activation from _set_up_pvmove here * if it's not running and we're not aborting */ if (_check_lv_status(cmd, vg, lv, name, parms, &finished) && !finished) parms->outstanding_count++; } return ECMD_PROCESSED; } static void _poll_for_all_vgs(struct cmd_context *cmd, struct daemon_parms *parms) { while (1) { parms->outstanding_count = 0; process_each_vg(cmd, 0, NULL, READ_FOR_UPDATE, parms, _poll_vg); if (!parms->outstanding_count) break; sleep(parms->interval); } } /* * Only allow *one* return from poll_daemon() (the parent). * If there is a child it must exit (ignoring the memory leak messages). * - 'background' is advisory so a child polldaemon may not be used even * if it was requested. */ int poll_daemon(struct cmd_context *cmd, const char *name, const char *uuid, unsigned background, uint64_t lv_type, struct poll_functions *poll_fns, const char *progress_title) { struct daemon_parms parms; int daemon_mode = 0; int ret = ECMD_PROCESSED; sign_t interval_sign; parms.aborting = arg_is_set(cmd, abort_ARG); parms.background = background; interval_sign = arg_sign_value(cmd, interval_ARG, SIGN_NONE); if (interval_sign == SIGN_MINUS) log_error("Argument to --interval cannot be negative"); parms.interval = arg_uint_value(cmd, interval_ARG, find_config_tree_int(cmd, "activation/polling_interval", DEFAULT_INTERVAL)); parms.wait_before_testing = (interval_sign == SIGN_PLUS); parms.progress_display = 1; parms.progress_title = progress_title; parms.lv_type = lv_type; parms.poll_fns = poll_fns; if (parms.interval && !parms.aborting) log_verbose("Checking progress %s waiting every %u seconds", (parms.wait_before_testing ? "after" : "before"), parms.interval); if (!parms.interval) { parms.progress_display = 0; /* FIXME Disabled multiple-copy wait_event */ if (!name) parms.interval = find_config_tree_int(cmd, "activation/polling_interval", DEFAULT_INTERVAL); } if (parms.background) { daemon_mode = _become_daemon(cmd); if (daemon_mode == 0) return ECMD_PROCESSED; /* Parent */ else if (daemon_mode == 1) parms.progress_display = 0; /* Child */ /* FIXME Use wait_event (i.e. interval = 0) and */ /* fork one daemon per copy? */ } /* * Process one specific task or all incomplete tasks? */ if (name) { if (!_wait_for_single_lv(cmd, name, uuid, &parms)) { stack; ret = ECMD_FAILED; } } else _poll_for_all_vgs(cmd, &parms); if (parms.background && daemon_mode == 1) { /* * child was successfully forked: * background polldaemon must not return to the caller * because it will redundantly continue performing the * caller's task (that the parent already performed) */ /* FIXME Attempt proper cleanup */ _exit(lvm_return_code(ret)); } return ret; } lvm2-2.02.98/tools/vgsplit.c0000640000175000017500000003067412037016273014517 0ustar blankblank/* * 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 */ #include "tools.h" /* FIXME Why not (lv->vg == vg) ? */ static int _lv_is_in_vg(struct volume_group *vg, struct logical_volume *lv) { struct lv_list *lvl; dm_list_iterate_items(lvl, &vg->lvs) if (lv == lvl->lv) return 1; return 0; } static int _move_one_lv(struct volume_group *vg_from, struct volume_group *vg_to, struct dm_list *lvh) { struct logical_volume *lv = dm_list_item(lvh, struct lv_list)->lv; dm_list_move(&vg_to->lvs, lvh); lv->vg = vg_to; if (lv_is_active(lv)) { log_error("Logical volume \"%s\" must be inactive", lv->name); return 0; } return 1; } static int _move_lvs(struct volume_group *vg_from, struct volume_group *vg_to) { struct dm_list *lvh, *lvht; struct logical_volume *lv; struct lv_segment *seg; struct physical_volume *pv; struct volume_group *vg_with; unsigned s; dm_list_iterate_safe(lvh, lvht, &vg_from->lvs) { lv = dm_list_item(lvh, struct lv_list)->lv; if ((lv->status & SNAPSHOT)) continue; if ((lv->status & MIRRORED)) continue; /* Ensure all the PVs used by this LV remain in the same */ /* VG as each other */ vg_with = NULL; dm_list_iterate_items(seg, &lv->segments) { for (s = 0; s < seg->area_count; s++) { /* FIXME Check AREA_LV too */ if (seg_type(seg, s) != AREA_PV) continue; pv = seg_pv(seg, s); if (vg_with) { if (!pv_is_in_vg(vg_with, pv)) { log_error("Can't split Logical " "Volume %s between " "two Volume Groups", lv->name); return 0; } continue; } if (pv_is_in_vg(vg_from, pv)) { vg_with = vg_from; continue; } if (pv_is_in_vg(vg_to, pv)) { vg_with = vg_to; continue; } log_error("Physical Volume %s not found", pv_dev_name(pv)); return 0; } } if (vg_with == vg_from) continue; /* Move this LV */ if (!_move_one_lv(vg_from, vg_to, lvh)) return_0; } /* FIXME Ensure no LVs contain segs pointing at LVs in the other VG */ return 1; } /* * Move the hidden / internal "snapshotN" LVs.from 'vg_from' to 'vg_to'. */ static int _move_snapshots(struct volume_group *vg_from, struct volume_group *vg_to) { struct dm_list *lvh, *lvht; struct logical_volume *lv; struct lv_segment *seg; int cow_from = 0; int origin_from = 0; dm_list_iterate_safe(lvh, lvht, &vg_from->lvs) { lv = dm_list_item(lvh, struct lv_list)->lv; if (!(lv->status & SNAPSHOT)) continue; dm_list_iterate_items(seg, &lv->segments) { cow_from = _lv_is_in_vg(vg_from, seg->cow); origin_from = _lv_is_in_vg(vg_from, seg->origin); if (cow_from && origin_from) continue; if ((!cow_from && origin_from) || (cow_from && !origin_from)) { log_error("Can't split snapshot %s between" " two Volume Groups", seg->cow->name); return 0; } /* * At this point, the cow and origin should already be * in vg_to. */ if (_lv_is_in_vg(vg_to, seg->cow) && _lv_is_in_vg(vg_to, seg->origin)) { if (!_move_one_lv(vg_from, vg_to, lvh)) return_0; } } } return 1; } static int _move_mirrors(struct volume_group *vg_from, struct volume_group *vg_to) { struct dm_list *lvh, *lvht; struct logical_volume *lv; struct lv_segment *seg, *log_seg; unsigned s, seg_in, log_in; dm_list_iterate_safe(lvh, lvht, &vg_from->lvs) { lv = dm_list_item(lvh, struct lv_list)->lv; if (!(lv->status & MIRRORED)) continue; seg = first_seg(lv); seg_in = 0; for (s = 0; s < seg->area_count; s++) if (_lv_is_in_vg(vg_to, seg_lv(seg, s))) seg_in++; log_in = !seg->log_lv; if (seg->log_lv) { log_seg = first_seg(seg->log_lv); if (seg_is_mirrored(log_seg)) { log_in = 1; /* Ensure each log dev is in vg_to */ for (s = 0; s < log_seg->area_count; s++) log_in = log_in && _lv_is_in_vg(vg_to, seg_lv(log_seg, s)); } else log_in = _lv_is_in_vg(vg_to, seg->log_lv); } if ((seg_in && seg_in < seg->area_count) || (seg_in && seg->log_lv && !log_in) || (!seg_in && seg->log_lv && log_in)) { log_error("Can't split mirror %s between " "two Volume Groups", lv->name); return 0; } if (seg_in == seg->area_count && log_in) { if (!_move_one_lv(vg_from, vg_to, lvh)) return_0; } } return 1; } /* * Create or open the destination of the vgsplit operation. * Returns * - non-NULL: VG handle w/VG lock held * - NULL: no VG lock held */ static struct volume_group *_vgsplit_to(struct cmd_context *cmd, const char *vg_name_to, int *existing_vg) { struct volume_group *vg_to = NULL; log_verbose("Checking for new volume group \"%s\"", vg_name_to); /* * First try to create a new VG. If we cannot create it, * and we get FAILED_EXIST (we will not be holding a lock), * a VG must already exist with this name. We then try to * read the existing VG - the vgsplit will be into an existing VG. * * Otherwise, if the lock was successful, it must be the case that * we obtained a WRITE lock and could not find the vgname in the * system. Thus, the split will be into a new VG. */ vg_to = vg_create(cmd, vg_name_to); if (vg_read_error(vg_to) == FAILED_LOCKING) { log_error("Can't get lock for %s", vg_name_to); release_vg(vg_to); return NULL; } if (vg_read_error(vg_to) == FAILED_EXIST) { *existing_vg = 1; release_vg(vg_to); vg_to = vg_read_for_update(cmd, vg_name_to, NULL, 0); if (vg_read_error(vg_to)) { release_vg(vg_to); stack; return NULL; } } else if (vg_read_error(vg_to) == SUCCESS) { *existing_vg = 0; } return vg_to; } /* * Open the source of the vgsplit operation. * Returns * - non-NULL: VG handle w/VG lock held * - NULL: no VG lock held */ static struct volume_group *_vgsplit_from(struct cmd_context *cmd, const char *vg_name_from) { struct volume_group *vg_from; log_verbose("Checking for volume group \"%s\"", vg_name_from); vg_from = vg_read_for_update(cmd, vg_name_from, NULL, 0); if (vg_read_error(vg_from)) { release_vg(vg_from); return NULL; } return vg_from; } /* * Has the user given an option related to a new vg as the split destination? */ static int new_vg_option_specified(struct cmd_context *cmd) { return(arg_count(cmd, clustered_ARG) || arg_count(cmd, alloc_ARG) || arg_count(cmd, maxphysicalvolumes_ARG) || arg_count(cmd, maxlogicalvolumes_ARG) || arg_count(cmd, vgmetadatacopies_ARG)); } int vgsplit(struct cmd_context *cmd, int argc, char **argv) { struct vgcreate_params vp_new; struct vgcreate_params vp_def; const char *vg_name_from, *vg_name_to; struct volume_group *vg_to = NULL, *vg_from = NULL; int opt; int existing_vg = 0; int r = ECMD_FAILED; const char *lv_name; int lock_vg_from_first = 1; if ((arg_count(cmd, name_ARG) + argc) < 3) { log_error("Existing VG, new VG and either physical volumes " "or logical volume required."); return EINVALID_CMD_LINE; } if (arg_count(cmd, name_ARG) && (argc > 2)) { log_error("A logical volume name cannot be given with " "physical volumes."); return ECMD_FAILED; } if (arg_count(cmd, name_ARG)) lv_name = arg_value(cmd, name_ARG); else lv_name = NULL; vg_name_from = skip_dev_dir(cmd, argv[0], NULL); vg_name_to = skip_dev_dir(cmd, argv[1], NULL); argc -= 2; argv += 2; if (!strcmp(vg_name_to, vg_name_from)) { log_error("Duplicate volume group name \"%s\"", vg_name_from); return ECMD_FAILED; } if (strcmp(vg_name_to, vg_name_from) < 0) lock_vg_from_first = 0; if (lock_vg_from_first) { vg_from = _vgsplit_from(cmd, vg_name_from); if (!vg_from) { stack; return ECMD_FAILED; } /* * Set metadata format of original VG. * NOTE: We must set the format before calling vg_create() * since vg_create() calls the per-format constructor. */ cmd->fmt = vg_from->fid->fmt; vg_to = _vgsplit_to(cmd, vg_name_to, &existing_vg); if (!vg_to) { unlock_and_release_vg(cmd, vg_from, vg_name_from); stack; return ECMD_FAILED; } } else { vg_to = _vgsplit_to(cmd, vg_name_to, &existing_vg); if (!vg_to) { stack; return ECMD_FAILED; } vg_from = _vgsplit_from(cmd, vg_name_from); if (!vg_from) { unlock_and_release_vg(cmd, vg_to, vg_name_to); stack; return ECMD_FAILED; } if (cmd->fmt != vg_from->fid->fmt) { /* In this case we don't know the vg_from->fid->fmt */ log_error("Unable to set new VG metadata type based on " "source VG format - use -M option."); goto bad; } } if (existing_vg) { if (new_vg_option_specified(cmd)) { log_error("Volume group \"%s\" exists, but new VG " "option specified", vg_name_to); goto bad; } if (!vgs_are_compatible(cmd, vg_from,vg_to)) goto_bad; } else { vgcreate_params_set_defaults(&vp_def, vg_from); vp_def.vg_name = vg_name_to; if (vgcreate_params_set_from_args(cmd, &vp_new, &vp_def)) { r = EINVALID_CMD_LINE; goto_bad; } if (vgcreate_params_validate(cmd, &vp_new)) { r = EINVALID_CMD_LINE; goto_bad; } if (!vg_set_extent_size(vg_to, vp_new.extent_size) || !vg_set_max_lv(vg_to, vp_new.max_lv) || !vg_set_max_pv(vg_to, vp_new.max_pv) || !vg_set_alloc_policy(vg_to, vp_new.alloc) || !vg_set_clustered(vg_to, vp_new.clustered) || !vg_set_mda_copies(vg_to, vp_new.vgmetadatacopies)) goto_bad; } /* Archive vg_from before changing it */ if (!archive(vg_from)) goto_bad; /* Move PVs across to new structure */ for (opt = 0; opt < argc; opt++) { dm_unescape_colons_and_at_signs(argv[opt], NULL, NULL); if (!move_pv(vg_from, vg_to, argv[opt])) goto_bad; } /* If an LV given on the cmdline, move used_by PVs */ if (lv_name && !move_pvs_used_by_lv(vg_from, vg_to, lv_name)) goto_bad; /* Move required LVs across, checking consistency */ if (!(_move_lvs(vg_from, vg_to))) goto_bad; /* FIXME Separate the 'move' from the 'validation' to fix dev stacks */ /* Move required mirrors across */ if (!(_move_mirrors(vg_from, vg_to))) goto_bad; /* Move required snapshots across */ if (!(_move_snapshots(vg_from, vg_to))) goto_bad; /* Split metadata areas and check if both vgs have at least one area */ if (!(vg_split_mdas(cmd, vg_from, vg_to)) && vg_from->pv_count) { log_error("Cannot split: Nowhere to store metadata for new Volume Group"); goto bad; } /* Set proper name for all PVs in new VG */ if (!vg_rename(cmd, vg_to, vg_name_to)) goto_bad; /* store it on disks */ log_verbose("Writing out updated volume groups"); /* * First, write out the new VG as EXPORTED. We do this first in case * there is a crash - we will still have the new VG information, in an * exported state. Recovery after this point would be removal of the * new VG and redoing the vgsplit. * FIXME: recover automatically or instruct the user? */ vg_to->status |= EXPORTED_VG; if (!archive(vg_to)) goto_bad; if (!vg_write(vg_to) || !vg_commit(vg_to)) goto_bad; backup(vg_to); /* * Next, write out the updated old VG. If we crash after this point, * recovery is a vgimport on the new VG. * FIXME: recover automatically or instruct the user? */ if (vg_from->pv_count) { if (!vg_write(vg_from) || !vg_commit(vg_from)) goto_bad; backup(vg_from); } /* * Finally, remove the EXPORTED flag from the new VG and write it out. */ if (!test_mode()) { release_vg(vg_to); vg_to = vg_read_for_update(cmd, vg_name_to, NULL, READ_ALLOW_EXPORTED); if (vg_read_error(vg_to)) { log_error("Volume group \"%s\" became inconsistent: " "please fix manually", vg_name_to); goto bad; } } vg_to->status &= ~EXPORTED_VG; if (!vg_write(vg_to) || !vg_commit(vg_to)) goto_bad; backup(vg_to); log_print_unless_silent("%s volume group \"%s\" successfully split from \"%s\"", existing_vg ? "Existing" : "New", vg_to->name, vg_from->name); r = ECMD_PROCESSED; bad: /* * vg_to references elements moved from vg_from * so vg_to has to be freed first. */ unlock_and_release_vg(cmd, vg_to, vg_name_to); unlock_and_release_vg(cmd, vg_from, vg_name_from); return r; } lvm2-2.02.98/tools/lvm2cmdline.h0000640000175000017500000000237512037016273015245 0ustar blankblank/* * Copyright (C) 2003-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_CMDLINE_H #define _LVM_CMDLINE_H struct cmd_context; struct cmdline_context { struct arg_props *arg_props; struct command *commands; int num_commands; int commands_size; int interactive; }; int lvm2_main(int argc, char **argv); void *cmdlib_lvm2_init(unsigned static_compile); void lvm_fin(struct cmd_context *cmd); struct cmd_context *init_lvm(void); void lvm_register_commands(void); int lvm_split(char *str, int *argc, char **argv, int max); int lvm_run_command(struct cmd_context *cmd, int argc, char **argv); int lvm_return_code(int ret); int lvm_shell(struct cmd_context *cmd, struct cmdline_context *cmdline); #endif lvm2-2.02.98/tools/args.h0000640000175000017500000001630212037016273013760 0ustar blankblank/* * 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 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 */ /* * Put all long args that don't have a corresponding short option first. */ /* *INDENT-OFF* */ arg(version_ARG, '\0', "version", NULL, 0) arg(physicalvolumesize_ARG, '\0', "setphysicalvolumesize", size_mb_arg, 0) arg(ignorelockingfailure_ARG, '\0', "ignorelockingfailure", NULL, 0) arg(nolocking_ARG, '\0', "nolocking", NULL, 0) arg(pvmetadatacopies_ARG, '\0', "pvmetadatacopies", int_arg, 0) arg(vgmetadatacopies_ARG, '\0', "vgmetadatacopies", metadatacopies_arg, 0) arg(metadatacopies_ARG, '\0', "metadatacopies", metadatacopies_arg, 0) arg(metadatasize_ARG, '\0', "metadatasize", size_mb_arg, 0) arg(metadataignore_ARG, '\0', "metadataignore", yes_no_arg, 0) arg(norestorefile_ARG, '\0', "norestorefile", NULL, 0) arg(restorefile_ARG, '\0', "restorefile", string_arg, 0) arg(labelsector_ARG, '\0', "labelsector", int_arg, 0) arg(driverloaded_ARG, '\0', "driverloaded", yes_no_arg, 0) arg(aligned_ARG, '\0', "aligned", NULL, 0) arg(unbuffered_ARG, '\0', "unbuffered", NULL, 0) arg(noheadings_ARG, '\0', "noheadings", NULL, 0) arg(segments_ARG, '\0', "segments", NULL, 0) arg(units_ARG, '\0', "units", string_arg, 0) arg(nosuffix_ARG, '\0', "nosuffix", NULL, 0) arg(removemissing_ARG, '\0', "removemissing", NULL, 0) arg(restoremissing_ARG, '\0', "restoremissing", NULL, 0) arg(abort_ARG, '\0', "abort", NULL, 0) arg(addtag_ARG, '\0', "addtag", tag_arg, ARG_GROUPABLE) arg(deltag_ARG, '\0', "deltag", tag_arg, ARG_GROUPABLE) arg(refresh_ARG, '\0', "refresh", NULL, 0) arg(mknodes_ARG, '\0', "mknodes", NULL, 0) arg(minor_ARG, '\0', "minor", int_arg, ARG_GROUPABLE) arg(type_ARG, '\0', "type", segtype_arg, 0) arg(alloc_ARG, '\0', "alloc", alloc_arg, 0) arg(separator_ARG, '\0', "separator", string_arg, 0) arg(mirrorsonly_ARG, '\0', "mirrorsonly", NULL, 0) arg(nosync_ARG, '\0', "nosync", NULL, 0) arg(resync_ARG, '\0', "resync", NULL, 0) arg(corelog_ARG, '\0', "corelog", NULL, 0) arg(mirrorlog_ARG, '\0', "mirrorlog", string_arg, 0) arg(splitmirrors_ARG, '\0', "splitmirrors", int_arg, 0) arg(trackchanges_ARG, '\0', "trackchanges", NULL, 0) arg(replace_ARG, '\0', "replace", string_arg, ARG_GROUPABLE) arg(repair_ARG, '\0', "repair", NULL, 0) arg(use_policies_ARG, '\0', "use-policies", NULL, 0) arg(monitor_ARG, '\0', "monitor", yes_no_arg, 0) arg(config_ARG, '\0', "config", string_arg, 0) arg(trustcache_ARG, '\0', "trustcache", NULL, 0) arg(cache_ARG, '\0', "cache", NULL, 0) arg(ignoremonitoring_ARG, '\0', "ignoremonitoring", NULL, 0) arg(nameprefixes_ARG, '\0', "nameprefixes", NULL, 0) arg(unquoted_ARG, '\0', "unquoted", NULL, 0) arg(rows_ARG, '\0', "rows", NULL, 0) arg(dataalignment_ARG, '\0', "dataalignment", size_kb_arg, 0) arg(dataalignmentoffset_ARG, '\0', "dataalignmentoffset", size_kb_arg, 0) arg(virtualoriginsize_ARG, '\0', "virtualoriginsize", size_mb_arg, 0) arg(noudevsync_ARG, '\0', "noudevsync", NULL, 0) arg(poll_ARG, '\0', "poll", yes_no_arg, 0) arg(poolmetadata_ARG, '\0', "poolmetadata", string_arg, 0) arg(poolmetadatasize_ARG, '\0', "poolmetadatasize", size_mb_arg, 0) arg(discards_ARG, '\0', "discards", discards_arg, 0) arg(stripes_long_ARG, '\0', "stripes", int_arg, 0) arg(sysinit_ARG, '\0', "sysinit", NULL, 0) arg(thinpool_ARG, '\0', "thinpool", string_arg, 0) /* Allow some variations */ arg(resizable_ARG, '\0', "resizable", yes_no_arg, 0) arg(allocation_ARG, '\0', "allocation", yes_no_arg, 0) arg(available_ARG, '\0', "available", activation_arg, 0) /* * ... and now the short args. */ arg(activate_ARG, 'a', "activate", activation_arg, 0) arg(all_ARG, 'a', "all", NULL, 0) arg(autobackup_ARG, 'A', "autobackup", yes_no_arg, 0) arg(activevolumegroups_ARG, 'A', "activevolumegroups", NULL, 0) arg(background_ARG, 'b', "background", NULL, 0) arg(blockdevice_ARG, 'b', "blockdevice", NULL, 0) arg(chunksize_ARG, 'c', "chunksize", size_kb_arg, 0) arg(clustered_ARG, 'c', "clustered", yes_no_arg, 0) arg(colon_ARG, 'c', "colon", NULL, 0) arg(columns_ARG, 'C', "columns", NULL, 0) arg(contiguous_ARG, 'C', "contiguous", yes_no_arg, 0) arg(debug_ARG, 'd', "debug", NULL, ARG_COUNTABLE) arg(exported_ARG, 'e', "exported", NULL, 0) arg(physicalextent_ARG, 'E', "physicalextent", NULL, 0) arg(file_ARG, 'f', "file", string_arg, 0) arg(force_ARG, 'f', "force", NULL, ARG_COUNTABLE) arg(full_ARG, 'f', "full", NULL, 0) arg(help_ARG, 'h', "help", NULL, 0) arg(help2_ARG, '?', "", NULL, 0) arg(stripesize_ARG, 'I', "stripesize", size_kb_arg, 0) arg(stripes_ARG, 'i', "stripes", int_arg, 0) arg(interval_ARG, 'i', "interval", int_arg, 0) arg(iop_version_ARG, 'i', "iop_version", NULL, 0) arg(logicalvolume_ARG, 'l', "logicalvolume", int_arg, 0) arg(maxlogicalvolumes_ARG, 'l', "maxlogicalvolumes", int_arg, 0) arg(extents_ARG, 'l', "extents", int_arg_with_sign_and_percent, 0) arg(lvmpartition_ARG, 'l', "lvmpartition", NULL, 0) arg(list_ARG, 'l', "list", NULL, 0) arg(size_ARG, 'L', "size", size_mb_arg, 0) arg(logicalextent_ARG, 'L', "logicalextent", int_arg_with_sign, 0) arg(persistent_ARG, 'M', "persistent", yes_no_arg, 0) arg(merge_ARG, '\0', "merge", NULL, 0) arg(major_ARG, 'j', "major", int_arg, ARG_GROUPABLE) arg(mirrors_ARG, 'm', "mirrors", int_arg_with_sign, 0) arg(metadatatype_ARG, 'M', "metadatatype", metadatatype_arg, 0) arg(maps_ARG, 'm', "maps", NULL, 0) arg(name_ARG, 'n', "name", string_arg, 0) arg(oldpath_ARG, 'n', "oldpath", NULL, 0) arg(nofsck_ARG, 'n', "nofsck", NULL, 0) arg(novolumegroup_ARG, 'n', "novolumegroup", NULL, 0) arg(options_ARG, 'o', "options", string_arg, 0) arg(sort_ARG, 'O', "sort", string_arg, 0) arg(permission_ARG, 'p', "permission", permission_arg, 0) arg(maxphysicalvolumes_ARG, 'p', "maxphysicalvolumes", int_arg, 0) arg(partial_ARG, 'P', "partial", NULL, 0) arg(physicalvolume_ARG, 'P', "physicalvolume", NULL, 0) arg(quiet_ARG, 'q', "quiet", NULL, ARG_COUNTABLE) arg(readahead_ARG, 'r', "readahead", readahead_arg, 0) arg(resizefs_ARG, 'r', "resizefs", NULL, 0) arg(reset_ARG, 'R', "reset", NULL, 0) arg(regionsize_ARG, 'R', "regionsize", size_mb_arg, 0) arg(physicalextentsize_ARG, 's', "physicalextentsize", size_mb_arg, 0) arg(stdin_ARG, 's', "stdin", NULL, 0) arg(snapshot_ARG, 's', "snapshot", NULL, 0) arg(short_ARG, 's', "short", NULL, 0) arg(thin_ARG, 'T', "thin", NULL, 0) arg(test_ARG, 't', "test", NULL, 0) arg(uuid_ARG, 'u', "uuid", NULL, 0) arg(uuidstr_ARG, 'u', "uuid", string_arg, 0) arg(uuidlist_ARG, 'U', "uuidlist", NULL, 0) arg(verbose_ARG, 'v', "verbose", NULL, ARG_COUNTABLE) arg(volumegroup_ARG, 'V', "volumegroup", NULL, 0) arg(virtualsize_ARG, 'V', "virtualsize", size_mb_arg, 0) arg(allocatable_ARG, 'x', "allocatable", yes_no_arg, 0) arg(resizeable_ARG, 'x', "resizeable", yes_no_arg, 0) arg(yes_ARG, 'y', "yes", NULL, 0) arg(zero_ARG, 'Z', "zero", yes_no_arg, 0) /* this should always be last */ arg(ARG_COUNT, '-', "", NULL, 0) /* *INDENT-ON* */ lvm2-2.02.98/tools/vgremove.c0000640000175000017500000000372412037016273014655 0ustar blankblank/* * 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 */ #include "tools.h" static int vgremove_single(struct cmd_context *cmd, const char *vg_name, struct volume_group *vg, void *handle __attribute__((unused))) { unsigned lv_count, missing; force_t force; if (!vg_check_status(vg, EXPORTED_VG)) { stack; return ECMD_FAILED; } lv_count = vg_visible_lvs(vg); force = (force_t) arg_count(cmd, force_ARG); if (lv_count) { if (force == PROMPT) { if ((missing = vg_missing_pv_count(vg))) log_warn("WARNING: %d physical volumes are currently missing " "from the system.", missing); if (yes_no_prompt("Do you really want to remove volume " "group \"%s\" containing %u " "logical volumes? [y/n]: ", vg_name, lv_count) == 'n') { log_error("Volume group \"%s\" not removed", vg_name); return ECMD_FAILED; } } if (!remove_lvs_in_vg(cmd, vg, force)) { stack; return ECMD_FAILED; } } if (!force && !vg_remove_check(vg)) { stack; return ECMD_FAILED; } vg_remove_pvs(vg); if (!vg_remove(vg)) { stack; return ECMD_FAILED; } return ECMD_PROCESSED; } int vgremove(struct cmd_context *cmd, int argc, char **argv) { int ret; if (!argc) { log_error("Please enter one or more volume group paths"); return EINVALID_CMD_LINE; } cmd->handles_missing_pvs = 1; ret = process_each_vg(cmd, argc, argv, READ_FOR_UPDATE, NULL, &vgremove_single); return ret; } lvm2-2.02.98/tools/lvm-static.c0000640000175000017500000000152312037016273015101 0ustar blankblank/* * 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 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 "tools.h" #include "lvm2cmdline.h" int main(int argc, char **argv) { init_is_static(1); return lvm2_main(argc, argv); } int lvm_shell(struct cmd_context *cmd __attribute__((unused)), struct cmdline_context *cmdline __attribute__((unused))) { return 0; } lvm2-2.02.98/tools/toollib.c0000640000175000017500000012106112037016273014462 0ustar blankblank/* * 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 */ #include "tools.h" #include const char *command_name(struct cmd_context *cmd) { return cmd->command->name; } /* * Strip dev_dir if present */ const char *skip_dev_dir(struct cmd_context *cmd, const char *vg_name, unsigned *dev_dir_found) { const char *dmdir = dm_dir(); size_t dmdir_len = strlen(dmdir), vglv_sz; char *vgname, *lvname, *layer, *vglv; /* FIXME Do this properly */ if (*vg_name == '/') { while (*vg_name == '/') vg_name++; vg_name--; } /* Reformat string if /dev/mapper found */ if (!strncmp(vg_name, dmdir, dmdir_len) && vg_name[dmdir_len] == '/') { if (dev_dir_found) *dev_dir_found = 1; vg_name += dmdir_len; while (*vg_name == '/') vg_name++; if (!dm_split_lvm_name(cmd->mem, vg_name, &vgname, &lvname, &layer) || *layer) { log_error("skip_dev_dir: Couldn't split up device name %s", vg_name); return vg_name; } vglv_sz = strlen(vgname) + strlen(lvname) + 2; if (!(vglv = dm_pool_alloc(cmd->mem, vglv_sz)) || dm_snprintf(vglv, vglv_sz, "%s%s%s", vgname, *lvname ? "/" : "", lvname) < 0) { log_error("vg/lv string alloc failed"); return vg_name; } return vglv; } if (!strncmp(vg_name, cmd->dev_dir, strlen(cmd->dev_dir))) { if (dev_dir_found) *dev_dir_found = 1; vg_name += strlen(cmd->dev_dir); while (*vg_name == '/') vg_name++; } else if (dev_dir_found) *dev_dir_found = 0; return vg_name; } /* * Metadata iteration functions */ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg, const struct dm_list *arg_lvnames, const struct dm_list *tags, struct dm_list *failed_lvnames, void *handle, process_single_lv_fn_t process_single_lv) { int ret_max = ECMD_PROCESSED; int ret = 0; unsigned process_all = 0; unsigned process_lv = 0; unsigned tags_supplied = 0; unsigned lvargs_supplied = 0; unsigned lvargs_matched = 0; char *lv_name; struct lv_list *lvl; if (!vg_check_status(vg, EXPORTED_VG)) return ECMD_FAILED; if (tags && !dm_list_empty(tags)) tags_supplied = 1; if (arg_lvnames && !dm_list_empty(arg_lvnames)) lvargs_supplied = 1; /* Process all LVs in this VG if no restrictions given */ if (!tags_supplied && !lvargs_supplied) process_all = 1; /* Or if VG tags match */ if (!process_lv && tags_supplied && str_list_match_list(tags, &vg->tags, NULL)) { process_all = 1; } /* * FIXME: In case of remove it goes through deleted entries, * but it works since entries are allocated from vg mem pool. */ dm_list_iterate_items(lvl, &vg->lvs) { if (lvl->lv->status & SNAPSHOT) continue; /* Skip availability change for non-virt snaps when processing all LVs */ /* FIXME: pass process_all to process_single_lv() */ if (process_all && arg_count(cmd, activate_ARG) && lv_is_cow(lvl->lv) && !lv_is_virtual_origin(origin_from_cow(lvl->lv))) continue; if (lv_is_virtual_origin(lvl->lv) && !arg_count(cmd, all_ARG)) continue; /* * Only let hidden LVs through it --all was used or the LVs * were specifically named on the command line. */ if (!lvargs_supplied && !lv_is_visible(lvl->lv) && !arg_count(cmd, all_ARG)) continue; /* Should we process this LV? */ if (process_all) process_lv = 1; else process_lv = 0; /* LV tag match? */ if (!process_lv && tags_supplied && str_list_match_list(tags, &lvl->lv->tags, NULL)) { process_lv = 1; } /* LV name match? */ if (lvargs_supplied && str_list_match_item(arg_lvnames, lvl->lv->name)) { process_lv = 1; lvargs_matched++; } if (!process_lv) continue; lvl->lv->vg->cmd_missing_vgs = 0; ret = process_single_lv(cmd, lvl->lv, handle); if (ret != ECMD_PROCESSED && failed_lvnames) { lv_name = dm_pool_strdup(cmd->mem, lvl->lv->name); if (!lv_name || !str_list_add(cmd->mem, failed_lvnames, lv_name)) { log_error("Allocation failed for str_list."); return ECMD_FAILED; } if (lvl->lv->vg->cmd_missing_vgs) ret = ECMD_PROCESSED; } if (ret > ret_max) ret_max = ret; if (sigint_caught()) { stack; return ret_max; } } if (lvargs_supplied && lvargs_matched != dm_list_size(arg_lvnames)) { /* * FIXME: lvm supports removal of LV with all its dependencies * this leads to miscalculation that depends on the order of args. */ log_error("One or more specified logical volume(s) not found."); if (ret_max < ECMD_FAILED) ret_max = ECMD_FAILED; } return ret_max; } int process_each_lv(struct cmd_context *cmd, int argc, char **argv, uint32_t flags, void *handle, process_single_lv_fn_t process_single_lv) { int opt = 0; int ret_max = ECMD_PROCESSED; int ret = 0; struct dm_list *tags_arg; struct dm_list *vgnames; /* VGs to process */ struct str_list *sll, *strl; struct cmd_vg *cvl_vg; struct dm_list cmd_vgs; struct dm_list failed_lvnames; struct dm_list tags, lvnames; struct dm_list arg_lvnames; /* Cmdline vgname or vgname/lvname */ struct dm_list arg_vgnames; char *vglv; size_t vglv_sz; const char *vgname; dm_list_init(&tags); dm_list_init(&arg_lvnames); dm_list_init(&failed_lvnames); if (argc) { log_verbose("Using logical volume(s) on command line"); dm_list_init(&arg_vgnames); for (; opt < argc; opt++) { const char *lv_name = argv[opt]; const char *tmp_lv_name; char *vgname_def; unsigned dev_dir_found = 0; /* Do we have a tag or vgname or lvname? */ vgname = lv_name; if (*vgname == '@') { if (!validate_tag(vgname + 1)) { log_error("Skipping invalid tag %s", vgname); continue; } if (!str_list_add(cmd->mem, &tags, dm_pool_strdup(cmd->mem, vgname + 1))) { log_error("strlist allocation failed"); return ECMD_FAILED; } continue; } /* FIXME Jumbled parsing */ vgname = skip_dev_dir(cmd, vgname, &dev_dir_found); if (*vgname == '/') { log_error("\"%s\": Invalid path for Logical " "Volume", argv[opt]); if (ret_max < ECMD_FAILED) ret_max = ECMD_FAILED; continue; } lv_name = vgname; if ((tmp_lv_name = strchr(vgname, '/'))) { /* Must be an LV */ lv_name = tmp_lv_name; while (*lv_name == '/') lv_name++; if (!(vgname = extract_vgname(cmd, vgname))) { if (ret_max < ECMD_FAILED) { stack; ret_max = ECMD_FAILED; } continue; } } else if (!dev_dir_found && (vgname_def = default_vgname(cmd))) { vgname = vgname_def; } else lv_name = NULL; if (!str_list_add(cmd->mem, &arg_vgnames, dm_pool_strdup(cmd->mem, vgname))) { log_error("strlist allocation failed"); return ECMD_FAILED; } if (!lv_name) { if (!str_list_add(cmd->mem, &arg_lvnames, dm_pool_strdup(cmd->mem, vgname))) { log_error("strlist allocation failed"); return ECMD_FAILED; } } else { vglv_sz = strlen(vgname) + strlen(lv_name) + 2; if (!(vglv = dm_pool_alloc(cmd->mem, vglv_sz)) || dm_snprintf(vglv, vglv_sz, "%s/%s", vgname, lv_name) < 0) { log_error("vg/lv string alloc failed"); return ECMD_FAILED; } if (!str_list_add(cmd->mem, &arg_lvnames, vglv)) { log_error("strlist allocation failed"); return ECMD_FAILED; } } } vgnames = &arg_vgnames; } if (!argc || !dm_list_empty(&tags)) { log_verbose("Finding all logical volumes"); if (!lvmetad_vg_list_to_lvmcache(cmd)) stack; if (!(vgnames = get_vgnames(cmd, 0)) || dm_list_empty(vgnames)) { log_error("No volume groups found"); return ret_max; } } dm_list_iterate_items(strl, vgnames) { vgname = strl->str; dm_list_init(&cmd_vgs); if (!(cvl_vg = cmd_vg_add(cmd->mem, &cmd_vgs, vgname, NULL, flags))) { stack; return ECMD_FAILED; } if (!cmd_vg_read(cmd, &cmd_vgs)) { free_cmd_vgs(&cmd_vgs); if (ret_max < ECMD_FAILED) { log_error("Skipping volume group %s", vgname); ret_max = ECMD_FAILED; } else stack; continue; } tags_arg = &tags; dm_list_init(&lvnames); /* LVs to be processed in this VG */ dm_list_iterate_items(sll, &arg_lvnames) { const char *vg_name = sll->str; const char *lv_name = strchr(vg_name, '/'); if ((!lv_name && !strcmp(vg_name, vgname))) { /* Process all LVs in this VG */ tags_arg = NULL; dm_list_init(&lvnames); break; } else if (!strncmp(vg_name, vgname, strlen(vgname)) && lv_name && strlen(vgname) == (size_t) (lv_name - vg_name)) { if (!str_list_add(cmd->mem, &lvnames, dm_pool_strdup(cmd->mem, lv_name + 1))) { log_error("strlist allocation failed"); free_cmd_vgs(&cmd_vgs); return ECMD_FAILED; } } } while (!sigint_caught()) { ret = process_each_lv_in_vg(cmd, cvl_vg->vg, &lvnames, tags_arg, &failed_lvnames, handle, process_single_lv); if (ret != ECMD_PROCESSED) { stack; break; } if (dm_list_empty(&failed_lvnames)) break; /* Try again with failed LVs in this VG */ dm_list_init(&lvnames); dm_list_splice(&lvnames, &failed_lvnames); free_cmd_vgs(&cmd_vgs); if (!cmd_vg_read(cmd, &cmd_vgs)) { stack; ret = ECMD_FAILED; /* break */ break; } } if (ret > ret_max) ret_max = ret; free_cmd_vgs(&cmd_vgs); /* FIXME: logic for breaking command is not consistent */ if (sigint_caught()) { stack; return ECMD_FAILED; } } return ret_max; } int process_each_segment_in_pv(struct cmd_context *cmd, struct volume_group *vg, struct physical_volume *pv, void *handle, process_single_pvseg_fn_t process_single_pvseg) { struct pv_segment *pvseg; struct pv_list *pvl; const char *vg_name = NULL; int ret_max = ECMD_PROCESSED; int ret; struct volume_group *old_vg = vg; struct pv_segment _free_pv_segment = { .pv = pv }; if (is_pv(pv) && !vg && !is_orphan(pv)) { vg_name = pv_vg_name(pv); vg = vg_read(cmd, vg_name, NULL, 0); if (vg_read_error(vg)) { release_vg(vg); log_error("Skipping volume group %s", vg_name); return ECMD_FAILED; } /* * Replace possibly incomplete PV structure with new one * allocated in vg_read_internal() path. */ if (!(pvl = find_pv_in_vg(vg, pv_dev_name(pv)))) { log_error("Unable to find %s in volume group %s", pv_dev_name(pv), vg_name); unlock_and_release_vg(cmd, vg, vg_name); return ECMD_FAILED; } pv = pvl->pv; } if (dm_list_empty(&pv->segments)) { ret = process_single_pvseg(cmd, NULL, &_free_pv_segment, handle); if (ret > ret_max) ret_max = ret; } else dm_list_iterate_items(pvseg, &pv->segments) { ret = process_single_pvseg(cmd, vg, pvseg, handle); if (ret > ret_max) ret_max = ret; if (sigint_caught()) break; } if (vg_name) unlock_vg(cmd, vg_name); if (!old_vg) release_vg(vg); return ret_max; } int process_each_segment_in_lv(struct cmd_context *cmd, struct logical_volume *lv, void *handle, process_single_seg_fn_t process_single_seg) { struct lv_segment *seg; int ret_max = ECMD_PROCESSED; int ret; dm_list_iterate_items(seg, &lv->segments) { ret = process_single_seg(cmd, seg, handle); if (ret > ret_max) ret_max = ret; /* FIXME: logic for breaking command is not consistent */ if (sigint_caught()) return ECMD_FAILED; } return ret_max; } static int _process_one_vg(struct cmd_context *cmd, const char *vg_name, const char *vgid, struct dm_list *tags, struct dm_list *arg_vgnames, uint32_t flags, void *handle, int ret_max, process_single_vg_fn_t process_single_vg) { struct dm_list cmd_vgs; struct cmd_vg *cvl_vg; int ret = 0; log_verbose("Finding volume group \"%s\"", vg_name); dm_list_init(&cmd_vgs); if (!(cvl_vg = cmd_vg_add(cmd->mem, &cmd_vgs, vg_name, vgid, flags))) return_0; for (;;) { /* FIXME: consistent handling of command break */ if (sigint_caught()) { ret = ECMD_FAILED; break; } if (!cmd_vg_read(cmd, &cmd_vgs)) /* Allow FAILED_INCONSISTENT through only for vgcfgrestore */ if (vg_read_error(cvl_vg->vg) && (!((flags & READ_ALLOW_INCONSISTENT) && (vg_read_error(cvl_vg->vg) == FAILED_INCONSISTENT)))) { ret = ECMD_FAILED; break; } if (!dm_list_empty(tags) && /* Only process if a tag matches or it's on arg_vgnames */ !str_list_match_item(arg_vgnames, vg_name) && !str_list_match_list(tags, &cvl_vg->vg->tags, NULL)) break; ret = process_single_vg(cmd, vg_name, cvl_vg->vg, handle); if (vg_read_error(cvl_vg->vg)) /* FAILED_INCONSISTENT */ break; if (!cvl_vg->vg->cmd_missing_vgs) break; free_cmd_vgs(&cmd_vgs); } free_cmd_vgs(&cmd_vgs); return (ret > ret_max) ? ret : ret_max; } int process_each_vg(struct cmd_context *cmd, int argc, char **argv, uint32_t flags, void *handle, process_single_vg_fn_t process_single_vg) { int opt = 0; int ret_max = ECMD_PROCESSED; struct str_list *sl; struct dm_list *vgnames, *vgids; struct dm_list arg_vgnames, tags; const char *vg_name, *vgid; dm_list_init(&tags); dm_list_init(&arg_vgnames); if (argc) { log_verbose("Using volume group(s) on command line"); for (; opt < argc; opt++) { vg_name = argv[opt]; if (*vg_name == '@') { if (!validate_tag(vg_name + 1)) { log_error("Skipping invalid tag %s", vg_name); if (ret_max < EINVALID_CMD_LINE) ret_max = EINVALID_CMD_LINE; continue; } if (!str_list_add(cmd->mem, &tags, dm_pool_strdup(cmd->mem, vg_name + 1))) { log_error("strlist allocation failed"); return ECMD_FAILED; } continue; } vg_name = skip_dev_dir(cmd, vg_name, NULL); if (strchr(vg_name, '/')) { log_error("Invalid volume group name: %s", vg_name); if (ret_max < EINVALID_CMD_LINE) ret_max = EINVALID_CMD_LINE; continue; } if (!str_list_add(cmd->mem, &arg_vgnames, dm_pool_strdup(cmd->mem, vg_name))) { log_error("strlist allocation failed"); return ECMD_FAILED; } } vgnames = &arg_vgnames; } if (!argc || !dm_list_empty(&tags)) { log_verbose("Finding all volume groups"); if (!lvmetad_vg_list_to_lvmcache(cmd)) stack; if (!(vgids = get_vgids(cmd, 0)) || dm_list_empty(vgids)) { log_error("No volume groups found"); return ret_max; } dm_list_iterate_items(sl, vgids) { vgid = sl->str; if (!(vgid) || !(vg_name = lvmcache_vgname_from_vgid(cmd->mem, vgid))) continue; ret_max = _process_one_vg(cmd, vg_name, vgid, &tags, &arg_vgnames, flags, handle, ret_max, process_single_vg); if (sigint_caught()) return ret_max; } } else { dm_list_iterate_items(sl, vgnames) { vg_name = sl->str; if (is_orphan_vg(vg_name)) continue; /* FIXME Unnecessary? */ ret_max = _process_one_vg(cmd, vg_name, NULL, &tags, &arg_vgnames, flags, handle, ret_max, process_single_vg); if (sigint_caught()) return ret_max; } } return ret_max; } int process_each_pv_in_vg(struct cmd_context *cmd, struct volume_group *vg, const struct dm_list *tags, void *handle, process_single_pv_fn_t process_single_pv) { int ret_max = ECMD_PROCESSED; int ret = 0; struct pv_list *pvl; dm_list_iterate_items(pvl, &vg->pvs) { if (tags && !dm_list_empty(tags) && !str_list_match_list(tags, &pvl->pv->tags, NULL)) { continue; } if ((ret = process_single_pv(cmd, vg, pvl->pv, handle)) > ret_max) ret_max = ret; if (sigint_caught()) return ret_max; } return ret_max; } static int _process_all_devs(struct cmd_context *cmd, void *handle, process_single_pv_fn_t process_single_pv) { struct physical_volume *pv; struct physical_volume pv_dummy; struct dev_iter *iter; struct device *dev; int ret_max = ECMD_PROCESSED; int ret = 0; if (!scan_vgs_for_pvs(cmd, 1)) { stack; return ECMD_FAILED; } if (!(iter = dev_iter_create(cmd->filter, 1))) { log_error("dev_iter creation failed"); return ECMD_FAILED; } while ((dev = dev_iter_get(iter))) { if (!(pv = pv_read(cmd, dev_name(dev), 0, 0))) { memset(&pv_dummy, 0, sizeof(pv_dummy)); dm_list_init(&pv_dummy.tags); dm_list_init(&pv_dummy.segments); pv_dummy.dev = dev; pv = &pv_dummy; } ret = process_single_pv(cmd, NULL, pv, handle); free_pv_fid(pv); if (ret > ret_max) ret_max = ret; if (sigint_caught()) break; } dev_iter_destroy(iter); return ret_max; } /* * If the lock_type is LCK_VG_READ (used only in reporting commands), * we lock VG_GLOBAL to enable use of metadata cache. * This can pause alongide pvscan or vgscan process for a while. */ int process_each_pv(struct cmd_context *cmd, int argc, char **argv, struct volume_group *vg, uint32_t flags, int scan_label_only, void *handle, process_single_pv_fn_t process_single_pv) { int opt = 0; int ret_max = ECMD_PROCESSED; int ret = 0; int lock_global = !(flags & READ_WITHOUT_LOCK) && !(flags & READ_FOR_UPDATE); struct pv_list *pvl; struct physical_volume *pv; struct dm_list *pvslist, *vgnames; struct dm_list tags; struct str_list *sll; char *at_sign, *tagname; int scanned = 0; dm_list_init(&tags); if (lock_global && !lock_vol(cmd, VG_GLOBAL, LCK_VG_READ)) { log_error("Unable to obtain global lock."); return ECMD_FAILED; } if (argc) { log_verbose("Using physical volume(s) on command line"); for (; opt < argc; opt++) { dm_unescape_colons_and_at_signs(argv[opt], NULL, &at_sign); if (at_sign && (at_sign == argv[opt])) { tagname = at_sign + 1; if (!validate_tag(tagname)) { log_error("Skipping invalid tag %s", tagname); if (ret_max < EINVALID_CMD_LINE) ret_max = EINVALID_CMD_LINE; continue; } if (!str_list_add(cmd->mem, &tags, dm_pool_strdup(cmd->mem, tagname))) { log_error("strlist allocation failed"); goto bad; } continue; } if (vg) { if (!(pvl = find_pv_in_vg(vg, argv[opt]))) { log_error("Physical Volume \"%s\" not " "found in Volume Group " "\"%s\"", argv[opt], vg->name); ret_max = ECMD_FAILED; continue; } pv = pvl->pv; } else { if (!(pv = pv_read(cmd, argv[opt], 1, scan_label_only))) { log_error("Failed to read physical " "volume \"%s\"", argv[opt]); ret_max = ECMD_FAILED; continue; } /* * If a PV has no MDAs it may appear to be an * orphan until the metadata is read off * another PV in the same VG. Detecting this * means checking every VG by scanning every * PV on the system. */ if (!scanned && is_orphan(pv) && !dm_list_size(&pv->fid->metadata_areas_in_use)) { if (!scan_label_only && !scan_vgs_for_pvs(cmd, 1)) { stack; ret_max = ECMD_FAILED; continue; } scanned = 1; free_pv_fid(pv); if (!(pv = pv_read(cmd, argv[opt], 1, scan_label_only))) { log_error("Failed to read " "physical volume " "\"%s\"", argv[opt]); ret_max = ECMD_FAILED; continue; } } } ret = process_single_pv(cmd, vg, pv, handle); /* * Free PV only if we called pv_read before, * otherwise the PV structure is part of the VG. */ if (!vg) free_pv_fid(pv); if (ret > ret_max) ret_max = ret; if (sigint_caught()) goto out; } if (!dm_list_empty(&tags) && (vgnames = get_vgnames(cmd, 1)) && !dm_list_empty(vgnames)) { dm_list_iterate_items(sll, vgnames) { vg = vg_read(cmd, sll->str, NULL, flags); if (vg_read_error(vg)) { ret_max = ECMD_FAILED; release_vg(vg); stack; continue; } ret = process_each_pv_in_vg(cmd, vg, &tags, handle, process_single_pv); unlock_and_release_vg(cmd, vg, sll->str); if (ret > ret_max) ret_max = ret; if (sigint_caught()) goto out; } } } else { if (vg) { log_verbose("Using all physical volume(s) in " "volume group"); ret = process_each_pv_in_vg(cmd, vg, NULL, handle, process_single_pv); if (ret > ret_max) ret_max = ret; if (sigint_caught()) goto out; } else if (arg_count(cmd, all_ARG)) { ret = _process_all_devs(cmd, handle, process_single_pv); if (ret > ret_max) ret_max = ret; if (sigint_caught()) goto out; } else { log_verbose("Scanning for physical volume names"); lvmcache_seed_infos_from_lvmetad(cmd); if (!(pvslist = get_pvs(cmd))) goto bad; dm_list_iterate_items(pvl, pvslist) { ret = process_single_pv(cmd, NULL, pvl->pv, handle); free_pv_fid(pvl->pv); if (ret > ret_max) ret_max = ret; if (sigint_caught()) goto out; } } } out: if (lock_global) unlock_vg(cmd, VG_GLOBAL); return ret_max; bad: if (lock_global) unlock_vg(cmd, VG_GLOBAL); return ECMD_FAILED; } /* * Determine volume group name from a logical volume name */ const char *extract_vgname(struct cmd_context *cmd, const char *lv_name) { const char *vg_name = lv_name; char *st; char *dev_dir = cmd->dev_dir; /* Path supplied? */ if (vg_name && strchr(vg_name, '/')) { /* Strip dev_dir (optional) */ if (*vg_name == '/') { while (*vg_name == '/') vg_name++; vg_name--; } if (!strncmp(vg_name, dev_dir, strlen(dev_dir))) { vg_name += strlen(dev_dir); while (*vg_name == '/') vg_name++; } if (*vg_name == '/') { log_error("\"%s\": Invalid path for Logical " "Volume", lv_name); return 0; } /* Require exactly one set of consecutive slashes */ if ((st = strchr(vg_name, '/'))) while (*st == '/') st++; if (!st || strchr(st, '/')) { log_error("\"%s\": Invalid path for Logical Volume", lv_name); return 0; } vg_name = dm_pool_strdup(cmd->mem, vg_name); if (!vg_name) { log_error("Allocation of vg_name failed"); return 0; } *strchr(vg_name, '/') = '\0'; return vg_name; } if (!(vg_name = default_vgname(cmd))) { if (lv_name) log_error("Path required for Logical Volume \"%s\"", lv_name); return 0; } return vg_name; } /* * Extract default volume group name from environment */ char *default_vgname(struct cmd_context *cmd) { const char *vg_path; /* Take default VG from environment? */ vg_path = getenv("LVM_VG_NAME"); if (!vg_path) return 0; vg_path = skip_dev_dir(cmd, vg_path, NULL); if (strchr(vg_path, '/')) { log_error("Environment Volume Group in LVM_VG_NAME invalid: " "\"%s\"", vg_path); return 0; } return dm_pool_strdup(cmd->mem, vg_path); } /* * Process physical extent range specifiers */ static int _add_pe_range(struct dm_pool *mem, const char *pvname, struct dm_list *pe_ranges, uint32_t start, uint32_t count) { struct pe_range *per; log_debug("Adding PE range: start PE %" PRIu32 " length %" PRIu32 " on %s", start, count, pvname); /* Ensure no overlap with existing areas */ dm_list_iterate_items(per, pe_ranges) { if (((start < per->start) && (start + count - 1 >= per->start)) || ((start >= per->start) && (per->start + per->count - 1) >= start)) { log_error("Overlapping PE ranges specified (%" PRIu32 "-%" PRIu32 ", %" PRIu32 "-%" PRIu32 ")" " on %s", start, start + count - 1, per->start, per->start + per->count - 1, pvname); return 0; } } if (!(per = dm_pool_alloc(mem, sizeof(*per)))) { log_error("Allocation of list failed"); return 0; } per->start = start; per->count = count; dm_list_add(pe_ranges, &per->list); return 1; } static int xstrtouint32(const char *s, char **p, int base, uint32_t *result) { unsigned long ul; errno = 0; ul = strtoul(s, p, base); if (errno || *p == s || ul > UINT32_MAX) return 0; *result = ul; return 1; } static int _parse_pes(struct dm_pool *mem, char *c, struct dm_list *pe_ranges, const char *pvname, uint32_t size) { char *endptr; uint32_t start, end; /* Default to whole PV */ if (!c) { if (!_add_pe_range(mem, pvname, pe_ranges, UINT32_C(0), size)) return_0; return 1; } while (*c) { if (*c != ':') goto error; c++; /* Disallow :: and :\0 */ if (*c == ':' || !*c) goto error; /* Default to whole range */ start = UINT32_C(0); end = size - 1; /* Start extent given? */ if (isdigit(*c)) { if (!xstrtouint32(c, &endptr, 10, &start)) goto error; c = endptr; /* Just one number given? */ if (!*c || *c == ':') end = start; } /* Range? */ if (*c == '-') { c++; if (isdigit(*c)) { if (!xstrtouint32(c, &endptr, 10, &end)) goto error; c = endptr; } } if (*c && *c != ':') goto error; if ((start > end) || (end > size - 1)) { log_error("PE range error: start extent %" PRIu32 " to " "end extent %" PRIu32, start, end); return 0; } if (!_add_pe_range(mem, pvname, pe_ranges, start, end - start + 1)) return_0; } return 1; error: log_error("Physical extent parsing error at %s", c); return 0; } static int _create_pv_entry(struct dm_pool *mem, struct pv_list *pvl, char *colon, int allocatable_only, struct dm_list *r) { const char *pvname; struct pv_list *new_pvl = NULL, *pvl2; struct dm_list *pe_ranges; pvname = pv_dev_name(pvl->pv); if (allocatable_only && !(pvl->pv->status & ALLOCATABLE_PV)) { log_error("Physical volume %s not allocatable", pvname); return 1; } if (allocatable_only && is_missing_pv(pvl->pv)) { log_error("Physical volume %s is missing", pvname); return 1; } if (allocatable_only && (pvl->pv->pe_count == pvl->pv->pe_alloc_count)) { log_error("No free extents on physical volume \"%s\"", pvname); return 1; } dm_list_iterate_items(pvl2, r) if (pvl->pv->dev == pvl2->pv->dev) { new_pvl = pvl2; break; } if (!new_pvl) { if (!(new_pvl = dm_pool_alloc(mem, sizeof(*new_pvl)))) { log_error("Unable to allocate physical volume list."); return 0; } memcpy(new_pvl, pvl, sizeof(*new_pvl)); if (!(pe_ranges = dm_pool_alloc(mem, sizeof(*pe_ranges)))) { log_error("Allocation of pe_ranges list failed"); return 0; } dm_list_init(pe_ranges); new_pvl->pe_ranges = pe_ranges; dm_list_add(r, &new_pvl->list); } /* Determine selected physical extents */ if (!_parse_pes(mem, colon, new_pvl->pe_ranges, pv_dev_name(pvl->pv), pvl->pv->pe_count)) return_0; return 1; } struct dm_list *create_pv_list(struct dm_pool *mem, struct volume_group *vg, int argc, char **argv, int allocatable_only) { struct dm_list *r; struct pv_list *pvl; struct dm_list tags, arg_pvnames; char *pvname = NULL; char *colon, *at_sign, *tagname; int i; /* Build up list of PVs */ if (!(r = dm_pool_alloc(mem, sizeof(*r)))) { log_error("Allocation of list failed"); return NULL; } dm_list_init(r); dm_list_init(&tags); dm_list_init(&arg_pvnames); for (i = 0; i < argc; i++) { dm_unescape_colons_and_at_signs(argv[i], &colon, &at_sign); if (at_sign && (at_sign == argv[i])) { tagname = at_sign + 1; if (!validate_tag(tagname)) { log_error("Skipping invalid tag %s", tagname); continue; } dm_list_iterate_items(pvl, &vg->pvs) { if (str_list_match_item(&pvl->pv->tags, tagname)) { if (!_create_pv_entry(mem, pvl, NULL, allocatable_only, r)) return_NULL; } } continue; } pvname = argv[i]; if (colon && !(pvname = dm_pool_strndup(mem, pvname, (unsigned) (colon - pvname)))) { log_error("Failed to clone PV name"); return NULL; } if (!(pvl = find_pv_in_vg(vg, pvname))) { log_error("Physical Volume \"%s\" not found in " "Volume Group \"%s\"", pvname, vg->name); return NULL; } if (!_create_pv_entry(mem, pvl, colon, allocatable_only, r)) return_NULL; } if (dm_list_empty(r)) log_error("No specified PVs have space available"); return dm_list_empty(r) ? NULL : r; } struct dm_list *clone_pv_list(struct dm_pool *mem, struct dm_list *pvsl) { struct dm_list *r; struct pv_list *pvl, *new_pvl; /* Build up list of PVs */ if (!(r = dm_pool_alloc(mem, sizeof(*r)))) { log_error("Allocation of list failed"); return NULL; } dm_list_init(r); dm_list_iterate_items(pvl, pvsl) { if (!(new_pvl = dm_pool_zalloc(mem, sizeof(*new_pvl)))) { log_error("Unable to allocate physical volume list."); return NULL; } memcpy(new_pvl, pvl, sizeof(*new_pvl)); dm_list_add(r, &new_pvl->list); } return r; } void vgcreate_params_set_defaults(struct vgcreate_params *vp_def, struct volume_group *vg) { if (vg) { vp_def->vg_name = NULL; vp_def->extent_size = vg->extent_size; vp_def->max_pv = vg->max_pv; vp_def->max_lv = vg->max_lv; vp_def->alloc = vg->alloc; vp_def->clustered = vg_is_clustered(vg); vp_def->vgmetadatacopies = vg->mda_copies; } else { vp_def->vg_name = NULL; vp_def->extent_size = DEFAULT_EXTENT_SIZE * 2; vp_def->max_pv = DEFAULT_MAX_PV; vp_def->max_lv = DEFAULT_MAX_LV; vp_def->alloc = DEFAULT_ALLOC_POLICY; vp_def->clustered = DEFAULT_CLUSTERED; vp_def->vgmetadatacopies = DEFAULT_VGMETADATACOPIES; } } /* * Set members of struct vgcreate_params from cmdline arguments. * Do preliminary validation with arg_*() interface. * Further, more generic validation is done in validate_vgcreate_params(). * This function is to remain in tools directory. */ int vgcreate_params_set_from_args(struct cmd_context *cmd, struct vgcreate_params *vp_new, struct vgcreate_params *vp_def) { vp_new->vg_name = skip_dev_dir(cmd, vp_def->vg_name, NULL); vp_new->max_lv = arg_uint_value(cmd, maxlogicalvolumes_ARG, vp_def->max_lv); vp_new->max_pv = arg_uint_value(cmd, maxphysicalvolumes_ARG, vp_def->max_pv); vp_new->alloc = (alloc_policy_t) arg_uint_value(cmd, alloc_ARG, vp_def->alloc); /* Units of 512-byte sectors */ vp_new->extent_size = arg_uint_value(cmd, physicalextentsize_ARG, vp_def->extent_size); if (arg_count(cmd, clustered_ARG)) vp_new->clustered = !strcmp(arg_str_value(cmd, clustered_ARG, vp_def->clustered ? "y":"n"), "y"); else /* Default depends on current locking type */ vp_new->clustered = locking_is_clustered(); if (arg_sign_value(cmd, physicalextentsize_ARG, SIGN_NONE) == SIGN_MINUS) { log_error("Physical extent size may not be negative"); return 1; } if (arg_uint64_value(cmd, physicalextentsize_ARG, 0) > MAX_EXTENT_SIZE) { log_error("Physical extent size cannot be larger than %s", display_size(cmd, (uint64_t) MAX_EXTENT_SIZE)); return 1; } if (arg_sign_value(cmd, maxlogicalvolumes_ARG, SIGN_NONE) == SIGN_MINUS) { log_error("Max Logical Volumes may not be negative"); return 1; } if (arg_sign_value(cmd, maxphysicalvolumes_ARG, SIGN_NONE) == SIGN_MINUS) { log_error("Max Physical Volumes may not be negative"); return 1; } if (arg_count(cmd, metadatacopies_ARG)) { vp_new->vgmetadatacopies = arg_int_value(cmd, metadatacopies_ARG, DEFAULT_VGMETADATACOPIES); } else if (arg_count(cmd, vgmetadatacopies_ARG)) { vp_new->vgmetadatacopies = arg_int_value(cmd, vgmetadatacopies_ARG, DEFAULT_VGMETADATACOPIES); } else { vp_new->vgmetadatacopies = find_config_tree_int(cmd, "metadata/vgmetadatacopies", DEFAULT_VGMETADATACOPIES); } return 0; } int lv_refresh(struct cmd_context *cmd, struct logical_volume *lv) { int r = 0; if (!cmd->partial_activation && (lv->status & PARTIAL_LV)) { log_error("Refusing refresh of partial LV %s. Use --partial to override.", lv->name); goto out; } r = suspend_lv(cmd, lv); if (!r) goto_out; r = resume_lv(cmd, lv); if (!r) goto_out; /* * check if snapshot merge should be polled * - unfortunately: even though the dev_manager will clear * the lv's merge attributes if a merge is not possible; * it is clearing a different instance of the lv (as * retrieved with lv_from_lvid) * - fortunately: polldaemon will immediately shutdown if the * origin doesn't have a status with a snapshot percentage */ if (background_polling() && lv_is_origin(lv) && lv_is_merging_origin(lv)) lv_spawn_background_polling(cmd, lv); out: return r; } int vg_refresh_visible(struct cmd_context *cmd, struct volume_group *vg) { struct lv_list *lvl; int r = 1; sigint_allow(); dm_list_iterate_items(lvl, &vg->lvs) { if (sigint_caught()) return_0; if (lv_is_visible(lvl->lv)) if (!lv_refresh(cmd, lvl->lv)) r = 0; } sigint_restore(); return r; } void lv_spawn_background_polling(struct cmd_context *cmd, struct logical_volume *lv) { const char *pvname; if ((lv->status & PVMOVE) && (pvname = get_pvmove_pvname_from_lv_mirr(lv))) { log_verbose("Spawning background pvmove process for %s", pvname); pvmove_poll(cmd, pvname, 1); } else if ((lv->status & LOCKED) && (pvname = get_pvmove_pvname_from_lv(lv))) { log_verbose("Spawning background pvmove process for %s", pvname); pvmove_poll(cmd, pvname, 1); } if (lv->status & (CONVERTING|MERGING)) { log_verbose("Spawning background lvconvert process for %s", lv->name); lvconvert_poll(cmd, lv, 1); } } /* * Intial sanity checking of non-recovery related command-line arguments. * * Output arguments: * pp: structure allocated by caller, fields written / validated here */ int pvcreate_params_validate(struct cmd_context *cmd, int argc, char **argv, struct pvcreate_params *pp) { if (!argc) { log_error("Please enter a physical volume path"); return 0; } pp->yes = arg_count(cmd, yes_ARG); pp->force = (force_t) arg_count(cmd, force_ARG); if (arg_int_value(cmd, labelsector_ARG, 0) >= LABEL_SCAN_SECTORS) { log_error("labelsector must be less than %lu", LABEL_SCAN_SECTORS); return 0; } else { pp->labelsector = arg_int64_value(cmd, labelsector_ARG, DEFAULT_LABELSECTOR); } if (!(cmd->fmt->features & FMT_MDAS) && (arg_count(cmd, pvmetadatacopies_ARG) || arg_count(cmd, metadatasize_ARG) || arg_count(cmd, dataalignment_ARG) || arg_count(cmd, dataalignmentoffset_ARG))) { log_error("Metadata and data alignment parameters only " "apply to text format."); return 0; } if (arg_count(cmd, pvmetadatacopies_ARG) && arg_int_value(cmd, pvmetadatacopies_ARG, -1) > 2) { log_error("Metadatacopies may only be 0, 1 or 2"); return 0; } if (arg_count(cmd, metadataignore_ARG)) { pp->metadataignore = !strcmp(arg_str_value(cmd, metadataignore_ARG, DEFAULT_PVMETADATAIGNORE_STR), "y"); } else { pp->metadataignore = !strcmp(find_config_tree_str(cmd, "metadata/pvmetadataignore", DEFAULT_PVMETADATAIGNORE_STR), "y"); } if (arg_count(cmd, pvmetadatacopies_ARG) && !arg_int_value(cmd, pvmetadatacopies_ARG, -1) && pp->metadataignore) { log_error("metadataignore only applies to metadatacopies > 0"); return 0; } if (arg_count(cmd, zero_ARG)) pp->zero = strcmp(arg_str_value(cmd, zero_ARG, "y"), "n"); if (arg_sign_value(cmd, dataalignment_ARG, SIGN_NONE) == SIGN_MINUS) { log_error("Physical volume data alignment may not be negative"); return 0; } pp->data_alignment = arg_uint64_value(cmd, dataalignment_ARG, UINT64_C(0)); if (pp->data_alignment > UINT32_MAX) { log_error("Physical volume data alignment is too big."); return 0; } if (pp->data_alignment && pp->pe_start) { if (pp->pe_start % pp->data_alignment) log_warn("WARNING: Ignoring data alignment %" PRIu64 " incompatible with --restorefile value (%" PRIu64").", pp->data_alignment, pp->pe_start); pp->data_alignment = 0; } if (arg_sign_value(cmd, dataalignmentoffset_ARG, SIGN_NONE) == SIGN_MINUS) { log_error("Physical volume data alignment offset may not be negative"); return 0; } pp->data_alignment_offset = arg_uint64_value(cmd, dataalignmentoffset_ARG, UINT64_C(0)); if (pp->data_alignment_offset > UINT32_MAX) { log_error("Physical volume data alignment offset is too big."); return 0; } if (pp->data_alignment_offset && pp->pe_start) { log_warn("WARNING: Ignoring data alignment offset %" PRIu64 " incompatible with --restorefile value (%" PRIu64").", pp->data_alignment_offset, pp->pe_start); pp->data_alignment_offset = 0; } if (arg_sign_value(cmd, metadatasize_ARG, SIGN_NONE) == SIGN_MINUS) { log_error("Metadata size may not be negative"); return 0; } pp->pvmetadatasize = arg_uint64_value(cmd, metadatasize_ARG, UINT64_C(0)); if (!pp->pvmetadatasize) pp->pvmetadatasize = find_config_tree_int(cmd, "metadata/pvmetadatasize", DEFAULT_PVMETADATASIZE); pp->pvmetadatacopies = arg_int_value(cmd, pvmetadatacopies_ARG, -1); if (pp->pvmetadatacopies < 0) pp->pvmetadatacopies = find_config_tree_int(cmd, "metadata/pvmetadatacopies", DEFAULT_PVMETADATACOPIES); return 1; } int get_activation_monitoring_mode(struct cmd_context *cmd, int *monitoring_mode) { *monitoring_mode = DEFAULT_DMEVENTD_MONITOR; if (arg_count(cmd, monitor_ARG) && (arg_count(cmd, ignoremonitoring_ARG) || arg_count(cmd, sysinit_ARG))) { log_error("--ignoremonitoring or --sysinit option not allowed with --monitor option"); return 0; } if (arg_count(cmd, monitor_ARG)) *monitoring_mode = arg_int_value(cmd, monitor_ARG, DEFAULT_DMEVENTD_MONITOR); else if (is_static() || arg_count(cmd, ignoremonitoring_ARG) || arg_count(cmd, sysinit_ARG) || !find_config_tree_bool(cmd, "activation/monitoring", DEFAULT_DMEVENTD_MONITOR)) *monitoring_mode = DMEVENTD_MONITOR_IGNORE; return 1; } /* * Generic stripe parameter checks. */ static int _validate_stripe_params(struct cmd_context *cmd, uint32_t *stripes, uint32_t *stripe_size) { if (*stripes == 1 && *stripe_size) { log_print_unless_silent("Ignoring stripesize argument with single stripe"); *stripe_size = 0; } if (*stripes > 1 && !*stripe_size) { *stripe_size = find_config_tree_int(cmd, "metadata/stripesize", DEFAULT_STRIPESIZE) * 2; log_print_unless_silent("Using default stripesize %s", display_size(cmd, (uint64_t) *stripe_size)); } if (*stripes < 1 || *stripes > MAX_STRIPES) { log_error("Number of stripes (%d) must be between %d and %d", *stripes, 1, MAX_STRIPES); return 0; } if (*stripes > 1 && (*stripe_size < STRIPE_SIZE_MIN || *stripe_size & (*stripe_size - 1))) { log_error("Invalid stripe size %s", display_size(cmd, (uint64_t) *stripe_size)); return 0; } return 1; } /* * The stripe size is limited by the size of a uint32_t, but since the * value given by the user is doubled, and the final result must be a * power of 2, we must divide UINT_MAX by four and add 1 (to round it * up to the power of 2) */ int get_stripe_params(struct cmd_context *cmd, uint32_t *stripes, uint32_t *stripe_size) { /* stripes_long_ARG takes precedence (for lvconvert) */ *stripes = arg_uint_value(cmd, arg_count(cmd, stripes_long_ARG) ? stripes_long_ARG : stripes_ARG, 1); *stripe_size = arg_uint_value(cmd, stripesize_ARG, 0); if (*stripe_size) { if (arg_sign_value(cmd, stripesize_ARG, SIGN_NONE) == SIGN_MINUS) { log_error("Negative stripesize is invalid"); return 0; } if(arg_uint64_value(cmd, stripesize_ARG, 0) > STRIPE_SIZE_LIMIT * 2) { log_error("Stripe size cannot be larger than %s", display_size(cmd, (uint64_t) STRIPE_SIZE_LIMIT)); return 0; } } return _validate_stripe_params(cmd, stripes, stripe_size); } /* FIXME move to lib */ static int _pv_change_tag(struct physical_volume *pv, const char *tag, int addtag) { if (addtag) { if (!str_list_add(pv->fmt->cmd->mem, &pv->tags, tag)) { log_error("Failed to add tag %s to physical volume %s", tag, pv_dev_name(pv)); return 0; } } else str_list_del(&pv->tags, tag); return 1; } /* Set exactly one of VG, LV or PV */ int change_tag(struct cmd_context *cmd, struct volume_group *vg, struct logical_volume *lv, struct physical_volume *pv, int arg) { const char *tag; struct arg_value_group_list *current_group; dm_list_iterate_items(current_group, &cmd->arg_value_groups) { if (!grouped_arg_is_set(current_group->arg_values, arg)) continue; if (!(tag = grouped_arg_str_value(current_group->arg_values, arg, NULL))) { log_error("Failed to get tag"); return 0; } if (vg && !vg_change_tag(vg, tag, arg == addtag_ARG)) return_0; else if (lv && !lv_change_tag(lv, tag, arg == addtag_ARG)) return_0; else if (pv && !_pv_change_tag(pv, tag, arg == addtag_ARG)) return_0; } return 1; } /* Return percents of extents and avoid overflow, with optional roundup */ uint32_t percent_of_extents(uint32_t percents, uint32_t count, int roundup) { return (uint32_t)(((uint64_t)percents * (uint64_t)count + ((roundup) ? 99 : 0)) / 100); } lvm2-2.02.98/tools/Makefile.in0000640000175000017500000001275112037016273014724 0ustar blankblank# # Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. # Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved. # # This file is part of LVM2. # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions # of the GNU General Public License v.2. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation, # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA srcdir = @srcdir@ top_srcdir = @top_srcdir@ top_builddir = @top_builddir@ SOURCES =\ dumpconfig.c \ formats.c \ lvchange.c \ lvconvert.c \ lvcreate.c \ lvdisplay.c \ lvextend.c \ lvmchange.c \ lvmcmdline.c \ lvmdiskscan.c \ lvreduce.c \ lvremove.c \ lvrename.c \ lvresize.c \ lvscan.c \ polldaemon.c \ pvchange.c \ pvck.c \ pvcreate.c \ pvdisplay.c \ pvmove.c \ pvremove.c \ pvresize.c \ pvscan.c \ reporter.c \ segtypes.c \ toollib.c \ vgcfgbackup.c \ vgcfgrestore.c \ vgchange.c \ vgck.c \ vgcreate.c \ vgconvert.c \ vgdisplay.c \ vgexport.c \ vgextend.c \ vgimport.c \ vgmerge.c \ vgmknodes.c \ vgreduce.c \ vgremove.c \ vgrename.c \ vgscan.c \ vgsplit.c SOURCES2 =\ dmsetup.c \ lvm.c \ lvm2cmd-static.c \ lvm2cmd.c \ lvmcmdlib.c TARGETS =\ .commands \ liblvm2cmd.a \ lvm TARGETS_DM = dmsetup INSTALL_LVM_TARGETS = install_tools_dynamic INSTALL_DMSETUP_TARGETS = install_dmsetup_dynamic INSTALL_CMDLIB_TARGETS = install_cmdlib_dynamic install_cmdlib_include ifeq ("@STATIC_LINK@", "yes") TARGETS += lvm.static TARGETS_DM += dmsetup.static INSTALL_LVM_TARGETS += install_tools_static INSTALL_DMSETUP_TARGETS += install_dmsetup_static INSTALL_CMDLIB_TARGETS += install_cmdlib_static endif LVMLIBS = $(LVMINTERNAL_LIBS) LIB_VERSION = $(LIB_VERSION_LVM) CLEAN_TARGETS = liblvm2cmd.$(LIB_SUFFIX) $(TARGETS_DM) \ liblvm2cmd.$(LIB_SUFFIX).$(LIB_VERSION) lvm-static.o \ liblvm2cmd-static.a dmsetup.static lvm.static ifeq ("@CMDLIB@", "yes") TARGETS += liblvm2cmd.$(LIB_SUFFIX).$(LIB_VERSION) INSTALL_LVM_TARGETS += $(INSTALL_CMDLIB_TARGETS) endif ifeq ("@DMEVENTD@", "yes") LVMLIBS += -ldevmapper-event endif LVMLIBS += -ldevmapper EXPORTED_HEADER = $(srcdir)/lvm2cmd.h EXPORTED_FN_PREFIX = lvm2 DEFS += -DLVM_SHARED_PATH=\"$(exec_prefix)/sbin/lvm\" CFLOW_LIST = lvmcmdlib.c lvm2cmd.c CFLOW_LIST_TARGET = liblvm2cmd.cflow CFLOW_TARGET = lvm include $(top_builddir)/make.tmpl LIBS += $(UDEV_LIBS) device-mapper: $(TARGETS_DM) dmsetup: dmsetup.o $(top_builddir)/libdm/libdevmapper.$(LIB_SUFFIX) $(CC) $(CFLAGS) $(LDFLAGS) -L$(top_builddir)/libdm \ -o $@ dmsetup.o -ldevmapper $(LIBS) dmsetup.static: dmsetup.o $(interfacebuilddir)/libdevmapper.a $(CC) $(CFLAGS) $(LDFLAGS) -static -L$(interfacebuilddir) \ -o $@ dmsetup.o -ldevmapper $(STATIC_LIBS) $(LIBS) all: device-mapper lvm: $(OBJECTS) lvm.o $(top_builddir)/lib/liblvm-internal.a $(CC) $(CFLAGS) $(LDFLAGS) $(ELDFLAGS) -o $@ $(OBJECTS) lvm.o \ $(LVMLIBS) $(READLINE_LIBS) $(LIBS) -rdynamic lvm.static: $(OBJECTS) lvm-static.o $(top_builddir)/lib/liblvm-internal.a $(interfacebuilddir)/libdevmapper.a $(CC) $(CFLAGS) $(LDFLAGS) -static -L$(interfacebuilddir) -o $@ \ $(OBJECTS) lvm-static.o $(LVMLIBS) $(STATIC_LIBS) $(LIBS) liblvm2cmd.a: $(top_builddir)/lib/liblvm-internal.a $(OBJECTS) lvmcmdlib.o lvm2cmd.o cat $(top_builddir)/lib/liblvm-internal.a > $@ $(AR) rs $@ $(OBJECTS) lvmcmdlib.o lvm2cmd.o liblvm2cmd-static.a: $(top_builddir)/lib/liblvm-internal.a $(OBJECTS) lvmcmdlib.o lvm2cmd-static.o cat $(top_builddir)/lib/liblvm-internal.a > $@ $(AR) rs $@ $(OBJECTS) lvmcmdlib.o lvm2cmd-static.o liblvm2cmd.$(LIB_SUFFIX): liblvm2cmd.a $(LDDEPS) $(CC) -shared -Wl,-soname,$@.$(LIB_VERSION) \ $(CFLAGS) $(CLDFLAGS) -o $@ \ @CLDWHOLEARCHIVE@ liblvm2cmd.a @CLDNOWHOLEARCHIVE@ \ $(LVMLIBS) $(LIBS) liblvm2cmd.$(LIB_SUFFIX).$(LIB_VERSION): liblvm2cmd.$(LIB_SUFFIX) $(LN_S) -f $< $@ .commands: $(srcdir)/commands.h $(srcdir)/cmdnames.h Makefile $(CC) -E -P $(srcdir)/cmdnames.h 2> /dev/null | \ egrep -v '^ *(|#.*|dumpconfig|formats|help|pvdata|segtypes|version) *$$' > .commands ifneq ("$(CFLOW_CMD)", "") CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES)) -include $(top_builddir)/libdm/libdevmapper.cflow -include $(top_builddir)/lib/liblvm-internal.cflow endif .PHONY: install_cmdlib_dynamic install_cmdlib_static install_cmdlib_include \ install_tools_dynamic install_tools_static \ install_dmsetup_dynamic install_dmsetup_static install_cmdlib_include: $(srcdir)/lvm2cmd.h $(INSTALL_DATA) -D $< $(includedir)/$(pv_count == 1) { log_error("Volume Groups must always contain at least one PV"); return 0; } if (!id_write_format(&pvl->pv->id, uuid, sizeof(uuid))) return_0; log_verbose("Removing PV with UUID %s from VG %s", uuid, vg->name); if (pvl->pv->pe_alloc_count) { if (!silent) log_error("LVs still present on PV with UUID %s: " "Can't remove from VG %s", uuid, vg->name); return 0; } vg->free_count -= pvl->pv->pe_count; vg->extent_count -= pvl->pv->pe_count; del_pvl_from_vgs(vg, pvl); free_pv_fid(pvl->pv); return 1; } static int _consolidate_vg(struct cmd_context *cmd, struct volume_group *vg) { struct pv_list *pvl; struct lv_list *lvl; int r = 1; dm_list_iterate_items(lvl, &vg->lvs) if (lvl->lv->status & PARTIAL_LV) { log_warn("WARNING: Partial LV %s needs to be repaired " "or removed. ", lvl->lv->name); r = 0; } if (!r) { cmd->handles_missing_pvs = 1; log_error("There are still partial LVs in VG %s.", vg->name); log_error("To remove them unconditionally use: vgreduce --removemissing --force."); log_warn("Proceeding to remove empty missing PVs."); } dm_list_iterate_items(pvl, &vg->pvs) { if (pvl->pv->dev && !is_missing_pv(pvl->pv)) continue; if (r && !_remove_pv(vg, pvl, 0)) return_0; } return r; } static int _make_vg_consistent(struct cmd_context *cmd, struct volume_group *vg) { struct lv_list *lvl; struct logical_volume *lv; cmd->partial_activation = 1; restart: vg_mark_partial_lvs(vg, 1); dm_list_iterate_items(lvl, &vg->lvs) { lv = lvl->lv; /* Are any segments of this LV on missing PVs? */ if (lv->status & PARTIAL_LV) { if (lv->status & MIRRORED) { if (!mirror_remove_missing(cmd, lv, 1)) return_0; goto restart; } if (arg_count(cmd, mirrorsonly_ARG) &&!(lv->status & MIRRORED)) { log_error("Non-mirror-image LV %s found: can't remove.", lv->name); continue; } if (!lv_is_visible(lv)) continue; log_warn("Removing partial LV %s.", lv->name); if (!lv_remove_with_dependencies(cmd, lv, DONT_PROMPT, 0)) return_0; goto restart; } } _consolidate_vg(cmd, vg); return 1; } /* Or take pv_name instead? */ static int _vgreduce_single(struct cmd_context *cmd, struct volume_group *vg, struct physical_volume *pv, void *handle __attribute__((unused))) { struct pv_list *pvl; struct volume_group *orphan_vg = NULL; int r = ECMD_FAILED; const char *name = pv_dev_name(pv); if (!vg) { log_error(INTERNAL_ERROR "VG is NULL."); return ECMD_FAILED; } if (pv_pe_alloc_count(pv)) { log_error("Physical volume \"%s\" still in use", name); return ECMD_FAILED; } if (vg->pv_count == 1) { log_error("Can't remove final physical volume \"%s\" from " "volume group \"%s\"", name, vg->name); return ECMD_FAILED; } if (!lock_vol(cmd, VG_ORPHANS, LCK_VG_WRITE)) { log_error("Can't get lock for orphan PVs"); return ECMD_FAILED; } pvl = find_pv_in_vg(vg, name); if (!archive(vg)) goto_bad; log_verbose("Removing \"%s\" from volume group \"%s\"", name, vg->name); if (pvl) del_pvl_from_vgs(vg, pvl); pv->vg_name = vg->fid->fmt->orphan_vg_name; pv->status = ALLOCATABLE_PV; if (!dev_get_size(pv_dev(pv), &pv->size)) { log_error("%s: Couldn't get size.", pv_dev_name(pv)); goto bad; } vg->free_count -= pv_pe_count(pv) - pv_pe_alloc_count(pv); vg->extent_count -= pv_pe_count(pv); orphan_vg = vg_read_for_update(cmd, vg->fid->fmt->orphan_vg_name, NULL, 0); if (vg_read_error(orphan_vg)) goto bad; if (!vg_split_mdas(cmd, vg, orphan_vg) || !vg->pv_count) { log_error("Cannot remove final metadata area on \"%s\" from \"%s\"", name, vg->name); goto bad; } if (!vg_write(vg) || !vg_commit(vg)) { log_error("Removal of physical volume \"%s\" from " "\"%s\" failed", name, vg->name); goto bad; } if (!pv_write(cmd, pv, 0)) { log_error("Failed to clear metadata from physical " "volume \"%s\" " "after removal from \"%s\"", name, vg->name); goto bad; } backup(vg); log_print_unless_silent("Removed \"%s\" from volume group \"%s\"", name, vg->name); r = ECMD_PROCESSED; bad: if (pvl) free_pv_fid(pvl->pv); unlock_and_release_vg(cmd, orphan_vg, VG_ORPHANS); return r; } int vgreduce(struct cmd_context *cmd, int argc, char **argv) { struct volume_group *vg; const char *vg_name; int ret = ECMD_FAILED; int fixed = 1; int repairing = arg_count(cmd, removemissing_ARG); int saved_ignore_suspended_devices = ignore_suspended_devices(); int locked = 0; if (!argc && !repairing) { log_error("Please give volume group name and " "physical volume paths"); return EINVALID_CMD_LINE; } if (!argc) { /* repairing */ log_error("Please give volume group name"); return EINVALID_CMD_LINE; } if (arg_count(cmd, mirrorsonly_ARG) && !repairing) { log_error("--mirrorsonly requires --removemissing"); return EINVALID_CMD_LINE; } if (argc == 1 && !arg_count(cmd, all_ARG) && !repairing) { log_error("Please enter physical volume paths or option -a"); return EINVALID_CMD_LINE; } if (argc > 1 && arg_count(cmd, all_ARG)) { log_error("Option -a and physical volume paths mutually " "exclusive"); return EINVALID_CMD_LINE; } if (argc > 1 && repairing) { log_error("Please only specify the volume group"); return EINVALID_CMD_LINE; } vg_name = skip_dev_dir(cmd, argv[0], NULL); argv++; argc--; log_verbose("Finding volume group \"%s\"", vg_name); if (repairing) { init_ignore_suspended_devices(1); cmd->handles_missing_pvs = 1; } vg = vg_read_for_update(cmd, vg_name, NULL, READ_ALLOW_EXPORTED); if (vg_read_error(vg) == FAILED_ALLOCATION || vg_read_error(vg) == FAILED_NOTFOUND) goto_out; /* FIXME We want to allow read-only VGs to be changed here? */ if (vg_read_error(vg) && vg_read_error(vg) != FAILED_READ_ONLY && !arg_count(cmd, removemissing_ARG)) goto_out; locked = !vg_read_error(vg); if (repairing) { if (!vg_read_error(vg) && !vg_missing_pv_count(vg)) { log_error("Volume group \"%s\" is already consistent", vg_name); ret = ECMD_PROCESSED; goto out; } release_vg(vg); log_verbose("Trying to open VG %s for recovery...", vg_name); vg = vg_read_for_update(cmd, vg_name, NULL, READ_ALLOW_INCONSISTENT | READ_ALLOW_EXPORTED); locked |= !vg_read_error(vg); if (vg_read_error(vg) && vg_read_error(vg) != FAILED_READ_ONLY && vg_read_error(vg) != FAILED_INCONSISTENT) goto_out; if (!archive(vg)) goto_out; if (arg_count(cmd, force_ARG)) { if (!_make_vg_consistent(cmd, vg)) goto_out; } else fixed = _consolidate_vg(cmd, vg); if (!vg_write(vg) || !vg_commit(vg)) { log_error("Failed to write out a consistent VG for %s", vg_name); goto out; } backup(vg); if (fixed) { log_print_unless_silent("Wrote out consistent volume group %s", vg_name); ret = ECMD_PROCESSED; } else ret = ECMD_FAILED; } else { if (!vg_check_status(vg, EXPORTED_VG | LVM_WRITE | RESIZEABLE_VG)) goto_out; /* FIXME: Pass private struct through to all these functions */ /* and update in batch here? */ ret = process_each_pv(cmd, argc, argv, vg, READ_FOR_UPDATE, 0, NULL, _vgreduce_single); } out: init_ignore_suspended_devices(saved_ignore_suspended_devices); if (locked) unlock_vg(cmd, vg_name); release_vg(vg); return ret; /******* FIXME log_error ("no empty physical volumes found in volume group \"%s\"", vg_name); log_verbose ("volume group \"%s\" will be reduced by %d physical volume%s", vg_name, np, np > 1 ? "s" : ""); log_verbose ("reducing volume group \"%s\" by physical volume \"%s\"", vg_name, pv_names[p]); log_print ("volume group \"%s\" %ssuccessfully reduced by physical volume%s:", vg_name, error > 0 ? "NOT " : "", p > 1 ? "s" : ""); log_print("%s", pv_this[p]->pv_name); ********/ } lvm2-2.02.98/tools/reporter.c0000640000175000017500000002733212037016273014666 0ustar blankblank/* * 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 */ #include "tools.h" #include "report.h" static int _vgs_single(struct cmd_context *cmd __attribute__((unused)), const char *vg_name, struct volume_group *vg, void *handle) { if (!report_object(handle, vg, NULL, NULL, NULL, NULL)) { stack; return ECMD_FAILED; } check_current_backup(vg); return ECMD_PROCESSED; } static int _lvs_single(struct cmd_context *cmd, struct logical_volume *lv, void *handle) { if (!report_object(handle, lv->vg, lv, NULL, NULL, NULL)) { stack; return ECMD_FAILED; } return ECMD_PROCESSED; } static int _segs_single(struct cmd_context *cmd __attribute__((unused)), struct lv_segment *seg, void *handle) { if (!report_object(handle, seg->lv->vg, seg->lv, NULL, seg, NULL)) { stack; return ECMD_FAILED; } return ECMD_PROCESSED; } static int _pvsegs_sub_single(struct cmd_context *cmd, struct volume_group *vg, struct pv_segment *pvseg, void *handle) { int ret = ECMD_PROCESSED; struct lv_segment *seg = pvseg->lvseg; struct volume_group _free_vg = { .cmd = cmd, .name = "", .vgmem = NULL, }; struct logical_volume _free_logical_volume = { .vg = vg ?: &_free_vg, .name = "", .snapshot = NULL, .status = VISIBLE_LV, .major = -1, .minor = -1, }; struct lv_segment _free_lv_segment = { .lv = &_free_logical_volume, .le = 0, .status = 0, .stripe_size = 0, .area_count = 0, .area_len = 0, .origin = NULL, .cow = NULL, .chunk_size = 0, .region_size = 0, .extents_copied = 0, .log_lv = NULL, .areas = NULL, }; _free_lv_segment.segtype = get_segtype_from_string(cmd, "free"); _free_lv_segment.len = pvseg->len; dm_list_init(&_free_vg.pvs); dm_list_init(&_free_vg.lvs); dm_list_init(&_free_vg.tags); dm_list_init(&_free_lv_segment.tags); dm_list_init(&_free_lv_segment.origin_list); dm_list_init(&_free_logical_volume.tags); dm_list_init(&_free_logical_volume.segments); dm_list_init(&_free_logical_volume.segs_using_this_lv); dm_list_init(&_free_logical_volume.snapshot_segs); if (!report_object(handle, vg, seg ? seg->lv : &_free_logical_volume, pvseg->pv, seg ? : &_free_lv_segment, pvseg)) { ret = ECMD_FAILED; goto_out; } out: return ret; } static int _lvsegs_single(struct cmd_context *cmd, struct logical_volume *lv, void *handle) { if (!arg_count(cmd, all_ARG) && !lv_is_visible(lv)) return ECMD_PROCESSED; return process_each_segment_in_lv(cmd, lv, handle, _segs_single); } static int _pvsegs_single(struct cmd_context *cmd, struct volume_group *vg, struct physical_volume *pv, void *handle) { return process_each_segment_in_pv(cmd, vg, pv, handle, _pvsegs_sub_single); } static int _pvs_single(struct cmd_context *cmd, struct volume_group *vg, struct physical_volume *pv, void *handle) { struct pv_list *pvl; int ret = ECMD_PROCESSED; const char *vg_name = NULL; struct volume_group *old_vg = vg; char uuid[64] __attribute__((aligned(8))); if (is_pv(pv) && !is_orphan(pv) && !vg) { vg_name = pv_vg_name(pv); vg = vg_read(cmd, vg_name, (char *)&pv->vgid, 0); if (vg_read_error(vg)) { log_error("Skipping volume group %s", vg_name); release_vg(vg); return ECMD_FAILED; } /* * Replace possibly incomplete PV structure with new one * allocated in vg_read. */ if (!is_missing_pv(pv)) { if (!(pvl = find_pv_in_vg(vg, pv_dev_name(pv)))) { log_error("Unable to find \"%s\" in volume group \"%s\"", pv_dev_name(pv), vg->name); ret = ECMD_FAILED; goto out; } } else if (!(pvl = find_pv_in_vg_by_uuid(vg, &pv->id))) { if (!id_write_format(&pv->id, uuid, sizeof(uuid))) { stack; uuid[0] = '\0'; } log_error("Unable to find missing PV %s in volume group %s", uuid, vg->name); ret = ECMD_FAILED; goto out; } pv = pvl->pv; } if (!report_object(handle, vg, NULL, pv, NULL, NULL)) { stack; ret = ECMD_FAILED; } out: if (vg_name) unlock_vg(cmd, vg_name); if (!old_vg) release_vg(vg); return ret; } static int _label_single(struct cmd_context *cmd, struct volume_group *vg, struct physical_volume *pv, void *handle) { if (!report_object(handle, vg, NULL, pv, NULL, NULL)) { stack; return ECMD_FAILED; } return ECMD_PROCESSED; } static int _pvs_in_vg(struct cmd_context *cmd, const char *vg_name, struct volume_group *vg, void *handle) { if (vg_read_error(vg)) { stack; return ECMD_FAILED; } return process_each_pv_in_vg(cmd, vg, NULL, handle, &_pvs_single); } static int _pvsegs_in_vg(struct cmd_context *cmd, const char *vg_name, struct volume_group *vg, void *handle) { if (vg_read_error(vg)) { stack; return ECMD_FAILED; } return process_each_pv_in_vg(cmd, vg, NULL, handle, &_pvsegs_single); } static int _report(struct cmd_context *cmd, int argc, char **argv, report_type_t report_type) { void *report_handle; const char *opts; char *str; const char *keys = NULL, *options = NULL, *separator; int r = ECMD_PROCESSED; int aligned, buffered, headings, field_prefixes, quoted; int columns_as_rows; unsigned args_are_pvs; aligned = find_config_tree_int(cmd, "report/aligned", DEFAULT_REP_ALIGNED); buffered = find_config_tree_int(cmd, "report/buffered", DEFAULT_REP_BUFFERED); headings = find_config_tree_int(cmd, "report/headings", DEFAULT_REP_HEADINGS); separator = find_config_tree_str(cmd, "report/separator", DEFAULT_REP_SEPARATOR); field_prefixes = find_config_tree_int(cmd, "report/prefixes", DEFAULT_REP_PREFIXES); quoted = find_config_tree_int(cmd, "report/quoted", DEFAULT_REP_QUOTED); columns_as_rows = find_config_tree_int(cmd, "report/columns_as_rows", DEFAULT_REP_COLUMNS_AS_ROWS); args_are_pvs = (report_type == PVS || report_type == LABEL || report_type == PVSEGS) ? 1 : 0; switch (report_type) { case LVS: keys = find_config_tree_str(cmd, "report/lvs_sort", DEFAULT_LVS_SORT); if (!arg_count(cmd, verbose_ARG)) options = find_config_tree_str(cmd, "report/lvs_cols", DEFAULT_LVS_COLS); else options = find_config_tree_str(cmd, "report/lvs_cols_verbose", DEFAULT_LVS_COLS_VERB); break; case VGS: keys = find_config_tree_str(cmd, "report/vgs_sort", DEFAULT_VGS_SORT); if (!arg_count(cmd, verbose_ARG)) options = find_config_tree_str(cmd, "report/vgs_cols", DEFAULT_VGS_COLS); else options = find_config_tree_str(cmd, "report/vgs_cols_verbose", DEFAULT_VGS_COLS_VERB); break; case LABEL: case PVS: keys = find_config_tree_str(cmd, "report/pvs_sort", DEFAULT_PVS_SORT); if (!arg_count(cmd, verbose_ARG)) options = find_config_tree_str(cmd, "report/pvs_cols", DEFAULT_PVS_COLS); else options = find_config_tree_str(cmd, "report/pvs_cols_verbose", DEFAULT_PVS_COLS_VERB); break; case SEGS: keys = find_config_tree_str(cmd, "report/segs_sort", DEFAULT_SEGS_SORT); if (!arg_count(cmd, verbose_ARG)) options = find_config_tree_str(cmd, "report/segs_cols", DEFAULT_SEGS_COLS); else options = find_config_tree_str(cmd, "report/segs_cols_verbose", DEFAULT_SEGS_COLS_VERB); break; case PVSEGS: keys = find_config_tree_str(cmd, "report/pvsegs_sort", DEFAULT_PVSEGS_SORT); if (!arg_count(cmd, verbose_ARG)) options = find_config_tree_str(cmd, "report/pvsegs_cols", DEFAULT_PVSEGS_COLS); else options = find_config_tree_str(cmd, "report/pvsegs_cols_verbose", DEFAULT_PVSEGS_COLS_VERB); break; default: log_error(INTERNAL_ERROR "Unknown report type."); return ECMD_FAILED; } /* If -o supplied use it, else use default for report_type */ if (arg_count(cmd, options_ARG)) { opts = arg_str_value(cmd, options_ARG, ""); if (!opts || !*opts) { log_error("Invalid options string: %s", opts); return EINVALID_CMD_LINE; } if (*opts == '+') { if (!(str = dm_pool_alloc(cmd->mem, strlen(options) + strlen(opts) + 1))) { log_error("options string allocation failed"); return ECMD_FAILED; } strcpy(str, options); strcat(str, ","); strcat(str, opts + 1); options = str; } else options = opts; } /* -O overrides default sort settings */ keys = arg_str_value(cmd, sort_ARG, keys); separator = arg_str_value(cmd, separator_ARG, separator); if (arg_count(cmd, separator_ARG)) aligned = 0; if (arg_count(cmd, aligned_ARG)) aligned = 1; if (arg_count(cmd, unbuffered_ARG) && !arg_count(cmd, sort_ARG)) buffered = 0; if (arg_count(cmd, noheadings_ARG)) headings = 0; if (arg_count(cmd, nameprefixes_ARG)) { aligned = 0; field_prefixes = 1; } if (arg_count(cmd, unquoted_ARG)) quoted = 0; if (arg_count(cmd, rows_ARG)) columns_as_rows = 1; if (!(report_handle = report_init(cmd, options, keys, &report_type, separator, aligned, buffered, headings, field_prefixes, quoted, columns_as_rows))) { if (!strcasecmp(options, "help") || !strcmp(options, "?")) return r; stack; return ECMD_FAILED; } /* Ensure options selected are compatible */ if (report_type & SEGS) report_type |= LVS; if (report_type & PVSEGS) report_type |= PVS; if ((report_type & LVS) && (report_type & (PVS | LABEL)) && !args_are_pvs) { log_error("Can't report LV and PV fields at the same time"); dm_report_free(report_handle); return ECMD_FAILED; } /* Change report type if fields specified makes this necessary */ if ((report_type & PVSEGS) || ((report_type & (PVS | LABEL)) && (report_type & LVS))) report_type = PVSEGS; else if ((report_type & LABEL) && (report_type & VGS)) report_type = PVS; else if (report_type & PVS) report_type = PVS; else if (report_type & SEGS) report_type = SEGS; else if (report_type & LVS) report_type = LVS; switch (report_type) { case LVS: r = process_each_lv(cmd, argc, argv, 0, report_handle, &_lvs_single); break; case VGS: r = process_each_vg(cmd, argc, argv, 0, report_handle, &_vgs_single); break; case LABEL: r = process_each_pv(cmd, argc, argv, NULL, READ_WITHOUT_LOCK, 1, report_handle, &_label_single); break; case PVS: if (args_are_pvs) r = process_each_pv(cmd, argc, argv, NULL, 0, 0, report_handle, &_pvs_single); else r = process_each_vg(cmd, argc, argv, 0, report_handle, &_pvs_in_vg); break; case SEGS: r = process_each_lv(cmd, argc, argv, 0, report_handle, &_lvsegs_single); break; case PVSEGS: if (args_are_pvs) r = process_each_pv(cmd, argc, argv, NULL, 0, 0, report_handle, &_pvsegs_single); else r = process_each_vg(cmd, argc, argv, 0, report_handle, &_pvsegs_in_vg); break; } dm_report_output(report_handle); dm_report_free(report_handle); return r; } int lvs(struct cmd_context *cmd, int argc, char **argv) { report_type_t type; if (arg_count(cmd, segments_ARG)) type = SEGS; else type = LVS; return _report(cmd, argc, argv, type); } int vgs(struct cmd_context *cmd, int argc, char **argv) { return _report(cmd, argc, argv, VGS); } int pvs(struct cmd_context *cmd, int argc, char **argv) { report_type_t type; if (arg_count(cmd, segments_ARG)) type = PVSEGS; else type = LABEL; return _report(cmd, argc, argv, type); } lvm2-2.02.98/tools/vgck.c0000640000175000017500000000237012037016273013751 0ustar blankblank/* * 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 "tools.h" #include "metadata.h" static int vgck_single(struct cmd_context *cmd __attribute__((unused)), const char *vg_name, struct volume_group *vg, void *handle __attribute__((unused))) { if (!vg_check_status(vg, EXPORTED_VG)) { stack; return ECMD_FAILED; } if (!vg_validate(vg)) { stack; return ECMD_FAILED; } if (vg_missing_pv_count(vg)) { log_error("The volume group is missing %d physical volumes.", vg_missing_pv_count(vg)); return ECMD_FAILED; } return ECMD_PROCESSED; } int vgck(struct cmd_context *cmd, int argc, char **argv) { return process_each_vg(cmd, argc, argv, 0, NULL, &vgck_single); } lvm2-2.02.98/tools/pvchange.c0000640000175000017500000001703412037016273014615 0ustar blankblank/* * 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 "tools.h" static int _pvchange_single(struct cmd_context *cmd, struct volume_group *vg, struct physical_volume *pv, void *handle __attribute__((unused))) { uint32_t orig_pe_alloc_count; /* FIXME Next three only required for format1. */ uint32_t orig_pe_count, orig_pe_size; uint64_t orig_pe_start; const char *pv_name = pv_dev_name(pv); const char *orig_vg_name; char uuid[64] __attribute__((aligned(8))); int allocatable = 0; int tagargs = 0; int mda_ignore = 0; tagargs = arg_count(cmd, addtag_ARG) + arg_count(cmd, deltag_ARG); if (arg_count(cmd, allocatable_ARG)) allocatable = !strcmp(arg_str_value(cmd, allocatable_ARG, "n"), "y"); if (arg_count(cmd, metadataignore_ARG)) mda_ignore = !strcmp(arg_str_value(cmd, metadataignore_ARG, "n"), "y"); /* If in a VG, must change using volume group. */ if (!is_orphan(pv)) { if (tagargs && !(vg->fid->fmt->features & FMT_TAGS)) { log_error("Volume group containing %s does not " "support tags", pv_name); return 0; } if (arg_count(cmd, uuid_ARG) && lvs_in_vg_activated(vg)) { log_error("Volume group containing %s has active " "logical volumes", pv_name); return 0; } if (!archive(vg)) return 0; } else { if (tagargs) { log_error("Can't change tag on Physical Volume %s not " "in volume group", pv_name); return 0; } } if (arg_count(cmd, allocatable_ARG)) { if (is_orphan(pv) && !(pv->fmt->features & FMT_ORPHAN_ALLOCATABLE)) { log_error("Allocatability not supported by orphan " "%s format PV %s", pv->fmt->name, pv_name); return 0; } /* change allocatability for a PV */ if (allocatable && (pv_status(pv) & ALLOCATABLE_PV)) { log_error("Physical volume \"%s\" is already " "allocatable", pv_name); return 1; } if (!allocatable && !(pv_status(pv) & ALLOCATABLE_PV)) { log_error("Physical volume \"%s\" is already " "unallocatable", pv_name); return 1; } if (allocatable) { log_verbose("Setting physical volume \"%s\" " "allocatable", pv_name); pv->status |= ALLOCATABLE_PV; } else { log_verbose("Setting physical volume \"%s\" NOT " "allocatable", pv_name); pv->status &= ~ALLOCATABLE_PV; } } if (tagargs) { /* tag or deltag */ if (arg_count(cmd, addtag_ARG) && !change_tag(cmd, NULL, NULL, pv, addtag_ARG)) return_0; if (arg_count(cmd, deltag_ARG) && !change_tag(cmd, NULL, NULL, pv, deltag_ARG)) return_0; } if (arg_count(cmd, metadataignore_ARG)) { if ((vg_mda_copies(vg) != VGMETADATACOPIES_UNMANAGED) && (arg_count(cmd, force_ARG) == PROMPT) && yes_no_prompt("Override preferred number of copies " "of VG %s metadata? [y/n]: ", pv_vg_name(pv)) == 'n') { log_error("Physical volume %s not changed", pv_name); return 0; } if (!pv_change_metadataignore(pv, mda_ignore)) return_0; } if (arg_count(cmd, uuid_ARG)) { /* --uuid: Change PV ID randomly */ memcpy(&pv->old_id, &pv->id, sizeof(pv->id)); if (!id_create(&pv->id)) { log_error("Failed to generate new random UUID for %s.", pv_name); return 0; } if (!id_write_format(&pv->id, uuid, sizeof(uuid))) return 0; log_verbose("Changing uuid of %s to %s.", pv_name, uuid); if (!is_orphan(pv)) { orig_vg_name = pv_vg_name(pv); orig_pe_alloc_count = pv_pe_alloc_count(pv); /* FIXME format1 pv_write doesn't preserve these. */ orig_pe_size = pv_pe_size(pv); orig_pe_start = pv_pe_start(pv); orig_pe_count = pv_pe_count(pv); pv->vg_name = pv->fmt->orphan_vg_name; pv->pe_alloc_count = 0; if (!(pv_write(cmd, pv, 0))) { log_error("pv_write with new uuid failed " "for %s.", pv_name); return 0; } pv->vg_name = orig_vg_name; pv->pe_alloc_count = orig_pe_alloc_count; pv->pe_size = orig_pe_size; pv->pe_start = orig_pe_start; pv->pe_count = orig_pe_count; } } log_verbose("Updating physical volume \"%s\"", pv_name); if (!is_orphan(pv)) { if (!vg_write(vg) || !vg_commit(vg)) { log_error("Failed to store physical volume \"%s\" in " "volume group \"%s\"", pv_name, vg->name); return 0; } backup(vg); } else if (!(pv_write(cmd, pv, 0))) { log_error("Failed to store physical volume \"%s\"", pv_name); return 0; } log_print_unless_silent("Physical volume \"%s\" changed", pv_name); return 1; } int pvchange(struct cmd_context *cmd, int argc, char **argv) { int opt = 0; int done = 0; int total = 0; struct volume_group *vg; const char *vg_name; char *pv_name; struct pv_list *pvl; struct dm_list *vgnames; struct str_list *sll; if (!(arg_count(cmd, allocatable_ARG) + arg_is_set(cmd, addtag_ARG) + arg_is_set(cmd, deltag_ARG) + arg_count(cmd, uuid_ARG) + arg_count(cmd, metadataignore_ARG))) { log_error("Please give one or more of -x, -uuid, " "--addtag, --deltag or --metadataignore"); return EINVALID_CMD_LINE; } if (!(arg_count(cmd, all_ARG)) && !argc) { log_error("Please give a physical volume path"); return EINVALID_CMD_LINE; } if (arg_count(cmd, all_ARG) && argc) { log_error("Option a and PhysicalVolumePath are exclusive"); return EINVALID_CMD_LINE; } if (argc) { log_verbose("Using physical volume(s) on command line"); for (; opt < argc; opt++) { pv_name = argv[opt]; dm_unescape_colons_and_at_signs(pv_name, NULL, NULL); vg_name = find_vgname_from_pvname(cmd, pv_name); if (!vg_name) { log_error("Failed to read physical volume %s", pv_name); continue; } vg = vg_read_for_update(cmd, vg_name, NULL, 0); if (vg_read_error(vg)) { release_vg(vg); stack; continue; } pvl = find_pv_in_vg(vg, pv_name); if (!pvl || !pvl->pv) { log_error("Unable to find %s in %s", pv_name, vg_name); continue; } total++; done += _pvchange_single(cmd, vg, pvl->pv, NULL); unlock_and_release_vg(cmd, vg, vg_name); } } else { log_verbose("Scanning for physical volume names"); /* FIXME: share code with toollib */ /* * Take the global lock here so the lvmcache remains * consistent across orphan/non-orphan vg locks. If we don't * take the lock here, pvs with 0 mdas in a non-orphan VG will * be processed twice. */ if (!lock_vol(cmd, VG_GLOBAL, LCK_VG_WRITE)) { log_error("Unable to obtain global lock."); return ECMD_FAILED; } if ((vgnames = get_vgnames(cmd, 1)) && !dm_list_empty(vgnames)) { dm_list_iterate_items(sll, vgnames) { vg = vg_read_for_update(cmd, sll->str, NULL, 0); if (vg_read_error(vg)) { release_vg(vg); stack; continue; } dm_list_iterate_items(pvl, &vg->pvs) { total++; done += _pvchange_single(cmd, vg, pvl->pv, NULL); } unlock_and_release_vg(cmd, vg, sll->str); } } unlock_vg(cmd, VG_GLOBAL); } log_print_unless_silent("%d physical volume%s changed / %d physical volume%s " "not changed", done, done == 1 ? "" : "s", total - done, (total - done) == 1 ? "" : "s"); return (total == done) ? ECMD_PROCESSED : ECMD_FAILED; } lvm2-2.02.98/tools/vgcfgrestore.c0000640000175000017500000000421612037016273015520 0ustar blankblank/* * 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 */ #include "tools.h" int vgcfgrestore(struct cmd_context *cmd, int argc, char **argv) { const char *vg_name = NULL; if (argc == 1) { vg_name = skip_dev_dir(cmd, argv[0], NULL); if (!validate_name(vg_name)) { log_error("Volume group name \"%s\" is invalid", vg_name); return ECMD_FAILED; } } else if (!(arg_count(cmd, list_ARG) && arg_count(cmd, file_ARG))) { log_error("Please specify a *single* volume group to restore."); return ECMD_FAILED; } /* * FIXME: overloading the -l arg for now to display a * list of archive files for a particular vg */ if (arg_count(cmd, list_ARG)) { if (!(arg_count(cmd,file_ARG) ? archive_display_file(cmd, arg_str_value(cmd, file_ARG, "")) : archive_display(cmd, vg_name))) { stack; return ECMD_FAILED; } return ECMD_PROCESSED; } lvmcache_seed_infos_from_lvmetad(cmd); if (!lock_vol(cmd, vg_name, LCK_VG_WRITE)) { log_error("Unable to lock volume group %s", vg_name); return ECMD_FAILED; } if (!lock_vol(cmd, VG_ORPHANS, LCK_VG_WRITE)) { log_error("Unable to lock orphans"); unlock_vg(cmd, vg_name); return ECMD_FAILED; } cmd->handles_unknown_segments = 1; if (!(arg_count(cmd, file_ARG) ? backup_restore_from_file(cmd, vg_name, arg_str_value(cmd, file_ARG, "")) : backup_restore(cmd, vg_name))) { unlock_vg(cmd, VG_ORPHANS); unlock_vg(cmd, vg_name); log_error("Restore failed."); return ECMD_FAILED; } log_print_unless_silent("Restored volume group %s", vg_name); unlock_vg(cmd, VG_ORPHANS); unlock_vg(cmd, vg_name); return ECMD_PROCESSED; } lvm2-2.02.98/tools/vgcreate.c0000640000175000017500000000676212037016273014630 0ustar blankblank/* * 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 */ #include "tools.h" int vgcreate(struct cmd_context *cmd, int argc, char **argv) { struct vgcreate_params vp_new; struct vgcreate_params vp_def; struct volume_group *vg; const char *tag; const char *clustered_message = ""; char *vg_name; struct pvcreate_params pp; struct arg_value_group_list *current_group; if (!argc) { log_error("Please provide volume group name and " "physical volumes"); return EINVALID_CMD_LINE; } vg_name = argv[0]; argc--; argv++; pvcreate_params_set_defaults(&pp); if (!pvcreate_params_validate(cmd, argc, argv, &pp)) { return EINVALID_CMD_LINE; } vgcreate_params_set_defaults(&vp_def, NULL); vp_def.vg_name = vg_name; if (vgcreate_params_set_from_args(cmd, &vp_new, &vp_def)) return EINVALID_CMD_LINE; if (vgcreate_params_validate(cmd, &vp_new)) return EINVALID_CMD_LINE; lvmcache_seed_infos_from_lvmetad(cmd); /* Create the new VG */ vg = vg_create(cmd, vp_new.vg_name); if (vg_read_error(vg)) { if (vg_read_error(vg) == FAILED_EXIST) log_error("A volume group called %s already exists.", vp_new.vg_name); else log_error("Can't get lock for %s.", vp_new.vg_name); release_vg(vg); return ECMD_FAILED; } if (!vg_set_extent_size(vg, vp_new.extent_size) || !vg_set_max_lv(vg, vp_new.max_lv) || !vg_set_max_pv(vg, vp_new.max_pv) || !vg_set_alloc_policy(vg, vp_new.alloc) || !vg_set_clustered(vg, vp_new.clustered) || !vg_set_mda_copies(vg, vp_new.vgmetadatacopies)) goto bad_orphan; if (!lock_vol(cmd, VG_ORPHANS, LCK_VG_WRITE)) { log_error("Can't get lock for orphan PVs"); goto bad_orphan; } /* attach the pv's */ if (!vg_extend(vg, argc, (const char* const*)argv, &pp)) goto_bad; if (vp_new.max_lv != vg->max_lv) log_warn("WARNING: Setting maxlogicalvolumes to %d " "(0 means unlimited)", vg->max_lv); if (vp_new.max_pv != vg->max_pv) log_warn("WARNING: Setting maxphysicalvolumes to %d " "(0 means unlimited)", vg->max_pv); if (arg_count(cmd, addtag_ARG)) { dm_list_iterate_items(current_group, &cmd->arg_value_groups) { if (!grouped_arg_is_set(current_group->arg_values, addtag_ARG)) continue; if (!(tag = grouped_arg_str_value(current_group->arg_values, addtag_ARG, NULL))) { log_error("Failed to get tag"); goto bad; } if (!vg_change_tag(vg, tag, 1)) goto_bad; } } if (vg_is_clustered(vg)) clustered_message = "Clustered "; else if (locking_is_clustered()) clustered_message = "Non-clustered "; if (!archive(vg)) goto_bad; /* Store VG on disk(s) */ if (!vg_write(vg) || !vg_commit(vg)) goto_bad; unlock_vg(cmd, VG_ORPHANS); unlock_vg(cmd, vp_new.vg_name); backup(vg); log_print_unless_silent("%s%colume group \"%s\" successfully created", clustered_message, *clustered_message ? 'v' : 'V', vg->name); release_vg(vg); return ECMD_PROCESSED; bad: unlock_vg(cmd, VG_ORPHANS); bad_orphan: release_vg(vg); unlock_vg(cmd, vp_new.vg_name); return ECMD_FAILED; } lvm2-2.02.98/tools/segtypes.c0000640000175000017500000000141412037016273014660 0ustar blankblank/* * 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 */ #include "tools.h" int segtypes(struct cmd_context *cmd, int argc __attribute__((unused)), char **argv __attribute__((unused))) { display_segtypes(cmd); return ECMD_PROCESSED; } lvm2-2.02.98/tools/vgcfgbackup.c0000640000175000017500000000477412037016273015313 0ustar blankblank/* * 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 "tools.h" static char *_expand_filename(const char *template, const char *vg_name, char **last_filename) { char *filename; if (security_level()) return dm_strdup(template); if (!(filename = dm_malloc(PATH_MAX))) { log_error("Failed to allocate filename."); return NULL; } if (dm_snprintf(filename, PATH_MAX, template, vg_name) < 0) { log_error("Error processing filename template %s", template); dm_free(filename); return NULL; } if (*last_filename && !strncmp(*last_filename, filename, PATH_MAX)) { log_error("VGs must be backed up into different files. " "Use %%s in filename for VG name."); dm_free(filename); return NULL; } dm_free(*last_filename); *last_filename = filename; return filename; } static int vg_backup_single(struct cmd_context *cmd, const char *vg_name, struct volume_group *vg, void *handle) { char **last_filename = (char **)handle; char *filename; if (arg_count(cmd, file_ARG)) { if (!(filename = _expand_filename(arg_value(cmd, file_ARG), vg->name, last_filename))) { stack; return ECMD_FAILED; } if (!backup_to_file(filename, vg->cmd->cmd_line, vg)) { stack; return ECMD_FAILED; } } else { if (vg_read_error(vg) == FAILED_INCONSISTENT) { log_error("No backup taken: specify filename with -f " "to backup an inconsistent VG"); stack; return ECMD_FAILED; } /* just use the normal backup code */ backup_enable(cmd, 1); /* force a backup */ if (!backup(vg)) { stack; return ECMD_FAILED; } } log_print_unless_silent("Volume group \"%s\" successfully backed up.", vg_name); return ECMD_PROCESSED; } int vgcfgbackup(struct cmd_context *cmd, int argc, char **argv) { int ret; char *last_filename = NULL; init_pvmove(1); ret = process_each_vg(cmd, argc, argv, READ_ALLOW_INCONSISTENT, &last_filename, &vg_backup_single); dm_free(last_filename); init_pvmove(0); return ret; } lvm2-2.02.98/tools/lvextend.c0000640000175000017500000000130312037016273014643 0ustar blankblank/* * 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 */ #include "tools.h" int lvextend(struct cmd_context *cmd, int argc, char **argv) { return lvresize(cmd, argc, argv); } lvm2-2.02.98/tools/vgrename.c0000640000175000017500000001203212037016273014617 0ustar blankblank/* * 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 */ #include "tools.h" static struct volume_group *_get_old_vg_for_rename(struct cmd_context *cmd, const char *vg_name_old, const char *vgid) { struct volume_group *vg; /* FIXME we used to print an error about EXPORTED, but proceeded nevertheless. */ vg = vg_read_for_update(cmd, vg_name_old, vgid, READ_ALLOW_EXPORTED); if (vg_read_error(vg)) { release_vg(vg); return_NULL; } return vg; } static int _lock_new_vg_for_rename(struct cmd_context *cmd, const char *vg_name_new) { int rc; log_verbose("Checking for new volume group \"%s\"", vg_name_new); rc = vg_lock_newname(cmd, vg_name_new); if (rc == FAILED_LOCKING) { log_error("Can't get lock for %s", vg_name_new); return 0; } if (rc == FAILED_EXIST) { log_error("New volume group \"%s\" already exists", vg_name_new); return 0; } return 1; } static int vg_rename_path(struct cmd_context *cmd, const char *old_vg_path, const char *new_vg_path) { char *dev_dir; struct id id; int match = 0; int found_id = 0; struct dm_list *vgids; struct str_list *sl; const char *vg_name_new; const char *vgid = NULL, *vg_name, *vg_name_old; char old_path[NAME_LEN], new_path[NAME_LEN]; struct volume_group *vg = NULL; int lock_vg_old_first = 1; vg_name_old = skip_dev_dir(cmd, old_vg_path, NULL); vg_name_new = skip_dev_dir(cmd, new_vg_path, NULL); dev_dir = cmd->dev_dir; if (!validate_vg_rename_params(cmd, vg_name_old, vg_name_new)) return_0; log_verbose("Checking for existing volume group \"%s\"", vg_name_old); /* populate lvmcache */ if (!lvmetad_vg_list_to_lvmcache(cmd)) stack; /* Avoid duplicates */ if (!(vgids = get_vgids(cmd, 0)) || dm_list_empty(vgids)) { log_error("No complete volume groups found"); return 0; } dm_list_iterate_items(sl, vgids) { vgid = sl->str; if (!vgid || !(vg_name = lvmcache_vgname_from_vgid(NULL, vgid))) continue; if (!strcmp(vg_name, vg_name_old)) { if (match) { log_error("Found more than one VG called %s. " "Please supply VG uuid.", vg_name_old); return 0; } match = 1; } } log_suppress(2); found_id = id_read_format(&id, vg_name_old); log_suppress(0); if (found_id && (vg_name = lvmcache_vgname_from_vgid(cmd->mem, (char *)id.uuid))) { vg_name_old = vg_name; vgid = (char *)id.uuid; } else vgid = NULL; if (strcmp(vg_name_new, vg_name_old) < 0) lock_vg_old_first = 0; if (lock_vg_old_first) { vg = _get_old_vg_for_rename(cmd, vg_name_old, vgid); if (!vg) return_0; if (!_lock_new_vg_for_rename(cmd, vg_name_new)) { unlock_and_release_vg(cmd, vg, vg_name_old); return_0; } } else { if (!_lock_new_vg_for_rename(cmd, vg_name_new)) return_0; vg = _get_old_vg_for_rename(cmd, vg_name_old, vgid); if (!vg) { unlock_vg(cmd, vg_name_new); return_0; } } if (!archive(vg)) goto error; /* Remove references based on old name */ if (!drop_cached_metadata(vg)) stack; /* Change the volume group name */ vg_rename(cmd, vg, vg_name_new); /* store it on disks */ log_verbose("Writing out updated volume group"); if (!vg_write(vg) || !vg_commit(vg)) { goto error; } sprintf(old_path, "%s%s", dev_dir, vg_name_old); sprintf(new_path, "%s%s", dev_dir, vg_name_new); if (activation() && dir_exists(old_path)) { log_verbose("Renaming \"%s\" to \"%s\"", old_path, new_path); if (test_mode()) log_verbose("Test mode: Skipping rename."); else if (lvs_in_vg_activated(vg)) { if (!vg_refresh_visible(cmd, vg)) { log_error("Renaming \"%s\" to \"%s\" failed", old_path, new_path); goto error; } } } if (!backup(vg)) stack; if (!backup_remove(cmd, vg_name_old)) stack; unlock_vg(cmd, vg_name_new); unlock_and_release_vg(cmd, vg, vg_name_old); log_print_unless_silent("Volume group \"%s\" successfully renamed to \"%s\"", vg_name_old, vg_name_new); /* FIXME lvmcache corruption - vginfo duplicated instead of renamed */ if (cmd->filter->wipe) cmd->filter->wipe(cmd->filter); lvmcache_destroy(cmd, 1); return 1; error: if (lock_vg_old_first) { unlock_vg(cmd, vg_name_new); unlock_and_release_vg(cmd, vg, vg_name_old); } else { unlock_and_release_vg(cmd, vg, vg_name_old); unlock_vg(cmd, vg_name_new); } return 0; } int vgrename(struct cmd_context *cmd, int argc, char **argv) { if (argc != 2) { log_error("Old and new volume group names need specifying"); return EINVALID_CMD_LINE; } if (!vg_rename_path(cmd, argv[0], argv[1])) { stack; return ECMD_FAILED; } return ECMD_PROCESSED; } lvm2-2.02.98/tools/pvremove.c0000640000175000017500000001014112037016273014655 0ustar blankblank/* * 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 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 "tools.h" const char _really_wipe[] = "Really WIPE LABELS from physical volume \"%s\" of volume group \"%s\" [y/n]? "; /* * Decide whether it is "safe" to wipe the labels on this device. * 0 indicates we may not. */ static int pvremove_check(struct cmd_context *cmd, const char *name) { struct physical_volume *pv; /* FIXME Check partition type is LVM unless --force is given */ /* Is there a pv here already? */ /* If not, this is an error unless you used -f. */ if (!(pv = pv_read(cmd, name, 1, 0))) { if (arg_count(cmd, force_ARG)) return 1; log_error("Physical Volume %s not found", name); return 0; } /* * If a PV has no MDAs it may appear to be an * orphan until the metadata is read off * another PV in the same VG. Detecting this * means checking every VG by scanning every * PV on the system. */ if (is_orphan(pv) && !dm_list_size(&pv->fid->metadata_areas_in_use) && !dm_list_size(&pv->fid->metadata_areas_ignored)) { if (!scan_vgs_for_pvs(cmd, 0)) { log_error("Rescan for PVs without metadata areas " "failed."); goto bad; } free_pv_fid(pv); if (!(pv = pv_read(cmd, name, 1, 0))) { log_error("Failed to read physical volume %s", name); goto bad; } } /* orphan ? */ if (is_orphan(pv)) { free_pv_fid(pv); return 1; } /* Allow partial & exported VGs to be destroyed. */ /* we must have -ff to overwrite a non orphan */ if (arg_count(cmd, force_ARG) < 2) { log_error("PV %s belongs to Volume Group %s so please use vgreduce first.", name, pv_vg_name(pv)); log_error("(If you are certain you need pvremove, then confirm by using --force twice.)"); goto bad; } /* prompt */ if (!arg_count(cmd, yes_ARG) && yes_no_prompt(_really_wipe, name, pv_vg_name(pv)) == 'n') { log_error("%s: physical volume label not removed", name); goto bad; } if (arg_count(cmd, force_ARG)) { log_warn("WARNING: Wiping physical volume label from " "%s%s%s%s", name, !is_orphan(pv) ? " of volume group \"" : "", !is_orphan(pv) ? pv_vg_name(pv) : "", !is_orphan(pv) ? "\"" : ""); } free_pv_fid(pv); return 1; bad: free_pv_fid(pv); return 0; } static int pvremove_single(struct cmd_context *cmd, const char *pv_name, void *handle __attribute__((unused))) { struct device *dev; int ret = ECMD_FAILED; if (!lock_vol(cmd, VG_ORPHANS, LCK_VG_WRITE)) { log_error("Can't get lock for orphan PVs"); return ECMD_FAILED; } if (!pvremove_check(cmd, pv_name)) goto out; if (!(dev = dev_cache_get(pv_name, cmd->filter))) { log_error("%s: Couldn't find device. Check your filters?", pv_name); goto out; } if (!dev_test_excl(dev)) { /* FIXME Detect whether device-mapper is still using the device */ log_error("Can't open %s exclusively - not removing. " "Mounted filesystem?", dev_name(dev)); goto out; } /* Wipe existing label(s) */ if (!label_remove(dev)) { log_error("Failed to wipe existing label(s) on %s", pv_name); goto out; } if (!lvmetad_pv_gone_by_dev(dev, NULL)) goto_out; log_print_unless_silent("Labels on physical volume \"%s\" successfully wiped", pv_name); ret = ECMD_PROCESSED; out: unlock_vg(cmd, VG_ORPHANS); return ret; } int pvremove(struct cmd_context *cmd, int argc, char **argv) { int i, r; int ret = ECMD_PROCESSED; if (!argc) { log_error("Please enter a physical volume path"); return EINVALID_CMD_LINE; } for (i = 0; i < argc; i++) { dm_unescape_colons_and_at_signs(argv[i], NULL, NULL); r = pvremove_single(cmd, argv[i], NULL); if (r > ret) ret = r; } return ret; } lvm2-2.02.98/tools/vgdisplay.c0000640000175000017500000000565012037016273015025 0ustar blankblank/* * 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 "tools.h" static int vgdisplay_single(struct cmd_context *cmd, const char *vg_name, struct volume_group *vg, void *handle __attribute__((unused))) { /* FIXME Do the active check here if activevolumegroups_ARG ? */ vg_check_status(vg, EXPORTED_VG); if (arg_count(cmd, colon_ARG)) { vgdisplay_colons(vg); return ECMD_PROCESSED; } if (arg_count(cmd, short_ARG)) { vgdisplay_short(vg); return ECMD_PROCESSED; } vgdisplay_full(vg); /* was vg_show */ if (arg_count(cmd, verbose_ARG)) { vgdisplay_extents(vg); process_each_lv_in_vg(cmd, vg, NULL, NULL, NULL, NULL, (process_single_lv_fn_t)lvdisplay_full); log_print("--- Physical volumes ---"); process_each_pv_in_vg(cmd, vg, NULL, NULL, (process_single_pv_fn_t)pvdisplay_short); } check_current_backup(vg); return ECMD_PROCESSED; } int vgdisplay(struct cmd_context *cmd, int argc, char **argv) { if (arg_count(cmd, columns_ARG)) { if (arg_count(cmd, colon_ARG) || arg_count(cmd, activevolumegroups_ARG) || arg_count(cmd, short_ARG)) { log_error("Incompatible options selected"); return EINVALID_CMD_LINE; } return vgs(cmd, argc, argv); } else if (arg_count(cmd, aligned_ARG) || arg_count(cmd, noheadings_ARG) || arg_count(cmd, options_ARG) || arg_count(cmd, separator_ARG) || arg_count(cmd, sort_ARG) || arg_count(cmd, unbuffered_ARG)) { log_error("Incompatible options selected"); return EINVALID_CMD_LINE; } if (arg_count(cmd, colon_ARG) && arg_count(cmd, short_ARG)) { log_error("Option -c is not allowed with option -s"); return EINVALID_CMD_LINE; } if (argc && arg_count(cmd, activevolumegroups_ARG)) { log_error("Option -A is not allowed with volume group names"); return EINVALID_CMD_LINE; } /********* FIXME: Do without this - or else 2(+) passes! Figure out longest volume group name for (c = opt; opt < argc; opt++) { len = strlen(argv[opt]); if (len > max_len) max_len = len; } **********/ return process_each_vg(cmd, argc, argv, 0, NULL, vgdisplay_single); /******** FIXME Need to count number processed Add this to process_each_vg if arg_count(cmd,activevolumegroups_ARG) ? if (opt == argc) { log_print("no "); if (arg_count(cmd,activevolumegroups_ARG)) printf("active "); printf("volume groups found\n\n"); return LVM_E_NO_VG; } ************/ } lvm2-2.02.98/tools/cmdnames.h0000640000175000017500000000117512037016273014615 0ustar blankblank/* * 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 */ #define xx(a, b, c...) a #include "commands.h" lvm2-2.02.98/tools/lvconvert.c0000640000175000017500000016563212037016273015054 0ustar blankblank/* * Copyright (C) 2005-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 "tools.h" #include "polldaemon.h" #include "lv_alloc.h" #include "metadata.h" struct lvconvert_params { int snapshot; int merge; int merge_mirror; int zero; const char *origin; const char *lv_name; const char *lv_split_name; const char *lv_name_full; const char *vg_name; int wait_completion; int need_polling; uint32_t chunk_size; uint32_t region_size; uint32_t mirrors; sign_t mirrors_sign; uint32_t keep_mimages; uint32_t stripes; uint32_t stripe_size; const struct segment_type *segtype; alloc_policy_t alloc; int pv_count; char **pvs; struct dm_list *pvh; int replace_pv_count; char **replace_pvs; struct dm_list *replace_pvh; struct logical_volume *lv_to_poll; uint64_t poolmetadata_size; const char *pool_data_lv_name; const char *pool_metadata_lv_name; thin_discards_t discards; }; static int _lvconvert_name_params(struct lvconvert_params *lp, struct cmd_context *cmd, int *pargc, char ***pargv) { char *ptr; const char *vg_name = NULL; if (lp->merge) return 1; if (lp->snapshot) { if (!*pargc) { log_error("Please specify a logical volume to act as " "the snapshot origin."); return 0; } lp->origin = *pargv[0]; (*pargv)++, (*pargc)--; if (!(lp->vg_name = extract_vgname(cmd, lp->origin))) { log_error("The origin name should include the " "volume group."); return 0; } /* Strip the volume group from the origin */ if ((ptr = strrchr(lp->origin, (int) '/'))) lp->origin = ptr + 1; } if (!*pargc && lp->pool_data_lv_name) { if (!lp->vg_name || !validate_name(lp->vg_name)) { log_error("Please provide a valid volume group name."); return 0; } lp->lv_name = lp->pool_data_lv_name; return 1; /* Create metadata LV on it's own */ } if (!*pargc) { log_error("Please provide logical volume path"); return 0; } lp->lv_name = lp->lv_name_full = (*pargv)[0]; (*pargv)++, (*pargc)--; if (strchr(lp->lv_name_full, '/') && (vg_name = extract_vgname(cmd, lp->lv_name_full)) && lp->vg_name && strcmp(vg_name, lp->vg_name)) { log_error("Please use a single volume group name " "(\"%s\" or \"%s\")", vg_name, lp->vg_name); return 0; } if (!lp->vg_name) lp->vg_name = vg_name; if (!validate_name(lp->vg_name)) { log_error("Please provide a valid volume group name"); return 0; } if ((ptr = strrchr(lp->lv_name_full, '/'))) lp->lv_name = ptr + 1; if (!lp->merge_mirror && !strstr(lp->lv_name, "_tdata") && !strstr(lp->lv_name, "_tmeta") && !apply_lvname_restrictions(lp->lv_name)) return_0; if (*pargc && lp->snapshot) { log_error("Too many arguments provided for snapshots"); return 0; } if (lp->pool_data_lv_name && lp->lv_name && lp->poolmetadata_size) { log_error("Please specify either metadata logical volume or its size."); return 0; } return 1; } static int _read_params(struct lvconvert_params *lp, struct cmd_context *cmd, int argc, char **argv) { int i; const char *tmp_str; struct arg_value_group_list *group; int region_size; int pagesize = lvm_getpagesize(); memset(lp, 0, sizeof(*lp)); if ((arg_count(cmd, snapshot_ARG) || arg_count(cmd, merge_ARG)) && (arg_count(cmd, mirrorlog_ARG) || arg_count(cmd, mirrors_ARG) || arg_count(cmd, repair_ARG))) { log_error("--snapshot or --merge argument cannot be mixed " "with --mirrors, --repair or --mirrorlog"); return 0; } if (!arg_count(cmd, background_ARG)) lp->wait_completion = 1; if (arg_count(cmd, snapshot_ARG)) lp->snapshot = 1; if (arg_count(cmd, snapshot_ARG) && arg_count(cmd, merge_ARG)) { log_error("--snapshot and --merge are mutually exclusive"); return 0; } if (arg_count(cmd, splitmirrors_ARG) && arg_count(cmd, mirrors_ARG)) { log_error("--mirrors and --splitmirrors are " "mutually exclusive"); return 0; } if (arg_count(cmd, thinpool_ARG)) { if (arg_count(cmd, merge_ARG)) { log_error("--thinpool and --merge are mutually exlusive."); return 0; } if (arg_count(cmd, mirrors_ARG)) { log_error("--thinpool and --mirrors are mutually exlusive."); return 0; } if (arg_count(cmd, repair_ARG)) { log_error("--thinpool and --repair are mutually exlusive."); return 0; } if (arg_count(cmd, snapshot_ARG)) { log_error("--thinpool and --snapshot are mutually exlusive."); return 0; } if (arg_count(cmd, splitmirrors_ARG)) { log_error("--thinpool and --splitmirrors are mutually exlusive."); return 0; } lp->discards = (thin_discards_t) arg_uint_value(cmd, discards_ARG, THIN_DISCARDS_PASSDOWN); } else if (arg_count(cmd, discards_ARG)) { log_error("--discards is only valid with --thinpool."); return 0; } /* * The '--splitmirrors n' argument is equivalent to '--mirrors -n' * (note the minus sign), except that it signifies the additional * intent to keep the mimage that is detached, rather than * discarding it. */ if (arg_count(cmd, splitmirrors_ARG)) { if (!arg_count(cmd, name_ARG) && !arg_count(cmd, trackchanges_ARG)) { log_error("Please name the new logical volume using '--name'"); return 0; } lp->lv_split_name = arg_value(cmd, name_ARG); if (lp->lv_split_name) { if (strchr(lp->lv_split_name, '/')) { if (!(lp->vg_name = extract_vgname(cmd, lp->lv_split_name))) return_0; /* Strip VG from lv_split_name */ if ((tmp_str = strrchr(lp->lv_split_name, '/'))) lp->lv_split_name = tmp_str + 1; } if (!apply_lvname_restrictions(lp->lv_split_name)) return_0; } lp->keep_mimages = 1; lp->mirrors = arg_uint_value(cmd, splitmirrors_ARG, 0); lp->mirrors_sign = SIGN_MINUS; } else if (arg_count(cmd, name_ARG)) { log_error("The 'name' argument is only valid" " with --splitmirrors"); return 0; } if (arg_count(cmd, merge_ARG)) { if ((argc == 1) && strstr(argv[0], "_rimage_")) lp->merge_mirror = 1; else lp->merge = 1; } if (arg_count(cmd, mirrors_ARG)) { /* * --splitmirrors has been chosen as the mechanism for * specifying the intent of detaching and keeping a mimage * versus an additional qualifying argument being added here. */ lp->mirrors = arg_uint_value(cmd, mirrors_ARG, 0); lp->mirrors_sign = arg_sign_value(cmd, mirrors_ARG, SIGN_NONE); } lp->alloc = (alloc_policy_t) arg_uint_value(cmd, alloc_ARG, ALLOC_INHERIT); /* There are three types of lvconvert. */ if (lp->merge) { /* Snapshot merge */ if (arg_count(cmd, regionsize_ARG) || arg_count(cmd, chunksize_ARG) || arg_count(cmd, zero_ARG) || arg_count(cmd, regionsize_ARG) || arg_count(cmd, stripes_long_ARG) || arg_count(cmd, stripesize_ARG)) { log_error("Only --background and --interval are valid " "arguments for snapshot merge"); return 0; } if (!(lp->segtype = get_segtype_from_string(cmd, "snapshot"))) return_0; } else if (lp->snapshot) { /* Snapshot creation from pre-existing cow */ if (arg_count(cmd, regionsize_ARG)) { log_error("--regionsize is only available with mirrors"); return 0; } if (arg_count(cmd, stripesize_ARG) || arg_count(cmd, stripes_long_ARG)) { log_error("--stripes and --stripesize are only available with striped mirrors"); return 0; } if (arg_sign_value(cmd, chunksize_ARG, SIGN_NONE) == SIGN_MINUS) { log_error("Negative chunk size is invalid"); return 0; } lp->chunk_size = arg_uint_value(cmd, chunksize_ARG, 8); if (lp->chunk_size < 8 || lp->chunk_size > 1024 || (lp->chunk_size & (lp->chunk_size - 1))) { log_error("Chunk size must be a power of 2 in the " "range 4K to 512K"); return 0; } log_verbose("Setting chunksize to %d sectors.", lp->chunk_size); if (!(lp->segtype = get_segtype_from_string(cmd, "snapshot"))) return_0; lp->zero = strcmp(arg_str_value(cmd, zero_ARG, (lp->segtype->flags & SEG_CANNOT_BE_ZEROED) ? "n" : "y"), "n"); } else if (arg_count(cmd, replace_ARG)) { /* RAID device replacement */ lp->replace_pv_count = arg_count(cmd, replace_ARG); lp->replace_pvs = dm_pool_alloc(cmd->mem, sizeof(char *) * lp->replace_pv_count); if (!lp->replace_pvs) return_0; i = 0; dm_list_iterate_items(group, &cmd->arg_value_groups) { if (!grouped_arg_is_set(group->arg_values, replace_ARG)) continue; if (!(tmp_str = grouped_arg_str_value(group->arg_values, replace_ARG, NULL))) { log_error("Failed to get '--replace' argument"); return 0; } if (!(lp->replace_pvs[i++] = dm_pool_strdup(cmd->mem, tmp_str))) return_0; } } else if (arg_count(cmd, thinpool_ARG)) { if (!(lp->pool_data_lv_name = arg_str_value(cmd, thinpool_ARG, NULL))) { log_error("Missing pool logical volume name."); return 0; } if (arg_count(cmd, poolmetadata_ARG)) { lp->pool_metadata_lv_name = arg_str_value(cmd, poolmetadata_ARG, ""); } else if (arg_count(cmd, poolmetadatasize_ARG)) { if (arg_sign_value(cmd, poolmetadatasize_ARG, SIGN_NONE) == SIGN_MINUS) { log_error("Negative pool metadata size is invalid."); return 0; } lp->poolmetadata_size = arg_uint64_value(cmd, poolmetadatasize_ARG, UINT64_C(0)); if (lp->poolmetadata_size > (2 * DEFAULT_THIN_POOL_MAX_METADATA_SIZE)) { if (arg_count(cmd, poolmetadatasize_ARG)) log_warn("WARNING: Maximum supported pool metadata size is 16GB."); lp->poolmetadata_size = 2 * DEFAULT_THIN_POOL_MAX_METADATA_SIZE; } else if (lp->poolmetadata_size < (2 * DEFAULT_THIN_POOL_MIN_METADATA_SIZE)) { if (arg_count(cmd, poolmetadatasize_ARG)) log_warn("WARNING: Minimum supported pool metadata size is 2M."); lp->poolmetadata_size = 2 * DEFAULT_THIN_POOL_MIN_METADATA_SIZE; } log_verbose("Setting pool metadata size to %" PRIu64 " sectors.", lp->poolmetadata_size); } if (arg_count(cmd, chunksize_ARG)) { if (arg_sign_value(cmd, chunksize_ARG, SIGN_NONE) == SIGN_MINUS) { log_error("Negative chunk size is invalid."); return 0; } lp->chunk_size = arg_uint_value(cmd, chunksize_ARG, DM_THIN_MIN_DATA_BLOCK_SIZE); if ((lp->chunk_size < DM_THIN_MIN_DATA_BLOCK_SIZE) || (lp->chunk_size > DM_THIN_MAX_DATA_BLOCK_SIZE)) { log_error("Chunk size must be in the range %uK to %uK.", (DM_THIN_MIN_DATA_BLOCK_SIZE / 2), (DM_THIN_MAX_DATA_BLOCK_SIZE / 2)); return 0; } } else lp->chunk_size = DM_THIN_MIN_DATA_BLOCK_SIZE; log_verbose("Setting pool metadata chunk size to %u sectors.", lp->chunk_size); if (arg_count(cmd, zero_ARG)) lp->zero = strcmp(arg_str_value(cmd, zero_ARG, "y"), "n"); /* If --thinpool contains VG name, extract it. */ if ((tmp_str = strchr(lp->pool_data_lv_name, (int) '/'))) { if (!(lp->vg_name = extract_vgname(cmd, lp->pool_data_lv_name))) return 0; /* Strip VG from pool */ lp->pool_data_lv_name = tmp_str + 1; } lp->segtype = get_segtype_from_string(cmd, arg_str_value(cmd, type_ARG, "thin-pool")); if (!lp->segtype) return_0; } else { /* Mirrors (and some RAID functions) */ if (arg_count(cmd, chunksize_ARG)) { log_error("--chunksize is only available with " "snapshots or thin pools."); return 0; } if (arg_count(cmd, zero_ARG)) { log_error("--zero is only available with snapshots or thin pools."); return 0; } /* * --regionsize is only valid if converting an LV into a mirror. * Checked when we know the state of the LV being converted. */ if (arg_count(cmd, regionsize_ARG)) { if (arg_sign_value(cmd, regionsize_ARG, SIGN_NONE) == SIGN_MINUS) { log_error("Negative regionsize is invalid"); return 0; } lp->region_size = arg_uint_value(cmd, regionsize_ARG, 0); } else { region_size = 2 * find_config_tree_int(cmd, "activation/mirror_region_size", DEFAULT_MIRROR_REGION_SIZE); if (region_size < 0) { log_error("Negative regionsize in " "configuration file is invalid"); return 0; } lp->region_size = region_size; } if (lp->region_size % (pagesize >> SECTOR_SHIFT)) { log_error("Region size (%" PRIu32 ") must be " "a multiple of machine memory " "page size (%d)", lp->region_size, pagesize >> SECTOR_SHIFT); return 0; } if (lp->region_size & (lp->region_size - 1)) { log_error("Region size (%" PRIu32 ") must be a power of 2", lp->region_size); return 0; } if (!lp->region_size) { log_error("Non-zero region size must be supplied."); return 0; } /* Default is never striped, regardless of existing LV configuration. */ if (!get_stripe_params(cmd, &lp->stripes, &lp->stripe_size)) { stack; return 0; } lp->segtype = get_segtype_from_string(cmd, arg_str_value(cmd, type_ARG, "mirror")); if (!lp->segtype) return_0; } if (activation() && lp->segtype && lp->segtype->ops->target_present && !lp->segtype->ops->target_present(cmd, NULL, NULL)) { log_error("%s: Required device-mapper target(s) not " "detected in your kernel", lp->segtype->name); return 0; } if (!_lvconvert_name_params(lp, cmd, &argc, &argv)) return_0; lp->pv_count = argc; lp->pvs = argv; return 1; } static struct volume_group *_get_lvconvert_vg(struct cmd_context *cmd, const char *name, const char *uuid __attribute__((unused))) { dev_close_all(); if (name && !strchr(name, '/')) return vg_read_for_update(cmd, name, NULL, 0); /* 'name' is the full LV name; must extract_vgname() */ return vg_read_for_update(cmd, extract_vgname(cmd, name), NULL, 0); } static struct logical_volume *_get_lvconvert_lv(struct cmd_context *cmd __attribute__((unused)), struct volume_group *vg, const char *name, const char *uuid, uint64_t lv_type __attribute__((unused))) { struct logical_volume *lv = find_lv(vg, name); if (!lv || (uuid && strcmp(uuid, (char *)&lv->lvid))) return NULL; return lv; } static int _reload_lv(struct cmd_context *cmd, struct volume_group *vg, struct logical_volume *lv) { int r = 0; log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name); if (!vg_write(vg)) return_0; if (!suspend_lv(cmd, lv)) { log_error("Failed to lock %s", lv->name); vg_revert(vg); goto out; } if (!vg_commit(vg)) { if (!resume_lv(cmd, lv)) stack; goto_out; } log_very_verbose("Updating \"%s\" in kernel", lv->name); if (!resume_lv(cmd, lv)) { log_error("Problem reactivating %s", lv->name); goto out; } r = 1; out: backup(vg); return r; } static int _finish_lvconvert_mirror(struct cmd_context *cmd, struct volume_group *vg, struct logical_volume *lv, struct dm_list *lvs_changed __attribute__((unused))) { if (!(lv->status & CONVERTING)) return 1; if (!collapse_mirrored_lv(lv)) { log_error("Failed to remove temporary sync layer."); return 0; } lv->status &= ~CONVERTING; log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name); if (!(_reload_lv(cmd, vg, lv))) return_0; log_print_unless_silent("Logical volume %s converted.", lv->name); return 1; } static int _finish_lvconvert_merge(struct cmd_context *cmd, struct volume_group *vg, struct logical_volume *lv, struct dm_list *lvs_changed __attribute__((unused))) { struct lv_segment *snap_seg = find_merging_cow(lv); if (!snap_seg) { log_error("Logical volume %s has no merging snapshot.", lv->name); return 0; } log_print_unless_silent("Merge of snapshot into logical volume %s has finished.", lv->name); if (!lv_remove_single(cmd, snap_seg->cow, DONT_PROMPT)) { log_error("Could not remove snapshot %s merged into %s.", snap_seg->cow->name, lv->name); return 0; } return 1; } static progress_t _poll_merge_progress(struct cmd_context *cmd, struct logical_volume *lv, const char *name __attribute__((unused)), struct daemon_parms *parms) { percent_t percent = PERCENT_0; if (!lv_snapshot_percent(lv, &percent)) { log_error("%s: Failed query for merging percentage. Aborting merge.", lv->name); return PROGRESS_CHECK_FAILED; } else if (percent == PERCENT_INVALID) { log_error("%s: Merging snapshot invalidated. Aborting merge.", lv->name); return PROGRESS_CHECK_FAILED; } else if (percent == PERCENT_MERGE_FAILED) { log_error("%s: Merge failed. Retry merge or inspect manually.", lv->name); return PROGRESS_CHECK_FAILED; } if (parms->progress_display) log_print_unless_silent("%s: %s: %.1f%%", lv->name, parms->progress_title, 100.0 - percent_to_float(percent)); else log_verbose("%s: %s: %.1f%%", lv->name, parms->progress_title, 100.0 - percent_to_float(percent)); if (percent == PERCENT_0) return PROGRESS_FINISHED_ALL; return PROGRESS_UNFINISHED; } static struct poll_functions _lvconvert_mirror_fns = { .get_copy_vg = _get_lvconvert_vg, .get_copy_lv = _get_lvconvert_lv, .poll_progress = poll_mirror_progress, .finish_copy = _finish_lvconvert_mirror, }; static struct poll_functions _lvconvert_merge_fns = { .get_copy_vg = _get_lvconvert_vg, .get_copy_lv = _get_lvconvert_lv, .poll_progress = _poll_merge_progress, .finish_copy = _finish_lvconvert_merge, }; int lvconvert_poll(struct cmd_context *cmd, struct logical_volume *lv, unsigned background) { /* * FIXME allocate an "object key" structure with split * out members (vg_name, lv_name, uuid, etc) and pass that * around the lvconvert and polldaemon code * - will avoid needless work, e.g. extract_vgname() * - unfortunately there are enough overloaded "name" dragons in * the polldaemon, lvconvert, pvmove code that a comprehensive * audit/rework is needed */ int len = strlen(lv->vg->name) + strlen(lv->name) + 2; char *uuid = alloca(sizeof(lv->lvid)); char *lv_full_name = alloca(len); if (!uuid || !lv_full_name) return_0; if (dm_snprintf(lv_full_name, len, "%s/%s", lv->vg->name, lv->name) < 0) return_0; memcpy(uuid, &lv->lvid, sizeof(lv->lvid)); if (!lv_is_merging_origin(lv)) return poll_daemon(cmd, lv_full_name, uuid, background, 0, &_lvconvert_mirror_fns, "Converted"); else return poll_daemon(cmd, lv_full_name, uuid, background, 0, &_lvconvert_merge_fns, "Merged"); } static int _insert_lvconvert_layer(struct cmd_context *cmd, struct logical_volume *lv) { char *format, *layer_name; size_t len; int i; /* * We would like to give the same number for this layer * and the newly added mimage. * However, LV name of newly added mimage is determined *after* * the LV name of this layer is determined. * * So, use generate_lv_name() to generate mimage name first * and take the number from it. */ len = strlen(lv->name) + 32; if (!(format = alloca(len)) || !(layer_name = alloca(len)) || dm_snprintf(format, len, "%s_mimage_%%d", lv->name) < 0) { log_error("lvconvert: layer name allocation failed."); return 0; } if (!generate_lv_name(lv->vg, format, layer_name, len) || sscanf(layer_name, format, &i) != 1) { log_error("lvconvert: layer name generation failed."); return 0; } if (dm_snprintf(layer_name, len, MIRROR_SYNC_LAYER "_%d", i) < 0) { log_error("layer name allocation failed."); return 0; } if (!insert_layer_for_lv(cmd, lv, 0, layer_name)) { log_error("Failed to insert resync layer"); return 0; } return 1; } static int _failed_mirrors_count(struct logical_volume *lv) { struct lv_segment *lvseg; int ret = 0; unsigned s; dm_list_iterate_items(lvseg, &lv->segments) { if (!seg_is_mirrored(lvseg)) return -1; for (s = 0; s < lvseg->area_count; s++) { if (seg_type(lvseg, s) == AREA_LV) { if (is_temporary_mirror_layer(seg_lv(lvseg, s))) ret += _failed_mirrors_count(seg_lv(lvseg, s)); else if (seg_lv(lvseg, s)->status & PARTIAL_LV) ++ ret; else if (seg_type(lvseg, s) == AREA_PV && is_missing_pv(seg_pv(lvseg, s))) ++ret; } } } return ret; } static int _failed_logs_count(struct logical_volume *lv) { int ret = 0; unsigned s; struct logical_volume *log_lv = first_seg(lv)->log_lv; if (log_lv && (log_lv->status & PARTIAL_LV)) { if (log_lv->status & MIRRORED) ret += _failed_mirrors_count(log_lv); else ret += 1; } for (s = 0; s < first_seg(lv)->area_count; s++) { if (seg_type(first_seg(lv), s) == AREA_LV && is_temporary_mirror_layer(seg_lv(first_seg(lv), s))) ret += _failed_logs_count(seg_lv(first_seg(lv), s)); } return ret; } static struct dm_list *_failed_pv_list(struct volume_group *vg) { struct dm_list *failed_pvs; struct pv_list *pvl, *new_pvl; if (!(failed_pvs = dm_pool_alloc(vg->vgmem, sizeof(*failed_pvs)))) { log_error("Allocation of list of failed_pvs failed."); return_NULL; } dm_list_init(failed_pvs); dm_list_iterate_items(pvl, &vg->pvs) { if (!is_missing_pv(pvl->pv)) continue; /* * Finally, --repair will remove empty PVs. * But we only want remove these which are output of repair, * Do not count these which are already empty here. * FIXME: code should traverse PV in LV not in whole VG. * FIXME: layer violation? should it depend on vgreduce --removemising? */ if (pvl->pv->pe_alloc_count == 0) continue; if (!(new_pvl = dm_pool_alloc(vg->vgmem, sizeof(*new_pvl)))) { log_error("Allocation of failed_pvs list entry failed."); return_NULL; } new_pvl->pv = pvl->pv; dm_list_add(failed_pvs, &new_pvl->list); } return failed_pvs; } static int _is_partial_lv(struct logical_volume *lv, void *baton __attribute__((unused))) { return lv->status & PARTIAL_LV; } /* * Walk down the stacked mirror LV to the original mirror LV. */ static struct logical_volume *_original_lv(struct logical_volume *lv) { struct logical_volume *next_lv = lv, *tmp_lv; while ((tmp_lv = find_temporary_mirror(next_lv))) next_lv = tmp_lv; return next_lv; } static void _lvconvert_mirrors_repair_ask(struct cmd_context *cmd, int failed_log, int failed_mirrors, int *replace_log, int *replace_mirrors) { const char *leg_policy = NULL, *log_policy = NULL; int force = arg_count(cmd, force_ARG); int yes = arg_count(cmd, yes_ARG); *replace_log = *replace_mirrors = 1; if (arg_count(cmd, use_policies_ARG)) { leg_policy = find_config_tree_str(cmd, "activation/mirror_image_fault_policy", NULL); if (!leg_policy) leg_policy = find_config_tree_str(cmd, "activation/mirror_device_fault_policy", DEFAULT_MIRROR_DEVICE_FAULT_POLICY); log_policy = find_config_tree_str(cmd, "activation/mirror_log_fault_policy", DEFAULT_MIRROR_LOG_FAULT_POLICY); *replace_mirrors = strcmp(leg_policy, "remove"); *replace_log = strcmp(log_policy, "remove"); return; } if (yes) return; if (force != PROMPT) { *replace_log = *replace_mirrors = 0; return; } if (failed_log && yes_no_prompt("Attempt to replace failed mirror log? [y/n]: ") == 'n') { *replace_log = 0; } if (failed_mirrors && yes_no_prompt("Attempt to replace failed mirror images " "(requires full device resync)? [y/n]: ") == 'n') { *replace_mirrors = 0; } } /* * _get_log_count * @lv: the mirror LV * * Get the number of on-disk copies of the log. * 0 = 'core' * 1 = 'disk' * 2+ = 'mirrored' */ static int _get_log_count(struct logical_volume *lv) { struct logical_volume *log_lv; log_lv = first_seg(_original_lv(lv))->log_lv; if (log_lv) return lv_mirror_count(log_lv); return 0; } static int _lv_update_mirrored_log(struct logical_volume *lv, struct dm_list *operable_pvs, int log_count) { int old_log_count; struct logical_volume *log_lv; /* * When log_count is 0, mirrored log doesn't need to be * updated here but it will be removed later. */ if (!log_count) return 1; log_lv = first_seg(_original_lv(lv))->log_lv; if (!log_lv || !(log_lv->status & MIRRORED)) return 1; old_log_count = _get_log_count(lv); if (old_log_count == log_count) return 1; /* Reducing redundancy of the log */ return remove_mirror_images(log_lv, log_count, is_mirror_image_removable, operable_pvs, 0U); } static int _lv_update_log_type(struct cmd_context *cmd, struct lvconvert_params *lp, struct logical_volume *lv, struct dm_list *operable_pvs, int log_count) { int old_log_count; uint32_t region_size = (lp) ? lp->region_size : first_seg(lv)->region_size; alloc_policy_t alloc = (lp) ? lp->alloc : lv->alloc; struct logical_volume *original_lv; struct logical_volume *log_lv; old_log_count = _get_log_count(lv); if (old_log_count == log_count) return 1; original_lv = _original_lv(lv); /* Remove an existing log completely */ if (!log_count) { if (!remove_mirror_log(cmd, original_lv, operable_pvs, arg_count(cmd, yes_ARG) || arg_count(cmd, force_ARG))) return_0; return 1; } log_lv = first_seg(original_lv)->log_lv; /* Adding redundancy to the log */ if (old_log_count < log_count) { region_size = adjusted_mirror_region_size(lv->vg->extent_size, lv->le_count, region_size); if (!add_mirror_log(cmd, original_lv, log_count, region_size, operable_pvs, alloc)) return_0; /* * FIXME: This simple approach won't work in cluster mirrors, * but it doesn't matter because we don't support * mirrored logs in cluster mirrors. */ if (old_log_count && !_reload_lv(cmd, log_lv->vg, log_lv)) return_0; return 1; } /* Reducing redundancy of the log */ return remove_mirror_images(log_lv, log_count, is_mirror_image_removable, operable_pvs, 1U); } /* * Reomove missing and empty PVs from VG, if are also in provided list */ static void _remove_missing_empty_pv(struct volume_group *vg, struct dm_list *remove_pvs) { struct pv_list *pvl, *pvl_vg, *pvlt; int removed = 0; if (!remove_pvs) return; dm_list_iterate_items(pvl, remove_pvs) { dm_list_iterate_items_safe(pvl_vg, pvlt, &vg->pvs) { if (!id_equal(&pvl->pv->id, &pvl_vg->pv->id) || !is_missing_pv(pvl_vg->pv) || pvl_vg->pv->pe_alloc_count != 0) continue; /* FIXME: duplication of vgreduce code, move this to library */ vg->free_count -= pvl_vg->pv->pe_count; vg->extent_count -= pvl_vg->pv->pe_count; del_pvl_from_vgs(vg, pvl_vg); free_pv_fid(pvl_vg->pv); removed++; } } if (removed) { if (!vg_write(vg) || !vg_commit(vg)) { stack; return; } log_warn("%d missing and now unallocated Physical Volumes removed from VG.", removed); } } /* * _lvconvert_mirrors_parse_params * * This function performs the following: * 1) Gets the old values of mimage and log counts * 2) Parses the CLI args to find the new desired values * 3) Adjusts 'lp->mirrors' to the appropriate absolute value. * (Remember, 'lp->mirrors' is specified in terms of the number of "copies" * vs. the number of mimages. It can also be a relative value.) * 4) Sets 'lp->need_polling' if collapsing * 5) Validates other mirror params * * Returns: 1 on success, 0 on error */ static int _lvconvert_mirrors_parse_params(struct cmd_context *cmd, struct logical_volume *lv, struct lvconvert_params *lp, uint32_t *old_mimage_count, uint32_t *old_log_count, uint32_t *new_mimage_count, uint32_t *new_log_count) { int repair = arg_count(cmd, repair_ARG); const char *mirrorlog; *old_mimage_count = lv_mirror_count(lv); *old_log_count = _get_log_count(lv); /* * Collapsing a stack of mirrors: * * If called with no argument, try collapsing the resync layers */ if (!arg_count(cmd, mirrors_ARG) && !arg_count(cmd, mirrorlog_ARG) && !arg_count(cmd, corelog_ARG) && !arg_count(cmd, regionsize_ARG) && !arg_count(cmd, splitmirrors_ARG) && !repair) { *new_mimage_count = *old_mimage_count; *new_log_count = *old_log_count; if (find_temporary_mirror(lv) || (lv->status & CONVERTING)) lp->need_polling = 1; return 1; } if ((arg_count(cmd, mirrors_ARG) && repair) || (arg_count(cmd, mirrorlog_ARG) && repair) || (arg_count(cmd, corelog_ARG) && repair)) { log_error("--repair cannot be used with --mirrors, --mirrorlog," " or --corelog"); return 0; } if (arg_count(cmd, mirrorlog_ARG) && arg_count(cmd, corelog_ARG)) { log_error("--mirrorlog and --corelog are incompatible"); return 0; } /* * Adjusting mimage count? */ if (!arg_count(cmd, mirrors_ARG) && !arg_count(cmd, splitmirrors_ARG)) lp->mirrors = *old_mimage_count; else if (lp->mirrors_sign == SIGN_PLUS) lp->mirrors = *old_mimage_count + lp->mirrors; else if (lp->mirrors_sign == SIGN_MINUS) lp->mirrors = (*old_mimage_count > lp->mirrors) ? *old_mimage_count - lp->mirrors: 0; else lp->mirrors += 1; *new_mimage_count = lp->mirrors; /* Too many mimages? */ if (lp->mirrors > DEFAULT_MIRROR_MAX_IMAGES) { log_error("Only up to %d images in mirror supported currently.", DEFAULT_MIRROR_MAX_IMAGES); return 0; } /* Did the user try to subtract more legs than available? */ if (lp->mirrors < 1) { log_error("Unable to reduce images by specified amount - only %d in %s", *old_mimage_count, lv->name); return 0; } /* * FIXME: It would be nice to say what we are adjusting to, but * I really don't know whether to specify the # of copies or mimages. */ if (*old_mimage_count != *new_mimage_count) log_verbose("Adjusting mirror image count of %s", lv->name); /* * Adjust log type * * If we are converting from a mirror to another mirror or simply * changing the log type, we start by assuming they want the log * type the same and then parse the given args. OTOH, If we are * converting from linear to mirror, then we start from the default * position that the user would like a 'disk' log. */ *new_log_count = (*old_mimage_count > 1) ? *old_log_count : 1; if (!arg_count(cmd, corelog_ARG) && !arg_count(cmd, mirrorlog_ARG)) return 1; if (arg_count(cmd, corelog_ARG)) *new_log_count = 0; mirrorlog = arg_str_value(cmd, mirrorlog_ARG, !*new_log_count ? "core" : DEFAULT_MIRRORLOG); if (!strcmp("mirrored", mirrorlog)) *new_log_count = 2; else if (!strcmp("disk", mirrorlog)) *new_log_count = 1; else if (!strcmp("core", mirrorlog)) *new_log_count = 0; else { log_error("Unknown mirrorlog type: %s", mirrorlog); return 0; } /* * No mirrored logs for cluster mirrors until * log daemon is multi-threaded. */ if ((*new_log_count == 2) && vg_is_clustered(lv->vg)) { log_error("Log type, \"mirrored\", is unavailable to cluster mirrors"); return 0; } log_verbose("Setting logging type to %s", mirrorlog); /* * Region size must not change on existing mirrors */ if (arg_count(cmd, regionsize_ARG) && (lv->status & MIRRORED) && (lp->region_size != first_seg(lv)->region_size)) { log_error("Mirror log region size cannot be changed on " "an existing mirror."); return 0; } /* * For the most part, we cannot handle multi-segment mirrors. Bail out * early if we have encountered one. */ if ((lv->status & MIRRORED) && dm_list_size(&lv->segments) != 1) { log_error("Logical volume %s has multiple " "mirror segments.", lv->name); return 0; } return 1; } /* * _lvconvert_mirrors_aux * * Add/remove mirror images and adjust log type. 'operable_pvs' * are the set of PVs open to removal or allocation - depending * on the operation being performed. */ static int _lvconvert_mirrors_aux(struct cmd_context *cmd, struct logical_volume *lv, struct lvconvert_params *lp, struct dm_list *operable_pvs, uint32_t new_mimage_count, uint32_t new_log_count) { uint32_t region_size; struct lv_segment *seg; struct logical_volume *layer_lv; uint32_t old_mimage_count = lv_mirror_count(lv); uint32_t old_log_count = _get_log_count(lv); if ((lp->mirrors == 1) && !(lv->status & MIRRORED)) { log_error("Logical volume %s is already not mirrored.", lv->name); return 1; } region_size = adjusted_mirror_region_size(lv->vg->extent_size, lv->le_count, lp->region_size); if (!operable_pvs) operable_pvs = lp->pvh; seg = first_seg(lv); /* * Up-convert from linear to mirror */ if (!(lv->status & MIRRORED)) { /* FIXME Share code with lvcreate */ /* * FIXME should we give not only lp->pvh, but also all PVs * currently taken by the mirror? Would make more sense from * user perspective. */ if (!lv_add_mirrors(cmd, lv, new_mimage_count - 1, lp->stripes, lp->stripe_size, region_size, new_log_count, operable_pvs, lp->alloc, MIRROR_BY_LV)) return_0; if (lp->wait_completion) lp->need_polling = 1; goto out; } /* * Up-convert m-way mirror to n-way mirror */ if (new_mimage_count > old_mimage_count) { if (lv->status & LV_NOTSYNCED) { log_error("Can't add mirror to out-of-sync mirrored " "LV: use lvchange --resync first."); return 0; } /* * We allow snapshots of mirrors, but for now, we * do not allow up converting mirrors that are under * snapshots. The layering logic is somewhat complex, * and preliminary test show that the conversion can't * seem to get the correct %'age of completion. */ if (lv_is_origin(lv)) { log_error("Can't add additional mirror images to " "mirrors that are under snapshots"); return 0; } /* * Is there already a convert in progress? We do not * currently allow more than one. */ if (find_temporary_mirror(lv) || (lv->status & CONVERTING)) { log_error("%s is already being converted. Unable to start another conversion.", lv->name); return 0; } /* * Log addition/removal should be done before the layer * insertion to make the end result consistent with * linear-to-mirror conversion. */ if (!_lv_update_log_type(cmd, lp, lv, operable_pvs, new_log_count)) { stack; return 0; } /* Insert a temporary layer for syncing, * only if the original lv is using disk log. */ if (seg->log_lv && !_insert_lvconvert_layer(cmd, lv)) { log_error("Failed to insert resync layer"); return 0; } /* FIXME: can't have multiple mlogs. force corelog. */ if (!lv_add_mirrors(cmd, lv, new_mimage_count - old_mimage_count, lp->stripes, lp->stripe_size, region_size, 0U, operable_pvs, lp->alloc, MIRROR_BY_LV)) { layer_lv = seg_lv(first_seg(lv), 0); if (!remove_layer_from_lv(lv, layer_lv) || !deactivate_lv(cmd, layer_lv) || !lv_remove(layer_lv) || !vg_write(lv->vg) || !vg_commit(lv->vg)) { log_error("ABORTING: Failed to remove " "temporary mirror layer %s.", layer_lv->name); log_error("Manual cleanup with vgcfgrestore " "and dmsetup may be required."); return 0; } stack; return 0; } if (seg->log_lv) lv->status |= CONVERTING; lp->need_polling = 1; goto out_skip_log_convert; } /* * Down-convert (reduce # of mimages). */ if (new_mimage_count < old_mimage_count) { uint32_t nmc = old_mimage_count - new_mimage_count; uint32_t nlc = (!new_log_count || lp->mirrors == 1) ? 1U : 0U; /* FIXME: Why did nlc used to be calculated that way? */ /* Reduce number of mirrors */ if (lp->keep_mimages) { if (arg_count(cmd, trackchanges_ARG)) { log_error("--trackchanges is not available " "to 'mirror' segment type"); return 0; } if (!lv_split_mirror_images(lv, lp->lv_split_name, nmc, operable_pvs)) return 0; } else if (!lv_remove_mirrors(cmd, lv, nmc, nlc, is_mirror_image_removable, operable_pvs, 0)) return_0; goto out; /* Just in case someone puts code between */ } out: /* * Converting the log type */ if ((lv->status & MIRRORED) && (old_log_count != new_log_count)) { if (!_lv_update_log_type(cmd, lp, lv, operable_pvs, new_log_count)) { stack; return 0; } } out_skip_log_convert: if (!_reload_lv(cmd, lv->vg, lv)) return_0; return 1; } int mirror_remove_missing(struct cmd_context *cmd, struct logical_volume *lv, int force) { struct dm_list *failed_pvs; int log_count = _get_log_count(lv) - _failed_logs_count(lv); if (!(failed_pvs = _failed_pv_list(lv->vg))) return_0; /* No point in keeping a log if the result is not a mirror */ if (_failed_mirrors_count(lv) + 1 >= lv_mirror_count(lv)) log_count = 0; if (force && _failed_mirrors_count(lv) == lv_mirror_count(lv)) { log_error("No usable images left in %s.", lv->name); return lv_remove_with_dependencies(cmd, lv, DONT_PROMPT, 0); } /* * We must adjust the log first, or the entire mirror * will get stuck during a suspend. */ if (!_lv_update_mirrored_log(lv, failed_pvs, log_count)) return 0; if (_failed_mirrors_count(lv) > 0 && !lv_remove_mirrors(cmd, lv, _failed_mirrors_count(lv), log_count ? 0U : 1U, _is_partial_lv, NULL, 0)) return 0; if (!_lv_update_log_type(cmd, NULL, lv, failed_pvs, log_count)) return 0; if (!_reload_lv(cmd, lv->vg, lv)) return_0; return 1; } /* * _lvconvert_mirrors_repair * * This function operates in two phases. First, all of the bad * devices are removed from the mirror. Then, if desired by the * user, the devices are replaced. * * 'old_mimage_count' and 'old_log_count' are there so we know * what to convert to after the removal of devices. */ static int _lvconvert_mirrors_repair(struct cmd_context *cmd, struct logical_volume *lv, struct lvconvert_params *lp) { int failed_logs = 0; int failed_mimages = 0; int replace_logs = 0; int replace_mimages = 0; uint32_t log_count; uint32_t original_mimages = lv_mirror_count(lv); uint32_t original_logs = _get_log_count(lv); cmd->handles_missing_pvs = 1; cmd->partial_activation = 1; lp->need_polling = 0; lv_check_transient(lv); /* TODO check this in lib for all commands? */ if (!(lv->status & PARTIAL_LV)) { log_error("%s is consistent. Nothing to repair.", lv->name); return 1; } failed_mimages = _failed_mirrors_count(lv); failed_logs = _failed_logs_count(lv); mirror_remove_missing(cmd, lv, 0); if (failed_mimages) log_error("Mirror status: %d of %d images failed.", failed_mimages, original_mimages); /* * Count the failed log devices */ if (failed_logs) log_error("Mirror log status: %d of %d images failed.", failed_logs, original_logs); /* * Find out our policies */ _lvconvert_mirrors_repair_ask(cmd, failed_logs, failed_mimages, &replace_logs, &replace_mimages); /* * Second phase - replace faulty devices */ lp->mirrors = replace_mimages ? original_mimages : (original_mimages - failed_mimages); /* * It does not make sense to replace the log if the volume is no longer * a mirror. */ if (lp->mirrors == 1) replace_logs = 0; log_count = replace_logs ? original_logs : (original_logs - failed_logs); while (replace_mimages || replace_logs) { log_warn("Trying to up-convert to %d images, %d logs.", lp->mirrors, log_count); if (_lvconvert_mirrors_aux(cmd, lv, lp, NULL, lp->mirrors, log_count)) break; else { if (lp->mirrors > 2) -- lp->mirrors; else if (log_count > 0) -- log_count; else break; /* nowhere to go, anymore... */ } } if (replace_mimages && lv_mirror_count(lv) != original_mimages) log_warn("WARNING: Failed to replace %d of %d images in volume %s", original_mimages - lv_mirror_count(lv), original_mimages, lv->name); if (replace_logs && _get_log_count(lv) != original_logs) log_warn("WARNING: Failed to replace %d of %d logs in volume %s", original_logs - _get_log_count(lv), original_logs, lv->name); /* if (!arg_count(cmd, use_policies_ARG) && (lp->mirrors != old_mimage_count || log_count != old_log_count)) return 0; */ return 1; } /* * _lvconvert_mirrors * * Determine what is being done. Are we doing a conversion, repair, or * collapsing a stack? Once determined, call helper functions. */ static int _lvconvert_mirrors(struct cmd_context *cmd, struct logical_volume *lv, struct lvconvert_params *lp) { int repair = arg_count(cmd, repair_ARG); uint32_t old_mimage_count; uint32_t old_log_count; uint32_t new_mimage_count; uint32_t new_log_count; if (lp->merge_mirror) { log_error("Unable to merge mirror images" "of segment type 'mirror'"); return 0; } /* TODO: decide what should be done here */ if (lv_is_thin_type(lv)) { log_error("Converting segment type for %s/%s to mirror is not yet supported.", lv->vg->name, lv->name); return 0; } /* Adjust mimage and/or log count */ if (!_lvconvert_mirrors_parse_params(cmd, lv, lp, &old_mimage_count, &old_log_count, &new_mimage_count, &new_log_count)) return 0; if (((old_mimage_count < new_mimage_count && old_log_count > new_log_count) || (old_mimage_count > new_mimage_count && old_log_count < new_log_count)) && lp->pv_count) { log_error("Cannot both allocate and free extents when " "specifying physical volumes to use."); log_error("Please specify the operation in two steps."); return 0; } /* Nothing to do? (Probably finishing collapse.) */ if ((old_mimage_count == new_mimage_count) && (old_log_count == new_log_count) && !repair) return 1; if (repair) return _lvconvert_mirrors_repair(cmd, lv, lp); if (!_lvconvert_mirrors_aux(cmd, lv, lp, NULL, new_mimage_count, new_log_count)) return 0; if (!lp->need_polling) log_print_unless_silent("Logical volume %s converted.", lv->name); backup(lv->vg); return 1; } static int is_valid_raid_conversion(const struct segment_type *from_segtype, const struct segment_type *to_segtype) { if (from_segtype == to_segtype) return 1; if (!segtype_is_raid(from_segtype) && !segtype_is_raid(to_segtype)) return_0; /* Not converting to or from RAID? */ return 1; } static void _lvconvert_raid_repair_ask(struct cmd_context *cmd, int *replace_dev) { const char *dev_policy = NULL; int force = arg_count(cmd, force_ARG); int yes = arg_count(cmd, yes_ARG); *replace_dev = 0; if (arg_count(cmd, use_policies_ARG)) { dev_policy = find_config_tree_str(cmd, "activation/raid_fault_policy", DEFAULT_RAID_FAULT_POLICY); if (!strcmp(dev_policy, "allocate") || !strcmp(dev_policy, "replace")) *replace_dev = 1; /* else if (!strcmp(dev_policy, "anything_else")) -- ignore */ return; } if (yes) { *replace_dev = 1; return; } if (force != PROMPT) return; if (yes_no_prompt("Attempt to replace failed RAID images " "(requires full device resync)? [y/n]: ") == 'y') { *replace_dev = 1; } } static int lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *lp) { int replace = 0; int uninitialized_var(image_count); struct dm_list *failed_pvs; struct cmd_context *cmd = lv->vg->cmd; struct lv_segment *seg = first_seg(lv); if (!arg_count(cmd, type_ARG)) lp->segtype = seg->segtype; /* Can only change image count for raid1 and linear */ if (arg_count(cmd, mirrors_ARG) && !seg_is_mirrored(seg) && !seg_is_linear(seg)) { log_error("'--mirrors/-m' is not compatible with %s", seg->segtype->ops->name(seg)); return 0; } if (!is_valid_raid_conversion(seg->segtype, lp->segtype)) { log_error("Unable to convert %s/%s from %s to %s", lv->vg->name, lv->name, seg->segtype->ops->name(seg), lp->segtype->name); return 0; } /* Change number of RAID1 images */ if (arg_count(cmd, mirrors_ARG) || arg_count(cmd, splitmirrors_ARG)) { image_count = lv_raid_image_count(lv); if (lp->mirrors_sign == SIGN_PLUS) image_count += lp->mirrors; else if (lp->mirrors_sign == SIGN_MINUS) image_count -= lp->mirrors; else image_count = lp->mirrors + 1; if (image_count < 1) { log_error("Unable to %s images by specified amount", arg_count(cmd, splitmirrors_ARG) ? "split" : "reduce"); return 0; } } if (lp->merge_mirror) return lv_raid_merge(lv); if (arg_count(cmd, trackchanges_ARG)) return lv_raid_split_and_track(lv, lp->pvh); if (arg_count(cmd, splitmirrors_ARG)) return lv_raid_split(lv, lp->lv_split_name, image_count, lp->pvh); if (arg_count(cmd, mirrors_ARG)) return lv_raid_change_image_count(lv, image_count, lp->pvh); if (arg_count(cmd, type_ARG)) return lv_raid_reshape(lv, lp->segtype); if (arg_count(cmd, replace_ARG)) return lv_raid_replace(lv, lp->replace_pvh, lp->pvh); if (arg_count(cmd, repair_ARG)) { _lvconvert_raid_repair_ask(cmd, &replace); if (replace) { if (!(failed_pvs = _failed_pv_list(lv->vg))) return_0; if (!lv_raid_replace(lv, failed_pvs, lp->pvh)) { log_error("Failed to replace faulty devices in" " %s/%s.", lv->vg->name, lv->name); return 0; } log_print_unless_silent("Faulty devices in %s/%s successfully" " replaced.", lv->vg->name, lv->name); return 1; } /* "warn" if policy not set to replace */ if (arg_count(cmd, use_policies_ARG)) log_error("Use 'lvconvert --repair %s/%s' to " "replace failed device", lv->vg->name, lv->name); return 1; } log_error("Conversion operation not yet supported."); return 0; } static int lvconvert_snapshot(struct cmd_context *cmd, struct logical_volume *lv, struct lvconvert_params *lp) { struct logical_volume *org; if (!(org = find_lv(lv->vg, lp->origin))) { log_error("Couldn't find origin volume '%s'.", lp->origin); return 0; } if (org == lv) { log_error("Unable to use \"%s\" as both snapshot and origin.", lv->name); return 0; } if (org->status & (LOCKED|PVMOVE|MIRRORED) || lv_is_cow(org)) { log_error("Unable to convert an LV into a snapshot of a %s LV.", org->status & LOCKED ? "locked" : org->status & PVMOVE ? "pvmove" : org->status & MIRRORED ? "mirrored" : "snapshot"); return 0; } if (!lp->zero || !(lv->status & LVM_WRITE)) log_warn("WARNING: \"%s\" not zeroed", lv->name); else if (!set_lv(cmd, lv, UINT64_C(0), 0)) { log_error("Aborting. Failed to wipe snapshot " "exception store."); return 0; } if (!deactivate_lv(cmd, lv)) { log_error("Couldn't deactivate LV %s.", lv->name); return 0; } if (!vg_add_snapshot(org, lv, NULL, org->le_count, lp->chunk_size)) { log_error("Couldn't create snapshot."); return 0; } /* store vg on disk(s) */ if (!_reload_lv(cmd, lv->vg, lv)) return_0; log_print_unless_silent("Logical volume %s converted to snapshot.", lv->name); return 1; } static int lvconvert_merge(struct cmd_context *cmd, struct logical_volume *lv, struct lvconvert_params *lp) { int r = 0; int merge_on_activate = 0; struct logical_volume *origin = origin_from_cow(lv); struct lv_segment *cow_seg = find_cow(lv); struct lvinfo info; /* Check if merge is possible */ if (lv_is_merging_cow(lv)) { log_error("Snapshot %s is already merging", lv->name); return 0; } if (lv_is_merging_origin(origin)) { log_error("Snapshot %s is already merging into the origin", find_merging_cow(origin)->cow->name); return 0; } /* * Prevent merge with open device(s) as it would likely lead * to application/filesystem failure. Merge on origin's next * activation if either the origin or snapshot LV are currently * open. * * FIXME testing open_count is racey; snapshot-merge target's * constructor and DM should prevent appropriate devices from * being open. */ if (lv_info(cmd, origin, 0, &info, 1, 0)) { if (info.open_count) { log_error("Can't merge over open origin volume"); merge_on_activate = 1; } } if (lv_info(cmd, lv, 0, &info, 1, 0)) { if (info.open_count) { log_print_unless_silent("Can't merge when snapshot is open"); merge_on_activate = 1; } } init_snapshot_merge(cow_seg, origin); /* store vg on disk(s) */ if (!vg_write(lv->vg)) return_0; if (merge_on_activate) { /* commit vg but skip starting the merge */ if (!vg_commit(lv->vg)) return_0; r = 1; log_print_unless_silent("Merging of snapshot %s will start " "next activation.", lv->name); goto out; } /* Perform merge */ if (!suspend_lv(cmd, origin)) { log_error("Failed to suspend origin %s", origin->name); vg_revert(lv->vg); goto out; } if (!vg_commit(lv->vg)) { if (!resume_lv(cmd, origin)) stack; goto_out; } if (!resume_lv(cmd, origin)) { log_error("Failed to reactivate origin %s", origin->name); goto out; } lp->need_polling = 1; lp->lv_to_poll = origin; r = 1; log_print_unless_silent("Merging of volume %s started.", lv->name); out: backup(lv->vg); return r; } /* * Thin lvconvert version which * rename metadata * convert/layers thinpool over data * attach metadata */ static int _lvconvert_thinpool(struct cmd_context *cmd, struct logical_volume *pool_lv, struct lvconvert_params *lp) { int r = 0; char *name; int len; struct lv_segment *seg; struct logical_volume *data_lv; struct logical_volume *metadata_lv; if (lv_is_thin_type(pool_lv)) { log_error("Can't use thin logical volume %s/%s for thin pool data.", pool_lv->vg->name, pool_lv->name); return 0; } /* We are changing target type, so deactivate first */ if (!deactivate_lv(cmd, pool_lv)) { log_error("Can't deactivate logical volume %s/%s.", pool_lv->vg->name, pool_lv->name); return 0; } if (lp->pool_metadata_lv_name) { metadata_lv = find_lv(pool_lv->vg, lp->pool_metadata_lv_name); if (!metadata_lv) { log_error("Unknown metadata LV %s", lp->pool_metadata_lv_name); return 0; } if (metadata_lv == pool_lv) { log_error("Can't use same LV for thin data and metadata LV %s", lp->pool_metadata_lv_name); return 0; } if (lv_is_thin_type(metadata_lv)) { log_error("Can't use thin pool logical volume %s/%s " "for thin pool metadata.", metadata_lv->vg->name, metadata_lv->name); return 0; } } else if (arg_count(cmd, poolmetadatasize_ARG)) { /* FIXME: allocate metadata LV! */ metadata_lv = NULL; log_error("Uncreated metadata."); return 0; } else { log_error("Uknown metadata."); return 0; } len = strlen(pool_lv->name) + 16; if (!(name = dm_pool_alloc(pool_lv->vg->vgmem, len))) { log_error("Cannot allocate new name."); return 0; } if (!lv_is_active(metadata_lv)) { if (!deactivate_lv(cmd, metadata_lv)) { log_error("Can't deactivate logical volume %s/%s.", metadata_lv->vg->name, metadata_lv->name); return 0; } if (!activate_lv_local(cmd, metadata_lv)) { log_error("Aborting. Failed to activate thin metadata lv."); return 0; } } if (!set_lv(cmd, metadata_lv, UINT64_C(0), 0)) { log_error("Aborting. Failed to wipe thin metadata lv."); return 0; } if (!deactivate_lv(cmd, metadata_lv)) { log_error("Aborting. Failed to deactivate thin metadata lv. " "Manual intervention required."); return 0; } if (dm_snprintf(name, len, "%s_tmeta", pool_lv->name) < 0) return_0; /* Rename deactivated metadata LV to have _tmeta suffix */ /* Implicit checks if metadata_lv is visible */ if (!lv_rename_update(cmd, metadata_lv, name, 0)) return_0; /* * Since we wish to have underlaying dev, to match _tdata * rename data LV first, also checks for visible LV */ /* FIXME: any more types prohibited here? */ /* FIXME: revert renamed LVs in fail path? */ /* FIXME: common code with metadata/thin_manip.c extend_pool() */ /* Create layer _tdata */ if (!(data_lv = insert_layer_for_lv(pool_lv->vg->cmd, pool_lv, pool_lv->status, "_tdata"))) return_0; seg = first_seg(pool_lv); seg->segtype = lp->segtype; seg->lv->status |= THIN_POOL; seg->chunk_size = lp->chunk_size; seg->zero_new_blocks = lp->zero ? 1 : 0; seg->discards = lp->discards; seg->low_water_mark = 0; seg->transaction_id = 0; if (!attach_pool_metadata_lv(seg, metadata_lv)) return_0; /* Drop reference as attach_pool_data_lv() takes it again */ remove_seg_from_segs_using_this_lv(data_lv, seg); if (!attach_pool_data_lv(seg, data_lv)) return_0; if (!vg_write(pool_lv->vg) || !vg_commit(pool_lv->vg)) return_0; if (!activate_lv_excl(cmd, pool_lv)) { log_error("Failed to activate pool logical volume %s/%s.", pool_lv->vg->name, pool_lv->name); goto out; } log_print_unless_silent("Converted %s/%s to thin pool.", pool_lv->vg->name, pool_lv->name); r = 1; out: backup(pool_lv->vg); return r; } static int _lvconvert_single(struct cmd_context *cmd, struct logical_volume *lv, void *handle) { struct lvconvert_params *lp = handle; struct dm_list *failed_pvs; struct lvinfo info; percent_t snap_percent; if (lv->status & LOCKED) { log_error("Cannot convert locked LV %s", lv->name); return ECMD_FAILED; } if (lv_is_cow(lv) && !lp->merge) { log_error("Can't convert snapshot logical volume \"%s\"", lv->name); return ECMD_FAILED; } if (lv->status & PVMOVE) { log_error("Unable to convert pvmove LV %s", lv->name); return ECMD_FAILED; } if (arg_count(cmd, repair_ARG) && !(lv->status & MIRRORED) && !(lv->status & RAID)) { if (arg_count(cmd, use_policies_ARG)) return ECMD_PROCESSED; /* nothing to be done here */ log_error("Can't repair non-mirrored LV \"%s\".", lv->name); return ECMD_FAILED; } if (!lp->segtype) lp->segtype = first_seg(lv)->segtype; if (lp->merge) { if (!lv_is_cow(lv)) { log_error("\"%s\" is not a mergeable logical volume", lv->name); return ECMD_FAILED; } if (lv_info(lv->vg->cmd, lv, 0, &info, 1, 0) && info.exists && info.live_table && (!lv_snapshot_percent(lv, &snap_percent) || snap_percent == PERCENT_INVALID)) { log_error("Unable to merge invalidated snapshot LV \"%s\"", lv->name); return ECMD_FAILED; } if (!archive(lv->vg)) { stack; return ECMD_FAILED; } if (!lvconvert_merge(cmd, lv, lp)) { log_error("Unable to merge LV \"%s\" into its origin.", lv->name); return ECMD_FAILED; } } else if (lp->snapshot) { if (lv->status & MIRRORED) { log_error("Unable to convert mirrored LV \"%s\" into a snapshot.", lv->name); return ECMD_FAILED; } if (!archive(lv->vg)) { stack; return ECMD_FAILED; } if (!lvconvert_snapshot(cmd, lv, lp)) { stack; return ECMD_FAILED; } } else if (arg_count(cmd, thinpool_ARG)) { if (!archive(lv->vg)) { stack; return ECMD_FAILED; } if (!_lvconvert_thinpool(cmd, lv, lp)) { stack; return ECMD_FAILED; } } else if (segtype_is_raid(lp->segtype) || (lv->status & RAID) || lp->merge_mirror) { if (!archive(lv->vg)) { stack; return ECMD_FAILED; } if (!lvconvert_raid(lv, lp)) { stack; return ECMD_FAILED; } if (!(failed_pvs = _failed_pv_list(lv->vg))) { stack; return ECMD_FAILED; } /* If repairing and using policies, remove missing PVs from VG */ if (arg_count(cmd, repair_ARG) && arg_count(cmd, use_policies_ARG)) _remove_missing_empty_pv(lv->vg, failed_pvs); } else if (arg_count(cmd, mirrors_ARG) || arg_count(cmd, splitmirrors_ARG) || (lv->status & MIRRORED)) { if (!archive(lv->vg)) { stack; return ECMD_FAILED; } if (!_lvconvert_mirrors(cmd, lv, lp)) { stack; return ECMD_FAILED; } if (!(failed_pvs = _failed_pv_list(lv->vg))) { stack; return ECMD_FAILED; } /* If repairing and using policies, remove missing PVs from VG */ if (arg_count(cmd, repair_ARG) && arg_count(cmd, use_policies_ARG)) _remove_missing_empty_pv(lv->vg, failed_pvs); } return ECMD_PROCESSED; } /* * FIXME move to toollib along with the rest of the drop/reacquire * VG locking that is used by lvconvert_merge_single() */ static struct logical_volume *get_vg_lock_and_logical_volume(struct cmd_context *cmd, const char *vg_name, const char *lv_name) { /* * Returns NULL if the requested LV doesn't exist; * otherwise the caller must release_vg(lv->vg) * - it is also up to the caller to unlock_vg() as needed */ struct volume_group *vg; struct logical_volume* lv = NULL; vg = _get_lvconvert_vg(cmd, vg_name, NULL); if (vg_read_error(vg)) { release_vg(vg); return_NULL; } if (!(lv = _get_lvconvert_lv(cmd, vg, lv_name, NULL, 0))) { log_error("Can't find LV %s in VG %s", lv_name, vg_name); unlock_and_release_vg(cmd, vg, vg_name); return NULL; } return lv; } static int poll_logical_volume(struct cmd_context *cmd, struct logical_volume *lv, int wait_completion) { struct lvinfo info; if (!lv_info(cmd, lv, 0, &info, 0, 0) || !info.exists) { log_print_unless_silent("Conversion starts after activation."); return ECMD_PROCESSED; } return lvconvert_poll(cmd, lv, wait_completion ? 0 : 1U); } static int lvconvert_single(struct cmd_context *cmd, struct lvconvert_params *lp) { struct logical_volume *lv = NULL; int ret = ECMD_FAILED; int saved_ignore_suspended_devices = ignore_suspended_devices(); if (arg_count(cmd, repair_ARG)) { init_ignore_suspended_devices(1); cmd->handles_missing_pvs = 1; } lv = get_vg_lock_and_logical_volume(cmd, lp->vg_name, lp->lv_name); if (!lv) goto_out; /* * lp->pvh holds the list of PVs available for allocation or removal */ if (lp->pv_count) { if (!(lp->pvh = create_pv_list(cmd->mem, lv->vg, lp->pv_count, lp->pvs, 0))) goto_bad; } else lp->pvh = &lv->vg->pvs; if (lp->replace_pv_count && !(lp->replace_pvh = create_pv_list(cmd->mem, lv->vg, lp->replace_pv_count, lp->replace_pvs, 0))) goto_bad; lp->lv_to_poll = lv; ret = _lvconvert_single(cmd, lv, lp); bad: unlock_vg(cmd, lp->vg_name); if (ret == ECMD_PROCESSED && lp->need_polling) ret = poll_logical_volume(cmd, lp->lv_to_poll, lp->wait_completion); release_vg(lv->vg); out: init_ignore_suspended_devices(saved_ignore_suspended_devices); return ret; } static int lvconvert_merge_single(struct cmd_context *cmd, struct logical_volume *lv, void *handle) { struct lvconvert_params *lp = handle; const char *vg_name = NULL; struct logical_volume *refreshed_lv = NULL; int ret; /* * FIXME can't trust lv's VG to be current given that caller * is process_each_lv() -- poll_logical_volume() may have * already updated the VG's metadata in an earlier iteration. * - preemptively drop the VG lock, as is needed for * poll_logical_volume(), refresh LV (and VG in the process). */ vg_name = lv->vg->name; unlock_vg(cmd, vg_name); refreshed_lv = get_vg_lock_and_logical_volume(cmd, vg_name, lv->name); if (!refreshed_lv) { log_error("ABORTING: Can't reread LV %s/%s", vg_name, lv->name); return ECMD_FAILED; } lp->lv_to_poll = refreshed_lv; ret = _lvconvert_single(cmd, refreshed_lv, lp); if (ret == ECMD_PROCESSED && lp->need_polling) { /* * Must drop VG lock, because lvconvert_poll() needs it, * then reacquire it after polling completes */ unlock_vg(cmd, vg_name); ret = poll_logical_volume(cmd, lp->lv_to_poll, lp->wait_completion); /* use LCK_VG_WRITE to match lvconvert()'s READ_FOR_UPDATE */ if (!lock_vol(cmd, vg_name, LCK_VG_WRITE)) { log_error("ABORTING: Can't relock VG for %s " "after polling finished", vg_name); ret = ECMD_FAILED; } } release_vg(refreshed_lv->vg); return ret; } int lvconvert(struct cmd_context * cmd, int argc, char **argv) { struct lvconvert_params lp; if (!_read_params(&lp, cmd, argc, argv)) { stack; return EINVALID_CMD_LINE; } if (lp.merge) { if (!argc) { log_error("Please provide logical volume path"); return EINVALID_CMD_LINE; } return process_each_lv(cmd, argc, argv, READ_FOR_UPDATE, &lp, &lvconvert_merge_single); } return lvconvert_single(cmd, &lp); } lvm2-2.02.98/tools/commands.h0000640000175000017500000007565312037016273014643 0ustar blankblank/* * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU 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 */ /*********** Replace with script? xx(e2fsadm, "Resize logical volume and ext2 filesystem", "e2fsadm " "[-d|--debug] " "[-h|--help] " "[-n|--nofsck]" "\n" "\t{[-l|--extents] [+|-]LogicalExtentsNumber |" "\n" "\t [-L|--size] [+|-]LogicalVolumeSize[bBsSkKmMgGtTpPeE]}" "\n" "\t[-t|--test] " "\n" "\t[-v|--verbose] " "\n" "\t[--version] " "\n" "\tLogicalVolumePath" "\n", extents_ARG, size_ARG, nofsck_ARG, test_ARG) *********/ xx(dumpconfig, "Dump active configuration", PERMITTED_READ_ONLY, "dumpconfig " "\t[-f|--file filename] " "\n" "[ConfigurationVariable...]\n", file_ARG) xx(formats, "List available metadata formats", PERMITTED_READ_ONLY, "formats\n") xx(help, "Display help for commands", PERMITTED_READ_ONLY, "help " "\n") /********* xx(lvactivate, "Activate logical volume on given partition(s)", "lvactivate " "\t[-d|--debug]\n" "\t[-h|--help]\n" "\t[-v|--verbose]\n" "Logical Volume(s)\n") ***********/ xx(lvchange, "Change the attributes of logical volume(s)", CACHE_VGMETADATA | PERMITTED_READ_ONLY, "lvchange\n" "\t[-A|--autobackup y|n]\n" "\t[-a|--activate [a|e|l]{y|n}]\n" "\t[--addtag Tag]\n" "\t[--alloc AllocationPolicy]\n" "\t[-C|--contiguous y|n]\n" "\t[-d|--debug]\n" "\t[--deltag Tag]\n" "\t[-f|--force]\n" "\t[-h|--help]\n" "\t[--discards {ignore|nopassdown|passdown}]\n" "\t[--ignorelockingfailure]\n" "\t[--ignoremonitoring]\n" "\t[--monitor {y|n}]\n" "\t[--poll {y|n}]\n" "\t[--noudevsync]\n" "\t[-M|--persistent y|n] [--major major] [--minor minor]\n" "\t[-P|--partial] " "\n" "\t[-p|--permission r|rw]\n" "\t[-r|--readahead ReadAheadSectors|auto|none]\n" "\t[--refresh]\n" "\t[--resync]\n" "\t[--sysinit]\n" "\t[-t|--test]\n" "\t[-v|--verbose]\n" "\t[-y|--yes]\n" "\t[--version]\n" "\t[-Z|--zero {y|n}]\n" "\tLogicalVolume[Path] [LogicalVolume[Path]...]\n", alloc_ARG, autobackup_ARG, activate_ARG, available_ARG, contiguous_ARG, discards_ARG, force_ARG, ignorelockingfailure_ARG, ignoremonitoring_ARG, major_ARG, minor_ARG, monitor_ARG, noudevsync_ARG, partial_ARG, permission_ARG, persistent_ARG, poll_ARG, readahead_ARG, resync_ARG, refresh_ARG, addtag_ARG, deltag_ARG, sysinit_ARG, test_ARG, yes_ARG, zero_ARG) xx(lvconvert, "Change logical volume layout", 0, "lvconvert " "[-m|--mirrors Mirrors [{--mirrorlog {disk|core|mirrored}|--corelog}]]\n" "\t[--type SegmentType]\n" "\t[--repair [--use-policies]]\n" "\t[--replace PhysicalVolume]\n" "\t[-R|--regionsize MirrorLogRegionSize]\n" "\t[--alloc AllocationPolicy]\n" "\t[-b|--background]\n" "\t[-d|--debug]\n" "\t[-f|--force]\n" "\t[-h|-?|--help]\n" "\t[-i|--interval seconds]\n" "\t[--stripes Stripes [-I|--stripesize StripeSize]]\n" "\t[--noudevsync]\n" "\t[-v|--verbose]\n" "\t[-y|--yes]\n" "\t[--version]" "\n" "\tLogicalVolume[Path] [PhysicalVolume[Path]...]\n\n" "lvconvert " "[--splitmirrors Images --trackchanges]\n" "[--splitmirrors Images --name SplitLogicalVolumeName]\n" "\tLogicalVolume[Path] [SplittablePhysicalVolume[Path]...]\n\n" "lvconvert " "[-s|--snapshot]\n" "\t[-c|--chunksize]\n" "\t[-d|--debug]\n" "\t[-h|-?|--help]\n" "\t[--noudevsync]\n" "\t[-v|--verbose]\n" "\t[-Z|--zero {y|n}]\n" "\t[--version]" "\n" "\tOriginalLogicalVolume[Path] SnapshotLogicalVolume[Path]\n\n" "lvconvert " "--merge\n" "\t[-b|--background]\n" "\t[-i|--interval seconds]\n" "\t[-d|--debug]\n" "\t[-h|-?|--help]\n" "\t[-v|--verbose]\n" "\tLogicalVolume[Path]\n\n" "lvconvert " "--thinpool ThinPoolLogicalVolume[Path]\n" "\t[--chunksize size]\n" "\t[--discards {ignore|nopassdown|passdown}]\n" "\t[[--poolmetadatasize size] | --poolmetadata ThinMetadataLogicalVolume[Path]]\n" "\t[-Z|--zero {y|n}]\n" "\t[-d|--debug] [-h|-?|--help] [-v|--verbose]\n", alloc_ARG, background_ARG, chunksize_ARG, corelog_ARG, interval_ARG, merge_ARG, mirrorlog_ARG, mirrors_ARG, name_ARG, noudevsync_ARG, regionsize_ARG, repair_ARG, replace_ARG, snapshot_ARG, splitmirrors_ARG, trackchanges_ARG, type_ARG, stripes_long_ARG, stripesize_ARG, test_ARG, chunksize_ARG, discards_ARG, poolmetadata_ARG, poolmetadatasize_ARG, thinpool_ARG, use_policies_ARG, yes_ARG, force_ARG, zero_ARG) xx(lvcreate, "Create a logical volume", 0, "lvcreate " "\n" "\t[-A|--autobackup {y|n}]\n" "\t[-a|--activate [a|e|l]{y|n}]\n" "\t[--addtag Tag]\n" "\t[--alloc AllocationPolicy]\n" "\t[-C|--contiguous {y|n}]\n" "\t[-d|--debug]\n" "\t[-h|-?|--help]\n" "\t[--ignoremonitoring]\n" "\t[--monitor {y|n}]\n" "\t[-i|--stripes Stripes [-I|--stripesize StripeSize]]\n" "\t{-l|--extents LogicalExtentsNumber[%{VG|PVS|FREE}] |\n" "\t -L|--size LogicalVolumeSize[bBsSkKmMgGtTpPeE]}\n" "\t[-M|--persistent {y|n}] [--major major] [--minor minor]\n" "\t[-m|--mirrors Mirrors [--nosync] [{--mirrorlog {disk|core|mirrored}|--corelog}]]\n" "\t[-n|--name LogicalVolumeName]\n" "\t[--noudevsync]\n" "\t[-p|--permission {r|rw}]\n" "\t[-r|--readahead ReadAheadSectors|auto|none]\n" "\t[-R|--regionsize MirrorLogRegionSize]\n" "\t[-T|--thin [-c|--chunksize ChunkSize]\n" "\t [--discards {ignore|nopassdown|passdown}]\n" "\t [--poolmetadatasize MetadataSize[bBsSkKmMgG]]]\n" "\t[--thinpool ThinPoolLogicalVolume{Name|Path}]\n" "\t[-t|--test]\n" "\t[--type VolumeType]\n" "\t[-v|--verbose]\n" "\t[-Z|--zero {y|n}]\n" "\t[--version]\n" "\tVolumeGroupName [PhysicalVolumePath...]\n\n" "lvcreate \n" "\t{ {-s|--snapshot} OriginalLogicalVolume[Path] |\n" "\t [-s|--snapshot] VolumeGroupName[Path] -V|--virtualsize VirtualSize}\n" "\t {-T|--thin} VolumeGroupName[Path][/PoolLogicalVolume] \n" "\t -V|--virtualsize VirtualSize}\n" "\t[-c|--chunksize]\n" "\t[-A|--autobackup {y|n}]\n" "\t[--addtag Tag]\n" "\t[--alloc AllocationPolicy]\n" "\t[-C|--contiguous {y|n}]\n" "\t[-d|--debug]\n" "\t[--discards {ignore|nopassdown|passdown}]\n" "\t[-h|-?|--help]\n" "\t[--ignoremonitoring]\n" "\t[--monitor {y|n}]\n" "\t[-i|--stripes Stripes [-I|--stripesize StripeSize]]\n" "\t{-l|--extents LogicalExtentsNumber[%{VG|FREE|ORIGIN}] |\n" "\t -L|--size LogicalVolumeSize[bBsSkKmMgGtTpPeE]}\n" "\t[--poolmetadatasize Size[bBsSkKmMgG]]\n" "\t[-M|--persistent {y|n}] [--major major] [--minor minor]\n" "\t[-n|--name LogicalVolumeName]\n" "\t[--noudevsync]\n" "\t[-p|--permission {r|rw}]\n" "\t[-r|--readahead ReadAheadSectors|auto|none]\n" "\t[-t|--test]\n" "\t[--thinpool ThinPoolLogicalVolume[Path]]\n" "\t[-v|--verbose]\n" "\t[--version]\n" "\t[PhysicalVolumePath...]\n\n", addtag_ARG, alloc_ARG, autobackup_ARG, activate_ARG, available_ARG, chunksize_ARG, contiguous_ARG, corelog_ARG, discards_ARG, extents_ARG, ignoremonitoring_ARG, major_ARG, minor_ARG, mirrorlog_ARG, mirrors_ARG, monitor_ARG, name_ARG, nosync_ARG, noudevsync_ARG, permission_ARG, persistent_ARG, readahead_ARG, regionsize_ARG, size_ARG, snapshot_ARG, stripes_ARG, stripesize_ARG, test_ARG, thin_ARG, thinpool_ARG, type_ARG, virtualoriginsize_ARG, poolmetadatasize_ARG, virtualsize_ARG, zero_ARG) xx(lvdisplay, "Display information about a logical volume", PERMITTED_READ_ONLY, "lvdisplay\n" "\t[-a|--all]\n" "\t[-c|--colon]\n" "\t[-d|--debug]\n" "\t[-h|--help]\n" "\t[--ignorelockingfailure]\n" "\t[-m|--maps]\n" "\t[--nosuffix]\n" "\t[-P|--partial] " "\n" "\t[--units hHbBsSkKmMgGtTpPeE]\n" "\t[-v|--verbose]\n" "\t[--version]" "\n" "\t[LogicalVolume[Path] [LogicalVolume[Path]...]]\n" "\n" "lvdisplay --columns|-C\n" "\t[--aligned]\n" "\t[-a|--all]\n" "\t[-d|--debug]\n" "\t[-h|--help]\n" "\t[--ignorelockingfailure]\n" "\t[--noheadings]\n" "\t[--nosuffix]\n" "\t[-o|--options [+]Field[,Field]]\n" "\t[-O|--sort [+|-]key1[,[+|-]key2[,...]]]\n" "\t[-P|--partial] " "\n" "\t[--segments]\n" "\t[--separator Separator]\n" "\t[--unbuffered]\n" "\t[--units hHbBsSkKmMgGtTpPeE]\n" "\t[-v|--verbose]\n" "\t[--version]" "\n" "\t[LogicalVolume[Path] [LogicalVolume[Path]...]]\n", aligned_ARG, all_ARG, colon_ARG, columns_ARG, ignorelockingfailure_ARG, maps_ARG, noheadings_ARG, nosuffix_ARG, options_ARG, sort_ARG, partial_ARG, segments_ARG, separator_ARG, unbuffered_ARG, units_ARG) xx(lvextend, "Add space to a logical volume", 0, "lvextend\n" "\t[-A|--autobackup y|n]\n" "\t[--alloc AllocationPolicy]\n" "\t[-d|--debug]\n" "\t[-f|--force]\n" "\t[-h|--help]\n" "\t[-i|--stripes Stripes [-I|--stripesize StripeSize]]\n" "\t{-l|--extents [+]LogicalExtentsNumber[%{VG|LV|PVS|FREE|ORIGIN}] |\n" "\t -L|--size [+]LogicalVolumeSize[bBsSkKmMgGtTpPeE]}\n" "\t[-m|--mirrors Mirrors]\n" "\t[--nosync]\n" "\t[--use-policies]\n" "\t[-n|--nofsck]\n" "\t[--noudevsync]\n" "\t[-r|--resizefs]\n" "\t[-t|--test]\n" "\t[--type VolumeType]\n" "\t[-v|--verbose]\n" "\t[--version]" "\n" "\tLogicalVolume[Path] [ PhysicalVolumePath... ]\n", alloc_ARG, autobackup_ARG, extents_ARG, force_ARG, mirrors_ARG, nofsck_ARG, nosync_ARG, noudevsync_ARG, resizefs_ARG, size_ARG, stripes_ARG, stripesize_ARG, test_ARG, type_ARG, use_policies_ARG) xx(lvmchange, "With the device mapper, this is obsolete and does nothing.", 0, "lvmchange\n" "\t[-d|--debug]\n" "\t[-h|--help]\n" "\t[-R|--reset]\n" "\t[-v|--verbose]\n" "\t[--version]" "\n", reset_ARG) xx(lvmdiskscan, "List devices that may be used as physical volumes", PERMITTED_READ_ONLY, "lvmdiskscan\n" "\t[-d|--debug]\n" "\t[-h|--help]\n" "\t[-l|--lvmpartition]\n" "\t[--version]" "\n", lvmpartition_ARG) xx(lvmsadc, "Collect activity data", 0, "lvmsadc\n" "\t[-d|--debug]\n" "\t[-h|--help]\n" "\t[-v|--verbose]\n" "\t[--version]" "\n" "\t[LogFilePath]\n" ) xx(lvmsar, "Create activity report", 0, "lvmsar\n" "\t[-d|--debug]\n" "\t[-f|--full]\n" "\t[-h|--help]\n" "\t[-s|--stdin]\n" "\t[-v|--verbose]\n" "\t[--version]" "\n" "\tLogFilePath\n", full_ARG, stdin_ARG) xx(lvreduce, "Reduce the size of a logical volume", 0, "lvreduce\n" "\t[-A|--autobackup y|n]\n" "\t[-d|--debug]\n" "\t[-f|--force]\n" "\t[-h|--help]\n" "\t{-l|--extents [-]LogicalExtentsNumber[%{VG|LV|FREE|ORIGIN}] |\n" "\t -L|--size [-]LogicalVolumeSize[bBsSkKmMgGtTpPeE]}\n" "\t[-n|--nofsck]\n" "\t[--noudevsync]\n" "\t[-r|--resizefs]\n" "\t[-t|--test]\n" "\t[-v|--verbose]\n" "\t[-y|--yes]\n" "\t[--version]" "\n" "\tLogicalVolume[Path]\n", autobackup_ARG, force_ARG, extents_ARG, nofsck_ARG, noudevsync_ARG, resizefs_ARG, size_ARG, test_ARG, yes_ARG) xx(lvremove, "Remove logical volume(s) from the system", 0, "lvremove\n" "\t[-A|--autobackup y|n]\n" "\t[-d|--debug]\n" "\t[-f|--force]\n" "\t[-h|--help]\n" "\t[--noudevsync]\n" "\t[-t|--test]\n" "\t[-v|--verbose]\n" "\t[--version]" "\n" "\tLogicalVolume[Path] [LogicalVolume[Path]...]\n", autobackup_ARG, force_ARG, noudevsync_ARG, test_ARG) xx(lvrename, "Rename a logical volume", 0, "lvrename\n" "\t[-A|--autobackup {y|n}] " "\n" "\t[-d|--debug] " "\n" "\t[-h|-?|--help] " "\n" "\t[--noudevsync]\n" "\t[-t|--test] " "\n" "\t[-v|--verbose]" "\n" "\t[--version] " "\n" "\t{ OldLogicalVolumePath NewLogicalVolumePath |" "\n" "\t VolumeGroupName OldLogicalVolumeName NewLogicalVolumeName }\n", autobackup_ARG, noudevsync_ARG, test_ARG) xx(lvresize, "Resize a logical volume", 0, "lvresize\n" "\t[-A|--autobackup y|n]\n" "\t[--alloc AllocationPolicy]\n" "\t[-d|--debug]\n" "\t[-f|--force]\n" "\t[-h|--help]\n" "\t[-i|--stripes Stripes [-I|--stripesize StripeSize]]\n" "\t{-l|--extents [+|-]LogicalExtentsNumber[%{VG|LV|PVS|FREE|ORIGIN}] |\n" "\t -L|--size [+|-]LogicalVolumeSize[bBsSkKmMgGtTpPeE]}\n" "\t[-n|--nofsck]\n" "\t[--noudevsync]\n" "\t[-r|--resizefs]\n" "\t[-t|--test]\n" "\t[--type VolumeType]\n" "\t[-v|--verbose]\n" "\t[--version]" "\n" "\tLogicalVolume[Path] [ PhysicalVolumePath... ]\n", alloc_ARG, autobackup_ARG, extents_ARG, force_ARG, nofsck_ARG, noudevsync_ARG, resizefs_ARG, size_ARG, stripes_ARG, stripesize_ARG, test_ARG, type_ARG) xx(lvs, "Display information about logical volumes", PERMITTED_READ_ONLY, "lvs" "\n" "\t[-a|--all]\n" "\t[--aligned]\n" "\t[-d|--debug]\n" "\t[-h|--help]\n" "\t[--ignorelockingfailure]\n" "\t[--nameprefixes]\n" "\t[--noheadings]\n" "\t[--nosuffix]\n" "\t[-o|--options [+]Field[,Field]]\n" "\t[-O|--sort [+|-]key1[,[+|-]key2[,...]]]\n" "\t[-P|--partial] " "\n" "\t[--rows]\n" "\t[--segments]\n" "\t[--separator Separator]\n" "\t[--trustcache]\n" "\t[--unbuffered]\n" "\t[--units hHbBsSkKmMgGtTpPeE]\n" "\t[--unquoted]\n" "\t[-v|--verbose]\n" "\t[--version]" "\n" "\t[LogicalVolume[Path] [LogicalVolume[Path]...]]\n", aligned_ARG, all_ARG, ignorelockingfailure_ARG, nameprefixes_ARG, noheadings_ARG, nolocking_ARG, nosuffix_ARG, options_ARG, partial_ARG, rows_ARG, segments_ARG, separator_ARG, sort_ARG, trustcache_ARG, unbuffered_ARG, units_ARG, unquoted_ARG) xx(lvscan, "List all logical volumes in all volume groups", PERMITTED_READ_ONLY, "lvscan " "\n" "\t[-a|--all]\n" "\t[-b|--blockdevice] " "\n" "\t[-d|--debug] " "\n" "\t[-h|-?|--help] " "\n" "\t[--ignorelockingfailure]\n" "\t[-P|--partial] " "\n" "\t[-v|--verbose] " "\n" "\t[--version]\n", all_ARG, blockdevice_ARG, ignorelockingfailure_ARG, partial_ARG) xx(pvchange, "Change attributes of physical volume(s)", 0, "pvchange\n" "\t[-a|--all]\n" "\t[-A|--autobackup y|n]\n" "\t[-d|--debug]\n" "\t[-f|--force]\n" "\t[-h|--help]\n" "\t[-t|--test]\n" "\t[-u|--uuid]\n" "\t[-x|--allocatable y|n]\n" "\t[--metadataignore y|n]\n" "\t[-v|--verbose]\n" "\t[--addtag Tag]\n" "\t[--deltag Tag]\n" "\t[--version]" "\n" "\t[PhysicalVolumePath...]\n", all_ARG, allocatable_ARG, allocation_ARG, autobackup_ARG, deltag_ARG, addtag_ARG, force_ARG, metadataignore_ARG, test_ARG, uuid_ARG) xx(pvresize, "Resize physical volume(s)", 0, "pvresize " "\n" "\t[-d|--debug]" "\n" "\t[-h|-?|--help] " "\n" "\t[--setphysicalvolumesize PhysicalVolumeSize[bBsSkKmMgGtTpPeE]" "\n" "\t[-t|--test] " "\n" "\t[-v|--verbose] " "\n" "\t[--version] " "\n" "\tPhysicalVolume [PhysicalVolume...]\n", physicalvolumesize_ARG, test_ARG) xx(pvck, "Check the consistency of physical volume(s)", 0, "pvck " "\t[-d|--debug]\n" "\t[-h|--help]\n" "\t[--labelsector sector] " "\n" "\t[-v|--verbose]\n" "\t[--version]" "\n" "\tPhysicalVolume [PhysicalVolume...]\n", labelsector_ARG) xx(pvcreate, "Initialize physical volume(s) for use by LVM", 0, "pvcreate " "\n" "\t[--norestorefile]\n" "\t[--restorefile file]\n" "\t[-d|--debug]" "\n" "\t[-f[f]|--force [--force]] " "\n" "\t[-h|-?|--help] " "\n" "\t[--labelsector sector] " "\n" "\t[-M|--metadatatype 1|2]" "\n" "\t[--pvmetadatacopies #copies]" "\n" "\t[--metadatasize MetadataSize[bBsSkKmMgGtTpPeE]]" "\n" "\t[--dataalignment Alignment[bBsSkKmMgGtTpPeE]]" "\n" "\t[--dataalignmentoffset AlignmentOffset[bBsSkKmMgGtTpPeE]]" "\n" "\t[--setphysicalvolumesize PhysicalVolumeSize[bBsSkKmMgGtTpPeE]" "\n" "\t[-t|--test] " "\n" "\t[-u|--uuid uuid] " "\n" "\t[-v|--verbose] " "\n" "\t[-y|--yes]" "\n" "\t[-Z|--zero {y|n}]\n" "\t[--version] " "\n" "\tPhysicalVolume [PhysicalVolume...]\n", dataalignment_ARG, dataalignmentoffset_ARG, force_ARG, test_ARG, labelsector_ARG, metadatatype_ARG, metadatacopies_ARG, metadatasize_ARG, metadataignore_ARG, norestorefile_ARG, physicalvolumesize_ARG, pvmetadatacopies_ARG, restorefile_ARG, uuidstr_ARG, yes_ARG, zero_ARG) xx(pvdata, "Display the on-disk metadata for physical volume(s)", 0, "pvdata " "\n" "\t[-a|--all] " "\n" "\t[-d|--debug] " "\n" "\t[-E|--physicalextent] " "\n" "\t[-h|-?|--help]" "\n" "\t[-L|--logicalvolume] " "\n" "\t[-P[P]|--physicalvolume [--physicalvolume]]" "\n" "\t[-U|--uuidlist] " "\n" "\t[-v[v]|--verbose [--verbose]] " "\n" "\t[-V|--volumegroup]" "\n" "\t[--version] " "\n" "\tPhysicalVolume [PhysicalVolume...]\n", all_ARG, logicalextent_ARG, physicalextent_ARG, physicalvolume_ARG, uuidlist_ARG, volumegroup_ARG) xx(pvdisplay, "Display various attributes of physical volume(s)", CACHE_VGMETADATA | PERMITTED_READ_ONLY, "pvdisplay\n" "\t[-c|--colon]\n" "\t[-d|--debug]\n" "\t[-h|--help]\n" "\t[--ignorelockingfailure]\n" "\t[-m|--maps]\n" "\t[--nosuffix]\n" "\t[-s|--short]\n" "\t[--units hHbBsSkKmMgGtTpPeE]\n" "\t[-v|--verbose]\n" "\t[--version]" "\n" "\t[PhysicalVolumePath [PhysicalVolumePath...]]\n" "\n" "pvdisplay --columns|-C\n" "\t[--aligned]\n" "\t[-a|--all]\n" "\t[-d|--debug]\n" "\t[-h|--help]\n" "\t[--ignorelockingfailure]\n" "\t[--noheadings]\n" "\t[--nosuffix]\n" "\t[-o|--options [+]Field[,Field]]\n" "\t[-O|--sort [+|-]key1[,[+|-]key2[,...]]]\n" "\t[--separator Separator]\n" "\t[--unbuffered]\n" "\t[--units hHbBsSkKmMgGtTpPeE]\n" "\t[-v|--verbose]\n" "\t[--version]" "\n" "\t[PhysicalVolumePath [PhysicalVolumePath...]]\n", aligned_ARG, all_ARG, colon_ARG, columns_ARG, ignorelockingfailure_ARG, maps_ARG, noheadings_ARG, nosuffix_ARG, options_ARG, separator_ARG, short_ARG, sort_ARG, unbuffered_ARG, units_ARG) xx(pvmove, "Move extents from one physical volume to another", 0, "pvmove " "\n" "\t[--abort]\n" "\t[-A|--autobackup {y|n}]\n" "\t[--alloc AllocationPolicy]\n" "\t[-b|--background]\n" "\t[-d|--debug]\n " "\t[-h|-?|--help]\n" "\t[-i|--interval seconds]\n" "\t[--noudevsync]\n" "\t[-t|--test]\n " "\t[-v|--verbose]\n " "\t[--version]\n" "\t[{-n|--name} LogicalVolume]\n" /* "\t[{-n|--name} LogicalVolume[:LogicalExtent[-LogicalExtent]...]]\n" */ "\tSourcePhysicalVolume[:PhysicalExtent[-PhysicalExtent]...]}\n" "\t[DestinationPhysicalVolume[:PhysicalExtent[-PhysicalExtent]...]...]\n", abort_ARG, alloc_ARG, autobackup_ARG, background_ARG, interval_ARG, name_ARG, noudevsync_ARG, test_ARG) xx(pvremove, "Remove LVM label(s) from physical volume(s)", 0, "pvremove " "\n" "\t[-d|--debug]" "\n" "\t[-f[f]|--force [--force]] " "\n" "\t[-h|-?|--help] " "\n" "\t[-t|--test] " "\n" "\t[-v|--verbose] " "\n" "\t[-y|--yes]" "\n" "\t[--version] " "\n" "\tPhysicalVolume [PhysicalVolume...]\n", force_ARG, test_ARG, yes_ARG) xx(pvs, "Display information about physical volumes", CACHE_VGMETADATA | PERMITTED_READ_ONLY, "pvs" "\n" "\t[-a|--all]\n" "\t[--aligned]\n" "\t[-d|--debug]" "\n" "\t[-h|-?|--help] " "\n" "\t[--ignorelockingfailure]\n" "\t[--nameprefixes]\n" "\t[--noheadings]\n" "\t[--nosuffix]\n" "\t[-o|--options [+]Field[,Field]]\n" "\t[-O|--sort [+|-]key1[,[+|-]key2[,...]]]\n" "\t[-P|--partial] " "\n" "\t[--rows]\n" "\t[--segments]\n" "\t[--separator Separator]\n" "\t[--trustcache]\n" "\t[--unbuffered]\n" "\t[--units hHbBsSkKmMgGtTpPeE]\n" "\t[--unquoted]\n" "\t[-v|--verbose]\n" "\t[--version]\n" "\t[PhysicalVolume [PhysicalVolume...]]\n", aligned_ARG, all_ARG, ignorelockingfailure_ARG, nameprefixes_ARG, noheadings_ARG, nolocking_ARG, nosuffix_ARG, options_ARG, partial_ARG, rows_ARG, segments_ARG, separator_ARG, sort_ARG, trustcache_ARG, unbuffered_ARG, units_ARG, unquoted_ARG) xx(pvscan, "List all physical volumes", PERMITTED_READ_ONLY, "pvscan " "\n" "\t[-a|--activate ay]\n" "\t[--cache [ DevicePath | --major major --minor minor]...]\n" "\t[-d|--debug] " "\n" "\t{-e|--exported | -n|--novolumegroup} " "\n" "\t[-h|-?|--help]" "\n" "\t[--ignorelockingfailure]\n" "\t[-P|--partial] " "\n" "\t[-s|--short] " "\n" "\t[-u|--uuid] " "\n" "\t[-v|--verbose] " "\n" "\t[--version]\n", activate_ARG, available_ARG, cache_ARG, exported_ARG, ignorelockingfailure_ARG, major_ARG, minor_ARG, novolumegroup_ARG, partial_ARG, short_ARG, uuid_ARG) xx(segtypes, "List available segment types", PERMITTED_READ_ONLY, "segtypes\n") xx(vgcfgbackup, "Backup volume group configuration(s)", PERMITTED_READ_ONLY, "vgcfgbackup " "\n" "\t[-d|--debug] " "\n" "\t[-f|--file filename] " "\n" "\t[-h|-?|--help] " "\n" "\t[--ignorelockingfailure]\n" "\t[-P|--partial] " "\n" "\t[-v|--verbose]" "\n" "\t[--version] " "\n" "\t[VolumeGroupName...]\n", file_ARG, ignorelockingfailure_ARG, partial_ARG) xx(vgcfgrestore, "Restore volume group configuration", 0, "vgcfgrestore " "\n" "\t[-d|--debug] " "\n" "\t[-f|--file filename] " "\n" "\t[-l[l]|--list [--list]]" "\n" "\t[-M|--metadatatype 1|2]" "\n" "\t[-h|--help]" "\n" "\t[-t|--test] " "\n" "\t[-v|--verbose]" "\n" "\t[--version] " "\n" "\tVolumeGroupName", file_ARG, list_ARG, metadatatype_ARG, test_ARG) xx(vgchange, "Change volume group attributes", CACHE_VGMETADATA | PERMITTED_READ_ONLY, "vgchange" "\n" "\t[-A|--autobackup {y|n}] " "\n" "\t[--alloc AllocationPolicy] " "\n" "\t[-P|--partial] " "\n" "\t[-d|--debug] " "\n" "\t[-h|--help] " "\n" "\t[--ignorelockingfailure]\n" "\t[--ignoremonitoring]\n" "\t[--monitor {y|n}]\n" "\t[--[vg]metadatacopies #copies] " "\n" "\t[--poll {y|n}]\n" "\t[--noudevsync]\n" "\t[--refresh]\n" "\t[--sysinit]\n" "\t[-t|--test]" "\n" "\t[-u|--uuid] " "\n" "\t[-v|--verbose] " "\n" "\t[--version]" "\n" "\t{-a|--activate [a|e|l]{y|n} |" "\n" "\t -c|--clustered {y|n} |" "\n" "\t -x|--resizeable {y|n} |" "\n" "\t -l|--logicalvolume MaxLogicalVolumes |" "\n" "\t -p|--maxphysicalvolumes MaxPhysicalVolumes |" "\n" "\t -s|--physicalextentsize PhysicalExtentSize[bBsSkKmMgGtTpPeE] |" "\n" "\t --addtag Tag |\n" "\t --deltag Tag}\n" "\t[VolumeGroupName...]\n", addtag_ARG, alloc_ARG, allocation_ARG, autobackup_ARG, activate_ARG, available_ARG, clustered_ARG, deltag_ARG, ignorelockingfailure_ARG, ignoremonitoring_ARG, logicalvolume_ARG, maxphysicalvolumes_ARG, monitor_ARG, noudevsync_ARG, metadatacopies_ARG, vgmetadatacopies_ARG, partial_ARG, physicalextentsize_ARG, poll_ARG, refresh_ARG, resizeable_ARG, resizable_ARG, sysinit_ARG, test_ARG, uuid_ARG) xx(vgck, "Check the consistency of volume group(s)", 0, "vgck " "\t[-d|--debug]\n" "\t[-h|--help]\n" "\t[-v|--verbose]\n" "\t[--version]" "\n" "\t[VolumeGroupName...]\n" ) xx(vgconvert, "Change volume group metadata format", 0, "vgconvert " "\n" "\t[-d|--debug]" "\n" "\t[-h|--help] " "\n" "\t[--labelsector sector] " "\n" "\t[-M|--metadatatype 1|2]" "\n" "\t[--pvmetadatacopies #copies]" "\n" "\t[--metadatasize MetadataSize[bBsSkKmMgGtTpPeE]]" "\n" "\t[-t|--test] " "\n" "\t[-v|--verbose] " "\n" "\t[--version] " "\n" "\tVolumeGroupName [VolumeGroupName...]\n", force_ARG, test_ARG, labelsector_ARG, metadatatype_ARG, metadatacopies_ARG, pvmetadatacopies_ARG, metadatasize_ARG ) xx(vgcreate, "Create a volume group", 0, "vgcreate" "\n" "\t[-A|--autobackup {y|n}] " "\n" "\t[--addtag Tag] " "\n" "\t[--alloc AllocationPolicy] " "\n" "\t[-c|--clustered {y|n}] " "\n" "\t[-d|--debug]" "\n" "\t[-h|--help]" "\n" "\t[-l|--maxlogicalvolumes MaxLogicalVolumes]" "\n" "\t[-M|--metadatatype 1|2] " "\n" "\t[--[vg]metadatacopies #copies] " "\n" "\t[-p|--maxphysicalvolumes MaxPhysicalVolumes] " "\n" "\t[-s|--physicalextentsize PhysicalExtentSize[bBsSkKmMgGtTpPeE]] " "\n" "\t[-t|--test] " "\n" "\t[-v|--verbose]" "\n" "\t[--version] " "\n" "\t[ PHYSICAL DEVICE OPTIONS ] " "\n" "\tVolumeGroupName PhysicalDevicePath [PhysicalDevicePath...]\n", addtag_ARG, alloc_ARG, autobackup_ARG, clustered_ARG, maxlogicalvolumes_ARG, maxphysicalvolumes_ARG, metadatatype_ARG, physicalextentsize_ARG, test_ARG, force_ARG, yes_ARG, zero_ARG, labelsector_ARG, metadatasize_ARG, pvmetadatacopies_ARG, metadatacopies_ARG, vgmetadatacopies_ARG, dataalignment_ARG, dataalignmentoffset_ARG) xx(vgdisplay, "Display volume group information", PERMITTED_READ_ONLY, "vgdisplay " "\n" "\t[-A|--activevolumegroups]" "\n" "\t[-c|--colon | -s|--short | -v|--verbose]" "\n" "\t[-d|--debug] " "\n" "\t[-h|--help] " "\n" "\t[--ignorelockingfailure]" "\n" "\t[--nosuffix]\n" "\t[-P|--partial] " "\n" "\t[--units hHbBsSkKmMgGtTpPeE]\n" "\t[--version]" "\n" "\t[VolumeGroupName [VolumeGroupName...]]\n" "\n" "vgdisplay --columns|-C\n" "\t[--aligned]\n" "\t[-d|--debug] " "\n" "\t[-h|--help] " "\n" "\t[--ignorelockingfailure]" "\n" "\t[--noheadings]\n" "\t[--nosuffix]\n" "\t[-o|--options [+]Field[,Field]]\n" "\t[-O|--sort [+|-]key1[,[+|-]key2[,...]]]\n" "\t[-P|--partial] " "\n" "\t[--separator Separator]\n" "\t[--unbuffered]\n" "\t[--units hHbBsSkKmMgGtTpPeE]\n" "\t[--verbose]" "\n" "\t[--version]" "\n" "\t[VolumeGroupName [VolumeGroupName...]]\n", activevolumegroups_ARG, aligned_ARG, colon_ARG, columns_ARG, ignorelockingfailure_ARG, noheadings_ARG, nosuffix_ARG, options_ARG, partial_ARG, short_ARG, separator_ARG, sort_ARG, unbuffered_ARG, units_ARG) xx(vgexport, "Unregister volume group(s) from the system", 0, "vgexport " "\n" "\t[-a|--all] " "\n" "\t[-d|--debug] " "\n" "\t[-h|--help]" "\n" "\t[-v|--verbose] " "\n" "\t[--version] " "\n" "\tVolumeGroupName [VolumeGroupName...]\n", all_ARG, test_ARG) xx(vgextend, "Add physical volumes to a volume group", 0, "vgextend\n" "\t[-A|--autobackup y|n]\n" "\t[--restoremissing]\n" "\t[-d|--debug]\n" "\t[-f|--force]\n" "\t[-h|--help]\n" "\t[-t|--test]\n" "\t[-v|--verbose]\n" "\t[--version]" "\n" "\t[ PHYSICAL DEVICE OPTIONS ] " "\n" "\tVolumeGroupName PhysicalDevicePath [PhysicalDevicePath...]\n", autobackup_ARG, test_ARG, force_ARG, yes_ARG, zero_ARG, labelsector_ARG, metadatatype_ARG, metadatasize_ARG, pvmetadatacopies_ARG, metadatacopies_ARG, metadataignore_ARG, dataalignment_ARG, dataalignmentoffset_ARG, restoremissing_ARG) xx(vgimport, "Register exported volume group with system", 0, "vgimport " "\n" "\t[-a|--all]\n" "\t[-d|--debug] " "\n" "\t[-f|--force] " "\n" "\t[-h|--help] " "\n" "\t[-t|--test] " "\n" "\t[-v|--verbose]" "\n" "\t[--version]" "\n" "\tVolumeGroupName..." "\n", all_ARG, force_ARG, test_ARG) xx(vgmerge, "Merge volume groups", 0, "vgmerge\n" "\t[-A|--autobackup y|n]\n" "\t[-d|--debug]\n" "\t[-h|--help]\n" "\t[-l|--list]\n" "\t[-t|--test]\n" "\t[-v|--verbose]\n" "\t[--version]" "\n" "\tDestinationVolumeGroupName SourceVolumeGroupName\n", autobackup_ARG, list_ARG, test_ARG) xx(vgmknodes, "Create the special files for volume group devices in /dev", 0, "vgmknodes\n" "\t[-d|--debug]\n" "\t[-h|--help]\n" "\t[--ignorelockingfailure]\n" "\t[--refresh]\n" "\t[-v|--verbose]\n" "\t[--version]" "\n" "\t[VolumeGroupName...]\n", ignorelockingfailure_ARG, refresh_ARG) xx(vgreduce, "Remove physical volume(s) from a volume group", 0, "vgreduce\n" "\t[-a|--all]\n" "\t[-A|--autobackup y|n]\n" "\t[-d|--debug]\n" "\t[-h|--help]\n" "\t[--mirrorsonly]\n" "\t[--removemissing]\n" "\t[-f|--force]\n" "\t[-t|--test]\n" "\t[-v|--verbose]\n" "\t[--version]" "\n" "\tVolumeGroupName\n" "\t[PhysicalVolumePath...]\n", all_ARG, autobackup_ARG, force_ARG, mirrorsonly_ARG, removemissing_ARG, test_ARG) xx(vgremove, "Remove volume group(s)", 0, "vgremove\n" "\t[-d|--debug]\n" "\t[-f|--force]\n" "\t[-h|--help]\n" "\t[--noudevsync]\n" "\t[-t|--test]\n" "\t[-v|--verbose]\n" "\t[--version]" "\n" "\tVolumeGroupName [VolumeGroupName...]\n", force_ARG, noudevsync_ARG, test_ARG) xx(vgrename, "Rename a volume group", 0, "vgrename\n" "\t[-A|--autobackup y|n]\n" "\t[-d|--debug]\n" "\t[-h|--help]\n" "\t[-t|--test]\n" "\t[-v|--verbose]\n" "\t[--version]" "\n" "\tOldVolumeGroupPath NewVolumeGroupPath |\n" "\tOldVolumeGroupName NewVolumeGroupName\n", autobackup_ARG, force_ARG, test_ARG) xx(vgs, "Display information about volume groups", PERMITTED_READ_ONLY, "vgs" "\n" "\t[--aligned]\n" "\t[-a|--all]\n" "\t[-d|--debug]\n" "\t[-h|--help]\n" "\t[--ignorelockingfailure]\n" "\t[--nameprefixes]\n" "\t[--noheadings]\n" "\t[--nosuffix]\n" "\t[-o|--options [+]Field[,Field]]\n" "\t[-O|--sort [+|-]key1[,[+|-]key2[,...]]]\n" "\t[-P|--partial] " "\n" "\t[--rows]\n" "\t[--separator Separator]\n" "\t[--trustcache]\n" "\t[--unbuffered]\n" "\t[--units hHbBsSkKmMgGtTpPeE]\n" "\t[--unquoted]\n" "\t[-v|--verbose]\n" "\t[--version]\n" "\t[VolumeGroupName [VolumeGroupName...]]\n", aligned_ARG, all_ARG, ignorelockingfailure_ARG, nameprefixes_ARG, noheadings_ARG, nolocking_ARG, nosuffix_ARG, options_ARG, partial_ARG, rows_ARG, separator_ARG, sort_ARG, trustcache_ARG, unbuffered_ARG, units_ARG, unquoted_ARG) xx(vgscan, "Search for all volume groups", PERMITTED_READ_ONLY, "vgscan " "\t[--cache]\n" "\t[-d|--debug]\n" "\t[-h|--help]\n" "\t[--ignorelockingfailure]\n" "\t[--mknodes]\n" "\t[-P|--partial] " "\n" "\t[-v|--verbose]\n" "\t[--version]" "\n", cache_ARG, ignorelockingfailure_ARG, mknodes_ARG, partial_ARG) xx(vgsplit, "Move physical volumes into a new or existing volume group", 0, "vgsplit " "\n" "\t[-A|--autobackup {y|n}] " "\n" "\t[--alloc AllocationPolicy] " "\n" "\t[-c|--clustered {y|n}] " "\n" "\t[-d|--debug] " "\n" "\t[-h|--help] " "\n" "\t[-l|--maxlogicalvolumes MaxLogicalVolumes]" "\n" "\t[-M|--metadatatype 1|2] " "\n" "\t[--[vg]metadatacopies #copies] " "\n" "\t[-n|--name LogicalVolumeName]\n" "\t[-p|--maxphysicalvolumes MaxPhysicalVolumes] " "\n" "\t[-t|--test] " "\n" "\t[-v|--verbose] " "\n" "\t[--version]" "\n" "\tSourceVolumeGroupName DestinationVolumeGroupName" "\n" "\t[PhysicalVolumePath...]\n", alloc_ARG, autobackup_ARG, clustered_ARG, maxlogicalvolumes_ARG, maxphysicalvolumes_ARG, metadatatype_ARG, vgmetadatacopies_ARG, name_ARG, test_ARG) xx(version, "Display software and driver version information", PERMITTED_READ_ONLY, "version\n" ) lvm2-2.02.98/tools/lvm2cmd-static.c0000640000175000017500000000115212037016273015645 0ustar blankblank/* * Copyright (C) 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 */ #include "lvm2cmdline.h" #include "lvm2cmd.h" void *lvm2_init(void) { return cmdlib_lvm2_init(1); } lvm2-2.02.98/tools/dumpconfig.c0000640000175000017500000000151512037016273015152 0ustar blankblank/* * Copyright (C) 2003-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 "tools.h" int dumpconfig(struct cmd_context *cmd, int argc, char **argv) { const char *file = arg_str_value(cmd, file_ARG, NULL); if (!config_write(cmd->cft, file, argc, argv)) { stack; return ECMD_FAILED; } return ECMD_PROCESSED; } lvm2-2.02.98/tools/stub.h0000640000175000017500000000271312037016273014002 0ustar blankblank/* * Copyright (C) 2001-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 */ #define unimplemented \ log_error("Command not implemented yet."); return ECMD_FAILED /*int e2fsadm(struct cmd_context *cmd, int argc, char **argv) unimplemented*/ int lvmsadc(struct cmd_context *cmd __attribute__((unused)), int argc __attribute__((unused)), char **argv __attribute__((unused))) { unimplemented; } int lvmsar(struct cmd_context *cmd __attribute__((unused)), int argc __attribute__((unused)), char **argv __attribute__((unused))) { unimplemented; } int pvdata(struct cmd_context *cmd __attribute__((unused)), int argc __attribute__((unused)), char **argv __attribute__((unused))) { log_error("There's no 'pvdata' command in LVM2."); log_error("Use lvs, pvs, vgs instead; or use vgcfgbackup and read the text file backup."); log_error("Metadata in LVM1 format can still be displayed using LVM1's pvdata command."); return ECMD_FAILED; } lvm2-2.02.98/tools/vgconvert.c0000640000175000017500000001524212037016273015036 0ustar blankblank/* * 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 "tools.h" static int vgconvert_single(struct cmd_context *cmd, const char *vg_name, struct volume_group *vg, void *handle __attribute__((unused))) { struct physical_volume *pv, *existing_pv; struct logical_volume *lv; struct lv_list *lvl; int pvmetadatacopies = 0; uint64_t pvmetadatasize = 0; uint64_t pe_start = 0; struct pv_list *pvl; int change_made = 0; struct lvinfo info; int active = 0; if (!vg_check_status(vg, LVM_WRITE | EXPORTED_VG)) { stack; return ECMD_FAILED; } if (vg->fid->fmt == cmd->fmt) { log_error("Volume group \"%s\" already uses format %s", vg_name, cmd->fmt->name); return ECMD_FAILED; } if (cmd->fmt->features & FMT_MDAS) { if (arg_sign_value(cmd, metadatasize_ARG, SIGN_NONE) == SIGN_MINUS) { log_error("Metadata size may not be negative"); return EINVALID_CMD_LINE; } pvmetadatasize = arg_uint64_value(cmd, metadatasize_ARG, UINT64_C(0)); if (!pvmetadatasize) pvmetadatasize = find_config_tree_int(cmd, "metadata/pvmetadatasize", DEFAULT_PVMETADATASIZE); pvmetadatacopies = arg_int_value(cmd, pvmetadatacopies_ARG, -1); if (pvmetadatacopies < 0) pvmetadatacopies = find_config_tree_int(cmd, "metadata/pvmetadatacopies", DEFAULT_PVMETADATACOPIES); } if (!archive(vg)) { log_error("Archive of \"%s\" metadata failed.", vg_name); return ECMD_FAILED; } /* Set PV/LV limit if converting from unlimited metadata format */ if (vg->fid->fmt->features & FMT_UNLIMITED_VOLS && !(cmd->fmt->features & FMT_UNLIMITED_VOLS)) { if (!vg->max_lv) vg->max_lv = 255; if (!vg->max_pv) vg->max_pv = 255; } /* If converting to restricted lvid, check if lvid is compatible */ if (!(vg->fid->fmt->features & FMT_RESTRICTED_LVIDS) && cmd->fmt->features & FMT_RESTRICTED_LVIDS) dm_list_iterate_items(lvl, &vg->lvs) if (!lvid_in_restricted_range(&lvl->lv->lvid)) { log_error("Logical volume %s lvid format is" " incompatible with requested" " metadata format.", lvl->lv->name); return ECMD_FAILED; } /* Attempt to change any LVIDs that are too big */ if (cmd->fmt->features & FMT_RESTRICTED_LVIDS) { dm_list_iterate_items(lvl, &vg->lvs) { lv = lvl->lv; if (lv->status & SNAPSHOT) continue; if (lvnum_from_lvid(&lv->lvid) < MAX_RESTRICTED_LVS) continue; if (lv_info(cmd, lv, 0, &info, 0, 0) && info.exists) { log_error("Logical volume %s must be " "deactivated before conversion.", lv->name); active++; continue; } lvid_from_lvnum(&lv->lvid, &lv->vg->id, find_free_lvnum(lv)); } } if (active) { stack; return ECMD_FAILED; } dm_list_iterate_items(pvl, &vg->pvs) { existing_pv = pvl->pv; pe_start = pv_pe_start(existing_pv); /* pe_end = pv_pe_count(existing_pv) * pv_pe_size(existing_pv) + pe_start - 1; */ if (!(pv = pv_create(cmd, pv_dev(existing_pv), &existing_pv->id, 0, 0, 0, pe_start, pv_pe_count(existing_pv), pv_pe_size(existing_pv), arg_int64_value(cmd, labelsector_ARG, DEFAULT_LABELSECTOR), pvmetadatacopies, pvmetadatasize, 0))) { log_error("Failed to setup physical volume \"%s\"", pv_dev_name(existing_pv)); if (change_made) log_error("Use pvcreate and vgcfgrestore to " "repair from archived metadata."); return ECMD_FAILED; } /* Need to revert manually if it fails after this point */ change_made = 1; log_verbose("Set up physical volume for \"%s\" with %" PRIu64 " available sectors", pv_dev_name(pv), pv_size(pv)); /* Wipe existing label first */ if (!label_remove(pv_dev(pv))) { log_error("Failed to wipe existing label on %s", pv_dev_name(pv)); log_error("Use pvcreate and vgcfgrestore to repair " "from archived metadata."); return ECMD_FAILED; } log_very_verbose("Writing physical volume data to disk \"%s\"", pv_dev_name(pv)); if (!(pv_write(cmd, pv, 0))) { log_error("Failed to write physical volume \"%s\"", pv_dev_name(pv)); log_error("Use pvcreate and vgcfgrestore to repair " "from archived metadata."); return ECMD_FAILED; } log_verbose("Physical volume \"%s\" successfully created", pv_dev_name(pv)); } log_verbose("Deleting existing metadata for VG %s", vg_name); if (!vg_remove_mdas(vg)) { log_error("Removal of existing metadata for %s failed.", vg_name); log_error("Use pvcreate and vgcfgrestore to repair " "from archived metadata."); return ECMD_FAILED; } /* FIXME Cache the label format change so we don't have to skip this */ if (test_mode()) { log_verbose("Test mode: Skipping metadata writing for VG %s in" " format %s", vg_name, cmd->fmt->name); return ECMD_PROCESSED; } log_verbose("Writing metadata for VG %s using format %s", vg_name, cmd->fmt->name); if (!backup_restore_vg(cmd, vg)) { log_error("Conversion failed for volume group %s.", vg_name); log_error("Use pvcreate and vgcfgrestore to repair from " "archived metadata."); return ECMD_FAILED; } log_print_unless_silent("Volume group %s successfully converted", vg_name); backup(vg); return ECMD_PROCESSED; } int vgconvert(struct cmd_context *cmd, int argc, char **argv) { if (!argc) { log_error("Please enter volume group(s)"); return EINVALID_CMD_LINE; } if (arg_int_value(cmd, labelsector_ARG, 0) >= LABEL_SCAN_SECTORS) { log_error("labelsector must be less than %lu", LABEL_SCAN_SECTORS); return EINVALID_CMD_LINE; } if (arg_count(cmd, metadatacopies_ARG)) { log_error("Invalid option --metadatacopies, " "use --pvmetadatacopies instead."); return EINVALID_CMD_LINE; } if (!(cmd->fmt->features & FMT_MDAS) && (arg_count(cmd, pvmetadatacopies_ARG) || arg_count(cmd, metadatasize_ARG))) { log_error("Metadata parameters only apply to text format"); return EINVALID_CMD_LINE; } if (arg_count(cmd, pvmetadatacopies_ARG) && arg_int_value(cmd, pvmetadatacopies_ARG, -1) > 2) { log_error("Metadatacopies may only be 0, 1 or 2"); return EINVALID_CMD_LINE; } return process_each_vg(cmd, argc, argv, READ_FOR_UPDATE, NULL, &vgconvert_single); } lvm2-2.02.98/tools/pvck.c0000640000175000017500000000236612037016273013767 0ustar blankblank/* * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. * 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 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 "tools.h" int pvck(struct cmd_context *cmd, int argc, char **argv) { int i; /* FIXME: validate cmdline options */ /* FIXME: what does the cmdline look like? */ /* * Use what's on the cmdline directly, and avoid calling into * some of the other infrastructure functions, so as to avoid * hitting some of the lvmcache behavior, scanning other devices, * etc. */ for (i = 0; i < argc; i++) { /* FIXME: warning and/or check if in use? */ log_verbose("Scanning %s", argv[i]); dm_unescape_colons_and_at_signs(argv[i], NULL, NULL); pv_analyze(cmd, argv[i], arg_uint64_value(cmd, labelsector_ARG, UINT64_C(0))); } return ECMD_PROCESSED; } lvm2-2.02.98/tools/lvchange.c0000640000175000017500000006266112037016273014617 0ustar blankblank/* * 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 "tools.h" static int lvchange_permission(struct cmd_context *cmd, struct logical_volume *lv) { uint32_t lv_access; struct lvinfo info; int r = 0; lv_access = arg_uint_value(cmd, permission_ARG, 0); if ((lv_access & LVM_WRITE) && (lv->status & LVM_WRITE)) { log_error("Logical volume \"%s\" is already writable", lv->name); return 0; } if (!(lv_access & LVM_WRITE) && !(lv->status & LVM_WRITE)) { log_error("Logical volume \"%s\" is already read only", lv->name); return 0; } if ((lv->status & MIRRORED) && (vg_is_clustered(lv->vg)) && lv_info(cmd, lv, 0, &info, 0, 0) && info.exists) { log_error("Cannot change permissions of mirror \"%s\" " "while active.", lv->name); return 0; } /* Not allowed to change permissions on RAID sub-LVs directly */ if ((lv->status & RAID_META) || (lv->status & RAID_IMAGE)) { log_error("Cannot change permissions of RAID %s \"%s\"", (lv->status & RAID_IMAGE) ? "image" : "metadata area", lv->name); return 0; } if (!(lv_access & LVM_WRITE) && lv_is_thin_pool(lv)) { log_error("Change permissions of thin pool \"%s\" not " "yes supported.", lv->name); return 0; } if (lv_access & LVM_WRITE) { lv->status |= LVM_WRITE; log_verbose("Setting logical volume \"%s\" read/write", lv->name); } else { lv->status &= ~LVM_WRITE; log_verbose("Setting logical volume \"%s\" read-only", lv->name); } log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name); if (!vg_write(lv->vg)) return_0; if (!suspend_lv(cmd, lv)) { log_error("Failed to lock %s", lv->name); vg_revert(lv->vg); goto out; } if (!vg_commit(lv->vg)) { if (!resume_lv(cmd, lv)) stack; goto_out; } log_very_verbose("Updating permissions for \"%s\" in kernel", lv->name); if (!resume_lv(cmd, lv)) { log_error("Problem reactivating %s", lv->name); goto out; } r = 1; out: backup(lv->vg); return r; } static int lvchange_pool_update(struct cmd_context *cmd, struct logical_volume *lv) { int r = 0; int update = 0; unsigned val; thin_discards_t discards; if (!lv_is_thin_pool(lv)) { log_error("Logical volume \"%s\" is not a thin pool.", lv->name); return 0; } if (arg_count(cmd, discards_ARG)) { discards = (thin_discards_t) arg_uint_value(cmd, discards_ARG, THIN_DISCARDS_IGNORE); if (discards != first_seg(lv)->discards) { if ((discards != THIN_DISCARDS_IGNORE) && (first_seg(lv)->chunk_size & (first_seg(lv)->chunk_size - 1))) log_error("Cannot change discards state for " "logical volume \"%s\" " "with non power of 2 chunk size.", lv->name); else if (((discards == THIN_DISCARDS_IGNORE) || (first_seg(lv)->discards == THIN_DISCARDS_IGNORE)) && lv_is_active(lv)) log_error("Cannot change discards state for active " "logical volume \"%s\".", lv->name); else { first_seg(lv)->discards = discards; update++; } } else log_error("Logical volume \"%s\" already uses --discards %s.", lv->name, get_pool_discards_name(discards)); } if (arg_count(cmd, zero_ARG)) { val = arg_uint_value(cmd, zero_ARG, 1); if (val != first_seg(lv)->zero_new_blocks) { first_seg(lv)->zero_new_blocks = val; update++; } else log_error("Logical volume \"%s\" already %szero new blocks.", lv->name, val ? "" : "does not "); } if (!update) return 0; log_very_verbose("Updating logical volume \"%s\" on disk(s).", lv->name); if (!vg_write(lv->vg)) return_0; if (!suspend_lv_origin(cmd, lv)) { log_error("Failed to update active %s/%s (deactivation is needed).", lv->vg->name, lv->name); vg_revert(lv->vg); goto out; } if (!vg_commit(lv->vg)) { if (!resume_lv_origin(cmd, lv)) stack; goto_out; } if (!resume_lv_origin(cmd, lv)) { log_error("Problem reactivating %s.", lv->name); goto out; } r = 1; out: backup(lv->vg); return r; } static int lvchange_monitoring(struct cmd_context *cmd, struct logical_volume *lv) { struct lvinfo info; if (!lv_info(cmd, lv, lv_is_thin_pool(lv) ? 1 : 0, &info, 0, 0) || !info.exists) { log_error("Logical volume, %s, is not active", lv->name); return 0; } /* do not monitor pvmove lv's */ if (lv->status & PVMOVE) return 1; if ((dmeventd_monitor_mode() != DMEVENTD_MONITOR_IGNORE) && !monitor_dev_for_events(cmd, lv, 0, dmeventd_monitor_mode())) return_0; return 1; } static int lvchange_background_polling(struct cmd_context *cmd, struct logical_volume *lv) { struct lvinfo info; if (!lv_info(cmd, lv, 0, &info, 0, 0) || !info.exists) { log_error("Logical volume, %s, is not active", lv->name); return 0; } if (background_polling()) lv_spawn_background_polling(cmd, lv); return 1; } static int _lvchange_activate(struct cmd_context *cmd, struct logical_volume *lv) { int activate; activate = arg_uint_value(cmd, activate_ARG, 0); if (lv_is_cow(lv) && !lv_is_virtual_origin(origin_from_cow(lv))) lv = origin_from_cow(lv); if (activate == CHANGE_AAY) { if (!lv_passes_auto_activation_filter(cmd, lv)) return 1; activate = CHANGE_ALY; } if (activate == CHANGE_ALN) { log_verbose("Deactivating logical volume \"%s\" locally", lv->name); if (!deactivate_lv_local(cmd, lv)) return_0; } else if (activate == CHANGE_AN) { log_verbose("Deactivating logical volume \"%s\"", lv->name); if (!deactivate_lv(cmd, lv)) return_0; } else { if ((activate == CHANGE_AE) || lv_is_origin(lv) || lv_is_thin_type(lv)) { log_verbose("Activating logical volume \"%s\" " "exclusively", lv->name); if (!activate_lv_excl(cmd, lv)) return_0; } else if (activate == CHANGE_ALY) { log_verbose("Activating logical volume \"%s\" locally", lv->name); if (!activate_lv_local(cmd, lv)) return_0; } else { log_verbose("Activating logical volume \"%s\"", lv->name); if (!activate_lv(cmd, lv)) return_0; } if (background_polling()) lv_spawn_background_polling(cmd, lv); } return 1; } static int lvchange_refresh(struct cmd_context *cmd, struct logical_volume *lv) { log_verbose("Refreshing logical volume \"%s\" (if active)", lv->name); return lv_refresh(cmd, lv); } static int detach_metadata_devices(struct lv_segment *seg, struct dm_list *list) { uint32_t s; uint32_t num_meta_lvs; struct cmd_context *cmd = seg->lv->vg->cmd; struct lv_list *lvl; num_meta_lvs = seg_is_raid(seg) ? seg->area_count : !!seg->log_lv; if (!num_meta_lvs) return_0; if (!(lvl = dm_pool_alloc(cmd->mem, sizeof(*lvl) * num_meta_lvs))) return_0; if (seg_is_raid(seg)) { for (s = 0; s < seg->area_count; s++) { if (!seg_metalv(seg, s)) return_0; /* Trap this future possibility */ lvl[s].lv = seg_metalv(seg, s); lv_set_visible(lvl[s].lv); dm_list_add(list, &lvl[s].list); } return 1; } lvl[0].lv = detach_mirror_log(seg); dm_list_add(list, &lvl[0].list); return 1; } static int attach_metadata_devices(struct lv_segment *seg, struct dm_list *list) { struct cmd_context *cmd = seg->lv->vg->cmd; struct lv_list *lvl, *tmp; if (seg_is_raid(seg)) { dm_list_iterate_items_safe(lvl, tmp, list) { lv_set_hidden(lvl->lv); dm_pool_free(cmd->mem, lvl); } return 1; } dm_list_iterate_items(lvl, list) break; /* get first item */ if (!attach_mirror_log(seg, lvl->lv)) { dm_pool_free(cmd->mem, lvl); return_0; } dm_pool_free(cmd->mem, lvl); return 1; } static int lvchange_resync(struct cmd_context *cmd, struct logical_volume *lv) { int active = 0; int monitored; struct lvinfo info; struct lv_segment *seg = first_seg(lv); struct dm_list device_list; struct lv_list *lvl; dm_list_init(&device_list); if (!(lv->status & MIRRORED) && !seg_is_raid(seg)) { log_error("Unable to resync %s. It is not RAID or mirrored.", lv->name); return 0; } if (lv->status & PVMOVE) { log_error("Unable to resync pvmove volume %s", lv->name); return 0; } if (lv->status & LOCKED) { log_error("Unable to resync locked volume %s", lv->name); return 0; } if (lv_info(cmd, lv, 0, &info, 1, 0)) { if (info.open_count) { log_error("Can't resync open logical volume \"%s\"", lv->name); return 0; } if (info.exists) { if (!arg_count(cmd, yes_ARG) && yes_no_prompt("Do you really want to deactivate " "logical volume %s to resync it? [y/n]: ", lv->name) == 'n') { log_error("Logical volume \"%s\" not resynced", lv->name); return 0; } if (sigint_caught()) return 0; active = 1; } } /* Activate exclusively to ensure no nodes still have LV active */ monitored = dmeventd_monitor_mode(); if (monitored != DMEVENTD_MONITOR_IGNORE) init_dmeventd_monitor(0); if (!deactivate_lv(cmd, lv)) { log_error("Unable to deactivate %s for resync", lv->name); return 0; } if (vg_is_clustered(lv->vg) && lv_is_active(lv)) { log_error("Can't get exclusive access to clustered volume %s", lv->name); return 0; } if (monitored != DMEVENTD_MONITOR_IGNORE) init_dmeventd_monitor(monitored); init_mirror_in_sync(0); log_very_verbose("Starting resync of %s%s%s%s \"%s\"", (active) ? "active " : "", vg_is_clustered(lv->vg) ? "clustered " : "", (seg->log_lv) ? "disk-logged " : seg_is_raid(seg) ? "" : "core-logged ", seg->segtype->ops->name(seg), lv->name); /* * If this mirror has a core log (i.e. !seg->log_lv), * then simply deactivating/activating will cause * it to reset the sync status. We only need to * worry about persistent logs. */ if (!seg_is_raid(seg) && !seg->log_lv) { if (lv->status & LV_NOTSYNCED) { lv->status &= ~LV_NOTSYNCED; log_very_verbose("Updating logical volume \"%s\"" " on disk(s)", lv->name); if (!vg_write(lv->vg) || !vg_commit(lv->vg)) { log_error("Failed to update metadata on disk."); return 0; } } if (active && !activate_lv(cmd, lv)) { log_error("Failed to reactivate %s to resynchronize " "mirror", lv->name); return 0; } return 1; } /* * Now we handle mirrors with log devices */ lv->status &= ~LV_NOTSYNCED; /* Separate mirror log or metadata devices so we can clear them */ if (!detach_metadata_devices(seg, &device_list)) { log_error("Failed to clear %s %s for %s", seg->segtype->name, seg_is_raid(seg) ? "metadata area" : "mirror log", lv->name); return 0; } if (!vg_write(lv->vg)) { log_error("Failed to write intermediate VG metadata."); if (!attach_metadata_devices(seg, &device_list)) stack; if (active && !activate_lv(cmd, lv)) stack; return 0; } if (!vg_commit(lv->vg)) { log_error("Failed to commit intermediate VG metadata."); if (!attach_metadata_devices(seg, &device_list)) stack; if (active && !activate_lv(cmd, lv)) stack; return 0; } backup(lv->vg); dm_list_iterate_items(lvl, &device_list) { if (!activate_lv(cmd, lvl->lv)) { log_error("Unable to activate %s for mirror log resync", lvl->lv->name); return 0; } log_very_verbose("Clearing %s device %s", (seg_is_raid(seg)) ? "metadata" : "log", lvl->lv->name); if (!set_lv(cmd, lvl->lv, lvl->lv->size, 0)) { log_error("Unable to reset sync status for %s", lv->name); if (!deactivate_lv(cmd, lvl->lv)) log_error("Failed to deactivate log LV after " "wiping failed"); return 0; } if (!deactivate_lv(cmd, lvl->lv)) { log_error("Unable to deactivate %s LV %s " "after wiping for resync", (seg_is_raid(seg)) ? "metadata" : "log", lvl->lv->name); return 0; } } /* Put metadata sub-LVs back in place */ if (!attach_metadata_devices(seg, &device_list)) { log_error("Failed to reattach %s device after clearing", (seg_is_raid(seg)) ? "metadata" : "log"); return 0; } log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name); if (!vg_write(lv->vg) || !vg_commit(lv->vg)) { log_error("Failed to update metadata on disk."); return 0; } if (active && !activate_lv(cmd, lv)) { log_error("Failed to reactivate %s after resync", lv->name); return 0; } return 1; } static int lvchange_alloc(struct cmd_context *cmd, struct logical_volume *lv) { int want_contiguous = 0; alloc_policy_t alloc; want_contiguous = strcmp(arg_str_value(cmd, contiguous_ARG, "n"), "n"); alloc = want_contiguous ? ALLOC_CONTIGUOUS : ALLOC_INHERIT; alloc = (alloc_policy_t) arg_uint_value(cmd, alloc_ARG, alloc); if (alloc == lv->alloc) { log_error("Allocation policy of logical volume \"%s\" is " "already %s", lv->name, get_alloc_string(alloc)); return 0; } lv->alloc = alloc; /* FIXME If contiguous, check existing extents already are */ log_verbose("Setting contiguous allocation policy for \"%s\" to %s", lv->name, get_alloc_string(alloc)); log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name); /* No need to suspend LV for this change */ if (!vg_write(lv->vg) || !vg_commit(lv->vg)) return_0; backup(lv->vg); return 1; } static int lvchange_readahead(struct cmd_context *cmd, struct logical_volume *lv) { unsigned read_ahead = 0; unsigned pagesize = (unsigned) lvm_getpagesize() >> SECTOR_SHIFT; int r = 0; read_ahead = arg_uint_value(cmd, readahead_ARG, 0); if (read_ahead != DM_READ_AHEAD_AUTO && (lv->vg->fid->fmt->features & FMT_RESTRICTED_READAHEAD) && (read_ahead < 2 || read_ahead > 120)) { log_error("Metadata only supports readahead values between 2 and 120."); return 0; } if (read_ahead != DM_READ_AHEAD_AUTO && read_ahead != DM_READ_AHEAD_NONE && read_ahead % pagesize) { if (read_ahead < pagesize) read_ahead = pagesize; else read_ahead = (read_ahead / pagesize) * pagesize; log_warn("WARNING: Overriding readahead to %u sectors, a multiple " "of %uK page size.", read_ahead, pagesize >> 1); } if (lv->read_ahead == read_ahead) { if (read_ahead == DM_READ_AHEAD_AUTO) log_error("Read ahead is already auto for \"%s\"", lv->name); else log_error("Read ahead is already %u for \"%s\"", read_ahead, lv->name); return 0; } lv->read_ahead = read_ahead; log_verbose("Setting read ahead to %u for \"%s\"", read_ahead, lv->name); log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name); if (!vg_write(lv->vg)) return_0; if (!suspend_lv(cmd, lv)) { log_error("Failed to lock %s", lv->name); vg_revert(lv->vg); goto out; } if (!vg_commit(lv->vg)) { if (!resume_lv(cmd, lv)) stack; goto_out; } log_very_verbose("Updating permissions for \"%s\" in kernel", lv->name); if (!resume_lv(cmd, lv)) { log_error("Problem reactivating %s", lv->name); goto out; } r = 1; out: backup(lv->vg); return r; } static int lvchange_persistent(struct cmd_context *cmd, struct logical_volume *lv) { struct lvinfo info; int active = 0; int32_t major, minor; if (!strcmp(arg_str_value(cmd, persistent_ARG, "n"), "n")) { if (!(lv->status & FIXED_MINOR)) { log_error("Minor number is already not persistent " "for \"%s\"", lv->name); return 0; } lv->status &= ~FIXED_MINOR; lv->minor = -1; lv->major = -1; log_verbose("Disabling persistent device number for \"%s\"", lv->name); } else { if (!arg_count(cmd, minor_ARG) && lv->minor < 0) { log_error("Minor number must be specified with -My"); return 0; } if (arg_count(cmd, major_ARG) > 1) { log_error("Option -j/--major may not be repeated."); return 0; } if (arg_count(cmd, minor_ARG) > 1) { log_error("Option --minor may not be repeated."); return 0; } if (!arg_count(cmd, major_ARG) && lv->major < 0) { log_error("Major number must be specified with -My"); return 0; } if (lv_info(cmd, lv, 0, &info, 0, 0) && info.exists) active = 1; major = arg_int_value(cmd, major_ARG, lv->major); minor = arg_int_value(cmd, minor_ARG, lv->minor); if (!major_minor_valid(cmd, lv->vg->fid->fmt, major, minor)) return 0; if (active && !arg_count(cmd, force_ARG) && yes_no_prompt("Logical volume %s will be " "deactivated temporarily. " "Continue? [y/n]: ", lv->name) == 'n') { log_error("%s device number not changed.", lv->name); return 0; } if (sigint_caught()) return 0; log_verbose("Ensuring %s is inactive.", lv->name); if (!deactivate_lv(cmd, lv)) { log_error("%s: deactivation failed", lv->name); return 0; } lv->status |= FIXED_MINOR; lv->minor = minor; lv->major = major; log_verbose("Setting persistent device number to (%d, %d) " "for \"%s\"", lv->major, lv->minor, lv->name); } log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name); if (!vg_write(lv->vg) || !vg_commit(lv->vg)) return_0; backup(lv->vg); if (active) { log_verbose("Re-activating logical volume \"%s\"", lv->name); if (!activate_lv(cmd, lv)) { log_error("%s: reactivation failed", lv->name); return 0; } } return 1; } static int lvchange_tag(struct cmd_context *cmd, struct logical_volume *lv, int arg) { if (!change_tag(cmd, NULL, lv, NULL, arg)) return_0; log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name); /* No need to suspend LV for this change */ if (!vg_write(lv->vg) || !vg_commit(lv->vg)) return_0; backup(lv->vg); return 1; } static int lvchange_single(struct cmd_context *cmd, struct logical_volume *lv, void *handle __attribute__((unused))) { int doit = 0, docmds = 0; int archived = 0; struct logical_volume *origin; char snaps_msg[128]; if (!(lv->vg->status & LVM_WRITE) && (arg_count(cmd, contiguous_ARG) || arg_count(cmd, permission_ARG) || arg_count(cmd, readahead_ARG) || arg_count(cmd, persistent_ARG) || arg_count(cmd, discards_ARG) || arg_count(cmd, zero_ARG) || arg_count(cmd, alloc_ARG))) { log_error("Only -a permitted with read-only volume " "group \"%s\"", lv->vg->name); return EINVALID_CMD_LINE; } if (lv_is_origin(lv) && !lv_is_thin_volume(lv) && (arg_count(cmd, contiguous_ARG) || arg_count(cmd, permission_ARG) || arg_count(cmd, readahead_ARG) || arg_count(cmd, persistent_ARG) || arg_count(cmd, alloc_ARG))) { log_error("Can't change logical volume \"%s\" under snapshot", lv->name); return ECMD_FAILED; } if (lv_is_cow(lv) && !lv_is_virtual_origin(origin = origin_from_cow(lv)) && arg_count(cmd, activate_ARG)) { if (origin->origin_count < 2) snaps_msg[0] = '\0'; else if (dm_snprintf(snaps_msg, sizeof(snaps_msg), " and %u other snapshot(s)", origin->origin_count - 1) < 0) { log_error("Failed to prepare message."); return ECMD_FAILED; } if (!arg_count(cmd, yes_ARG) && (yes_no_prompt("Change of snapshot %s will also change its" " origin %s%s. Proceed? [y/n]: ", lv->name, origin->name, snaps_msg) == 'n')) { log_error("Logical volume %s not changed.", lv->name); return ECMD_FAILED; } } if (lv->status & PVMOVE) { log_error("Unable to change pvmove LV %s", lv->name); if (arg_count(cmd, activate_ARG)) log_error("Use 'pvmove --abort' to abandon a pvmove"); return ECMD_FAILED; } if (lv->status & MIRROR_LOG) { log_error("Unable to change mirror log LV %s directly", lv->name); return ECMD_FAILED; } if (lv->status & MIRROR_IMAGE) { log_error("Unable to change mirror image LV %s directly", lv->name); return ECMD_FAILED; } /* If LV is sparse, activate origin instead */ if (arg_count(cmd, activate_ARG) && lv_is_cow(lv) && lv_is_virtual_origin(origin = origin_from_cow(lv))) lv = origin; if (!(lv_is_visible(lv)) && !lv_is_virtual_origin(lv)) { log_error("Unable to change internal LV %s directly", lv->name); return ECMD_FAILED; } /* * FIXME: DEFAULT_BACKGROUND_POLLING should be "unspecified". * If --poll is explicitly provided use it; otherwise polling * should only be started if the LV is not already active. So: * 1) change the activation code to say if the LV was actually activated * 2) make polling of an LV tightly coupled with LV activation * * Do not initiate any polling if --sysinit option is used. */ init_background_polling(arg_count(cmd, sysinit_ARG) ? 0 : arg_int_value(cmd, poll_ARG, DEFAULT_BACKGROUND_POLLING)); /* access permission change */ if (arg_count(cmd, permission_ARG)) { if (!archive(lv->vg)) { stack; return ECMD_FAILED; } archived = 1; doit += lvchange_permission(cmd, lv); docmds++; } /* allocation policy change */ if (arg_count(cmd, contiguous_ARG) || arg_count(cmd, alloc_ARG)) { if (!archived && !archive(lv->vg)) { stack; return ECMD_FAILED; } archived = 1; doit += lvchange_alloc(cmd, lv); docmds++; } /* read ahead sector change */ if (arg_count(cmd, readahead_ARG)) { if (!archived && !archive(lv->vg)) { stack; return ECMD_FAILED; } archived = 1; doit += lvchange_readahead(cmd, lv); docmds++; } /* persistent device number change */ if (arg_count(cmd, persistent_ARG)) { if (!archived && !archive(lv->vg)) { stack; return ECMD_FAILED; } archived = 1; doit += lvchange_persistent(cmd, lv); docmds++; if (sigint_caught()) { stack; return ECMD_FAILED; } } if (arg_count(cmd, discards_ARG) || arg_count(cmd, zero_ARG)) { if (!archived && !archive(lv->vg)) { stack; return ECMD_FAILED; } archived = 1; doit += lvchange_pool_update(cmd, lv); docmds++; } /* add tag */ if (arg_count(cmd, addtag_ARG)) { if (!archived && !archive(lv->vg)) { stack; return ECMD_FAILED; } archived = 1; doit += lvchange_tag(cmd, lv, addtag_ARG); docmds++; } /* del tag */ if (arg_count(cmd, deltag_ARG)) { if (!archived && !archive(lv->vg)) { stack; return ECMD_FAILED; } archived = 1; doit += lvchange_tag(cmd, lv, deltag_ARG); docmds++; } if (doit) log_print_unless_silent("Logical volume \"%s\" changed", lv->name); if (arg_count(cmd, resync_ARG)) if (!lvchange_resync(cmd, lv)) { stack; return ECMD_FAILED; } /* activation change */ if (arg_count(cmd, activate_ARG)) { if (!_lvchange_activate(cmd, lv)) { stack; return ECMD_FAILED; } } if (arg_count(cmd, refresh_ARG)) if (!lvchange_refresh(cmd, lv)) { stack; return ECMD_FAILED; } if (!arg_count(cmd, activate_ARG) && !arg_count(cmd, refresh_ARG) && arg_count(cmd, monitor_ARG)) { if (!lvchange_monitoring(cmd, lv)) { stack; return ECMD_FAILED; } } if (!arg_count(cmd, activate_ARG) && !arg_count(cmd, refresh_ARG) && arg_count(cmd, poll_ARG)) { if (!lvchange_background_polling(cmd, lv)) { stack; return ECMD_FAILED; } } if (doit != docmds) { stack; return ECMD_FAILED; } return ECMD_PROCESSED; } int lvchange(struct cmd_context *cmd, int argc, char **argv) { /* * Options that update metadata should be listed in one of * the two lists below (i.e. options other than -a, --refresh, * --monitor or --poll). */ int update_partial_safe = /* options safe to update if partial */ arg_count(cmd, contiguous_ARG) || arg_count(cmd, permission_ARG) || arg_count(cmd, readahead_ARG) || arg_count(cmd, persistent_ARG) || arg_count(cmd, addtag_ARG) || arg_count(cmd, deltag_ARG); int update_partial_unsafe = arg_count(cmd, resync_ARG) || arg_count(cmd, alloc_ARG) || arg_count(cmd, discards_ARG) || arg_count(cmd, zero_ARG); int update = update_partial_safe || update_partial_unsafe; if (!update && !arg_count(cmd, activate_ARG) && !arg_count(cmd, refresh_ARG) && !arg_count(cmd, monitor_ARG) && !arg_count(cmd, poll_ARG)) { log_error("Need 1 or more of -a, -C, -M, -p, -r, -Z, " "--resync, --refresh, --alloc, --addtag, --deltag, " "--monitor, --poll or --discards"); return EINVALID_CMD_LINE; } if (arg_count(cmd, activate_ARG) && arg_count(cmd, refresh_ARG)) { log_error("Only one of -a and --refresh permitted."); return EINVALID_CMD_LINE; } if ((arg_count(cmd, ignorelockingfailure_ARG) || arg_count(cmd, sysinit_ARG)) && update) { log_error("Only -a permitted with --ignorelockingfailure and --sysinit"); return EINVALID_CMD_LINE; } if (!update || !update_partial_unsafe) cmd->handles_missing_pvs = 1; if (!argc) { log_error("Please give logical volume path(s)"); return EINVALID_CMD_LINE; } if ((arg_count(cmd, minor_ARG) || arg_count(cmd, major_ARG)) && !arg_count(cmd, persistent_ARG)) { log_error("--major and --minor require -My"); return EINVALID_CMD_LINE; } if (arg_count(cmd, minor_ARG) && argc != 1) { log_error("Only give one logical volume when specifying minor"); return EINVALID_CMD_LINE; } if (arg_count(cmd, contiguous_ARG) && arg_count(cmd, alloc_ARG)) { log_error("Only one of --alloc and --contiguous permitted"); return EINVALID_CMD_LINE; } if (arg_count(cmd, poll_ARG) && arg_count(cmd, sysinit_ARG)) { log_error("Only one of --poll and --sysinit permitted"); return EINVALID_CMD_LINE; } if (arg_count(cmd, sysinit_ARG) && lvmetad_active() && arg_uint_value(cmd, activate_ARG, 0) == CHANGE_AAY) { log_warn("lvmetad is active while using --sysinit -a ay, " "skipping manual activation"); return ECMD_PROCESSED; } return process_each_lv(cmd, argc, argv, update ? READ_FOR_UPDATE : 0, NULL, &lvchange_single); } lvm2-2.02.98/tools/lvmcmdlib.c0000640000175000017500000000472412037016273014775 0ustar blankblank/* * 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 */ #include "tools.h" #include "lvm2cmdline.h" #include "label.h" #include "memlock.h" #include "lvm2cmd.h" #include #include #include #include void *cmdlib_lvm2_init(unsigned static_compile) { struct cmd_context *cmd; lvm_register_commands(); init_is_static(static_compile); if (!(cmd = init_lvm())) return NULL; return (void *) cmd; } int lvm2_run(void *handle, const char *cmdline) { int argc, ret, oneoff = 0; char *args[MAX_ARGS], **argv, *cmdcopy = NULL; struct cmd_context *cmd; argv = args; if (!handle) { oneoff = 1; if (!(handle = lvm2_init())) { log_error("Handle initialisation failed."); return ECMD_FAILED; } } cmd = (struct cmd_context *) handle; cmd->argv = argv; if (!(cmdcopy = dm_strdup(cmdline))) { log_error("Cmdline copy failed."); ret = ECMD_FAILED; goto out; } if (lvm_split(cmdcopy, &argc, argv, MAX_ARGS) == MAX_ARGS) { log_error("Too many arguments. Limit is %d.", MAX_ARGS); ret = EINVALID_CMD_LINE; goto out; } if (!argc) { log_error("No command supplied"); ret = EINVALID_CMD_LINE; goto out; } /* FIXME Temporary - move to libdevmapper */ ret = ECMD_PROCESSED; if (!strcmp(cmdline, "_memlock_inc")) memlock_inc_daemon(cmd); else if (!strcmp(cmdline, "_memlock_dec")) memlock_dec_daemon(cmd); else ret = lvm_run_command(cmd, argc, argv); out: dm_free(cmdcopy); if (oneoff) lvm2_exit(handle); return ret; } void lvm2_disable_dmeventd_monitoring(void *handle) { init_dmeventd_monitor(DMEVENTD_MONITOR_IGNORE); } void lvm2_log_level(void *handle, int level) { struct cmd_context *cmd = (struct cmd_context *) handle; cmd->default_settings.verbose = level - VERBOSE_BASE_LEVEL; } void lvm2_log_fn(lvm2_log_fn_t log_fn) { init_log_fn(log_fn); } void lvm2_exit(void *handle) { struct cmd_context *cmd = (struct cmd_context *) handle; lvm_fin(cmd); } lvm2-2.02.98/tools/lvmdiskscan.c0000640000175000017500000000727312037016273015344 0ustar blankblank/* * 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 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 */ /* * Changelog * * 05/02/2002 - First drop [HM] */ #include "tools.h" int disks_found; int parts_found; int pv_disks_found; int pv_parts_found; int max_len; static int _get_max_dev_name_len(struct dev_filter *filter) { int len = 0; int maxlen = 0; struct dev_iter *iter; struct device *dev; if (!(iter = dev_iter_create(filter, 1))) { log_error("dev_iter_create failed"); return 0; } /* Do scan */ for (dev = dev_iter_get(iter); dev; dev = dev_iter_get(iter)) { len = strlen(dev_name(dev)); if (len > maxlen) maxlen = len; } dev_iter_destroy(iter); return maxlen; } static void _count(struct device *dev, int *disks, int *parts) { int c = dev_name(dev)[strlen(dev_name(dev)) - 1]; if (!isdigit(c)) (*disks)++; else (*parts)++; } static void _print(struct cmd_context *cmd, const struct device *dev, uint64_t size, const char *what) { log_print("%-*s [%15s] %s", max_len, dev_name(dev), display_size(cmd, size), what ? : ""); } static int _check_device(struct cmd_context *cmd, struct device *dev) { char buffer; uint64_t size; if (!dev_open_readonly(dev)) return_0; if (!dev_read(dev, UINT64_C(0), (size_t) 1, &buffer)) { stack; if (!dev_close(dev)) stack; return 0; } if (!dev_get_size(dev, &size)) { log_error("Couldn't get size of \"%s\"", dev_name(dev)); size = 0; } _print(cmd, dev, size, NULL); _count(dev, &disks_found, &parts_found); if (!dev_close(dev)) { log_error("dev_close on \"%s\" failed", dev_name(dev)); return 0; } return 1; } int lvmdiskscan(struct cmd_context *cmd, int argc __attribute__((unused)), char **argv __attribute__((unused))) { uint64_t size; struct dev_iter *iter; struct device *dev; struct label *label; /* initialise these here to avoid problems with the lvm shell */ disks_found = 0; parts_found = 0; pv_disks_found = 0; pv_parts_found = 0; if (arg_count(cmd, lvmpartition_ARG)) log_warn("WARNING: only considering LVM devices"); max_len = _get_max_dev_name_len(cmd->filter); if (!(iter = dev_iter_create(cmd->filter, 0))) { log_error("dev_iter_create failed"); return ECMD_FAILED; } /* Do scan */ for (dev = dev_iter_get(iter); dev; dev = dev_iter_get(iter)) { /* Try if it is a PV first */ if ((label_read(dev, &label, UINT64_C(0)))) { if (!dev_get_size(dev, &size)) { log_error("Couldn't get size of \"%s\"", dev_name(dev)); continue; } _print(cmd, dev, size, "LVM physical volume"); _count(dev, &pv_disks_found, &pv_parts_found); continue; } /* If user just wants PVs we are done */ if (arg_count(cmd, lvmpartition_ARG)) continue; /* What other device is it? */ if (!_check_device(cmd, dev)) continue; } dev_iter_destroy(iter); /* Display totals */ if (!arg_count(cmd, lvmpartition_ARG)) { log_print("%d disk%s", disks_found, disks_found == 1 ? "" : "s"); log_print("%d partition%s", parts_found, parts_found == 1 ? "" : "s"); } log_print("%d LVM physical volume whole disk%s", pv_disks_found, pv_disks_found == 1 ? "" : "s"); log_print("%d LVM physical volume%s", pv_parts_found, pv_parts_found == 1 ? "" : "s"); return ECMD_PROCESSED; } lvm2-2.02.98/tools/lvdisplay.c0000640000175000017500000000337712037016273015036 0ustar blankblank/* * Copyright (C) 2001-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 */ #include "tools.h" static int _lvdisplay_single(struct cmd_context *cmd, struct logical_volume *lv, void *handle) { if (!arg_count(cmd, all_ARG) && !lv_is_visible(lv)) return ECMD_PROCESSED; if (arg_count(cmd, colon_ARG)) lvdisplay_colons(lv); else { lvdisplay_full(cmd, lv, handle); if (arg_count(cmd, maps_ARG)) lvdisplay_segments(lv); } return ECMD_PROCESSED; } int lvdisplay(struct cmd_context *cmd, int argc, char **argv) { if (arg_count(cmd, columns_ARG)) { if (arg_count(cmd, colon_ARG) || arg_count(cmd, maps_ARG)) { log_error("Incompatible options selected"); return EINVALID_CMD_LINE; } return lvs(cmd, argc, argv); } else if (arg_count(cmd, aligned_ARG) || arg_count(cmd, noheadings_ARG) || arg_count(cmd, options_ARG) || arg_count(cmd, separator_ARG) || arg_count(cmd, sort_ARG) || arg_count(cmd, unbuffered_ARG)) { log_error("Incompatible options selected"); return EINVALID_CMD_LINE; } if (arg_count(cmd, colon_ARG) && arg_count(cmd, verbose_ARG)) { log_error("Options -v and -c are incompatible"); return EINVALID_CMD_LINE; } return process_each_lv(cmd, argc, argv, 0, NULL, &_lvdisplay_single); } lvm2-2.02.98/tools/toollib.h0000640000175000017500000001047012037016273014470 0ustar blankblank/* * 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_TOOLLIB_H #define _LVM_TOOLLIB_H #include "metadata-exported.h" int autobackup_set(void); int autobackup_init(const char *backup_dir, int keep_days, int keep_number, int autobackup); int autobackup(struct volume_group *vg); struct volume_group *recover_vg(struct cmd_context *cmd, const char *vgname, uint32_t lock_type); typedef int (*process_single_vg_fn_t) (struct cmd_context * cmd, const char *vg_name, struct volume_group * vg, void *handle); typedef int (*process_single_pv_fn_t) (struct cmd_context *cmd, struct volume_group *vg, struct physical_volume *pv, void *handle); typedef int (*process_single_lv_fn_t) (struct cmd_context *cmd, struct logical_volume *lv, void *handle); typedef int (*process_single_seg_fn_t) (struct cmd_context * cmd, struct lv_segment * seg, void *handle); typedef int (*process_single_pvseg_fn_t) (struct cmd_context * cmd, struct volume_group * vg, struct pv_segment * pvseg, void *handle); int process_each_vg(struct cmd_context *cmd, int argc, char **argv, uint32_t flags, void *handle, process_single_vg_fn_t process_single_vg); int process_each_pv(struct cmd_context *cmd, int argc, char **argv, struct volume_group *vg, uint32_t lock_type, int scan_label_only, void *handle, process_single_pv_fn_t process_single_pv); int process_each_segment_in_pv(struct cmd_context *cmd, struct volume_group *vg, struct physical_volume *pv, void *handle, process_single_pvseg_fn_t process_single_pvseg); int process_each_lv(struct cmd_context *cmd, int argc, char **argv, uint32_t flags, void *handle, process_single_lv_fn_t process_single_lv); int process_each_segment_in_lv(struct cmd_context *cmd, struct logical_volume *lv, void *handle, process_single_seg_fn_t process_single_seg); int process_each_pv_in_vg(struct cmd_context *cmd, struct volume_group *vg, const struct dm_list *tags, void *handle, process_single_pv_fn_t process_single_pv); int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg, const struct dm_list *arg_lvnames, const struct dm_list *tags, struct dm_list *failed_lvnames, void *handle, process_single_lv_fn_t process_single_lv); char *default_vgname(struct cmd_context *cmd); const char *extract_vgname(struct cmd_context *cmd, const char *lv_name); const char *skip_dev_dir(struct cmd_context *cmd, const char *vg_name, unsigned *dev_dir_found); /* * Builds a list of pv's from the names in argv. Used in * lvcreate/extend. */ struct dm_list *create_pv_list(struct dm_pool *mem, struct volume_group *vg, int argc, char **argv, int allocatable_only); struct dm_list *clone_pv_list(struct dm_pool *mem, struct dm_list *pvs); void vgcreate_params_set_defaults(struct vgcreate_params *vp_def, struct volume_group *vg); int vgcreate_params_set_from_args(struct cmd_context *cmd, struct vgcreate_params *vp_new, struct vgcreate_params *vp_def); int lv_refresh(struct cmd_context *cmd, struct logical_volume *lv); int vg_refresh_visible(struct cmd_context *cmd, struct volume_group *vg); void lv_spawn_background_polling(struct cmd_context *cmd, struct logical_volume *lv); int pvcreate_params_validate(struct cmd_context *cmd, int argc, char **argv, struct pvcreate_params *pp); int get_activation_monitoring_mode(struct cmd_context *cmd, int *monitoring_mode); int get_stripe_params(struct cmd_context *cmd, uint32_t *stripes, uint32_t *stripe_size); int change_tag(struct cmd_context *cmd, struct volume_group *vg, struct logical_volume *lv, struct physical_volume *pv, int arg); #endif lvm2-2.02.98/tools/vgexport.c0000640000175000017500000000331112037016273014671 0ustar blankblank/* * 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 "tools.h" static int vgexport_single(struct cmd_context *cmd __attribute__((unused)), const char *vg_name, struct volume_group *vg, void *handle __attribute__((unused))) { struct pv_list *pvl; struct physical_volume *pv; if (lvs_in_vg_activated(vg)) { log_error("Volume group \"%s\" has active logical volumes", vg_name); goto bad; } if (!archive(vg)) goto_bad; vg->status |= EXPORTED_VG; dm_list_iterate_items(pvl, &vg->pvs) { pv = pvl->pv; pv->status |= EXPORTED_VG; } if (!vg_write(vg) || !vg_commit(vg)) goto_bad; backup(vg); log_print_unless_silent("Volume group \"%s\" successfully exported", vg->name); return ECMD_PROCESSED; bad: return ECMD_FAILED; } int vgexport(struct cmd_context *cmd, int argc, char **argv) { if (!argc && !arg_count(cmd, all_ARG)) { log_error("Please supply volume groups or use -a for all."); return ECMD_FAILED; } if (argc && arg_count(cmd, all_ARG)) { log_error("No arguments permitted when using -a for all."); return ECMD_FAILED; } return process_each_vg(cmd, argc, argv, READ_FOR_UPDATE, NULL, &vgexport_single); } lvm2-2.02.98/tools/lvcreate.c0000640000175000017500000007475112037016273014640 0ustar blankblank/* * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU 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 "tools.h" #include struct lvcreate_cmdline_params { percent_type_t percent; uint64_t size; char **pvs; int pv_count; }; static int _set_vg_name(struct lvcreate_params *lp, const char *vg_name) { /* Can't do anything */ if (!vg_name) return 1; /* If VG name already known, ensure this 2nd copy is identical */ if (lp->vg_name && strcmp(lp->vg_name, vg_name)) { log_error("Inconsistent volume group names " "given: \"%s\" and \"%s\"", lp->vg_name, vg_name); return 0; } lp->vg_name = vg_name; return 1; } static int _lvcreate_name_params(struct lvcreate_params *lp, struct cmd_context *cmd, int *pargc, char ***pargv) { int argc = *pargc; char **argv = *pargv, *ptr; const char *vg_name; lp->pool = arg_str_value(cmd, thinpool_ARG, NULL); /* If --thinpool contains VG name, extract it. */ if (lp->pool && strchr(lp->pool, '/')) { if (!(lp->vg_name = extract_vgname(cmd, lp->pool))) return 0; /* Strip VG from pool */ if ((ptr = strrchr(lp->pool, (int) '/'))) lp->pool = ptr + 1; } lp->lv_name = arg_str_value(cmd, name_ARG, NULL); /* If --name contains VG name, extract it. */ if (lp->lv_name && strchr(lp->lv_name, '/')) { if (!_set_vg_name(lp, extract_vgname(cmd, lp->lv_name))) return_0; /* Strip VG from lv_name */ if ((ptr = strrchr(lp->lv_name, (int) '/'))) lp->lv_name = ptr + 1; } /* Need an origin? */ if (lp->snapshot && !arg_count(cmd, virtualsize_ARG)) { /* argv[0] might be origin or vg/origin */ if (!argc) { log_error("Please specify a logical volume to act as " "the snapshot origin."); return 0; } lp->origin = skip_dev_dir(cmd, argv[0], NULL); if (strrchr(lp->origin, '/')) { if (!_set_vg_name(lp, extract_vgname(cmd, lp->origin))) return_0; /* Strip the volume group from the origin */ if ((ptr = strrchr(lp->origin, (int) '/'))) lp->origin = ptr + 1; } if (!lp->vg_name && !_set_vg_name(lp, extract_vgname(cmd, NULL))) return_0; if (!lp->vg_name) { log_error("The origin name should include the " "volume group."); return 0; } (*pargv)++, (*pargc)--; } else if (seg_is_thin(lp) && !lp->pool && argc) { /* argv[0] might be vg or vg/Pool */ vg_name = skip_dev_dir(cmd, argv[0], NULL); if (!strrchr(vg_name, '/')) { if (!_set_vg_name(lp, vg_name)) return_0; } else { lp->pool = vg_name; if (!_set_vg_name(lp, extract_vgname(cmd, lp->pool))) return_0; if (!lp->vg_name && !_set_vg_name(lp, extract_vgname(cmd, NULL))) return_0; if (!lp->vg_name) { log_error("The pool name should include the " "volume group."); return 0; } /* Strip the volume group */ if ((ptr = strrchr(lp->pool, (int) '/'))) lp->pool = ptr + 1; } (*pargv)++, (*pargc)--; } else { /* * If VG not on command line, try environment default. */ if (!argc) { if (!lp->vg_name && !(lp->vg_name = extract_vgname(cmd, NULL))) { log_error("Please provide a volume group name"); return 0; } } else { vg_name = skip_dev_dir(cmd, argv[0], NULL); if (strrchr(vg_name, '/')) { log_error("Volume group name expected " "(no slash)"); return 0; } if (!_set_vg_name(lp, vg_name)) return_0; (*pargv)++, (*pargc)--; } } if (!validate_name(lp->vg_name)) { log_error("Volume group name %s has invalid characters", lp->vg_name); return 0; } if (lp->lv_name) { if (!apply_lvname_restrictions(lp->lv_name)) return_0; if (!validate_name(lp->lv_name)) { log_error("Logical volume name \"%s\" is invalid", lp->lv_name); return 0; } } if (lp->pool) { if (!apply_lvname_restrictions(lp->pool)) return_0; if (!validate_name(lp->pool)) { log_error("Logical volume name \"%s\" is invalid", lp->pool); return 0; } if (lp->lv_name && !strcmp(lp->lv_name, lp->pool)) { log_error("Logical volume name %s and pool name %s must be different.", lp->lv_name, lp->pool); return 0; } } return 1; } /* * Normal snapshot or thinly-provisioned snapshot? */ static int _determine_snapshot_type(struct volume_group *vg, struct lvcreate_params *lp) { struct lv_list *lvl; if (!(lvl = find_lv_in_vg(vg, lp->origin))) { log_error("Snapshot origin LV %s not found in Volume group %s.", lp->origin, vg->name); return 0; } if (!arg_count(vg->cmd, extents_ARG) && !arg_count(vg->cmd, size_ARG)) { if (!lv_is_thin_volume(lvl->lv)) { log_error("Please specify either size or extents with snapshots."); return 0; } lp->thin = 1; if (!(lp->segtype = get_segtype_from_string(vg->cmd, "thin"))) return_0; lp->pool = first_seg(lvl->lv)->pool_lv->name; } return 1; } /* * Update extents parameters based on other parameters which affect the size * calculation. * NOTE: We must do this here because of the percent_t typedef and because we * need the vg. */ static int _update_extents_params(struct volume_group *vg, struct lvcreate_params *lp, struct lvcreate_cmdline_params *lcp) { uint32_t pv_extent_count; struct logical_volume *origin = NULL; int changed = 0; uint32_t size_rest; uint32_t stripesize_extents; if (lcp->size && !(lp->extents = extents_from_size(vg->cmd, lcp->size, vg->extent_size))) return_0; if (lp->voriginsize && !(lp->voriginextents = extents_from_size(vg->cmd, lp->voriginsize, vg->extent_size))) return_0; /* * Create the pv list before we parse lcp->percent - might be * PERCENT_PVSs */ if (lcp->pv_count) { if (!(lp->pvh = create_pv_list(vg->cmd->mem, vg, lcp->pv_count, lcp->pvs, 1))) return_0; } else lp->pvh = &vg->pvs; switch(lcp->percent) { case PERCENT_VG: lp->extents = percent_of_extents(lp->extents, vg->extent_count, 0); break; case PERCENT_FREE: lp->extents = percent_of_extents(lp->extents, vg->free_count, 0); break; case PERCENT_PVS: if (!lcp->pv_count) lp->extents = percent_of_extents(lp->extents, vg->extent_count, 0); else { pv_extent_count = pv_list_extents_free(lp->pvh); lp->extents = percent_of_extents(lp->extents, pv_extent_count, 0); } break; case PERCENT_LV: log_error("Please express size as %%VG, %%PVS, or " "%%FREE."); return 0; case PERCENT_ORIGIN: if (lp->snapshot && lp->origin && !(origin = find_lv(vg, lp->origin))) { log_error("Couldn't find origin volume '%s'.", lp->origin); return 0; } if (!origin) { log_error(INTERNAL_ERROR "Couldn't find origin volume."); return 0; } lp->extents = percent_of_extents(lp->extents, origin->le_count, 0); break; case PERCENT_NONE: break; } if (!(stripesize_extents = lp->stripe_size / vg->extent_size)) stripesize_extents = 1; if ((lcp->percent != PERCENT_NONE) && lp->stripes && (size_rest = lp->extents % (lp->stripes * stripesize_extents)) && (vg->free_count < lp->extents - size_rest + (lp->stripes * stripesize_extents))) { log_print_unless_silent("Rounding size (%d extents) down to stripe boundary " "size (%d extents)", lp->extents, lp->extents - size_rest); lp->extents = lp->extents - size_rest; } if (lp->create_thin_pool) { if (!arg_count(vg->cmd, poolmetadatasize_ARG)) { /* Defaults to nr_pool_blocks * 64b */ lp->poolmetadatasize = (uint64_t) lp->extents * vg->extent_size / (uint64_t) (lp->chunk_size * (SECTOR_SIZE / UINT64_C(64))); /* Check if we could eventually use bigger chunk size */ if (!arg_count(vg->cmd, chunksize_ARG)) { while ((lp->poolmetadatasize > (DEFAULT_THIN_POOL_OPTIMAL_SIZE / SECTOR_SIZE)) && (lp->chunk_size < DM_THIN_MAX_DATA_BLOCK_SIZE)) { lp->chunk_size <<= 1; lp->poolmetadatasize >>= 1; changed++; } if (changed) log_verbose("Changed chunksize to %u sectors.", lp->chunk_size); } } if (lp->poolmetadatasize > (2 * DEFAULT_THIN_POOL_MAX_METADATA_SIZE)) { if (arg_count(vg->cmd, poolmetadatasize_ARG)) log_warn("WARNING: Maximum supported pool metadata size is 16GB."); lp->poolmetadatasize = 2 * DEFAULT_THIN_POOL_MAX_METADATA_SIZE; } else if (lp->poolmetadatasize < (2 * DEFAULT_THIN_POOL_MIN_METADATA_SIZE)) { if (arg_count(vg->cmd, poolmetadatasize_ARG)) log_warn("WARNING: Minimum supported pool metadata size is 2M."); lp->poolmetadatasize = 2 * DEFAULT_THIN_POOL_MIN_METADATA_SIZE; } log_verbose("Setting pool metadata size to %" PRIu64 " sectors.", lp->poolmetadatasize); if (!(lp->poolmetadataextents = extents_from_size(vg->cmd, lp->poolmetadatasize, vg->extent_size))) return_0; } return 1; } static int _read_size_params(struct lvcreate_params *lp, struct lvcreate_cmdline_params *lcp, struct cmd_context *cmd) { if (arg_count(cmd, extents_ARG) && arg_count(cmd, size_ARG)) { log_error("Please specify either size or extents (not both)"); return 0; } if (!lp->thin && !lp->snapshot && !arg_count(cmd, extents_ARG) && !arg_count(cmd, size_ARG)) { log_error("Please specify either size or extents"); return 0; } if (arg_count(cmd, extents_ARG)) { if (arg_sign_value(cmd, extents_ARG, SIGN_NONE) == SIGN_MINUS) { log_error("Negative number of extents is invalid"); return 0; } lp->extents = arg_uint_value(cmd, extents_ARG, 0); lcp->percent = arg_percent_value(cmd, extents_ARG, PERCENT_NONE); } /* Size returned in kilobyte units; held in sectors */ if (arg_count(cmd, size_ARG)) { if (arg_sign_value(cmd, size_ARG, SIGN_NONE) == SIGN_MINUS) { log_error("Negative size is invalid"); return 0; } lcp->size = arg_uint64_value(cmd, size_ARG, UINT64_C(0)); lcp->percent = PERCENT_NONE; } /* If size/extents given with thin, then we are creating a thin pool */ if (lp->thin && (arg_count(cmd, size_ARG) || arg_count(cmd, extents_ARG))) lp->create_thin_pool = 1; if (arg_count(cmd, poolmetadatasize_ARG)) { if (!seg_is_thin(lp)) { log_error("--poolmetadatasize may only be specified when allocating the thin pool."); return 0; } if (arg_sign_value(cmd, poolmetadatasize_ARG, SIGN_NONE) == SIGN_MINUS) { log_error("Negative poolmetadatasize is invalid."); return 0; } lp->poolmetadatasize = arg_uint64_value(cmd, poolmetadatasize_ARG, UINT64_C(0)); } /* Size returned in kilobyte units; held in sectors */ if (arg_count(cmd, virtualsize_ARG)) { if (seg_is_thin_pool(lp)) { log_error("Virtual size in incompatible with thin_pool segment type."); return 0; } if (arg_sign_value(cmd, virtualsize_ARG, SIGN_NONE) == SIGN_MINUS) { log_error("Negative virtual origin size is invalid"); return 0; } lp->voriginsize = arg_uint64_value(cmd, virtualsize_ARG, UINT64_C(0)); if (!lp->voriginsize) { log_error("Virtual origin size may not be zero"); return 0; } } else { /* No virtual size given, so no thin LV to create. */ if (seg_is_thin_volume(lp) && !(lp->segtype = get_segtype_from_string(cmd, "thin-pool"))) return_0; lp->thin = 0; } return 1; } /* * Generic mirror parameter checks. * FIXME: Should eventually be moved into lvm library. */ static int _validate_mirror_params(const struct cmd_context *cmd __attribute__((unused)), const struct lvcreate_params *lp) { int pagesize = lvm_getpagesize(); if (lp->region_size & (lp->region_size - 1)) { log_error("Region size (%" PRIu32 ") must be a power of 2", lp->region_size); return 0; } if (lp->region_size % (pagesize >> SECTOR_SHIFT)) { log_error("Region size (%" PRIu32 ") must be a multiple of " "machine memory page size (%d)", lp->region_size, pagesize >> SECTOR_SHIFT); return 0; } if (!lp->region_size) { log_error("Non-zero region size must be supplied."); return 0; } return 1; } static int _read_mirror_params(struct lvcreate_params *lp, struct cmd_context *cmd) { int region_size; const char *mirrorlog; int corelog = arg_count(cmd, corelog_ARG); mirrorlog = arg_str_value(cmd, mirrorlog_ARG, corelog ? "core" : DEFAULT_MIRRORLOG); if (strcmp("core", mirrorlog) && corelog) { log_error("Please use only one of --mirrorlog or --corelog"); return 0; } if (!strcmp("mirrored", mirrorlog)) { lp->log_count = 2; } else if (!strcmp("disk", mirrorlog)) { lp->log_count = 1; } else if (!strcmp("core", mirrorlog)) lp->log_count = 0; else { log_error("Unknown mirrorlog type: %s", mirrorlog); return 0; } log_verbose("Setting logging type to %s", mirrorlog); lp->nosync = arg_is_set(cmd, nosync_ARG); if (arg_count(cmd, regionsize_ARG)) { if (arg_sign_value(cmd, regionsize_ARG, SIGN_NONE) == SIGN_MINUS) { log_error("Negative regionsize is invalid"); return 0; } lp->region_size = arg_uint_value(cmd, regionsize_ARG, 0); } else { region_size = 2 * find_config_tree_int(cmd, "activation/mirror_region_size", DEFAULT_MIRROR_REGION_SIZE); if (region_size < 0) { log_error("Negative regionsize in configuration file " "is invalid"); return 0; } lp->region_size = region_size; } if (!_validate_mirror_params(cmd, lp)) return 0; return 1; } static int _read_raid_params(struct lvcreate_params *lp, struct cmd_context *cmd) { if (!segtype_is_raid(lp->segtype)) return 1; if (arg_count(cmd, corelog_ARG) || arg_count(cmd, mirrorlog_ARG)) { log_error("Log options not applicable to %s segtype", lp->segtype->name); return 0; } /* * get_stripe_params is called before _read_raid_params * and already sets: * lp->stripes * lp->stripe_size * * For RAID 4/5/6, these values must be set. */ if (!segtype_is_mirrored(lp->segtype) && (lp->stripes <= lp->segtype->parity_devs)) { log_error("Number of stripes must be at least %d for %s", lp->segtype->parity_devs + 1, lp->segtype->name); return 0; } /* * RAID types without a mirror component do not take '-m' arg */ if (!segtype_is_mirrored(lp->segtype) && arg_count(cmd, mirrors_ARG)) { log_error("Mirror argument cannot be used with segment type, %s", lp->segtype->name); return 0; } /* * RAID1 does not take a stripe arg */ if ((lp->stripes > 1) && segtype_is_mirrored(lp->segtype) && strcmp(lp->segtype->name, "raid10")) { log_error("Stripe argument cannot be used with segment type, %s", lp->segtype->name); return 0; } /* * _read_mirror_params is called before _read_raid_params * and already sets: * lp->nosync * lp->region_size * * But let's ensure that programmers don't reorder * that by checking and warning if they aren't set. */ if (!lp->region_size) { log_error(INTERNAL_ERROR "region_size not set."); return 0; } return 1; } static int _read_activation_params(struct lvcreate_params *lp, struct cmd_context *cmd, struct volume_group *vg) { unsigned pagesize; lp->activate = (activation_change_t) arg_uint_value(cmd, activate_ARG, CHANGE_AY); if (lp->activate == CHANGE_AN || lp->activate == CHANGE_ALN) { if (lp->zero && !seg_is_thin(lp)) { log_error("--activate n requires --zero n"); return 0; } } else if (lp->activate == CHANGE_AAY) { if (arg_count(cmd, zero_ARG)) { log_error("-Z is incompatible with --activate a"); return 0; } lp->zero = 0; } /* * Read ahead. */ lp->read_ahead = arg_uint_value(cmd, readahead_ARG, cmd->default_settings.read_ahead); pagesize = lvm_getpagesize() >> SECTOR_SHIFT; if (lp->read_ahead != DM_READ_AHEAD_AUTO && lp->read_ahead != DM_READ_AHEAD_NONE && lp->read_ahead % pagesize) { if (lp->read_ahead < pagesize) lp->read_ahead = pagesize; else lp->read_ahead = (lp->read_ahead / pagesize) * pagesize; log_warn("WARNING: Overriding readahead to %u sectors, a multiple " "of %uK page size.", lp->read_ahead, pagesize >> 1); } /* * Permissions. */ lp->permission = arg_uint_value(cmd, permission_ARG, LVM_READ | LVM_WRITE); /* Must not zero read only volume */ if (!(lp->permission & LVM_WRITE)) lp->zero = 0; if (arg_count(cmd, major_ARG) > 1) { log_error("Option -j/--major may not be repeated."); return 0; } if (arg_count(cmd, minor_ARG) > 1) { log_error("Option --minor may not be repeated."); return 0; } lp->minor = arg_int_value(cmd, minor_ARG, -1); lp->major = arg_int_value(cmd, major_ARG, -1); /* Persistent minor */ if (arg_count(cmd, persistent_ARG)) { if (lp->create_thin_pool && !lp->thin) { log_error("--persistent is not permitted when creating a thin pool device."); return 0; } if (!strcmp(arg_str_value(cmd, persistent_ARG, "n"), "y")) { if (lp->minor == -1) { log_error("Please specify minor number with " "--minor when using -My"); return 0; } if (lp->major == -1) { log_error("Please specify major number with " "--major when using -My"); return 0; } if (!major_minor_valid(cmd, vg->fid->fmt, lp->major, lp->minor)) return 0; } else { if ((lp->minor != -1) || (lp->major != -1)) { log_error("--major and --minor incompatible " "with -Mn"); return 0; } } } else if (arg_count(cmd, minor_ARG) || arg_count(cmd, major_ARG)) { log_error("--major and --minor require -My"); return 0; } return 1; } static int _lvcreate_params(struct lvcreate_params *lp, struct lvcreate_cmdline_params *lcp, struct cmd_context *cmd, int argc, char **argv) { int contiguous; struct arg_value_group_list *current_group; const char *segtype_str; const char *tag; unsigned attr = 0; memset(lp, 0, sizeof(*lp)); memset(lcp, 0, sizeof(*lcp)); dm_list_init(&lp->tags); /* * Check selected options are compatible and determine segtype */ // FIXME -m0 implies *striped* if ((arg_count(cmd, thin_ARG) || arg_count(cmd, thinpool_ARG)) && arg_count(cmd,mirrors_ARG)) { log_error("--thin,--thinpool and --mirrors are incompatible."); return 0; } // FIXME -m0 implies *striped* /* Set default segtype */ if (arg_count(cmd, mirrors_ARG)) /* * FIXME: Add default setting for when -i and -m arguments * are both given. We should default to "raid10". */ segtype_str = find_config_tree_str(cmd, "global/mirror_segtype_default", DEFAULT_MIRROR_SEGTYPE); else if (arg_count(cmd, thin_ARG) || arg_count(cmd, thinpool_ARG)) segtype_str = "thin"; else segtype_str = "striped"; segtype_str = arg_str_value(cmd, type_ARG, segtype_str); if (!(lp->segtype = get_segtype_from_string(cmd, segtype_str))) return_0; if (seg_unknown(lp)) { log_error("Unable to create LV with unknown segment type %s.", segtype_str); return 0; } if (arg_count(cmd, snapshot_ARG) || seg_is_snapshot(lp) || (!seg_is_thin(lp) && arg_count(cmd, virtualsize_ARG))) lp->snapshot = 1; if (seg_is_thin_pool(lp)) { if (lp->snapshot) { log_error("Snapshots are incompatible with thin_pool segment_type."); return 0; } lp->create_thin_pool = 1; } if (seg_is_thin_volume(lp)) lp->thin = 1; lp->mirrors = 1; /* Default to 2 mirrored areas if '--type mirror|raid1|raid10' */ if (segtype_is_mirrored(lp->segtype)) lp->mirrors = 2; if (arg_count(cmd, mirrors_ARG)) { lp->mirrors = arg_uint_value(cmd, mirrors_ARG, 0) + 1; if (lp->mirrors == 1) { if (segtype_is_mirrored(lp->segtype)) { log_error("--mirrors must be at least 1 with segment type %s.", lp->segtype->name); return 0; } log_print_unless_silent("Redundant mirrors argument: default is 0"); } if ((lp->mirrors > 2) && !strcmp(lp->segtype->name, "raid10")) { /* * FIXME: When RAID10 is no longer limited to * 2-way mirror, 'lv_mirror_count()' * must also change for RAID10. */ log_error("RAID10 currently supports " "only 2-way mirroring (i.e. '-m 1')"); return 0; } if (arg_sign_value(cmd, mirrors_ARG, SIGN_NONE) == SIGN_MINUS) { log_error("Mirrors argument may not be negative"); return 0; } } if (lp->snapshot && arg_count(cmd, zero_ARG)) { log_error("-Z is incompatible with snapshots"); return 0; } if (segtype_is_mirrored(lp->segtype) || segtype_is_raid(lp->segtype)) { if (lp->snapshot) { log_error("mirrors and snapshots are currently " "incompatible"); return 0; } } else { if (arg_count(cmd, corelog_ARG)) { log_error("--corelog is only available with mirrors"); return 0; } if (arg_count(cmd, mirrorlog_ARG)) { log_error("--mirrorlog is only available with mirrors"); return 0; } if (arg_count(cmd, nosync_ARG)) { log_error("--nosync is only available with mirrors"); return 0; } } if (activation() && lp->segtype->ops->target_present && !lp->segtype->ops->target_present(cmd, NULL, &attr)) { log_error("%s: Required device-mapper target(s) not " "detected in your kernel", lp->segtype->name); return 0; } else if (!strcmp(lp->segtype->name, "raid10")) { uint32_t maj, min, patchlevel; if (!target_version("raid", &maj, &min, &patchlevel)) { log_error("Failed to determine version of RAID kernel module"); return 0; } if ((maj != 1) || (min < 3)) { log_error("RAID module does not support RAID10"); return 0; } } if (!_lvcreate_name_params(lp, cmd, &argc, &argv) || !_read_size_params(lp, lcp, cmd) || !get_stripe_params(cmd, &lp->stripes, &lp->stripe_size) || !_read_mirror_params(lp, cmd) || !_read_raid_params(lp, cmd)) return_0; if (lp->create_thin_pool) lp->discards = (thin_discards_t) arg_uint_value(cmd, discards_ARG, THIN_DISCARDS_PASSDOWN); else if (arg_count(cmd, discards_ARG)) { log_error("--discards is only available for thin pool creation."); return 0; } if (lp->snapshot && lp->thin && arg_count(cmd, chunksize_ARG)) log_warn("WARNING: Ignoring --chunksize with thin snapshots."); else if (lp->thin && !lp->create_thin_pool) { if (arg_count(cmd, chunksize_ARG)) log_warn("WARNING: Ignoring --chunksize when using an existing pool."); } else if (lp->snapshot || lp->create_thin_pool) { if (arg_sign_value(cmd, chunksize_ARG, SIGN_NONE) == SIGN_MINUS) { log_error("Negative chunk size is invalid"); return 0; } if (lp->snapshot) { lp->chunk_size = arg_uint_value(cmd, chunksize_ARG, 8); if (lp->chunk_size < 8 || lp->chunk_size > 1024 || (lp->chunk_size & (lp->chunk_size - 1))) { log_error("Chunk size must be a power of 2 in the " "range 4K to 512K"); return 0; } } else { lp->chunk_size = arg_uint_value(cmd, chunksize_ARG, DM_THIN_MIN_DATA_BLOCK_SIZE); if ((lp->chunk_size < DM_THIN_MIN_DATA_BLOCK_SIZE) || (lp->chunk_size > DM_THIN_MAX_DATA_BLOCK_SIZE)) { log_error("Chunk size must be in the range %uK to %uK", (DM_THIN_MIN_DATA_BLOCK_SIZE / 2), (DM_THIN_MAX_DATA_BLOCK_SIZE / 2)); return 0; } if (!(attr & THIN_FEATURE_BLOCK_SIZE) && (lp->chunk_size & (lp->chunk_size - 1))) { log_error("Chunk size must be a power of 2 for this thin target version."); return 0; } else if (lp->chunk_size & (DM_THIN_MIN_DATA_BLOCK_SIZE - 1)) { log_error("Chunk size must be multiple of %uK.", DM_THIN_MIN_DATA_BLOCK_SIZE / 2); return 0; } else if ((lp->discards != THIN_DISCARDS_IGNORE) && (lp->chunk_size & (lp->chunk_size - 1))) { log_warn("WARNING: Using discards ignore for chunk size non power of 2."); lp->discards = THIN_DISCARDS_IGNORE; } } log_verbose("Setting chunksize to %u sectors.", lp->chunk_size); if (!lp->thin && lp->snapshot && !(lp->segtype = get_segtype_from_string(cmd, "snapshot"))) return_0; } else if (arg_count(cmd, chunksize_ARG)) { log_error("-c is only available with snapshots and thin pools"); return 0; } /* * Should we zero the lv. */ lp->zero = strcmp(arg_str_value(cmd, zero_ARG, (lp->segtype->flags & SEG_CANNOT_BE_ZEROED) ? "n" : "y"), "n"); if (lp->mirrors > DEFAULT_MIRROR_MAX_IMAGES) { log_error("Only up to %d images in mirror supported currently.", DEFAULT_MIRROR_MAX_IMAGES); return 0; } /* * Allocation parameters */ contiguous = strcmp(arg_str_value(cmd, contiguous_ARG, "n"), "n"); lp->alloc = contiguous ? ALLOC_CONTIGUOUS : ALLOC_INHERIT; lp->alloc = (alloc_policy_t) arg_uint_value(cmd, alloc_ARG, lp->alloc); if (contiguous && (lp->alloc != ALLOC_CONTIGUOUS)) { log_error("Conflicting contiguous and alloc arguments"); return 0; } dm_list_iterate_items(current_group, &cmd->arg_value_groups) { if (!grouped_arg_is_set(current_group->arg_values, addtag_ARG)) continue; if (!(tag = grouped_arg_str_value(current_group->arg_values, addtag_ARG, NULL))) { log_error("Failed to get tag"); return 0; } if (!str_list_add(cmd->mem, &lp->tags, tag)) { log_error("Unable to allocate memory for tag %s", tag); return 0; } } lcp->pv_count = argc; lcp->pvs = argv; return 1; } static int _check_thin_parameters(struct volume_group *vg, struct lvcreate_params *lp, struct lvcreate_cmdline_params *lcp) { struct lv_list *lvl; if (!lp->thin && !lp->create_thin_pool) { log_error("Please specify device size(s)."); return 0; } if (lp->thin && !lp->create_thin_pool) { if (arg_count(vg->cmd, chunksize_ARG)) { log_error("Only specify --chunksize when originally creating the thin pool."); return 0; } if (lcp->pv_count) { log_error("Only specify Physical volumes when allocating the thin pool."); return 0; } if (arg_count(vg->cmd, alloc_ARG)) { log_error("--alloc may only be specified when allocating the thin pool."); return 0; } if (arg_count(vg->cmd, poolmetadatasize_ARG)) { log_error("--poolmetadatasize may only be specified when allocating the thin pool."); return 0; } if (arg_count(vg->cmd, stripesize_ARG)) { log_error("--stripesize may only be specified when allocating the thin pool."); return 0; } if (arg_count(vg->cmd, stripes_ARG)) { log_error("--stripes may only be specified when allocating the thin pool."); return 0; } if (arg_count(vg->cmd, contiguous_ARG)) { log_error("--contiguous may only be specified when allocating the thin pool."); return 0; } if (arg_count(vg->cmd, zero_ARG)) { log_error("--zero may only be specified when allocating the thin pool."); return 0; } } if (lp->create_thin_pool && lp->pool) { if (find_lv_in_vg(vg, lp->pool)) { log_error("Pool %s already exists in Volume group %s.", lp->pool, vg->name); return 0; } } else if (lp->pool) { if (!(lvl = find_lv_in_vg(vg, lp->pool))) { log_error("Pool %s not found in Volume group %s.", lp->pool, vg->name); return 0; } if (!lv_is_thin_pool(lvl->lv)) { log_error("Logical volume %s is not a thin pool.", lp->pool); return 0; } } else if (!lp->create_thin_pool) { log_error("Please specify name of existing pool."); return 0; } if (!lp->thin && lp->lv_name) { log_error("--name may only be given when creating a new thin Logical volume or snapshot."); return 0; } if (!lp->thin) { if (arg_count(vg->cmd, readahead_ARG)) { log_error("--readhead may only be given when creating a new thin Logical volume or snapshot."); return 0; } if (arg_count(vg->cmd, permission_ARG)) { log_error("--permission may only be given when creating a new thin Logical volume or snapshot."); return 0; } if (arg_count(vg->cmd, persistent_ARG)) { log_error("--persistent may only be given when creating a new thin Logical volume or snapshot."); return 0; } } return 1; } /* * Ensure the set of thin parameters extracted from the command line is consistent. */ static int _validate_internal_thin_processing(const struct lvcreate_params *lp) { int r = 1; /* The final state should be one of: thin create_thin_pool snapshot origin pool 1 1 0 0 y/n - create new pool and a thin LV in it 1 0 0 0 y - create new thin LV in existing pool 0 1 0 0 y/n - create new pool only 1 0 1 1 y - create thin snapshot of existing thin LV */ if (!lp->create_thin_pool && !lp->pool) { log_error(INTERNAL_ERROR "--thinpool not identified."); r = 0; } if ((lp->snapshot && !lp->origin) || (!lp->snapshot && lp->origin)) { log_error(INTERNAL_ERROR "Inconsistent snapshot and origin parameters identified."); r = 0; } if (lp->snapshot && (lp->create_thin_pool || !lp->thin)) { log_error(INTERNAL_ERROR "Inconsistent thin and snapshot parameters identified."); r = 0; } if (!lp->thin && !lp->create_thin_pool) { log_error(INTERNAL_ERROR "Failed to identify what type of thin target to use."); r = 0; } if (seg_is_thin_pool(lp) && lp->thin) { log_error(INTERNAL_ERROR "Thin volume cannot be created with thin pool segment type."); r = 0; } return r; } int lvcreate(struct cmd_context *cmd, int argc, char **argv) { int r = ECMD_PROCESSED; struct lvcreate_params lp; struct lvcreate_cmdline_params lcp; struct volume_group *vg; if (!_lvcreate_params(&lp, &lcp, cmd, argc, argv)) return EINVALID_CMD_LINE; log_verbose("Finding volume group \"%s\"", lp.vg_name); vg = vg_read_for_update(cmd, lp.vg_name, NULL, 0); if (vg_read_error(vg)) { release_vg(vg); stack; return ECMD_FAILED; } if (lp.snapshot && lp.origin && !_determine_snapshot_type(vg, &lp)) { r = ECMD_FAILED; goto_out; } if (seg_is_thin(&lp) && !_check_thin_parameters(vg, &lp, &lcp)) { r = ECMD_FAILED; goto_out; } /* * Check activation parameters to support inactive thin snapshot creation * FIXME: anything else needs to be moved past _determine_snapshot_type()? */ if (!_read_activation_params(&lp, cmd, vg)) { r = ECMD_FAILED; goto_out; } if (!_update_extents_params(vg, &lp, &lcp)) { r = ECMD_FAILED; goto_out; } if (seg_is_thin(&lp) && !_validate_internal_thin_processing(&lp)) { r = ECMD_FAILED; goto_out; } if (lp.create_thin_pool) log_verbose("Making thin pool %s in VG %s using segtype %s", lp.pool ? : "with generated name", lp.vg_name, lp.segtype->name); if (lp.thin) log_verbose("Making thin LV %s in pool %s in VG %s%s%s using segtype %s", lp.lv_name ? : "with generated name", lp.pool ? : "with generated name", lp.vg_name, lp.snapshot ? " as snapshot of " : "", lp.snapshot ? lp.origin : "", lp.segtype->name); if (!lv_create_single(vg, &lp)) { stack; r = ECMD_FAILED; } out: unlock_and_release_vg(cmd, vg, lp.vg_name); return r; } lvm2-2.02.98/tools/pvscan.c0000640000175000017500000002104112037016273014305 0ustar blankblank/* * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU 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 "tools.h" #include "lvmetad.h" #include "lvmcache.h" int pv_max_name_len = 0; int vg_max_name_len = 0; static void _pvscan_display_single(struct cmd_context *cmd, struct physical_volume *pv, void *handle __attribute__((unused))) { char uuid[64] __attribute__((aligned(8))); unsigned vg_name_len = 0; char pv_tmp_name[NAME_LEN] = { 0 }; char vg_tmp_name[NAME_LEN] = { 0 }; char vg_name_this[NAME_LEN] = { 0 }; /* short listing? */ if (arg_count(cmd, short_ARG) > 0) { log_print_unless_silent("%s", pv_dev_name(pv)); return; } if (arg_count(cmd, verbose_ARG) > 1) { /* FIXME As per pv_display! Drop through for now. */ /* pv_show(pv); */ /* FIXME - Moved to Volume Group structure */ /* log_print("System Id %s", pv->vg->system_id); */ /* log_print(" "); */ /* return; */ } vg_name_len = strlen(pv_vg_name(pv)) + 1; if (arg_count(cmd, uuid_ARG)) { if (!id_write_format(&pv->id, uuid, sizeof(uuid))) { stack; return; } sprintf(pv_tmp_name, "%-*s with UUID %s", pv_max_name_len - 2, pv_dev_name(pv), uuid); } else { sprintf(pv_tmp_name, "%s", pv_dev_name(pv)); } if (is_orphan(pv)) { log_print_unless_silent("PV %-*s %-*s %s [%s]", pv_max_name_len, pv_tmp_name, vg_max_name_len, " ", pv->fmt ? pv->fmt->name : " ", display_size(cmd, pv_size(pv))); return; } if (pv_status(pv) & EXPORTED_VG) { strncpy(vg_name_this, pv_vg_name(pv), vg_name_len); log_print_unless_silent("PV %-*s is in exported VG %s " "[%s / %s free]", pv_max_name_len, pv_tmp_name, vg_name_this, display_size(cmd, (uint64_t) pv_pe_count(pv) * pv_pe_size(pv)), display_size(cmd, (uint64_t) (pv_pe_count(pv) - pv_pe_alloc_count(pv)) * pv_pe_size(pv))); return; } sprintf(vg_tmp_name, "%s", pv_vg_name(pv)); log_print_unless_silent("PV %-*s VG %-*s %s [%s / %s free]", pv_max_name_len, pv_tmp_name, vg_max_name_len, vg_tmp_name, pv->fmt ? pv->fmt->name : " ", display_size(cmd, (uint64_t) pv_pe_count(pv) * pv_pe_size(pv)), display_size(cmd, (uint64_t) (pv_pe_count(pv) - pv_pe_alloc_count(pv)) * pv_pe_size(pv))); } static int _auto_activation_handler(struct volume_group *vg, int partial, activation_change_t activate) { /* TODO: add support for partial and clustered VGs */ if (partial || vg_is_clustered(vg)) return 1; if (!vgchange_activate(vg->cmd, vg, activate)) { log_error("%s: autoactivation failed.", vg->name); return 0; } return 1; } static int _pvscan_lvmetad(struct cmd_context *cmd, int argc, char **argv) { int ret = ECMD_PROCESSED; struct device *dev; const char *pv_name; int32_t major = -1; int32_t minor = -1; int devno_args = 0; struct arg_value_group_list *current_group; dev_t devno; char *buf; activation_handler handler = NULL; if (arg_count(cmd, activate_ARG)) { if (arg_uint_value(cmd, activate_ARG, CHANGE_AAY) != CHANGE_AAY) { log_error("Only --activate ay allowed with pvscan."); return 0; } handler = _auto_activation_handler; } if (arg_count(cmd, major_ARG) + arg_count(cmd, minor_ARG)) devno_args = 1; if (devno_args && (!arg_count(cmd, major_ARG) || !arg_count(cmd, minor_ARG))) { log_error("Both --major and --minor required to identify devices."); return EINVALID_CMD_LINE; } if (!lock_vol(cmd, VG_GLOBAL, LCK_VG_READ)) { log_error("Unable to obtain global lock."); return ECMD_FAILED; } /* Scan everything? */ if (!argc && !devno_args) { if (!lvmetad_pvscan_all_devs(cmd, handler)) ret = ECMD_FAILED; goto out; } log_verbose("Using physical volume(s) on command line"); /* Process any command line PVs first. */ while (argc--) { pv_name = *argv++; dev = dev_cache_get(pv_name, NULL); if (!dev) { log_error("Physical Volume %s not found.", pv_name); ret = ECMD_FAILED; continue; } if (!lvmetad_pvscan_single(cmd, dev, handler)) { ret = ECMD_FAILED; break; } if (sigint_caught()) break; } if (!devno_args) goto out; /* Process any grouped --major --minor args */ dm_list_iterate_items(current_group, &cmd->arg_value_groups) { major = grouped_arg_int_value(current_group->arg_values, major_ARG, major); minor = grouped_arg_int_value(current_group->arg_values, minor_ARG, minor); if (major < 0 || minor < 0) continue; devno = MKDEV((dev_t)major, minor); if (!(dev = dev_cache_get_by_devt(devno, NULL))) { if (!dm_asprintf(&buf, "%" PRIi32 ":%" PRIi32, major, minor)) stack; /* FIXME Filters? */ if (!lvmetad_pv_gone(devno, buf ? : "", handler)) { ret = ECMD_FAILED; if (buf) dm_free(buf); break; } log_print_unless_silent("Device %s not found. " "Cleared from lvmetad cache.", buf ? : ""); if (buf) dm_free(buf); continue; } if (!lvmetad_pvscan_single(cmd, dev, handler)) { ret = ECMD_FAILED; break; } if (sigint_caught()) break; } out: unlock_vg(cmd, VG_GLOBAL); return ret; } int pvscan(struct cmd_context *cmd, int argc, char **argv) { int new_pvs_found = 0; int pvs_found = 0; struct dm_list *pvslist; struct pv_list *pvl; struct physical_volume *pv; uint64_t size_total = 0; uint64_t size_new = 0; int len = 0; pv_max_name_len = 0; vg_max_name_len = 0; if (arg_count(cmd, cache_ARG)) return _pvscan_lvmetad(cmd, argc, argv); if (arg_count(cmd, activate_ARG)) { log_error("--activate is only valid with --cache."); return EINVALID_CMD_LINE; } if (arg_count(cmd, major_ARG) + arg_count(cmd, minor_ARG)) { log_error("--major and --minor are only valid with --cache."); return EINVALID_CMD_LINE; } if (arg_count(cmd, novolumegroup_ARG) && arg_count(cmd, exported_ARG)) { log_error("Options -e and -n are incompatible"); return EINVALID_CMD_LINE; } if (arg_count(cmd, exported_ARG) || arg_count(cmd, novolumegroup_ARG)) log_warn("WARNING: only considering physical volumes %s", arg_count(cmd, exported_ARG) ? "of exported volume group(s)" : "in no volume group"); if (!lock_vol(cmd, VG_GLOBAL, LCK_VG_WRITE)) { log_error("Unable to obtain global lock."); return ECMD_FAILED; } if (cmd->filter->wipe) cmd->filter->wipe(cmd->filter); lvmcache_destroy(cmd, 1); /* populate lvmcache */ if (!lvmetad_vg_list_to_lvmcache(cmd)) stack; log_verbose("Walking through all physical volumes"); if (!(pvslist = get_pvs(cmd))) { unlock_vg(cmd, VG_GLOBAL); stack; return ECMD_FAILED; } /* eliminate exported/new if required */ dm_list_iterate_items(pvl, pvslist) { pv = pvl->pv; if ((arg_count(cmd, exported_ARG) && !(pv_status(pv) & EXPORTED_VG)) || (arg_count(cmd, novolumegroup_ARG) && (!is_orphan(pv)))) { dm_list_del(&pvl->list); free_pv_fid(pv); continue; } /* Also check for MD use? */ /******* if (MAJOR(pv_create_kdev_t(pv[p]->pv_name)) != MD_MAJOR) { log_warn ("WARNING: physical volume \"%s\" belongs to a meta device", pv[p]->pv_name); } if (MAJOR(pv[p]->pv_dev) != MD_MAJOR) continue; ********/ pvs_found++; if (is_orphan(pv)) { new_pvs_found++; size_new += pv_size(pv); size_total += pv_size(pv); } else size_total += (uint64_t) pv_pe_count(pv) * pv_pe_size(pv); } /* find maximum pv name length */ pv_max_name_len = vg_max_name_len = 0; dm_list_iterate_items(pvl, pvslist) { pv = pvl->pv; len = strlen(pv_dev_name(pv)); if (pv_max_name_len < len) pv_max_name_len = len; len = strlen(pv_vg_name(pv)); if (vg_max_name_len < len) vg_max_name_len = len; } pv_max_name_len += 2; vg_max_name_len += 2; dm_list_iterate_items(pvl, pvslist) { _pvscan_display_single(cmd, pvl->pv, NULL); free_pv_fid(pvl->pv); } if (!pvs_found) { log_print_unless_silent("No matching physical volumes found"); unlock_vg(cmd, VG_GLOBAL); return ECMD_PROCESSED; } log_print_unless_silent("Total: %d [%s] / in use: %d [%s] / in no VG: %d [%s]", pvs_found, display_size(cmd, size_total), pvs_found - new_pvs_found, display_size(cmd, (size_total - size_new)), new_pvs_found, display_size(cmd, size_new)); unlock_vg(cmd, VG_GLOBAL); return ECMD_PROCESSED; } lvm2-2.02.98/scripts/0000750000175000017500000000000012037016273013177 5ustar blankblanklvm2-2.02.98/scripts/lvm2_monitoring_init_red_hat.in0000640000175000017500000000517212037016272021372 0ustar blankblank#!/bin/bash # # Copyright (C) 2007-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 # # This file is part of LVM2. # It is required for the proper handling of failures of LVM2 mirror # devices that were created using the -m option of lvcreate. # # # chkconfig: 12345 02 99 # description: Starts and stops dmeventd monitoring for lvm2 # # For Red-Hat-based distributions such as Fedora, RHEL, CentOS. # ### BEGIN INIT INFO # Provides: lvm2-monitor # Required-Start: $local_fs # Required-Stop: $local_fs # Default-Start: 1 2 3 4 5 # Default-Stop: 0 6 # Short-Description: Monitoring of LVM2 mirrors, snapshots etc. using dmeventd or progress polling ### END INIT INFO . /etc/init.d/functions DAEMON=lvm2-monitor exec_prefix=@exec_prefix@ sbindir=@sbindir@ VGCHANGE=${sbindir}/vgchange VGS=${sbindir}/vgs LOCK_FILE="/var/lock/subsys/$DAEMON" WARN=1 export LVM_SUPPRESS_LOCKING_FAILURE_MESSAGES=1 start() { ret=0 # TODO do we want to separate out already active groups only? VGSLIST=`$VGS --noheadings -o name --config 'log{command_names=0 prefix=" "}' 2> /dev/null` for vg in $VGSLIST do action "Starting monitoring for VG $vg:" $VGCHANGE --monitor y --poll y --config 'log{command_names=0 prefix=" "}' $vg || ret=$? done return $ret } stop() { ret=0 # TODO do we want to separate out already active groups only? if test "$WARN" = "1"; then echo "Not stopping monitoring, this is a dangerous operation. Please use force-stop to override." return 1 fi VGSLIST=`$VGS --noheadings -o name --config 'log{command_names=0 prefix=" "}' 2> /dev/null` for vg in $VGSLIST do action "Stopping monitoring for VG $vg:" $VGCHANGE --monitor n --config 'log{command_names=0 prefix=" "}' $vg || ret=$? done return $ret } rtrn=1 # See how we were called. case "$1" in start) start rtrn=$? [ $rtrn = 0 ] && touch $LOCK_FILE ;; force-stop) WARN=0 stop rtrn=$? [ $rtrn = 0 ] && rm -f $LOCK_FILE ;; stop) test "$runlevel" = "0" && WARN=0 test "$runlevel" = "6" && WARN=0 stop rtrn=$? [ $rtrn = 0 ] && rm -f $LOCK_FILE ;; restart) WARN=0 if stop then start fi rtrn=$? ;; status) # TODO anyone with an idea how to dump monitored volumes? ;; *) echo $"Usage: $0 {start|stop|restart|status|force-stop}" ;; esac exit $rtrn lvm2-2.02.98/scripts/lvm2_lvmetad_systemd_red_hat.service.in0000640000175000017500000000057412037016272023026 0ustar blankblank[Unit] Description=LVM2 metadata daemon Documentation=man:lvmetad(8) Requires=lvm2-lvmetad.socket After=lvm2-lvmetad.socket DefaultDependencies=no Conflicts=shutdown.target [Service] Type=forking NonBlocking=true ExecStart=@sbindir@/lvmetad ExecReload=@sbindir@/lvmetad -R Environment=SD_ACTIVATION=1 Restart=on-abort PIDFile=@LVMETAD_PIDFILE@ [Install] WantedBy=sysinit.target lvm2-2.02.98/scripts/lvmconf.sh0000640000175000017500000001504312037016272015202 0ustar blankblank#!/bin/bash # # Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved. # # This file is part of the lvm2 package. # # 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 # # Edit an lvm.conf file to adjust various properties # function usage { echo "usage: $0 " echo "" echo "Commands:" echo "Enable clvm: --enable-cluster [--lockinglibdir ] [--lockinglib ]" echo "Disable clvm: --disable-cluster" echo "Set locking library: --lockinglibdir [--lockinglib ]" echo "" echo "Global options:" echo "Config file location: --file " echo "" } function parse_args { while [ -n "$1" ]; do case $1 in --enable-cluster) LOCKING_TYPE=3 shift ;; --disable-cluster) LOCKING_TYPE=1 shift ;; --lockinglibdir) if [ -n "$2" ]; then LOCKINGLIBDIR=$2 shift 2 else usage exit 1 fi ;; --lockinglib) if [ -n "$2" ]; then LOCKINGLIB=$2 shift 2 else usage exit 1 fi ;; --file) if [ -n "$2" ]; then CONFIGFILE=$2 shift 2 else usage exit 1 fi ;; *) usage exit 1 esac done } function validate_args { [ -z "$CONFIGFILE" ] && CONFIGFILE="/etc/lvm/lvm.conf" if [ ! -f "$CONFIGFILE" ] then echo "$CONFIGFILE does not exist" exit 10 fi if [ -z "$LOCKING_TYPE" ] && [ -z "$LOCKINGLIBDIR" ]; then usage exit 1 fi if [ -n "$LOCKINGLIBDIR" ]; then if [ "${LOCKINGLIBDIR:0:1}" != "/" ] then echo "Prefix must be an absolute path name (starting with a /)" exit 12 fi if [ -n "$LOCKINGLIB" ] && [ ! -f "$LOCKINGLIBDIR/$LOCKINGLIB" ] then echo "$LOCKINGLIBDIR/$LOCKINGLIB does not exist, did you do a \"make install\" ?" exit 11 fi fi if [ "$LOCKING_TYPE" = "1" ] && [ -n "$LOCKINGLIBDIR" -o -n "$LOCKINGLIB" ]; then echo "Superfluous locking lib parameter, ignoring" fi } umask 0077 parse_args "$@" validate_args SCRIPTFILE=/etc/lvm/.lvmconf-script.tmp TMPFILE=/etc/lvm/.lvmconf-tmp.tmp # Flags so we know which parts of the file we can replace and which need # adding. These are return codes from grep, so zero means it IS present! have_type=1 have_dir=1 have_library=1 have_global=1 grep -q '^[[:blank:]]*locking_type[[:blank:]]*=' $CONFIGFILE have_type=$? grep -q '^[[:blank:]]*library_dir[[:blank:]]*=' $CONFIGFILE have_dir=$? grep -q '^[[:blank:]]*locking_library[[:blank:]]*=' $CONFIGFILE have_library=$? # Those options are in section "global {" so we must have one if any are present. if [ "$have_type" = "0" -o "$have_dir" = "0" -o "$have_library" = "0" ] then # See if we can find it... grep -q '^[[:blank:]]*global[[:blank:]]*{' $CONFIGFILE have_global=$? if [ "$have_global" = "1" ] then echo "global keys but no 'global {' found, can't edit file" exit 13 fi fi if [ "$LOCKING_TYPE" = "2" ] && [ -z "$LOCKINGLIBDIR" ] && [ "$have_dir" = "1" ]; then echo "no library_dir specified in $CONFIGFILE" exit 16 fi # So if we don't have "global {" we need to create one and # populate it if [ "$have_global" = "1" ] then if [ -z "$LOCKING_TYPE" ]; then LOCKING_TYPE=1 fi if [ "$LOCKING_TYPE" = "3" ] || [ "$LOCKING_TYPE" = "2" ]; then cat $CONFIGFILE - < $TMPFILE global { # Enable locking for cluster LVM locking_type = $LOCKING_TYPE library_dir = "$LOCKINGLIBDIR" EOF if [ $? != 0 ] then echo "failed to create temporary config file, $CONFIGFILE not updated" exit 14 fi if [ -n "$LOCKINGLIB" ]; then cat - <> $TMPFILE locking_library = "$LOCKINGLIB" EOF if [ $? != 0 ] then echo "failed to create temporary config file, $CONFIGFILE not updated" exit 16 fi fi cat - <> $TMPFILE } EOF fi # if we aren't setting cluster locking, we don't need to create a global section if [ $? != 0 ] then echo "failed to create temporary config file, $CONFIGFILE not updated" exit 17 fi else # # We have a "global {" section, so add or replace the # locking entries as appropriate # if [ -n "$LOCKING_TYPE" ]; then if [ "$have_type" = "0" ] then SEDCMD=" s/^[[:blank:]]*locking_type[[:blank:]]*=.*/\ \ \ \ locking_type = $LOCKING_TYPE/g" else SEDCMD=" /global[[:blank:]]*{/a\ \ \ \ locking_type = $LOCKING_TYPE" fi fi if [ -n "$LOCKINGLIBDIR" ]; then if [ "$have_dir" = "0" ] then SEDCMD="${SEDCMD}\ns'^[[:blank:]]*library_dir[[:blank:]]*=.*'\ \ \ \ library_dir = \"$LOCKINGLIBDIR\"'g" else SEDCMD="${SEDCMD}\n/global[[:blank:]]*{/a\ \ \ \ library_dir = \"$LOCKINGLIBDIR\"" fi fi if [ -n "$LOCKINGLIB" ]; then if [ "$have_library" = "0" ] then SEDCMD="${SEDCMD}\ns/^[[:blank:]]*locking_library[[:blank:]]*=.*/\ \ \ \ locking_library = \"$LOCKINGLIB\"/g" else SEDCMD="${SEDCMD}\n/global[[:blank:]]*{/a\ \ \ \ locking_library = \"$LOCKINGLIB\"" fi fi echo -e $SEDCMD > $SCRIPTFILE sed <$CONFIGFILE >$TMPFILE -f $SCRIPTFILE if [ $? != 0 ] then echo "sed failed, $CONFIGFILE not updated" exit 15 fi fi # Now we have a suitably editted config file in a temp place, # backup the original and copy our new one into place. cp $CONFIGFILE $CONFIGFILE.lvmconfold if [ $? != 0 ] then echo "failed to backup old config file, $CONFIGFILE not updated" exit 2 fi cp $TMPFILE $CONFIGFILE if [ $? != 0 ] then echo "failed to copy new config file into place, check $CONFIGFILE is still OK" exit 3 fi rm -f $SCRIPTFILE $TMPFILE lvm2-2.02.98/scripts/blkdeactivate.sh.in0000640000175000017500000002206712037016272016751 0ustar blankblank#!/bin/bash # # Copyright (C) 2012 Red Hat, Inc. All rights reserved. # # This file is part of LVM2. # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions # of the GNU General Public License v.2. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation, # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Author: Peter Rajnoha # # Script for deactivating block devices # # Requires: # bash >= 4.0 (associative array support) # lsblk >= 2.22 (lsblk -s support) # umount # dmsetup >= 1.02.68 (--retry option support) # lvm >= 2.2.89 (activation/retry_deactivation config support) # #set -x shopt -s dotglob nullglob TOOL=blkdeactivate DEV_DIR='/dev' SYS_BLK_DIR='/sys/block' UMOUNT="/bin/umount" DMSETUP="@sbindir@/dmsetup" LVM="@sbindir@/lvm" LSBLK="/bin/lsblk -r --noheadings -o TYPE,KNAME,NAME,MOUNTPOINT" LSBLK_VARS="local devtype local kname local name local mnt" LSBLK_READ="read -r devtype kname name mnt" # Do not unmount mounted devices by default. DO_UMOUNT=0 # Deactivate each LV separately by default (not the whole VG). LVM_DO_WHOLE_VG=0 # Do not retry LV deactivation by default. LVM_CONFIG="activation{retry_deactivation=0}" # # List of device names and/or VGs to be skipped. # Device name is the KNAME from lsblk output. # # If deactivation of any device fails, it's automatically # added to the SKIP_DEVICE_LIST (also a particular VG # added to the SKIP_VG_LIST for a device that is an LV). # # These lists provide device tree pruning to skip # particular device/VG deactivation that failed already. # (lists are associative arrays!) # declare -A SKIP_DEVICE_LIST=() declare -A SKIP_VG_LIST=() # # List of mountpoints to be skipped. Any device that is mounted on the mountpoint # listed here will be added to SKIP_DEVICE_LIST (and SKIP_VG_LIST) automatically. # (list is an associative array!) # declare -A SKIP_UMOUNT_LIST=(["/"]=1 ["/boot"]=1 \ ["/lib"]=1 ["/lib64"]=1 \ ["/bin"]=1 ["/sbin"]=1 \ ["/usr"]=1 \ ["/usr/lib"]=1 ["/usr/lib64"]=1 \ ["/usr/sbin"]=1 ["/usr/bin"]=1) # Bash can't properly handle '[' and ']' used as a subscript # within the '()'initialization - it needs to be done separately! SKIP_UMOUNT_LIST["[SWAP]"]=1 usage() { echo "${TOOL}: Utility to deactivate block devices" echo echo " ${TOOL} [options] [device...]" echo " - Deactivate block device tree." echo " If devices are specified, deactivate only supplied devices and their holders." echo echo " Options:" echo " -h | --help Show this help message" echo " -d | --dmoption DM_OPTIONS Comma separated DM specific options" echo " -l | --lvmoption LVM_OPTIONS Comma separated LVM specific options" echo " -u | --umount Unmount the device if mounted" echo echo " Device specific options:" echo " DM_OPTIONS:" echo " retry retry removal several times in case of failure" echo " force force device removal" echo " LVM_OPTIONS:" echo " retry retry removal several times in case of failure" echo " wholevg deactivate the whole VG when processing an LV" exit } add_device_to_skip_list() { SKIP_DEVICE_LIST+=(["$kname"]=1) return 1 } add_vg_to_skip_list() { SKIP_VG_LIST+=(["$DM_VG_NAME"]=1) return 1 } is_top_level_device() { # top level devices do not have any holders, that is # the SYS_BLK_DIR//holders dir is empty files="`echo $SYS_BLK_DIR/$kname/holders/*`" test -z "$files" } device_umount () { test -z "$mnt" && return 0; if test -z "${SKIP_UMOUNT_LIST["$mnt"]}" -a "$DO_UMOUNT" -eq "1"; then echo " UMOUNT: unmounting $name ($kname) mounted on $mnt" $UMOUNT "$mnt" || add_device_to_skip_list else echo " [SKIP]: unmount of $name ($kname) mounted on $mnt" add_device_to_skip_list fi } deactivate_holders () { local skip=1; $LSBLK_VARS # Get holders for the device - either a mount or another device. # First line on the lsblk output is the device itself - skip it for # the deactivate call as this device is already being deactivated. while $LSBLK_READ; do test -e $SYS_BLK_DIR/$kname || continue # check if the device not on the skip list already test -z ${SKIP_DEVICE_LIST["$kname"]} || return 1 # try to unmount it if mounted device_umount || return 1 # try to deactivate the holder test $skip -eq 1 && skip=0 && continue deactivate || return 1 done <<< "`$LSBLK $1`" } deactivate_dm () { local name=$(printf $name) test -b "$DEV_DIR/mapper/$name" || return 0 test -z ${SKIP_DEVICE_LIST["$kname"]} || return 1 deactivate_holders "$DEV_DIR/mapper/$name" || return 1 echo " DM: deactivating $devtype device $name ($kname)" $DMSETUP $DMSETUP_OPTS remove "$name" || add_device_to_skip_list } deactivate_lvm () { local DM_VG_NAME; local DM_LV_NAME; local DM_LV_LAYER eval $($DMSETUP splitname --nameprefixes --noheadings --rows "$name" LVM) test -b "$DEV_DIR/$DM_VG_NAME/$DM_LV_NAME" || return 0 test -z ${SKIP_VG_LIST["$DM_VG_NAME"]} || return 1 # Deactivating only the LV specified test $LVM_DO_WHOLE_VG -eq 0 && { deactivate_holders "$DEV_DIR/$DM_VG_NAME/$DM_LV_NAME" || { add_device_to_skip_list return 1 } echo " LVM: deactivating Logical Volume $DM_VG_NAME/$DM_LV_NAME" $LVM lvchange --config "log{prefix=\"\"} $LVM_CONFIG" -aln $DM_VG_NAME/$DM_LV_NAME || { add_device_to_skip_list return 1 } return 0 } # Deactivating the whole VG the LV is part of lv_list=$($LVM vgs --config "$LVM_CONFIG" --noheadings --rows -o lv_name $DM_VG_NAME) for lv in $lv_list; do test -b "$DEV_DIR/$DM_VG_NAME/$lv" || continue deactivate_holders "$DEV_DIR/$DM_VG_NAME/$lv" || { add_vg_to_skip_list return 1 } done echo " LVM: deactivating Volume Group $DM_VG_NAME" $LVM vgchange --config "log{prefix=\" \"} $LVM_CONFIG" -aln $DM_VG_NAME || add_vg_to_skip_list } deactivate () { ###################################################################### # DEACTIVATION HOOKS FOR NEW DEVICE TYPES GO HERE! # # # # Identify a new device type either by inspecting the TYPE provided # # by lsblk directly ($devtype) or by any other mean that is suitable # # e.g. the KNAME provided by lsblk ($kname). See $LSBLK_VARS for # # complete list of variables that may be used. Then call a # # device-specific deactivation function that handles the exact type. # # # # This device-specific function will certainly need to call # # deactivate_holders first to recursively deactivate any existing # # holders it might have before deactivating the device it processes. # ###################################################################### if test "$devtype" = "lvm"; then deactivate_lvm elif test "${kname:0:3}" = "dm-"; then deactivate_dm fi } deactivate_all() { $LSBLK_VARS skip=0 echo "Deactivating block devices:" if test $# -eq 0; then # Deactivate all devices while $LSBLK_READ; do # 'disk' is at the bottom already and it's a real device test "$devtype" = "disk" && continue # if deactivation of any device fails, skip processing # any subsequent devices within its subtree as the # top-level device could not be deactivated anyway test $skip -eq 1 && { # reset 'skip' on top level device is_top_level_device && skip=0 || continue } # check if the device is not on the skip list already test -z ${SKIP_DEVICE_LIST["$kname"]} || continue # try to deactivate top-level device, set 'skip=1' # if it fails to do so - this will cause all the # device's subtree to be skipped when processing # devices further in this loop deactivate || skip=1 done <<< "`$LSBLK -s`" else # Deactivate only specified devices while test $# -ne 0; do # Single dm device tree deactivation. if test -b "$1"; then $LSBLK_READ <<< "`$LSBLK --nodeps $1`" # check if the device is not on the skip list already test -z ${SKIP_DEVICE_LIST["$kname"]} || continue deactivate else echo "$1: device not found" return 1 fi shift done; fi } get_dmopts() { ORIG_IFS=$IFS; IFS=',' for opt in $1; do case $opt in "") ;; "retry") DMSETUP_OPTS+="--retry " ;; "force") DMSETUP_OPTS+="--force " ;; *) echo "$opt: unknown DM option" esac done IFS=$ORIG_IFS } get_lvmopts() { ORIG_IFS=$IFS; IFS=',' for opt in $1; do case "$opt" in "") ;; "retry") LVM_CONFIG="activation{retry_deactivation=1}" ;; "wholevg") LVM_DO_WHOLE_VG=1 ;; *) echo "$opt: unknown LVM option" esac done IFS=$ORIG_IFS } while test $# -ne 0; do case "$1" in "") ;; "-h"|"--help") usage ;; "-d"|"--dmoption ") get_dmopts "$2" ; shift ;; "-l"|"--lvmoption ") get_lvmopts "$2" ; shift ;; "-u"|"--umount") DO_UMOUNT=1 ;; *) break ;; esac shift done deactivate_all "$@" lvm2-2.02.98/scripts/relpath.awk0000750000175000017500000000214512037016272015346 0ustar blankblank#!/usr/bin/awk -f # # 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 # relpath.awk: Script is used to calculate relative path # between two real absolute paths. # # echo /a/b/c/d /a/b/e/f | relpath.awk # -> ../../e/f/ { length_from = split($1, from, "/"); length_to = split($2, to, "/") ; l = 1; while (l <= length_from && l <= length_to && from[l] == to[l]) l++; for (i = l; i <= length_from && length(from[i]); i++) { if (i > l) p = sprintf("%s/", p); p = sprintf("%s..", p); } for (i = l; i <= length_to && length(to[i]); i++) { if (length(p) > 0) p = sprintf("%s/", p); p = sprintf("%s%s", p, to[i]); } if (length(p)) p = sprintf("%s/", p); print p } lvm2-2.02.98/scripts/dm_event_systemd_red_hat.service.in0000640000175000017500000000055612037016272022233 0ustar blankblank[Unit] Description=Device-mapper event daemon Documentation=man:dmeventd(8) Requires=dm-event.socket After=dm-event.socket Before=local-fs.target DefaultDependencies=no [Service] Type=forking ExecStart=@sbindir@/dmeventd ExecReload=@sbindir@/dmeventd -R Environment=SD_ACTIVATION=1 PIDFile=@DMEVENTD_PIDFILE@ OOMScoreAdjust=-1000 [Install] WantedBy=sysinit.target lvm2-2.02.98/scripts/lvmdump.sh0000750000175000017500000001620512037016272015225 0ustar blankblank#!/bin/bash # We use some bash-isms (getopts?) # 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 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 # lvm_dump: This script is used to collect pertinent information for # the debugging of lvm issues. # following external commands are used throughout the script # echo and test are internal in bash at least MKDIR=mkdir # need -p TAR=tar # need czf RM=rm # need -rf CP=cp TAIL=tail # we need -n LS=ls # need -la PS=ps # need alx SED=sed DD=dd CUT=cut DATE=date BASENAME=basename UDEVADM=udevadm UNAME=uname TR=tr SOCAT=socat # either socat or nc is needed for dumping lvmetad state NC=nc # user may override lvm and dmsetup location by setting LVM_BINARY # and DMSETUP_BINARY respectively LVM=${LVM_BINARY-lvm} DMSETUP=${DMSETUP_BINARY-dmsetup} LVMETAD_SOCKET=${LVM_LVMETAD_SOCKET-/var/run/lvm/lvmetad.socket} die() { code=$1; shift echo "$@" 1>&2 exit $code } "$LVM" version >& /dev/null || die 2 "Could not run lvm binary '$LVM'" "$DMSETUP" version >& /dev/null || DMSETUP=: function usage { echo "$0 [options]" echo " -h print this message" echo " -a advanced collection - warning: if lvm is already hung," echo " then this script may hang as well if -a is used" echo " -m gather LVM metadata from the PVs" echo " -d dump into a directory instead of tarball" echo " -c if running clvmd, gather cluster data as well" echo " -u gather udev info and context" echo " -l gather lvmetad state if running" echo "" exit 1 } advanced=0 clustered=0 metadata=0 udev=0 while getopts :acd:hmul opt; do case $opt in s) sysreport=1 ;; a) advanced=1 ;; c) clustered=1 ;; d) userdir=$OPTARG ;; h) usage ;; m) metadata=1 ;; u) udev=1 ;; l) lvmetad=1 ;; :) echo "$0: $OPTARG requires a value:"; usage ;; \?) echo "$0: unknown option $OPTARG"; usage ;; *) usage ;; esac done NOW=`$DATE -u +%G%m%d%k%M%S | $TR -d ' '` if test -n "$userdir"; then dir="$userdir" else dirbase="lvmdump-$HOSTNAME-$NOW" dir="$HOME/$dirbase" fi test -e $dir && die 3 "Fatal: $dir already exists" $MKDIR -p $dir || die 4 "Fatal: could not create $dir" log="$dir/lvmdump.log" myecho() { echo "$@" echo "$@" >> "$log" } log() { echo "$@" >> "$log" eval "$@" } warnings() { if test "$UID" != "0" && test "$EUID" != "0"; then myecho "WARNING! Running as non-privileged user, dump is likely incomplete!" elif test "$DMSETUP" = ":"; then myecho "WARNING! Could not run dmsetup, dump is likely incomplete." fi } warnings myecho "Creating dump directory: $dir" echo " " if (( $advanced )); then myecho "Gathering LVM volume info..." myecho " vgscan..." log "\"$LVM\" vgscan -vvvv >> \"$dir/vgscan\" 2>&1" myecho " pvscan..." log "\"$LVM\" pvscan -v >> \"$dir/pvscan\" 2>> \"$log\"" myecho " lvs..." log "\"$LVM\" lvs -a -o +devices >> \"$dir/lvs\" 2>> \"$log\"" myecho " pvs..." log "\"$LVM\" pvs -a -v >> \"$dir/pvs\" 2>> \"$log\"" myecho " vgs..." log "\"$LVM\" vgs -v >> \"$dir/vgs\" 2>> \"$log\"" fi if (( $clustered )); then myecho "Gathering cluster info..." { for i in nodes status services; do cap_i=$(echo $i|tr a-z A-Z) printf "$cap_i:\n----------------------------------\n" log "cman_tool $i 2>> \"$log\"" echo done echo "LOCKS:" echo "----------------------------------" if [ -f /proc/cluster/dlm_locks ] then echo clvmd > /proc/cluster/dlm_locks cat /proc/cluster/dlm_locks echo echo "RESOURCE DIR:" cat /proc/cluster/dlm_dir echo echo "DEBUG LOG:" cat /proc/cluster/dlm_debug echo fi if [ -f /debug/dlm/clvmd ] then cat /debug/dlm/clvmd echo echo "WAITERS:" cat /debug/dlm/clvmd_waiters echo echo "MASTER:" cat /debug/dlm/clvmd_master fi } >> $dir/cluster_info fi myecho "Gathering LVM & device-mapper version info..." echo "LVM VERSION:" >> "$dir/versions" "$LVM" lvs --version >> "$dir/versions" 2>> "$log" echo "DEVICE MAPPER VERSION:" >> "$dir/versions" "$DMSETUP" --version >> "$dir/versions" 2>> "$log" echo "KERNEL VERSION:" >> "$dir/versions" "$UNAME" -a >> "$dir/versions" 2>> "$log" echo "DM TARGETS VERSIONS:" >> "$dir/versions" "$DMSETUP" targets >> "$dir/versions" 2>> "$log" myecho "Gathering dmsetup info..." log "\"$DMSETUP\" info -c >> \"$dir/dmsetup_info\" 2>> \"$log\"" log "\"$DMSETUP\" table >> \"$dir/dmsetup_table\" 2>> \"$log\"" log "\"$DMSETUP\" status >> \"$dir/dmsetup_status\" 2>> \"$log\"" # cat as workaround to avoid tty ioctl (selinux) log "\"$DMSETUP\" ls --tree 2>> \"$log\" | cat >> \"$dir/dmsetup_ls_tree\"" myecho "Gathering process info..." log "$PS alx >> \"$dir/ps_info\" 2>> \"$log\"" myecho "Gathering console messages..." log "$TAIL -n 75 /var/log/messages >> \"$dir/messages\" 2>> \"$log\"" myecho "Gathering /etc/lvm info..." log "$CP -a /etc/lvm \"$dir/lvm\" 2>> \"$log\"" myecho "Gathering /dev listing..." log "$LS -laR /dev >> \"$dir/dev_listing\" 2>> \"$log\"" myecho "Gathering /sys/block listing..." log "$LS -laR /sys/block >> \"$dir/sysblock_listing\" 2>> \"$log\"" log "$LS -laR /sys/devices/virtual/block >> \"$dir/sysblock_listing\" 2>> \"$log\"" if (( $metadata )); then myecho "Gathering LVM metadata from Physical Volumes..." log "$MKDIR -p \"$dir/metadata\"" pvs="$("$LVM" pvs --separator , --noheadings --units s --nosuffix -o \ name,pe_start 2>> "$log" | $SED -e 's/^ *//')" for line in $pvs do test -z "$line" && continue pv="$(echo $line | $CUT -d, -f1)" pe_start="$(echo $line | $CUT -d, -f2)" name="$($BASENAME "$pv")" myecho " $pv" log "$DD if=$pv \"of=$dir/metadata/$name\" bs=512 count=$pe_start 2>> \"$log\"" done fi if (( $udev )); then myecho "Gathering udev info..." udev_dir="$dir/udev" log "$MKDIR -p \"$udev_dir\"" log "$UDEVADM info --version >> \"$udev_dir/version\" 2>> \"$log\"" log "$UDEVADM info --export-db >> \"$udev_dir/db\" 2>> \"$log\"" log "$CP -a /etc/udev/udev.conf \"$udev_dir/conf\" 2>> \"$log\"" log "$LS -la /lib/udev >> \"$udev_dir/lib_dir\" 2>> \"$log\"" log "$CP -aR /etc/udev/rules.d \"$udev_dir/rules_etc\" 2>> \"$log\"" log "$CP -aR /lib/udev/rules.d \"$udev_dir/rules_lib\" 2>> \"$log\"" fi if (( $lvmetad )); then (echo 'request="dump"'; echo '##') | { if type -p $SOCAT >& /dev/null; then echo "$SOCAT unix-connect:$LVMETAD_SOCKET -" >> "$log" $SOCAT "unix-connect:$LVMETAD_SOCKET" - 2>> "$log" elif echo | $NC -U "$LVMETAD_SOCKET"; then echo "$NC -U $LVMETAD_SOCKET" >> "$log" $NC -U "$LVMETAD_SOCKET" 2>> "$log" else myecho "WARNING: Neither socat nor nc -U seems to be available." 1>&2 echo "# DUMP FAILED" return 1 fi } > "$dir/lvmetad.txt" fi if test -z "$userdir"; then lvm_dump="$dirbase.tgz" myecho "Creating report tarball in $HOME/$lvm_dump..." fi warnings if test -z "$userdir"; then cd "$HOME" "$TAR" czf "$lvm_dump" "$dirbase" 2>/dev/null "$RM" -rf "$dir" fi exit 0 lvm2-2.02.98/scripts/blk_availability_systemd_red_hat.service.in0000640000175000017500000000052512037016272023730 0ustar blankblank[Unit] Description=Availability of block devices After=lvm2-activation.service lvm2-lvmetad.service iscsi.service iscsid.service fcoe.service DefaultDependencies=no Conflicts=shutdown.target [Service] Type=oneshot ExecStart=/usr/bin/true ExecStop=@sbindir@/blkdeactivate -u -l wholevg RemainAfterExit=yes [Install] WantedBy=sysinit.target lvm2-2.02.98/scripts/lvmconf_lockingtype2.sh0000640000175000017500000001512112037016272017671 0ustar blankblank#!/bin/bash # # Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. # # This file is part of the lvm2-cluster package. # # 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 # # Edit an lvm.conf file to adjust various properties # function usage { echo "usage: $0 " echo "" echo "Commands:" echo "Enable clvm: --enable-cluster [--lockinglibdir ] [--lockinglib ]" echo "Disable clvm: --disable-cluster" echo "Set locking library: --lockinglibdir [--lockinglib ]" echo "" echo "Global options:" echo "Config file location: --file " echo "" } function parse_args { while [ -n "$1" ]; do case $1 in --enable-cluster) LOCKING_TYPE=2 shift ;; --disable-cluster) LOCKING_TYPE=1 shift ;; --lockinglibdir) if [ -n "$2" ]; then LOCKINGLIBDIR=$2 shift 2 else usage exit 1 fi ;; --lockinglib) if [ -n "$2" ]; then LOCKINGLIB=$2 shift 2 else usage exit 1 fi ;; --file) if [ -n "$2" ]; then CONFIGFILE=$2 shift 2 else usage exit 1 fi ;; *) usage exit 1 esac done } function validate_args { [ -z "$CONFIGFILE" ] && CONFIGFILE="/etc/lvm/lvm.conf" if [ ! -f "$CONFIGFILE" ] then echo "$CONFIGFILE does not exist" exit 10 fi if [ -z "$LOCKING_TYPE" ] && [ -z "$LOCKINGLIBDIR" ]; then usage exit 1 fi if [ -n "$LOCKINGLIBDIR" ]; then [ -z "$LOCKINGLIB" ] && LOCKINGLIB="liblvm2clusterlock.so" if [ "${LOCKINGLIBDIR:0:1}" != "/" ] then echo "Prefix must be an absolute path name (starting with a /)" exit 12 fi if [ ! -f "$LOCKINGLIBDIR/$LOCKINGLIB" ] then echo "$LOCKINGLIBDIR/$LOCKINGLIB does not exist, did you do a \"make install\" ?" exit 11 fi fi if [ "$LOCKING_TYPE" = "1" ] && [ -n "$LOCKINGLIBDIR" -o -n "$LOCKINGLIB" ]; then echo "Superfluous locking lib parameter, ignoring" fi } umask 0077 parse_args "$@" validate_args SCRIPTFILE=/etc/lvm/.lvmconf-script.tmp TMPFILE=/etc/lvm/.lvmconf-tmp.tmp # Flags so we know which parts of the file we can replace and which need # adding. These are return codes from grep, so zero means it IS present! have_type=1 have_dir=1 have_library=1 have_global=1 grep -q '^[[:blank:]]*locking_type[[:blank:]]*=' $CONFIGFILE have_type=$? grep -q '^[[:blank:]]*library_dir[[:blank:]]*=' $CONFIGFILE have_dir=$? grep -q '^[[:blank:]]*locking_library[[:blank:]]*=' $CONFIGFILE have_library=$? # Those options are in section "global {" so we must have one if any are present. if [ "$have_type" = "0" -o "$have_dir" = "0" -o "$have_library" = "0" ] then # See if we can find it... grep -q '^[[:blank:]]*global[[:blank:]]*{' $CONFIGFILE have_global=$? if [ "$have_global" = "1" ] then echo "global keys but no 'global {' found, can't edit file" exit 13 fi fi if [ "$LOCKING_TYPE" = "2" ] && [ -z "$LOCKINGLIBDIR" ] && [ "$have_dir" = "1" ]; then echo "no library_dir specified in $CONFIGFILE" exit 16 fi # So if we don't have "global {" we need to create one and # populate it if [ "$have_global" = "1" ] then if [ -z "$LOCKING_TYPE" ]; then LOCKING_TYPE=1 fi if [ "$LOCKING_TYPE" = "2" ]; then cat $CONFIGFILE - < $TMPFILE global { # Enable locking for cluster LVM locking_type = $LOCKING_TYPE library_dir = "$LOCKINGLIBDIR" locking_library = "$LOCKINGLIB" } EOF fi # if we aren't setting cluster locking, we don't need to create a global section if [ $? != 0 ] then echo "failed to create temporary config file, $CONFIGFILE not updated" exit 14 fi else # # We have a "global {" section, so add or replace the # locking entries as appropriate # if [ -n "$LOCKING_TYPE" ]; then if [ "$have_type" = "0" ] then SEDCMD=" s/^[[:blank:]]*locking_type[[:blank:]]*=.*/\ \ \ \ locking_type = $LOCKING_TYPE/g" else SEDCMD=" /global[[:blank:]]*{/a\ \ \ \ locking_type = $LOCKING_TYPE" fi fi if [ -n "$LOCKINGLIBDIR" ]; then if [ "$have_dir" = "0" ] then SEDCMD="${SEDCMD}\ns'^[[:blank:]]*library_dir[[:blank:]]*=.*'\ \ \ \ library_dir = \"$LOCKINGLIBDIR\"'g" else SEDCMD="${SEDCMD}\n/global[[:blank:]]*{/a\ \ \ \ library_dir = \"$LOCKINGLIBDIR\"" fi if [ "$have_library" = "0" ] then SEDCMD="${SEDCMD}\ns/^[[:blank:]]*locking_library[[:blank:]]*=.*/\ \ \ \ locking_library = \"$LOCKINGLIB\"/g" else SEDCMD="${SEDCMD}\n/global[[:blank:]]*{/a\ \ \ \ locking_library = \"$LOCKINGLIB\"" fi fi if [ "$LOCKING_TYPE" = "1" ]; then # if we're not using cluster locking, remove the library dir and locking library name if [ "$have_dir" = "0" ] then SEDCMD="${SEDCMD}\n/^[[:blank:]]*library_dir[[:blank:]]*=.*/d" fi if [ "$have_library" = "0" ] then SEDCMD="${SEDCMD}\n/^[[:blank:]]*locking_library[[:blank:]]*=.*/d" fi fi echo -e $SEDCMD > $SCRIPTFILE sed <$CONFIGFILE >$TMPFILE -f $SCRIPTFILE if [ $? != 0 ] then echo "sed failed, $CONFIGFILE not updated" exit 15 fi fi # Now we have a suitably editted config file in a temp place, # backup the original and copy our new one into place. cp $CONFIGFILE $CONFIGFILE.lvmconfold if [ $? != 0 ] then echo "failed to backup old config file, $CONFIGFILE not updated" exit 2 fi cp $TMPFILE $CONFIGFILE if [ $? != 0 ] then echo "failed to copy new config file into place, check $CONFIGFILE is still OK" exit 3 fi rm -f $SCRIPTFILE $TMPFILE lvm2-2.02.98/scripts/lvm2_activation_generator_systemd_red_hat.c0000640000175000017500000001115712037016272023755 0ustar blankblank/* * Copyright (C) 2012 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 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 #include #include #include #include #include #include #include "lvm2app.h" #define KMSG_DEV_PATH "/dev/kmsg" #define LVM_CONF_USE_LVMETAD "global/use_lvmetad" #define DEFAULT_UNIT_DIR "/tmp" #define UNIT_NAME_EARLY "lvm2-activation-early.service" #define UNIT_NAME "lvm2-activation.service" #define UNIT_TARGET "local-fs.target" static char unit_path[PATH_MAX]; static char target_path[PATH_MAX]; static char message[PATH_MAX]; static int kmsg_fd = -1; __attribute__ ((format(printf, 1, 2))) static void kmsg(const char *format, ...) { va_list ap; int n; va_start(ap, format); n = vsnprintf(message, sizeof(message), format, ap); va_end(ap); if (kmsg_fd < 0 || (n < 0 || ((unsigned) n + 1 > sizeof(message)))) return; (void) write(kmsg_fd, message, n + 1); } static int lvm_uses_lvmetad(void) { lvm_t lvm; int r; if (!(lvm = lvm_init(NULL))) { kmsg("LVM: Failed to initialize library context for activation generator.\n"); return 0; } r = lvm_config_find_bool(lvm, LVM_CONF_USE_LVMETAD, 0); lvm_quit(lvm); return r; } static int register_unit_with_target(const char *dir, const char *unit, const char *target) { int r = 1; if (dm_snprintf(target_path, PATH_MAX, "%s/%s.wants", dir, target) < 0) { r = 0; goto out; } (void) dm_prepare_selinux_context(target_path, S_IFDIR); if (mkdir(target_path, 0755) < 0 && errno != EEXIST) { kmsg("LVM: Failed to create target directory %s: %m.\n", target_path); r = 0; goto out; } if (dm_snprintf(target_path, PATH_MAX, "%s/%s.wants/%s", dir, target, unit) < 0) { r = 0; goto out; } (void) dm_prepare_selinux_context(target_path, S_IFLNK); if (symlink(unit_path, target_path) < 0) { kmsg("LVM: Failed to create symlink for unit %s: %m.\n", unit); r = 0; } out: dm_prepare_selinux_context(NULL, 0); return r; } static int generate_unit(const char *dir, int early) { FILE *f; const char *unit = early ? UNIT_NAME_EARLY : UNIT_NAME; if (dm_snprintf(unit_path, PATH_MAX, "%s/%s", dir, unit) < 0) return 0; if (!(f = fopen(unit_path, "wxe"))) { kmsg("LVM: Failed to create unit file %s: %m.\n", unit); return 0; } fputs("# Automatically generated by lvm2-activation-generator.\n" "#\n" "# This unit is responsible for direct activation of LVM2 logical volumes\n" "# if lvmetad daemon is not used (global/use_lvmetad=0 lvm.conf setting),\n" "# hence volume autoactivation is not applicable.\n" "# Direct LVM2 activation requires udev to be settled!\n\n" "[Unit]\n" "Description=Activation of LVM2 logical volumes\n" "Documentation=man:lvm(8) man:vgchange(8)\n" "SourcePath=/etc/lvm/lvm.conf\n" "DefaultDependencies=no\n", f); if (early) { fputs("After=systemd-udev-settle.service\n", f); fputs("Before=cryptsetup.target\n", f); } else fputs("After=lvm2-activation-early.service cryptsetup.target\n", f); fputs("Before=local-fs.target shutdown.target\n" "Wants=systemd-udev-settle.service\n\n" "[Service]\n" "ExecStart=/usr/sbin/lvm vgchange -aay --sysinit\n" "Type=oneshot\n", f); if (fclose(f) < 0) { kmsg("LVM: Failed to write unit file %s: %m.\n", unit); return 0; } if (!register_unit_with_target(dir, unit, UNIT_TARGET)) { kmsg("LVM: Failed to register unit %s with target %s.\n", unit, UNIT_TARGET); return 0; } return 1; } int main(int argc, char *argv[]) { const char *dir; int r = EXIT_SUCCESS; kmsg_fd = open(KMSG_DEV_PATH, O_WRONLY|O_NOCTTY); if (argc > 1 && argc != 4) { kmsg("LVM: Activation generator takes three or no arguments.\n"); r = EXIT_FAILURE; goto out; } /* If lvmetad used, rely on autoactivation instead of direct activation. */ if (lvm_uses_lvmetad()) { kmsg("LVM: Logical Volume autoactivation enabled.\n"); goto out; } dir = argc > 1 ? argv[1] : DEFAULT_UNIT_DIR; if (!generate_unit(dir, 1) || !generate_unit(dir, 0)) r = EXIT_FAILURE; out: kmsg("LVM: Activation generator %s.\n", r ? "failed" : "successfully completed"); if (kmsg_fd != -1) (void) close(kmsg_fd); return r; } lvm2-2.02.98/scripts/lvm2create_initrd/0000750000175000017500000000000012037016273016614 5ustar blankblanklvm2-2.02.98/scripts/lvm2create_initrd/README0000640000175000017500000000363312037016272017501 0ustar blankblankhttp://poochiereds.net/svn/lvm2/ This is the lvm2create_initrd script written by Miguel Cabeca, with some small modifications by myself. Here are some other requirements and tips for using it: 1) this script uses busybox on the initrd image, hence busybox needs to be installed when you create your initrd. 2) Make sure /etc/lvm/lvm.conf is set up correctly before running this. In particular, if you're using LVM on RAID, make sure that you have a filter that excludes the RAID component devices (this may not be necessary with the latest patch by Luca Berra, but it doesn't hurt). 3) This initrd image does not support modules. If you need to plug in any kernel modules during the initrd phase, then you'll need to hand-modify the image. 4) The generated initrd image supports an 'lvm2rescue' mode as well. If you add the parameter 'lvmrescue' on the kernel command line, it will run a shell at the end of the initrd 'init' script. This can be helpful when trying to fix a corrupt root volume or root LVM2 volume group. 5) No userspace md tools are installed, so if you're using LVM on RAID, then you'll probably want to mark your RAID partitions as type 'fd' so that the kernel will start them automagically (or hand-modify the image). 6) I'm not sure if devfs will work with this or not. udev, however does work, and is recommended. Because the dm-* devices use dynamically allocated major and minor numbers, kernel upgrades and the like can renumber your devices. To fix this, you need to run a 'vgscan --mknodes' prior to fscking and mounting your rootfs. Doing this with a static /dev creates a problem though -- you will be modifying the root filesystem before it has been fsck'ed. udev gets around this by mounting a ramdisk over /dev, but you'll probably need to add a startup script that creates devices in /dev. The lvm2udev script in this directory is an example of such a beast. -- Jeffrey Layton lvm2-2.02.98/scripts/lvm2create_initrd/lvm2create_initrd0000640000175000017500000003724312037016272022165 0ustar blankblank#!/bin/bash # # lvm2create_initrd # # Miguel Cabeca # cabeca (at) ist (dot) utl (dot) pt # # Inspiration to write this script came from various sources # # Original LVM lvmcreate_initrd: ftp://ftp.sistina.com/pub/LVM/1.0/ # Kernel initrd.txt: http://www.kernel.org/ # EVMS INSTALL.initrd & linuxrc: http://evms.sourceforge.net/ # Jeffrey Layton's lvm2create_initrd: http://poochiereds.net/svn/lvm2create_initrd/ # Christophe Saout's initrd & linuxrc: http://www.saout.de/misc/ # # This script was only tested with kernel 2.6 with everything required to boot # the root filesystem built-in (not as modules). Ex: SCSI or IDE, RAID, device mapper # It does not support devfs as it is deprecated in the 2.6 kernel series # # It needs lvm2 tools, busybox, pivot_root, MAKEDEV # # It has been tested on Debian sid (unstable) only # # Changelog # 26/02/2004 Initial release -- Miguel Cabeca # 27/02/2004 Removed the BUSYBOXSYMLINKS var. The links are now determined at runtime. # some changes in init script to call a shell if something goes wrong. -- Miguel Cabeca # 19/04/2004 Several small changes. Pass args to init so single user mode works. Add some # PATH entries to /sbin/init shell script so chroot works without /usr mounted. Remove # mkdir /initrd so we don't cause problems if root filesystem is corrupted. -- Jeff Layton # 15/05/2004 initial support for modules, create lvm.conf from lvm dumpconfig, other cleanups -- Jeff Layton # 14/11/2006 Update handling of ldd output to handle hardcoded library links and virtual dll linux-gate. # Add support for Gentoo-style MAKEDEV. Remove hardcoded BINUTILS paths -- Douglas Mayle # # Copyright Miguel Cabeca, Jeffrey Layton, 2004 # # 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 # # $Id$ TMPMNT=/tmp/mnt.$$ DEVRAM=/tmp/initrd.$$ # set defaults BINFILES=${BINFILES:-"`which lvm` `which bash` `which busybox` `which pivot_root`"} BASICDEVICES=${BASICDEVICES:-"std consoleonly fd"} BLOCKDEVICES=${BLOCKDEVICES:-"md hda hdb hdc hdd sda sdb sdc sdd"} MAKEDEV=${MAKEDEV:-"debian"} # Uncomment this if you want to disable automatic size detection #INITRDSIZE=4096 PATH=/bin:/sbin:/usr/bin:/usr/sbin:$PATH usage () { echo "Create an initial ramdisk image for LVM2 root filesystem" echo "$cmd: [-h] [-v] [-c lvm.conf] [-m modulelist] [-e extrafiles] -r [raiddevs] [-R mdadm.conf] [-M style] [kernel version]" echo " -h|--help print this usage message" echo " -v|--verbose verbose progress messages" echo " -c|--lvmconf path to lvm.conf (/etc/lvm/lvm.conf)" echo " -m|--modules modules to copy to initrd image" echo " -e|--extra extra files to add to initrd" echo " -r|--raid raid devices to start in initrd" echo " -R|--raidconf location of mdadm.conf file to include" echo " -M|--makedev set MAKEDEV type (debian, redhat, gentoo)" } verbose () { [ "$VERBOSE" ] && echo "`echo $cmd | tr '[a-z0-9/_]' ' '` -- $1" || true } cleanup () { [ "`mount | grep $DEVRAM`" ] && verbose "unmounting $DEVRAM" && umount $DEVRAM [ -f $DEVRAM ] && verbose "removing $DEVRAM" && rm $DEVRAM [ -d $TMPMNT ] && verbose "removing $TMPMNT" && rmdir $TMPMNT verbose "exit with code $1" exit $1 } trap " verbose 'Caught interrupt' echo 'Bye bye...' cleanup 1 " 1 2 3 15 create_init () { cat << 'INIT' > $TMPMNT/sbin/init #!/bin/bash # include in the path some dirs from the real root filesystem # for chroot, blockdev PATH="/sbin:/bin:/usr/sbin:/usr/bin:/lib/lvm-200:/initrd/bin:/initrd/sbin" PRE="initrd:" do_shell(){ /bin/echo /bin/echo "*** Entering LVM2 rescue shell. Exit shell to continue booting. ***" /bin/echo /bin/bash } echo "$PRE Remounting / read/write" mount -t ext2 -o remount,rw /dev/ram0 / # We need /proc for device mapper echo "$PRE Mounting /proc" mount -t proc none /proc # plug in modules listed in /etc/modules if [ -f /etc/modules ]; then echo -n "$PRE plugging in kernel modules:" cat /etc/modules | while read module; do echo -n " $module" modprobe $module done echo '.' fi # start raid devices if raid_autostart file exists if [ -f /etc/raid_autostart ]; then if [ ! -f /etc/mdadm/mdadm.conf ]; then mdoptions='--super-minor=dev' fi cat /etc/raid_autostart| while read dev; do echo "Starting RAID device $dev" /sbin/mdadm --assemble $dev $mdoptions done fi # Create the /dev/mapper/control device for the ioctl # interface using the major and minor numbers that have been allocated # dynamically. echo -n "$PRE Finding device mapper major and minor numbers " MAJOR=$(sed -n 's/^ *\([0-9]\+\) \+misc$/\1/p' /proc/devices) MINOR=$(sed -n 's/^ *\([0-9]\+\) \+device-mapper$/\1/p' /proc/misc) if test -n "$MAJOR" -a -n "$MINOR" ; then mkdir -p -m 755 /dev/mapper mknod -m 600 /dev/mapper/control c $MAJOR $MINOR fi echo "($MAJOR,$MINOR)" # Device-Mapper dynamically allocates all device numbers. This means it is possible # that the root volume specified to LILO or Grub may have a different number when the # initrd runs than when the system was last running. In order to make sure the # correct volume is mounted as root, the init script must determine what the # desired root volume name is by getting the LVM2 root volume name from the kernel command line. In order for # this to work correctly, "lvm2root=/dev/Volume_Group_Name/Root_Volume_Name" needs to be passed # to the kernel command line (where Root_Volume_Name is replaced by your actual # root volume's name. for arg in `cat /proc/cmdline`; do echo $arg | grep '^lvm2root=' > /dev/null if [ $? -eq 0 ]; then rootvol=${arg#lvm2root=} break fi done echo "$PRE Activating LVM2 volumes" # run a shell if we're passed lvm2rescue on commandline grep lvm2rescue /proc/cmdline 1>/dev/null 2>&1 if [ $? -eq 0 ]; then lvm vgchange --ignorelockingfailure -P -a y do_shell else lvm vgchange --ignorelockingfailure -a y fi echo "$PRE Mounting root filesystem $rootvol ro" mkdir /rootvol if ! mount -t auto -o ro $rootvol /rootvol; then echo "\t*FAILED*"; do_shell fi echo "$PRE Umounting /proc" umount /proc echo "$PRE Changing roots" cd /rootvol if ! pivot_root . initrd ; then echo "\t*FAILED*" do_shell fi echo "$PRE Proceeding with boot..." exec chroot . /bin/sh -c "umount /initrd; blockdev --flushbufs /dev/ram0 ; exec /sbin/init $*" < dev/console > dev/console 2>&1 INIT chmod 555 $TMPMNT/sbin/init } # create lvm.conf file from dumpconfig. Just use filter options create_lvmconf () { echo 'devices {' > $TMPMNT/etc/lvm/lvm.conf lvm dumpconfig | grep 'filter=' >> $TMPMNT/etc/lvm/lvm.conf echo '}' >> $TMPMNT/etc/lvm/lvm.conf } # # Main # cmd=`basename $0` VERSION=`uname -r` while [ $# -gt 0 ]; do case $1 in -h|--help) usage; exit 0;; -v|--verbose) VERBOSE="y";; -c|--lvmconf) LVMCONF=$2; shift;; -m|--modules) MODULES=$2; shift;; -e|--extra) EXTRAFILES=$2; shift;; -r|--raid) RAID=$2; shift;; -R|--raidconf) RAIDCONF=$2; shift;; -M|--makedev) MAKEDEV=$2; shift;; [2-9].[0-9]*.[0-9]*) VERSION=$1;; *) echo "$cmd -- invalid option '$1'"; usage; exit 0;; esac shift done INITRD=${INITRD:-"/boot/initrd-lvm2-$VERSION.gz"} echo "$cmd -- make LVM initial ram disk $INITRD" echo "" if [ -n "$RAID" ]; then BINFILES="$BINFILES /sbin/mdadm" RAIDCONF=${RAIDCONF:-"/etc/mdadm/mdadm.conf"} if [ -r $RAIDCONF ]; then EXTRAFILES="$EXTRAFILES $RAIDCONF" else echo "$cmd -- WARNING: No $RAIDCONF! Your RAID device minor numbers must match their superblock values!" fi fi # add modprobe if we declared any modules if [ -n "$MODULES" ]; then BINFILES="$BINFILES /sbin/modprobe /sbin/insmod /sbin/rmmod" fi for a in $BINFILES $EXTRAFILES; do if [ ! -r "$a" ] ; then echo "$cmd -- ERROR: you need $a" exit 1; fi; done # Figure out which shared libraries we actually need in our initrd echo "$cmd -- finding required shared libraries" verbose "BINFILES: `echo $BINFILES`" # We need to strip certain lines from ldd output. This is the full output of an example ldd: #lvmhost~ # ldd /sbin/lvm /bin/bash #/sbin/lvm: # not a dynamic executable #/bin/bash: # linux-gate.so.1 => (0xbfffe000) # libncurses.so.5 => /lib/libncurses.so.5 (0xb7ee3000) # libdl.so.2 => /lib/libdl.so.2 (0xb7edf000) # libc.so.6 => /lib/libc.so.6 (0xb7dc1000) # /lib/ld-linux.so.2 (0xb7f28000) # # 1) Lines with a ":" contain the name of the original binary we're examining, and so are unnecessary. # We need to strip them because they contain "/", and can be confused with links with a hardcoded path. # 2) The linux-gate library is a virtual dll that does not exist on disk, but is instead loaded automatically # into the process space, and can't be copied to the ramdisk # # After these lines have been stripped, we're interested in the lines remaining if they # 1) Contain "=>" because they are pathless links, and the value following the token is the path on the disk # 2) Contain "/" because it's a link with a hardcoded path, and so we're interested in the link itself. LIBFILES=`ldd $BINFILES 2>/dev/null |grep -v -E \(linux-gate\|:\) | awk '{if (/=>/) { print $3 } else if (/\//) { print $1 }}' | sort -u` if [ $? -ne 0 ]; then echo "$cmd -- ERROR figuring out needed shared libraries" exit 1 fi verbose "Shared libraries needed: `echo $LIBFILES`" INITRDFILES="$BINFILES $LIBFILES $MODULES $EXTRAFILES" # tack on stuff for modules if we declared any and the files exist if [ -n "$MODULES" ]; then if [ -f "/etc/modprobe.conf" ]; then INITRDFILES="$INITRDFILES /etc/modprobe.conf" fi if [ -f "/lib/modules/modprobe.conf" ]; then INITRDFILES="$INITRDFILES /lib/modules/modprobe.conf" fi fi # Calculate the the size of the ramdisk image. # Don't forget that inodes take up space too, as does the filesystem metadata. echo "$cmd -- calculating initrd filesystem parameters" if [ -z "$INITRDSIZE" ]; then echo "$cmd -- calculating loopback file size" verbose "finding size" INITRDSIZE="`du -Lck $INITRDFILES | tail -1 | cut -f 1`" verbose "minimum: $INITRDSIZE kB for files + inodes + filesystem metadata" INITRDSIZE=`expr $INITRDSIZE + 512` # enough for ext2 fs + a bit fi echo "$cmd -- making loopback file ($INITRDSIZE kB)" verbose "using $DEVRAM as a temporary loopback file" dd if=/dev/zero of=$DEVRAM count=$INITRDSIZE bs=1024 > /dev/null 2>&1 if [ $? -ne 0 ]; then echo "$cmd -- ERROR creating loopback file" cleanup 1 fi echo "$cmd -- making ram disk filesystem" verbose "mke2fs -F -m0 -L LVM-$VERSION $DEVRAM $INITRDSIZE" [ "$VERBOSE" ] && OPT_Q="" || OPT_Q="-q" mke2fs $OPT_Q -F -m0 -L LVM-$VERSION $DEVRAM $INITRDSIZE if [ $? -ne 0 ]; then echo "$cmd -- ERROR making ram disk filesystem" echo "$cmd -- ERROR you need to use mke2fs >= 1.14 or increase INITRDSIZE" cleanup 1 fi verbose "creating mountpoint $TMPMNT" mkdir $TMPMNT if [ $? -ne 0 ]; then echo "$cmd -- ERROR making $TMPMNT" cleanup 1 fi echo "$cmd -- mounting ram disk filesystem" verbose "mount -o loop $DEVRAM $TMPMNT" mount -oloop $DEVRAM $TMPMNT if [ $? -ne 0 ]; then echo "$cmd -- ERROR mounting $DEVRAM on $TMPMNT" cleanup 1 fi verbose "creating basic set of directories in $TMPMNT" (cd $TMPMNT; mkdir bin dev etc lib proc sbin var) if [ $? -ne 0 ]; then echo "$cmd -- ERROR creating directories in $TMPMNT" cleanup 1 fi # Add some /dev files. We have to handle different types of MAKEDEV invocations # here, so this is rather messy. RETCODE=0 echo "$cmd -- adding required /dev files" verbose "BASICDEVICES: `echo $BASICDEVICES`" verbose "BLOCKDEVICES: `echo $BLOCKDEVICES`" [ "$VERBOSE" ] && OPT_Q="-v" || OPT_Q="" case "$MAKEDEV" in debian) (cd $TMPMNT/dev; /dev/MAKEDEV $OPT_Q $BASICDEVICES $BLOCKDEVICES) RETCODE=$? ;; redhat) (cd $TMPMNT/dev; /dev/MAKEDEV $OPT_Q -d $TMPMNT/dev -m 2) RETCODE=$? ;; gentoo) (cd $TMPMNT/dev; /sbin/MAKEDEV $OPT_Q $BASICDEVICES $BLOCKDEVICES) RETCODE=$? ;; *) echo "$cmd -- ERROR: $MAKEDEV is not a known MAKEDEV style." RETCODE=1 ;; esac if [ $RETCODE -ne 0 ]; then echo "$cmd -- ERROR adding /dev files" cleanup 1 fi # copy necessary files to ram disk echo "$cmd -- copying initrd files to ram disk" [ "$VERBOSE" ] && OPT_Q="-v" || OPT_Q="--quiet" verbose "find \$INITRDFILES | cpio -pdmL $OPT_Q $TMPMNT" find $INITRDFILES | cpio -pdmL $OPT_Q $TMPMNT if [ $? -ne 0 ]; then echo "$cmd -- ERROR cpio to ram disk" cleanup 1 fi echo "$cmd -- creating symlinks to busybox" shopt -s extglob [ "$VERBOSE" ] && OPT_Q="-v" || OPT_Q="" BUSYBOXSYMLINKS=`busybox 2>&1| awk '/^Currently defined functions:$/ {i++;next} i'|tr ',\t\n' ' '` for link in ${BUSYBOXSYMLINKS//@(linuxrc|init|busybox)}; do ln -s $OPT_Q busybox $TMPMNT/bin/$link; done shopt -u extglob echo "$cmd -- creating new $TMPMNT/sbin/init" create_init if [ $? -ne 0 ]; then echo "$cmd -- ERROR creating init" cleanup exit 1 fi # copy LVMCONF into place or create a stripped down one from lvm dumpconfig mkdir -p $TMPMNT/etc/lvm if [ -n "$LVMCONF" ]; then echo "$cmd -- copying $LVMCONF to $TMPMNT/etc/lvm/lvm.conf" if [ -f "$LVMCONF" ]; then cp $LVMCONF $TMPMNT/etc/lvm/lvm.conf else echo "$cmd -- ERROR: $LVMCONF does not exist!" cleanup exit 1 fi else echo "$cmd -- creating new $TMPMNT/etc/lvm/lvm.conf" create_lvmconf fi if [ -n "$RAID" ]; then RAIDLIST="$TMPMNT/etc/raid_autostart" echo "$cmd -- creating $RAIDLIST file." for device in $RAID; do echo $device >> $RAIDLIST done fi # create modules.dep and /etc/modules files if needed if [ -n "$MODULES" ]; then echo "$cmd -- creating $MODDIR/modules.dep file and $TMPMNT/etc/modules" depmod -b $TMPMNT $VERSION for module in $MODULES; do basename $module | sed 's/\.k\{0,1\}o$//' >> $TMPMNT/etc/modules done fi verbose "removing $TMPMNT/lost+found" rmdir $TMPMNT/lost+found echo "$cmd -- ummounting ram disk" umount $DEVRAM if [ $? -ne 0 ]; then echo "$cmd -- ERROR umounting $DEVRAM" cleanup 1 fi echo "$cmd -- creating compressed initrd $INITRD" verbose "dd if=$DEVRAM bs=1k count=$INITRDSIZE | gzip -9" dd if=$DEVRAM bs=1k count=$INITRDSIZE 2>/dev/null | gzip -9 > $INITRD if [ $? -ne 0 ]; then echo "$cmd -- ERROR creating $INITRD" cleanup 1 fi cat << FINALTXT -------------------------------------------------------- Your initrd is ready in $INITRD Don't forget to set root=/dev/ram0 in kernel parameters Don't forget to set lvm2root=/dev/VG/LV in kernel parameters, where LV is your root volume If you use lilo try adding/modifying an entry similar to this one in lilo.conf: image=/boot/vmlinuz-lvm2-$VERSION label="ramdisk_LVM" initrd=/boot/initrd-lvm2-$VERSION.gz append="root=/dev/ram0 lvm2root=/dev/system/root " If using grub try adding/modifying an entry similar to this one in menu.lst title ramdisk LVM kernel /boot/vmlinuz-lvm2-$VERSION root=/dev/ram0 lvm2root=/dev/system/root initrd /boot/initrd-lvm2-$VERSION.gz You can also pass lvm2rescue to the kernel to get a shell -------------------------------------------------------- FINALTXT cleanup 0 lvm2-2.02.98/scripts/lvm2create_initrd/Makefile0000640000175000017500000000030612037016272020253 0ustar blankblankall: echo "Nothing to do for make all" manpage: pod2man --center="create LVM2 initrd" --name='lvm2create_initrd' --section=8 -r 'lvm2create_initrd' ./lvm2create_initrd.pod > lvm2create_initrd.8 lvm2-2.02.98/scripts/lvm2create_initrd/lvm2create_initrd.80000640000175000017500000003015112037016272022322 0ustar blankblank.\" Automatically generated by Pod::Man 2.23 (Pod::Simple 3.14) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is turned on, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .ie \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . nr % 0 . rr F .\} .el \{\ . de IX .. .\} .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "lvm2create_initrd 8" .TH lvm2create_initrd 8 "2011-11-12" "lvm2create_initrd" "create LVM2 initrd" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" lvm2create_initrd \- create initrd image for booting to root\e\-on\e\-LVM2 .SH "SYNOPSIS" .IX Header "SYNOPSIS" \&\fBlvm2create_initrd\fR [ \fB\-h|\-\-help\fR ] [ \fB\-v|\-\-verbose\fR ] [ \fB\-c|\-\-lvmconf\fR \fI/path/to/lvm.conf\fR ] [ \fB\-m|\-\-modules\fR "\fImodule1 module2 ...\fR" ] [ \fB\-e|\-\-extra\fR "\fIfile1 file2 ...\fR" ] [ \fB\-r|\-\-raid\fR "\fI/dev/md1 /dev/md2 ...\fR" ] [ \fB\-R|\-\-raidconf\fR \fI/path/to/mdadm.conf\fR ] [ \fB\-M|\-\-makedev\fR \fIstyle\fR ] .SH "DESCRIPTION" .IX Header "DESCRIPTION" lvm2create_initrd creates an initial ramdisk (initrd) image suitable for booting to system that has an \s-1LVM2\s0 volume as its root filesystem. .PP To boot to such a setup, you'll either need a bootloader that understands \s-1LVM2\s0 volumes, or you'll need a filesystem on a regular volume to act as a boot partition (typically mounted on /boot). .PP The resulting initrd image is fairly full-featured. It can harbor and load kernel modules, start \s-1MD\s0 devices, and boot to a shell to perform rescue operations. .SS "Booting to your initrd Image:" .IX Subsection "Booting to your initrd Image:" The filesystem image created is an ext2fs filesystem, hence your kernel must have ext2fs built into it statically in order to boot to the image. .PP Once you create your initrd image, you must pass the correct options to the kernel when you boot using it. Your kernel command line should look something like this: .PP \&\fBroot=/dev/ram0 lvm2root=/dev/rootvg/root [ lvm2rescue ]\fR .PP of course there may be other options. .IP "\fBroot=/dev/ram0\fR" 4 .IX Item "root=/dev/ram0" This option is required. It tells the kernel that the root filesystem should initially be set to the ramdisk (/dev/ram0). .IP "\fBlvm2root=/dev/rootvg/root\fR" 4 .IX Item "lvm2root=/dev/rootvg/root" This option is also required. It tells the initrd image which \s-1LVM2\s0 device the root filesystem is located on. .IP "\fBlvm2rescue\fR" 4 .IX Item "lvm2rescue" Causes the initrd image to run a shell prior to mounting the root filesystem. This is helpful in disaster situations where your initrd image is accessable, but there is a problem with the root filesystem (corrupted image, incorrect device setup, etc.). This option is (of course) optional. .SH "OPTIONS" .IX Header "OPTIONS" Most of parameters that can be set via command-line options can also be set via environment variables. Options specified on the command-line always take precedence. .IP "\fB\-h|\-\-help\fR" 4 .IX Item "-h|--help" Display short help text and exit. If used, other options are ignored. .IP "\fB\-v|\-\-verbose\fR" 4 .IX Item "-v|--verbose" Turn on extra verbosity for debugging, etc. .IP "\fB\-c|\-\-lvmconf\fR \fI/path/to/lvm.conf\fR" 4 .IX Item "-c|--lvmconf /path/to/lvm.conf" Specify an lvm.conf file to include in the image. This is useful if you have special device filters or other options you wish to use during the initrd stage. If this option is not included, then a lvm.conf file is created that contains only the current device filter from an \fBlvm dumpconfig\fR. This can also be set via the \fB\f(CB$LVMCONF\fB\fR environment variable. .ie n .IP "\fB\-m|\-\-modules\fR ""\fI/path/to/module1.ko /path/to/module2.ko ...\fR""" 4 .el .IP "\fB\-m|\-\-modules\fR ``\fI/path/to/module1.ko /path/to/module2.ko ...\fR''" 4 .IX Item "-m|--modules ""/path/to/module1.ko /path/to/module2.ko ...""" Specify modules to include and plug in during the initrd phase. This option takes a quoted, space-separated list of modules. Full pathnames are required. These modules are loaded into the kernel early in the initrd phase of the boot process. The current modprobe.conf file is also copied to the initrd image as well. This can also be specified via the \fB\f(CB$MODULES\fB\fR environment variable. .ie n .IP "\fB\-e|\-\-extra\fR ""\fI/path/to/file1 /path/to/file2 ...\fR""" 4 .el .IP "\fB\-e|\-\-extra\fR ``\fI/path/to/file1 /path/to/file2 ...\fR''" 4 .IX Item "-e|--extra ""/path/to/file1 /path/to/file2 ...""" Extra files that should be included in the initrd image. These files will be copied to the same location in the initrd image that they are in the current filesystem. Again full pathnames are required. This can also be specified via the \fB\f(CB$EXTRAFILES\fB\fR environment variable. .ie n .IP "\fB\-r|\-\-raid\fR ""\fI/dev/md1 /dev/md2...\fR""" 4 .el .IP "\fB\-r|\-\-raid\fR ``\fI/dev/md1 /dev/md2...\fR''" 4 .IX Item "-r|--raid ""/dev/md1 /dev/md2...""" \&\s-1RAID\s0 devices to be started prior to scanning for \s-1LVM2\s0 volume groups. If this option is used then then \fBmdadm\fR program must be installed. This can also be specified via the \fB\f(CB$RAID\fB\fR environment variable. .ie n .IP "\fB\-R|\-\-raidconf\fR ""\fI/path/to/mdadm.conf\fR""" 4 .el .IP "\fB\-R|\-\-raidconf\fR ``\fI/path/to/mdadm.conf\fR''" 4 .IX Item "-R|--raidconf ""/path/to/mdadm.conf""" Location of a mdadm.conf file to include. If this is not specified, then no files are included, and any devices specified with the \fB\-r\fR option above must have minor numbers that match their superblock values. This can also be specified via the \fB\f(CB$RAIDCONF\fB\fR environment variable. .IP "\fB\-M|\-\-makedev\fR \fIstyle\fR" 4 .IX Item "-M|--makedev style" Set \s-1MAKEDEV\s0 invocation style. The script currently supports 3 styles of \&\s-1MAKEDEV\s0 programs \fIdebian\fR, \fIredhat\fR and \fIgentoo\fR. The default is \fIdebian\fR. Set to \fIredhat\fR if using the RedHat/Fedora binary \s-1MAKEDEV\s0 program. \fIgentoo\fR has the same binary but in /sbin instead of /dev. Please send a bug report to maintainer if your distribution doesn't work with any of the current options. .SH "ENVIRONMENT VARIABLES" .IX Header "ENVIRONMENT VARIABLES" Most of the options to this script can be set via environment variables. In situations where both are set, then the command-line options take precedence. .ie n .IP "\fB\fB$LVMCONF\fB\fR" 4 .el .IP "\fB\f(CB$LVMCONF\fB\fR" 4 .IX Item "$LVMCONF" Same as \-c option. .ie n .IP "\fB\fB$MODULES\fB\fR" 4 .el .IP "\fB\f(CB$MODULES\fB\fR" 4 .IX Item "$MODULES" Same as \-m option. .ie n .IP "\fB\fB$EXTRAFILES\fB\fR" 4 .el .IP "\fB\f(CB$EXTRAFILES\fB\fR" 4 .IX Item "$EXTRAFILES" Same as \-e option. .ie n .IP "\fB\fB$RAID\fB\fR" 4 .el .IP "\fB\f(CB$RAID\fB\fR" 4 .IX Item "$RAID" Same as \-r option. .ie n .IP "\fB\fB$RAIDCONF\fB\fR" 4 .el .IP "\fB\f(CB$RAIDCONF\fB\fR" 4 .IX Item "$RAIDCONF" Same as \-R option. .ie n .IP "\fB\fB$MAKEDEV\fB\fR" 4 .el .IP "\fB\f(CB$MAKEDEV\fB\fR" 4 .IX Item "$MAKEDEV" Same as \-M option. .ie n .IP "\fB\fB$BASICDEVICES\fB\fR" 4 .el .IP "\fB\f(CB$BASICDEVICES\fB\fR" 4 .IX Item "$BASICDEVICES" Overrides the default value of \f(CW$BASICDEVICES\fR in the script (which is \*(L"std consoleonly fd\*(R"). These values are passed to the \fB\s-1MAKEDEV\s0\fR program to create device entries in the initrd image. .ie n .IP "\fB\fB$BLOCKDEVICES\fB\fR" 4 .el .IP "\fB\f(CB$BLOCKDEVICES\fB\fR" 4 .IX Item "$BLOCKDEVICES" Overrides the default value of \f(CW$BLOCKDEVICES\fR in the script (which is \*(L"md hda hdb hdc hdd sda sdb sdc sdd\*(R"). This value is passed to the \fB\s-1MAKEDEV\s0\fR program to create device entries in the initrd image. .ie n .IP "\fB\fB$BINFILES\fB\fR" 4 .el .IP "\fB\f(CB$BINFILES\fB\fR" 4 .IX Item "$BINFILES" Overrides the default value of \f(CW$BINFILES\fR (which is \*(L"/lib/lvm\-200/lvm /bin/bash /bin/busybox /sbin/pivot_root\*(R"). The difference between using this and adding a file to the \f(CW$EXTRAFILES\fR list above is that libraries that these depend upon are also included. You can still use \f(CW$EXTRAFILES\fR to achieve the same effect, but you must resolve library dependencies youself. .ie n .IP "\fB\fB$INITRDSIZE\fB\fR" 4 .el .IP "\fB\f(CB$INITRDSIZE\fB\fR" 4 .IX Item "$INITRDSIZE" Force a particular size for your initrd image. The default is to total up the size of the included files and to add 512K as a buffer. .SH "BUGS" .IX Header "BUGS" I don't like having to specify a \-M option to set the \s-1MAKEDEV\s0 style, but I know of no way to reliably detect what type of \s-1MAKEDEV\s0 is being used. We'll probably have to add other \s-1MAKEDEV\s0 styles in the future as this script is tested on other distributions. .SH "AUTHORS" .IX Header "AUTHORS" The script was originally written by Miguel Cabeca, with significant improvements by Jeffrey Layton. Comments, bug reports and patches should be sent to Jeffrey Layton at \fBjtlayton@poochiereds.net\fR. .SH "SEE ALSO" .IX Header "SEE ALSO" \&\fB\s-1MAKEDEV\s0\fR(8), \fBmdadm\fR(8), \fBbusybox\fR(8), \fBlvm.conf\fR(5) lvm2-2.02.98/scripts/lvm2create_initrd/lvm2create_initrd.pod0000640000175000017500000001456112037016272022744 0ustar blankblank=head1 NAME lvm2create_initrd - create initrd image for booting to root\-on\-LVM2 =head1 SYNOPSIS B [ B<-h|--help> ] [ B<-v|--verbose> ] [ B<-c|--lvmconf> I ] [ B<-m|--modules> "I" ] [ B<-e|--extra> "I" ] [ B<-r|--raid> "I" ] [ B<-R|--raidconf> I ] [ B<-M|--makedev> I