├── .github ├── actions │ └── spelling │ │ ├── expect.txt │ │ ├── only.txt │ │ └── patterns.txt └── workflows │ ├── abi-stable.yaml │ ├── abi.yaml │ ├── build-and-unittest.yaml │ ├── coverity.yaml │ ├── foreign.yaml │ ├── multiarch-stable.yaml │ ├── multiarch.yaml │ ├── native.yaml │ ├── rolling.yaml │ └── spelling.yml ├── .gitignore ├── .mailmap ├── COPYING ├── LICENSES ├── GPL-2.0 ├── GPL-3.0 ├── LGPL-2.0 └── LGPL-2.1 ├── Makefile ├── Makefile.inc ├── NEWS.md ├── README.md ├── create-config.mk ├── kpartx ├── Makefile ├── bsd.c ├── byteorder.h ├── crc32.c ├── crc32.h ├── dasd.c ├── dasd.h ├── del-part-nodes.rules ├── devmapper.c ├── devmapper.h ├── dm-parts.rules ├── dos.c ├── dos.h ├── efi.h ├── gpt.c ├── gpt.h ├── kpartx.8 ├── kpartx.c ├── kpartx.h ├── kpartx.rules.in ├── kpartx_id ├── lopart.c ├── lopart.h ├── mac.c ├── mac.h ├── ps3.c ├── solaris.c ├── sun.c ├── test-kpartx ├── unixware.c ├── xstrncpy.c └── xstrncpy.h ├── libdmmp ├── DEV_NOTES ├── Makefile ├── docs │ ├── doc-preclean.pl │ ├── kernel-doc │ ├── man │ │ ├── dmmp_context_free.3 │ │ ├── dmmp_context_log_func_set.3 │ │ ├── dmmp_context_log_priority_get.3 │ │ ├── dmmp_context_log_priority_set.3 │ │ ├── dmmp_context_new.3 │ │ ├── dmmp_context_timeout_get.3 │ │ ├── dmmp_context_timeout_set.3 │ │ ├── dmmp_context_userdata_get.3 │ │ ├── dmmp_context_userdata_set.3 │ │ ├── dmmp_flush_mpath.3 │ │ ├── dmmp_last_error_msg.3 │ │ ├── dmmp_log_priority_str.3 │ │ ├── dmmp_mpath_array_free.3 │ │ ├── dmmp_mpath_array_get.3 │ │ ├── dmmp_mpath_kdev_name_get.3 │ │ ├── dmmp_mpath_name_get.3 │ │ ├── dmmp_mpath_wwid_get.3 │ │ ├── dmmp_path_array_get.3 │ │ ├── dmmp_path_blk_name_get.3 │ │ ├── dmmp_path_group_array_get.3 │ │ ├── dmmp_path_group_id_get.3 │ │ ├── dmmp_path_group_priority_get.3 │ │ ├── dmmp_path_group_selector_get.3 │ │ ├── dmmp_path_group_status_get.3 │ │ ├── dmmp_path_group_status_str.3 │ │ ├── dmmp_path_status_get.3 │ │ ├── dmmp_path_status_str.3 │ │ ├── dmmp_reconfig.3 │ │ ├── dmmp_strerror.3 │ │ └── libdmmp.h.3 │ └── split-man.pl ├── libdmmp.c ├── libdmmp.pc.in ├── libdmmp │ └── libdmmp.h ├── libdmmp_misc.c ├── libdmmp_mp.c ├── libdmmp_path.c ├── libdmmp_pg.c ├── libdmmp_private.h └── test │ ├── Makefile │ ├── libdmmp_speed_test.c │ └── libdmmp_test.c ├── libmpathcmd ├── Makefile ├── libmpathcmd.version ├── mpath_cmd.c └── mpath_cmd.h ├── libmpathpersist ├── Makefile ├── libmpathpersist.version ├── mpath_persist.c ├── mpath_persist.h ├── mpath_persist_int.c ├── mpath_persist_int.h ├── mpath_persistent_reserve_in.3 ├── mpath_persistent_reserve_out.3 ├── mpath_pr_ioctl.c ├── mpath_pr_ioctl.h ├── mpath_updatepr.c └── mpathpr.h ├── libmpathutil ├── Makefile ├── debug.c ├── debug.h ├── globals.c ├── globals.h ├── libmpathutil.version ├── log.c ├── log.h ├── log_pthread.c ├── log_pthread.h ├── msort.c ├── msort.h ├── parser.c ├── parser.h ├── strbuf.c ├── strbuf.h ├── time-util.c ├── time-util.h ├── util.c ├── util.h ├── uxsock.c ├── uxsock.h ├── vector.c └── vector.h ├── libmpathvalid ├── Makefile ├── libmpathvalid.version ├── mpath_valid.c └── mpath_valid.h ├── libmultipath ├── Makefile ├── alias.c ├── alias.h ├── blacklist.c ├── blacklist.h ├── byteorder.h ├── checkers.c ├── checkers.h ├── checkers │ ├── Makefile │ ├── cciss.h │ ├── cciss_tur.c │ ├── directio.c │ ├── directio.h │ ├── emc_clariion.c │ ├── emc_clariion.h │ ├── hp_sw.c │ ├── hp_sw.h │ ├── rdac.c │ ├── rdac.h │ ├── readsector0.c │ ├── readsector0.h │ ├── tur.c │ └── tur.h ├── config.c ├── config.h ├── configure.c ├── configure.h ├── defaults.c ├── defaults.h ├── devmapper.c ├── devmapper.h ├── dict.c ├── dict.h ├── discovery.c ├── discovery.h ├── dm-generic.c ├── dm-generic.h ├── dmparser.c ├── dmparser.h ├── file.c ├── file.h ├── foreign.c ├── foreign.h ├── foreign │ ├── Makefile │ └── nvme.c ├── generic.c ├── generic.h ├── hwtable.c ├── hwtable.h ├── io_err_stat.c ├── io_err_stat.h ├── libmultipath.version ├── libsg.c ├── libsg.h ├── list.h ├── lock.c ├── lock.h ├── nvme-lib.c ├── nvme-lib.h ├── nvme │ ├── argconfig.h │ ├── json.h │ ├── linux │ │ ├── nvme.h │ │ └── nvme_ioctl.h │ ├── nvme-ioctl.c │ ├── nvme-ioctl.h │ ├── nvme.h │ └── plugin.h ├── pgpolicies.c ├── pgpolicies.h ├── print.c ├── print.h ├── prio.c ├── prio.h ├── prioritizers │ ├── Makefile │ ├── alua.c │ ├── alua.h │ ├── alua_rtpg.c │ ├── alua_rtpg.h │ ├── alua_spc3.h │ ├── ana.c │ ├── const.c │ ├── datacore.c │ ├── emc.c │ ├── hds.c │ ├── hp_sw.c │ ├── iet.c │ ├── ontap.c │ ├── path_latency.c │ ├── random.c │ ├── rdac.c │ ├── sysfs.c │ ├── weightedpath.c │ └── weightedpath.h ├── prkey.c ├── prkey.h ├── propsel.c ├── propsel.h ├── sg_include.h ├── structs.c ├── structs.h ├── structs_vec.c ├── structs_vec.h ├── switchgroup.c ├── switchgroup.h ├── sysfs.c ├── sysfs.h ├── uevent.c ├── uevent.h ├── unaligned.h ├── valid.c ├── valid.h ├── version.h ├── wwids.c └── wwids.h ├── mpathpersist ├── Makefile ├── main.c ├── main.h └── mpathpersist.8.in ├── multipath ├── 11-dm-mpath.rules.in ├── 99-z-dm-mpath-late.rules ├── Makefile ├── main.c ├── modules-load.conf ├── multipath.8.in ├── multipath.conf.5.in ├── multipath.rules.in ├── scsi_dh.conf └── tmpfiles.conf.in ├── multipathd ├── Makefile ├── callbacks.c ├── cli.c ├── cli.h ├── cli_handlers.c ├── cli_handlers.h ├── dmevents.c ├── dmevents.h ├── fpin.h ├── fpin_handlers.c ├── init_unwinder.c ├── init_unwinder.h ├── main.c ├── main.h ├── multipathc.8 ├── multipathc.c ├── multipathd.8.in ├── multipathd.service.in ├── multipathd.socket ├── pidfile.c ├── pidfile.h ├── uxclnt.c ├── uxclnt.h ├── uxlsnr.c ├── uxlsnr.h ├── waiter.c └── waiter.h ├── rules.mk ├── tests ├── Makefile ├── README.md ├── alias.c ├── blacklist.c ├── cli.c ├── devt.c ├── directio.c ├── dmevents.c ├── features.c ├── globals.c ├── hwtable.c ├── mapinfo.c ├── mpathvalid.c ├── parser.c ├── pgpolicy.c ├── strbuf.c ├── sysfs.c ├── test-lib.c ├── test-lib.h ├── test-log.c ├── test-log.h ├── uevent.c ├── unaligned.c ├── util.c ├── valid.c ├── vpd.c └── wrap64.h └── third-party └── valgrind ├── drd.h ├── mpath-tools.supp └── valgrind.h /.github/actions/spelling/only.txt: -------------------------------------------------------------------------------- 1 | # Files to check - see on.push.paths in spelling.yml 2 | # public header files 3 | libdmmp\.h 4 | mpath_valid\.h 5 | mpath_cmd\.h 6 | mpath_persist\.h 7 | # udev rules 8 | \.rules 9 | \.rules\.in 10 | # systemd unit files 11 | \.service 12 | \.service\.in 13 | \.socket 14 | # man pages 15 | \.[358] 16 | \.[358]\.in 17 | README\.md 18 | NEWS\.md 19 | -------------------------------------------------------------------------------- /.github/actions/spelling/patterns.txt: -------------------------------------------------------------------------------- 1 | # https://www.gnu.org/software/groff/manual/groff.html 2 | # man troff content 3 | \\f[BCIPR] 4 | # '/" 5 | \\\([ad]q 6 | 7 | # uuid: 8 | \b[0-9a-fA-F]{8}-(?:[0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}\b 9 | 10 | # WWNN/WWPN (NAA identifiers) 11 | \b(?:0x)?10[0-9a-f]{14}\b 12 | \b(?:0x|3)?[25][0-9a-f]{15}\b 13 | \b(?:0x|3)?6[0-9a-f]{31}\b 14 | 15 | # iSCSI iqn (approximate regex) 16 | \biqn\.[0-9]{4}-[0-9]{2}(?:[\.-][a-z][a-z0-9]*)*\b 17 | 18 | # identifiers 19 | \bCODESET_UTF8\b 20 | \bdev_loss_tmo\b 21 | \bdmmp_mps\b 22 | \bdmmp_pgs\b 23 | \bdmmp_mpath_kdev_name_get\b 24 | \bfast_io_fail_tmo\b 25 | \blibmp_mapinfo\b 26 | \bLimitRTPRIO=?\b 27 | \bmax_fds\b 28 | \bmissing_uev_wait_timeout\b 29 | \bMPATH_MAX_PARAM_LEN\b 30 | \bMPATH_MX_TIDS\b 31 | \bMPATH_MX_TID_LEN\b 32 | \bMPATH_PRIN_RKEY_SA\b 33 | \bMPATH_PRIN_RRES_SA\b 34 | \bMPATH_PRIN_RCAP_SA\b 35 | \bMPATH_PRIN_RFSTAT_SA\b 36 | \bMPATH_PROUT_REG_SA\b 37 | \bMPATH_PROUT_RES_SA\b 38 | \bMPATH_PROUT_REL_SA\b 39 | \bMPATH_PROUT_CLEAR_SA\b 40 | \bMPATH_PROUT_PREE_SA\b 41 | \bMPATH_PROUT_PREE_AB_SA\b 42 | \bMPATH_PROUT_REG_IGN_SA\b 43 | \bMPATH_PROUT_REG_MOV_SA\b 44 | \bMPATH_LU_SCOPE\b 45 | \bMPATH_PRTPE_WE\b 46 | \bMPATH_PRTPE_EA\b 47 | \bMPATH_PRTPE_WE_RO\b 48 | \bMPATH_PRTPE_EA_RO\b 49 | \bMPATH_PRTPE_WE_AR\b 50 | \bMPATH_PRTPE_EA_AR\b 51 | \bMPATH_PR_SKIP\b 52 | \bMPATH_PR_SUCCESS\b 53 | \bMPATH_PR_SYNTAX_ERROR\b 54 | \bMPATH_PR_SENSE_NOT_READY\b 55 | \bMPATH_PR_SENSE_MEDIUM_ERROR\b 56 | \bMPATH_PR_SENSE_HARDWARE_ERROR\b 57 | \bMPATH_PR_ILLEGAL_REQ\b 58 | \bMPATH_PR_SENSE_UNIT_ATTENTION\b 59 | \bMPATH_PR_SENSE_INVALID_OP\b 60 | \bMPATH_PR_SENSE_ABORTED_COMMAND\b 61 | \bMPATH_PR_NO_SENSE\b 62 | \bMPATH_PR_SENSE_MALFORMED\b 63 | \bMPATH_PR_RESERV_CONFLICT\b 64 | \bMPATH_PR_FILE_ERROR\b 65 | \bMPATH_PR_DMMP_ERROR\b 66 | \bMPATH_PR_THREAD_ERROR\b 67 | \bMPATH_PR_OTHER\b 68 | \bMPATH_F_APTPL_MASK\b 69 | \bMPATH_F_ALL_TG_PT_MASK\b 70 | \bMPATH_F_SPEC_I_PT_MASK\b 71 | \bMPATH_PR_TYPE_MASK\b 72 | \bMPATH_PR_SCOPE_MASK\b 73 | \bMPATH_PROTOCOL_ID_FC\b 74 | \bMPATH_PROTOCOL_ID_ISCSI\b 75 | \bMPATH_PROTOCOL_ID_SAS\b 76 | \bMPATH_WWUI_DEVICE_NAME\b 77 | \bMPATH_WWUI_PORT_IDENTIFIER\b 78 | \bmpath_persistent_reserve_init_vecs\b 79 | \bmpath_persistent_reserve_free_vecs\b 80 | \bmpath_recv_reply\b 81 | \bmpath_recv_reply_len\b 82 | \bmpath_recv_reply_data\b 83 | \bMPATHTEST_VERBOSITY\b 84 | \bprkeys_file\b 85 | \bprout-type\b 86 | \bprin_capdescr\b 87 | \bprin_readresv\b 88 | \bprin_resvdescr\b 89 | \bprout_param_descriptor\b 90 | \brq_servact\b 91 | \bRLIMIT_RTPRIO\b 92 | \bSCHED_RT_PRIO\b 93 | \bssize_t\b 94 | \btrnptid_list\b 95 | \buxsock_timeout\b 96 | 97 | # Other 98 | \bTutf8\b 99 | \bUTF-8\b 100 | \bCLARiiON\b 101 | \bGPLv2\b 102 | \bHBAs\b 103 | \bSANtricity\b 104 | \bVTrak\b 105 | \bXSG1\b 106 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /.github/workflows/abi-stable.yaml: -------------------------------------------------------------------------------- 1 | name: check-abi for stable branch 2 | on: 3 | push: 4 | branches: 5 | - 'stable-*' 6 | paths: 7 | - '.github/workflows/abi-stable.yaml' 8 | - '**.h' 9 | - '**.c' 10 | - '**.version' 11 | pull_request: 12 | branches: 13 | - 'stable-*' 14 | workflow_dispatch: 15 | 16 | jobs: 17 | reference-abi: 18 | runs-on: ubuntu-20.04 19 | steps: 20 | - name: get parent tag 21 | run: > 22 | echo ${{ github.ref }} | 23 | sed -E 's,refs/heads/stable-([0-9]\.[0-9]*)\.y,PARENT_TAG=\1.0,' >> $GITHUB_ENV 24 | - name: assert parent tag 25 | run: /bin/false 26 | if: ${{ env.PARENT_TAG == '' }} 27 | - name: update 28 | run: sudo apt-get update 29 | - name: dependencies 30 | run: > 31 | sudo apt-get install --yes gcc 32 | gcc make pkg-config abigail-tools 33 | libdevmapper-dev libreadline-dev libaio-dev libsystemd-dev 34 | libudev-dev libjson-c-dev liburcu-dev libcmocka-dev libedit-dev 35 | - name: checkout ${{ env.PARENT_TAG }} 36 | uses: actions/checkout@v4 37 | with: 38 | ref: ${{ env.PARENT_TAG }} 39 | - name: build ABI for ${{ env.PARENT_TAG }} 40 | run: make -j$(grep -c ^processor /proc/cpuinfo) -Orecurse abi 41 | - name: save ABI 42 | uses: actions/upload-artifact@v4 43 | with: 44 | name: multipath-abi-${{ env.PARENT_TAG }} 45 | path: abi 46 | 47 | check-abi: 48 | runs-on: ubuntu-20.04 49 | needs: reference-abi 50 | steps: 51 | - name: get parent tag 52 | run: > 53 | echo ${{ github.ref }} | 54 | sed -E 's,refs/heads/stable-([0-9]\.[0-9]*)\.y,PARENT_TAG=\1.0,' >> $GITHUB_ENV 55 | - name: assert parent tag 56 | run: /bin/false 57 | if: ${{ env.PARENT_TAG == '' }} 58 | - name: checkout ${{ env.PARENT_TAG }} 59 | uses: actions/checkout@v4 60 | with: 61 | ref: ${{ env.PARENT_TAG }} 62 | - name: download ABI for ${{ env.PARENT_TAG }} 63 | id: download_abi 64 | uses: actions/download-artifact@v4 65 | with: 66 | name: multipath-abi-${{ env.PARENT_TAG }} 67 | path: reference-abi 68 | - name: update 69 | run: sudo apt-get update 70 | if: steps.download_abi.outcome != 'success' 71 | - name: dependencies 72 | run: > 73 | sudo apt-get install --yes gcc 74 | gcc make pkg-config abigail-tools 75 | libdevmapper-dev libreadline-dev libaio-dev libsystemd-dev 76 | libudev-dev libjson-c-dev liburcu-dev libcmocka-dev libedit-dev 77 | - name: check ABI of ${{ github.ref }} against ${{ env.PARENT_TAG }} 78 | id: check_abi 79 | run: make -j$(grep -c ^processor /proc/cpuinfo) -Orecurse abi-test 80 | continue-on-error: true 81 | - name: save differences 82 | if: ${{ steps.check_abi.outcome != 'success' }} 83 | uses: actions/upload-artifact@v4 84 | with: 85 | name: abi-test 86 | path: abi-test 87 | - name: fail 88 | run: /bin/false 89 | if: steps.check_abi.outcome != 'success' 90 | -------------------------------------------------------------------------------- /.github/workflows/abi.yaml: -------------------------------------------------------------------------------- 1 | name: check-abi 2 | on: 3 | push: 4 | branches: 5 | - queue 6 | - abi 7 | paths: 8 | - '.github/workflows/abi.yaml' 9 | - '**.h' 10 | - '**.c' 11 | pull_request: 12 | branches: 13 | - master 14 | - queue 15 | workflow_dispatch: 16 | env: 17 | ABI_BRANCH: ${{ secrets.ABI_BRANCH }} 18 | 19 | jobs: 20 | save-and-test-ABI: 21 | runs-on: ubuntu-20.04 22 | steps: 23 | - name: set ABI branch 24 | if: ${{ env.ABI_BRANCH == '' }} 25 | run: echo "ABI_BRANCH=master" >> $GITHUB_ENV 26 | - name: checkout 27 | uses: actions/checkout@v4 28 | - name: get reference ABI 29 | id: reference 30 | continue-on-error: true 31 | uses: dawidd6/action-download-artifact@v6 32 | with: 33 | workflow: abi.yaml 34 | branch: ${{ env.ABI_BRANCH }} 35 | name: abi 36 | path: reference-abi 37 | - name: update 38 | run: sudo apt-get update 39 | - name: dependencies 40 | run: > 41 | sudo apt-get install --yes gcc 42 | gcc make pkg-config abigail-tools 43 | libdevmapper-dev libreadline-dev libaio-dev libsystemd-dev 44 | libudev-dev libjson-c-dev liburcu-dev libcmocka-dev libedit-dev 45 | - name: create ABI 46 | run: make -Orecurse -j$(grep -c ^processor /proc/cpuinfo) abi.tar.gz 47 | - name: save ABI 48 | uses: actions/upload-artifact@v4 49 | with: 50 | name: abi 51 | path: abi 52 | overwrite: true 53 | - name: compare ABI against reference 54 | id: compare 55 | continue-on-error: true 56 | if: ${{ steps.reference.outcome == 'success' }} 57 | run: make abi-test 58 | - name: save differences 59 | if: ${{ steps.compare.outcome == 'failure' }} 60 | uses: actions/upload-artifact@v4 61 | with: 62 | name: abi-test 63 | path: abi-test 64 | overwrite: true 65 | 66 | - name: fail 67 | # MUST use >- here, otherwise the condition always evaluates to true 68 | if: >- 69 | ${{ 70 | env.ABI_BRANCH != github.ref_name && 71 | (steps.reference.outcome == 'failure' || 72 | steps.compare.outcome == 'failure') 73 | }} 74 | run: false 75 | -------------------------------------------------------------------------------- /.github/workflows/coverity.yaml: -------------------------------------------------------------------------------- 1 | name: coverity 2 | on: 3 | push: 4 | branches: 5 | - coverity 6 | 7 | jobs: 8 | upload-coverity-scan: 9 | runs-on: ubuntu-22.04 10 | steps: 11 | - name: checkout 12 | uses: actions/checkout@v4 13 | - name: dependencies 14 | run: > 15 | sudo apt-get install --yes 16 | gcc make pkg-config 17 | libdevmapper-dev libreadline-dev libaio-dev libsystemd-dev 18 | libudev-dev libjson-c-dev liburcu-dev libcmocka-dev libedit-dev 19 | - name: download coverity 20 | run: > 21 | curl -o cov-analysis-linux64.tar.gz 22 | --form token="$COV_TOKEN" 23 | --form project="$COV_PROJECT" 24 | https://scan.coverity.com/download/cxx/linux64 25 | env: 26 | COV_TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }} 27 | COV_PROJECT: ${{ secrets.COVERITY_SCAN_PROJECT }} 28 | - name: unpack coverity 29 | run: | 30 | mkdir -p coverity 31 | tar xfz cov-analysis-linux64.tar.gz --strip 1 -C coverity 32 | - name: build with cov-build 33 | run: > 34 | PATH="$PWD/coverity/bin:$PATH" 35 | cov-build --dir cov-int make -Orecurse -j"$(grep -c ^processor /proc/cpuinfo)" 36 | - name: pack results 37 | run: tar cfz multipath-tools.tgz cov-int 38 | - name: submit results 39 | run: > 40 | curl 41 | --form token="$COV_TOKEN" 42 | --form email="$COV_EMAIL" 43 | --form file="@multipath-tools.tgz" 44 | --form version="${{ github.ref_name }}" 45 | --form description="$(git describe --tags --match "0.*")" 46 | --form project="$COV_PROJECT" 47 | https://scan.coverity.com/builds 48 | env: 49 | COV_TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }} 50 | COV_PROJECT: ${{ secrets.COVERITY_SCAN_PROJECT }} 51 | COV_EMAIL: ${{ secrets.COVERITY_SCAN_EMAIL }} 52 | -------------------------------------------------------------------------------- /.github/workflows/multiarch-stable.yaml: -------------------------------------------------------------------------------- 1 | name: multiarch test for stable distros 2 | on: 3 | push: 4 | branches: 5 | - master 6 | - queue 7 | - tip 8 | - 'stable-*' 9 | paths: 10 | - '.github/workflows/multiarch-stable.yaml' 11 | - '**.h' 12 | - '**.c' 13 | - '**Makefile*' 14 | - '**.mk' 15 | pull_request: 16 | branches: 17 | - master 18 | - queue 19 | - 'stable-*' 20 | paths: 21 | - '.github/workflows/multiarch-stable.yaml' 22 | - '**.h' 23 | - '**.c' 24 | - '**Makefile*' 25 | - '**.mk' 26 | jobs: 27 | 28 | build-old: 29 | runs-on: ubuntu-22.04 30 | strategy: 31 | fail-fast: false 32 | matrix: 33 | os: 34 | - debian-bookworm 35 | - debian-buster 36 | - ubuntu-trusty 37 | arch: [386, arm/v7] 38 | include: 39 | - os: debian-bookworm 40 | arch: aarch64 41 | - os: debian-bookworm 42 | arch: s390x 43 | - os: debian-bookworm 44 | arch: ppc64le 45 | steps: 46 | - name: checkout 47 | uses: actions/checkout@v4 48 | - name: enable foreign arch 49 | uses: dbhi/qus/action@main 50 | - name: compile and run unit tests 51 | uses: mosteo-actions/docker-run@v1 52 | with: 53 | image: ghcr.io/mwilck/multipath-build-${{ matrix.os }} 54 | guest-dir: /build 55 | host-dir: ${{ github.workspace }} 56 | command: test 57 | params: "--platform linux/${{ matrix.arch }}" 58 | pull-params: "--platform linux/${{ matrix.arch }}" 59 | -------------------------------------------------------------------------------- /.github/workflows/multiarch.yaml: -------------------------------------------------------------------------------- 1 | name: multiarch test for rolling distros 2 | on: 3 | push: 4 | branches: 5 | - master 6 | - queue 7 | - tip 8 | - 'stable-*' 9 | paths: 10 | - '.github/workflows/multiarch.yaml' 11 | - '**.h' 12 | - '**.c' 13 | - '**Makefile*' 14 | - '**.mk' 15 | pull_request: 16 | branches: 17 | - master 18 | - queue 19 | - 'stable-*' 20 | paths: 21 | - '.github/workflows/multiarch.yaml' 22 | - '**.h' 23 | - '**.c' 24 | - '**Makefile*' 25 | - '**.mk' 26 | # run monthly to catch rolling distro changes 27 | schedule: 28 | - cron: '45 02 1 * *' 29 | 30 | jobs: 31 | 32 | build-current: 33 | runs-on: ubuntu-22.04 34 | strategy: 35 | fail-fast: false 36 | matrix: 37 | os: 38 | - alpine 39 | - debian-sid 40 | - fedora-rawhide 41 | - opensuse-tumbleweed 42 | arch: [amd64, ppc64le, aarch64, s390x, 386, arm/v7] 43 | exclude: 44 | - os: fedora-rawhide 45 | arch: 386 46 | - os: fedora-rawhide 47 | arch: arm/v7 48 | steps: 49 | - name: checkout 50 | uses: actions/checkout@v4 51 | - name: enable foreign arch 52 | uses: dbhi/qus/action@main 53 | - name: compile and run unit tests 54 | uses: mosteo-actions/docker-run@v1 55 | with: 56 | image: ghcr.io/mwilck/multipath-build-${{ matrix.os }} 57 | guest-dir: /build 58 | host-dir: ${{ github.workspace }} 59 | command: test 60 | params: "--platform linux/${{ matrix.arch }}" 61 | pull-params: "--platform linux/${{ matrix.arch }}" 62 | 63 | -------------------------------------------------------------------------------- /.github/workflows/rolling.yaml: -------------------------------------------------------------------------------- 1 | name: compile and unit test on rolling distros 2 | on: 3 | push: 4 | branches: 5 | - master 6 | - queue 7 | - tip 8 | - 'stable-*' 9 | paths: 10 | - '.github/workflows/rolling.yaml' 11 | - '**.h' 12 | - '**.c' 13 | - '**Makefile*' 14 | - '**.mk' 15 | pull_request: 16 | branches: 17 | - master 18 | - queue 19 | - 'stable-*' 20 | paths: 21 | - '.github/workflows/rolling.yaml' 22 | - '**.h' 23 | - '**.c' 24 | - '**Makefile*' 25 | - '**.mk' 26 | # run weekly to catch rolling distro changes 27 | schedule: 28 | - cron: '30 06 * * 1' 29 | 30 | jobs: 31 | rolling: 32 | runs-on: ubuntu-22.04 33 | strategy: 34 | fail-fast: false 35 | matrix: 36 | os: 37 | - debian-sid 38 | - alpine 39 | - opensuse-tumbleweed 40 | - fedora-rawhide 41 | container: ghcr.io/mwilck/multipath-build-${{ matrix.os }} 42 | steps: 43 | - name: checkout 44 | uses: actions/checkout@v4 45 | - name: build and test 46 | run: make READLINE=libreadline -j -Orecurse test 47 | - name: clean 48 | run: make -j -Orecurse clean 49 | - name: clang 50 | env: 51 | CC: clang 52 | run: make READLINE=libedit -j -Orecurse test 53 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | .dotest 3 | *~ 4 | *.so 5 | *.so.0 6 | *.abi 7 | *.a 8 | *.gz 9 | *.d 10 | \#* 11 | compile_commands.json 12 | config.mk 13 | cscope.files 14 | cscope.out 15 | kpartx/kpartx 16 | kpartx/kpartx.rules 17 | multipath/multipath 18 | multipath/multipath.8 19 | multipath/multipath.conf.5 20 | multipath/multipath.rules 21 | multipath/11-dm-mpath.rules 22 | multipath/tmpfiles.conf 23 | multipathd/multipathd 24 | multipathd/multipathd.8 25 | multipathd/multipathc 26 | multipathd/multipathd.service 27 | mpathpersist/mpathpersist 28 | mpathpersist/mpathpersist.8 29 | abi.tar.gz 30 | abi 31 | abi-test 32 | compile_commands.json 33 | .nfs* 34 | *.swp 35 | *.patch 36 | *.rej 37 | *.orig 38 | libdmmp/docs/man/*.3.gz 39 | libdmmp/*.so.* 40 | libdmmp/test/libdmmp_test 41 | libdmmp/test/libdmmp_speed_test 42 | tests/*-test 43 | tests/*.out 44 | tests/*.vgr 45 | tests/test-lib.o.wrap 46 | tests/test-log.o.wrap 47 | libmultipath/nvme-ioctl.c 48 | libmultipath/nvme-ioctl.h 49 | libmultipath/autoconfig.h 50 | */*-nv.version 51 | reference-abi 52 | -------------------------------------------------------------------------------- /.mailmap: -------------------------------------------------------------------------------- 1 | # 2 | # This list is used by git-shortlog to fix a few botched name translations 3 | # in the git archive, either because the author's full name was messed up 4 | # and/or not always written the same way, making contributions from the 5 | # same person appearing not to be so or badly displayed. Also allows for 6 | # old email addresses to map to new email addresses. 7 | # 8 | # For format details, see "MAPPING AUTHORS" in "man git-shortlog". 9 | # 10 | # Please keep this list dictionary sorted. 11 | # 12 | Bart Van Assche 13 | Bart Van Assche 14 | Benjamin Marzinski 15 | Benjamin Marzinski 16 | Benjamin Marzinski bmarzins@sourceware.org 17 | Chongyun Wu Wuchongyun 18 | Chongyun Wu 19 | Christophe Varoqui 20 | Christophe Varoqui 21 | Christophe Varoqui 22 | Christophe Varoqui 23 | Christophe Varoqui root 24 | Christophe Varoqui root 25 | Christophe Varoqui root 26 | Christophe Varoqui 27 | Hannes Reinecke 28 | Hannes Reinecke 29 | Martin Wilck 30 | Martin Wilck 31 | wei huang wei.huang 32 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | LICENSES/LGPL-2.0 -------------------------------------------------------------------------------- /kpartx/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2003 Christophe Varoqui, 3 | # 4 | include ../Makefile.inc 5 | 6 | EXEC := kpartx 7 | 8 | CPPFLAGS += -I. -I$(multipathdir) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 9 | CFLAGS += $(BIN_CFLAGS) 10 | LDFLAGS += $(BIN_LDFLAGS) 11 | LIBDEPS += -ldevmapper 12 | 13 | OBJS := bsd.o dos.o kpartx.o solaris.o unixware.o dasd.o sun.o \ 14 | gpt.o mac.o ps3.o crc32.o lopart.o xstrncpy.o devmapper.o 15 | 16 | all: $(EXEC) kpartx.rules 17 | 18 | $(EXEC): $(OBJS) 19 | @echo building $@ because of $? 20 | $(Q)$(CC) $(CFLAGS) $(OBJS) -o $(EXEC) $(LDFLAGS) $(LIBDEPS) 21 | 22 | install: $(EXEC) $(EXEC).8 kpartx.rules 23 | $(Q)$(INSTALL_PROGRAM) -d $(DESTDIR)$(bindir) 24 | $(Q)$(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir) 25 | $(Q)$(INSTALL_PROGRAM) -d $(DESTDIR)$(libudevdir) 26 | $(Q)$(INSTALL_PROGRAM) -m 755 kpartx_id $(DESTDIR)$(libudevdir) 27 | $(Q)$(INSTALL_PROGRAM) -d $(DESTDIR)$(libudevdir)/rules.d 28 | $(Q)$(INSTALL_PROGRAM) -m 644 dm-parts.rules $(DESTDIR)$(libudevdir)/rules.d/11-dm-parts.rules 29 | $(Q)$(INSTALL_PROGRAM) -m 644 kpartx.rules $(DESTDIR)$(libudevdir)/rules.d/66-kpartx.rules 30 | $(Q)$(INSTALL_PROGRAM) -m 644 del-part-nodes.rules $(DESTDIR)$(libudevdir)/rules.d/68-del-part-nodes.rules 31 | $(Q)$(INSTALL_PROGRAM) -d $(DESTDIR)$(mandir)/man8 32 | $(Q)$(INSTALL_PROGRAM) -m 644 $(EXEC).8 $(DESTDIR)$(mandir)/man8 33 | 34 | uninstall: 35 | $(Q)$(RM) $(DESTDIR)$(bindir)/$(EXEC) 36 | $(Q)$(RM) $(DESTDIR)$(mandir)/man8/$(EXEC).8 37 | $(Q)$(RM) $(DESTDIR)$(libudevdir)/kpartx_id 38 | $(Q)$(RM) $(DESTDIR)$(libudevdir)/rules.d/11-dm-parts.rules 39 | $(Q)$(RM) $(DESTDIR)$(libudevdir)/rules.d/66-kpartx.rules 40 | $(Q)$(RM) $(DESTDIR)$(libudevdir)/rules.d/67-kpartx-compat.rules 41 | $(Q)$(RM) $(DESTDIR)$(libudevdir)/rules.d/68-del-part-nodes.rules 42 | 43 | clean: dep_clean 44 | $(Q)$(RM) core *.o $(EXEC) kpartx.rules 45 | 46 | include $(wildcard $(OBJS:.o=.d)) 47 | 48 | dep_clean: 49 | $(Q)$(RM) $(OBJS:.o=.d) 50 | -------------------------------------------------------------------------------- /kpartx/byteorder.h: -------------------------------------------------------------------------------- 1 | #ifndef KPARTX_BYTEORDER_H_INCLUDED 2 | #define KPARTX_BYTEORDER_H_INCLUDED 3 | 4 | #ifdef __linux__ 5 | # include 6 | # include 7 | #else 8 | # error unsupported 9 | #endif 10 | 11 | #if BYTE_ORDER == LITTLE_ENDIAN 12 | # define le16_to_cpu(x) (x) 13 | # define be16_to_cpu(x) bswap_16(x) 14 | # define le32_to_cpu(x) (x) 15 | # define le64_to_cpu(x) (x) 16 | # define be32_to_cpu(x) bswap_32(x) 17 | # define be64_to_cpu(x) bswap_64(x) 18 | #elif BYTE_ORDER == BIG_ENDIAN 19 | # define le16_to_cpu(x) bswap_16(x) 20 | # define be16_to_cpu(x) (x) 21 | # define le32_to_cpu(x) bswap_32(x) 22 | # define le64_to_cpu(x) bswap_64(x) 23 | # define be32_to_cpu(x) (x) 24 | # define be64_to_cpu(x) (x) 25 | #else 26 | # error unsupported 27 | #endif 28 | 29 | #endif /* KPARTX_BYTEORDER_H_INCLUDED */ 30 | -------------------------------------------------------------------------------- /kpartx/crc32.h: -------------------------------------------------------------------------------- 1 | /* 2 | * crc32.h 3 | */ 4 | #ifndef CRC32_H_INCLUDED 5 | #define CRC32_H_INCLUDED 6 | 7 | #include 8 | #include 9 | 10 | extern int init_crc32(void); 11 | extern void cleanup_crc32(void); 12 | extern uint32_t crc32_le(uint32_t crc, unsigned char const *p, size_t len); 13 | extern uint32_t crc32_be(uint32_t crc, unsigned char const *p, size_t len); 14 | 15 | #define crc32(seed, data, length) crc32_le(seed, (unsigned char const *)data, length) 16 | #define ether_crc_le(length, data) crc32_le(~0, data, length) 17 | #define ether_crc(length, data) crc32_be(~0, data, length) 18 | 19 | #endif /* CRC32_H_INCLUDED */ 20 | -------------------------------------------------------------------------------- /kpartx/del-part-nodes.rules: -------------------------------------------------------------------------------- 1 | # These rules can delete partitions devnodes for slave devices 2 | # for certain aggregate devices such as multipath. 3 | # This is desirable to avoid confusion and keep the number 4 | # of device nodes and symlinks within limits. 5 | # 6 | # This is done only once on the first "add" or "change" event for 7 | # any given device. 8 | # 9 | # To suppress this, use the kernel parameter "dont_del_part_nodes", 10 | # or create an udev rule file that sets ENV{DONT_DEL_PART_NODES}="1". 11 | 12 | SUBSYSTEM!="block", GOTO="end_del_part_nodes" 13 | KERNEL!="sd*|dasd*", GOTO="end_del_part_nodes" 14 | ACTION!="add|change", GOTO="end_del_part_nodes" 15 | ENV{DEVTYPE}=="partition", GOTO="end_del_part_nodes" 16 | 17 | IMPORT{cmdline}="dont_del_part_nodes" 18 | ENV{dont_del_part_nodes}=="1", GOTO="end_del_part_nodes" 19 | ENV{DONT_DEL_PART_NODES}=="1", GOTO="end_del_part_nodes" 20 | 21 | # dm-multipath 22 | ENV{DM_MULTIPATH_DEVICE_PATH}=="1", GOTO="del_part_nodes" 23 | 24 | # Other aggregate device types can be added here. 25 | 26 | GOTO="end_del_part_nodes" 27 | 28 | LABEL="del_part_nodes" 29 | IMPORT{db}="DM_DEL_PART_NODES" 30 | ENV{DM_DEL_PART_NODES}!="1", ENV{DM_DEL_PART_NODES}="1", \ 31 | RUN+="/usr/sbin/partx -d --nr 1-1024 $env{DEVNAME}" 32 | 33 | LABEL="end_del_part_nodes" 34 | -------------------------------------------------------------------------------- /kpartx/devmapper.h: -------------------------------------------------------------------------------- 1 | #ifndef KPARTX_DEVMAPPER_H_INCLUDED 2 | #define KPARTX_DEVMAPPER_H_INCLUDED 3 | 4 | #ifdef DM_SUBSYSTEM_UDEV_FLAG0 5 | #define MPATH_UDEV_RELOAD_FLAG DM_SUBSYSTEM_UDEV_FLAG0 6 | #else 7 | #define MPATH_UDEV_RELOAD_FLAG 0 8 | #endif 9 | 10 | extern int udev_sync; 11 | 12 | int dm_prereq (char *, uint32_t, uint32_t, uint32_t); 13 | int dm_simplecmd (int, const char *, int, uint16_t); 14 | int dm_addmap (int, const char *, const char *, const char *, uint64_t, 15 | int, const char *, int, mode_t, uid_t, gid_t); 16 | char * dm_mapname(int major, int minor); 17 | dev_t dm_get_first_dep(char *devname); 18 | char * dm_mapuuid(const char *mapname); 19 | int dm_devn (const char * mapname, unsigned int *major, unsigned int *minor); 20 | int dm_remove_partmaps (char * mapname, char *uuid, dev_t devt, int verbose); 21 | int dm_find_part(const char *parent, const char *delim, int part, 22 | const char *parent_uuid, 23 | char *name, size_t namesiz, char **part_uuid, int verbose); 24 | 25 | /* 26 | * UUID format for partitions created on non-DM devices 27 | * ${UUID_PREFIX}devnode_${MAJOR}:${MINOR}_${NONDM_UUID_SUFFIX}" 28 | * where ${UUID_PREFIX} is "part${PARTNO}-" (see devmapper.c). 29 | * 30 | * The suffix should be sufficiently unique to avoid incidental conflicts; 31 | * the value below is a base64-encoded random number. 32 | * The UUID format shouldn't be changed between kpartx releases. 33 | */ 34 | #define NONDM_UUID_PREFIX "devnode" 35 | #define NONDM_UUID_SUFFIX "Wh5pYvM" 36 | char *nondm_create_uuid(dev_t devt); 37 | int nondm_parse_uuid(const char *uuid, 38 | unsigned int *major, unsigned int *minor); 39 | #endif /* KPARTX_DEVMAPPER_H_INCLUDED */ 40 | -------------------------------------------------------------------------------- /kpartx/dm-parts.rules: -------------------------------------------------------------------------------- 1 | # Rules for partitions created by kpartx 2 | 3 | KERNEL!="dm-*", GOTO="dm_parts_end" 4 | ACTION!="add|change", GOTO="dm_parts_end" 5 | ENV{DM_UUID}!="part[0-9]*", GOTO="dm_parts_end" 6 | 7 | # We must take care that symlinks don't get lost, 8 | # even if blkid fails in 13-dm-disk.rules later. 9 | # 10 | # Fixme: we have currently no way to avoid calling blkid on 11 | # partitions of broken mpath maps such as DM_NOSCAN. 12 | # But when partition devices appear, kpartx has likely read 13 | # the partition table shortly before, so odds are not bad 14 | # that blkid will also succeed. 15 | 16 | IMPORT{db}="ID_FS_USAGE" 17 | IMPORT{db}="ID_FS_UUID_ENC" 18 | IMPORT{db}="ID_FS_LABEL_ENC" 19 | IMPORT{db}="ID_PART_ENTRY_NAME" 20 | IMPORT{db}="ID_PART_ENTRY_UUID" 21 | IMPORT{db}="ID_PART_ENTRY_SCHEME" 22 | 23 | # Maps should take precedence over their members. 24 | ENV{DM_UDEV_LOW_PRIORITY_FLAG}!="1", OPTIONS+="link_priority=50" 25 | 26 | # Set some additional symlinks that typically exist for mpath 27 | # path members, too, and should be overridden. 28 | # 29 | # kpartx_id is very robust, it works for suspended maps and maps 30 | # with 0 dependencies. It sets DM_TYPE, DM_PART, DM_WWN 31 | IMPORT{program}=="kpartx_id %M %m $env{DM_UUID}" 32 | 33 | # DM_TYPE only has a reasonable value for partitions on multipath. 34 | ENV{DM_UUID}=="*-mpath-*", ENV{DM_TYPE}=="?*", ENV{DM_SERIAL}=="?*", \ 35 | SYMLINK+="disk/by-id/$env{DM_TYPE}-$env{DM_SERIAL}-part$env{DM_PART}" 36 | ENV{DM_WWN}=="?*", ENV{DM_PART}=="?*", \ 37 | SYMLINK+="disk/by-id/wwn-$env{DM_WWN}-part$env{DM_PART}" 38 | 39 | LABEL="dm_parts_end" 40 | -------------------------------------------------------------------------------- /kpartx/dos.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Source: copy of util-linux' partx dos.c 3 | * 4 | * Copyrights of the original file apply 5 | * Copyright (c) 2005 Bastian Blank 6 | */ 7 | #include "kpartx.h" 8 | #include "byteorder.h" 9 | #include 10 | #include 11 | #include "dos.h" 12 | 13 | static int 14 | is_extended(int type) { 15 | return (type == 5 || type == 0xf || type == 0x85); 16 | } 17 | 18 | static int 19 | read_extended_partition(int fd, struct partition *ep, int en, 20 | struct slice *sp, int ns) 21 | { 22 | struct partition p; 23 | unsigned long start, here, next; 24 | unsigned char *bp; 25 | int loopct = 0; 26 | int moretodo = 1; 27 | int i, n=0; 28 | 29 | int sector_size_mul = get_sector_size(fd)/512; 30 | 31 | next = start = sector_size_mul * le32_to_cpu(ep->start_sect); 32 | 33 | while (moretodo) { 34 | here = next; 35 | moretodo = 0; 36 | if (++loopct > 100) 37 | return n; 38 | 39 | bp = (unsigned char *)getblock(fd, here); 40 | if (bp == NULL) 41 | return n; 42 | 43 | if (bp[510] != 0x55 || bp[511] != 0xaa) 44 | return n; 45 | 46 | for (i=0; i<2; i++) { 47 | memcpy(&p, bp + 0x1be + i * sizeof (p), sizeof (p)); 48 | if (is_extended(p.sys_type)) { 49 | if (p.start_sect && p.nr_sects && !moretodo) { 50 | next = start + sector_size_mul * le32_to_cpu(p.start_sect); 51 | moretodo = 1; 52 | } 53 | continue; 54 | } 55 | if (n < ns) { 56 | sp[n].start = here + sector_size_mul * le32_to_cpu(p.start_sect); 57 | sp[n].size = sector_size_mul * le32_to_cpu(p.nr_sects); 58 | sp[n].container = en + 1; 59 | n++; 60 | } else { 61 | fprintf(stderr, 62 | "dos_extd_partition: too many slices\n"); 63 | return n; 64 | } 65 | loopct = 0; 66 | } 67 | } 68 | return n; 69 | } 70 | 71 | static int 72 | is_gpt(int type) { 73 | return (type == 0xEE); 74 | } 75 | 76 | int 77 | read_dos_pt(int fd, struct slice all, struct slice *sp, unsigned int ns) { 78 | struct partition p; 79 | unsigned long offset = all.start; 80 | unsigned int i, n=4; 81 | unsigned char *bp; 82 | uint64_t sector_size_mul = get_sector_size(fd)/512; 83 | 84 | bp = (unsigned char *)getblock(fd, offset); 85 | if (bp == NULL) 86 | return -1; 87 | 88 | if (bp[510] != 0x55 || bp[511] != 0xaa) 89 | return -1; 90 | 91 | for (i=0; i<4; i++) { 92 | memcpy(&p, bp + 0x1be + i * sizeof (p), sizeof (p)); 93 | if (is_gpt(p.sys_type)) 94 | return 0; 95 | if (i < ns) { 96 | sp[i].start = sector_size_mul * le32_to_cpu(p.start_sect); 97 | sp[i].size = sector_size_mul * le32_to_cpu(p.nr_sects); 98 | } else { 99 | fprintf(stderr, 100 | "dos_partition: too many slices\n"); 101 | break; 102 | } 103 | if (is_extended(p.sys_type)) { 104 | /* extended partitions only get one or 105 | two sectors mapped for LILO to install, 106 | whichever is needed to have 1kb of space */ 107 | if (sector_size_mul == 1) 108 | sp[i].size = 2; 109 | else sp[i].size = sector_size_mul; 110 | n += read_extended_partition(fd, &p, i, sp+n, ns-n); 111 | } 112 | } 113 | return n; 114 | } 115 | -------------------------------------------------------------------------------- /kpartx/dos.h: -------------------------------------------------------------------------------- 1 | #ifndef DOS_H_INCLUDED 2 | #define DOS_H_INCLUDED 3 | 4 | struct partition { 5 | unsigned char boot_ind; /* 0x80 - active */ 6 | unsigned char bh, bs, bc; 7 | unsigned char sys_type; 8 | unsigned char eh, es, ec; 9 | unsigned int start_sect; 10 | unsigned int nr_sects; 11 | } __attribute__((packed)); 12 | 13 | #endif /* DOS_H_INCLUDED */ 14 | -------------------------------------------------------------------------------- /kpartx/efi.h: -------------------------------------------------------------------------------- 1 | /* 2 | efi.[ch] - Manipulates EFI variables as exported in /proc/efi/vars 3 | 4 | Copyright (C) 2001 Dell Computer Corporation 5 | 6 | This program is free software; you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation; either version 2 of the License, or 9 | (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | */ 19 | 20 | #ifndef EFI_H_INCLUDED 21 | #define EFI_H_INCLUDED 22 | 23 | /* 24 | * Extensible Firmware Interface 25 | * Based on 'Extensible Firmware Interface Specification' 26 | * version 1.02, 12 December, 2000 27 | */ 28 | #include 29 | #include 30 | 31 | typedef struct { 32 | uint8_t b[16]; 33 | } efi_guid_t; 34 | 35 | #define EFI_GUID(a,b,c,d0,d1,d2,d3,d4,d5,d6,d7) \ 36 | ((efi_guid_t) \ 37 | {{ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \ 38 | (b) & 0xff, ((b) >> 8) & 0xff, \ 39 | (c) & 0xff, ((c) >> 8) & 0xff, \ 40 | (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }}) 41 | 42 | 43 | /****************************************************** 44 | * GUIDs 45 | ******************************************************/ 46 | #define NULL_GUID \ 47 | EFI_GUID( 0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) 48 | 49 | static inline int 50 | efi_guidcmp(efi_guid_t left, efi_guid_t right) 51 | { 52 | return memcmp(&left, &right, sizeof (efi_guid_t)); 53 | } 54 | 55 | typedef uint16_t efi_char16_t; /* UNICODE character */ 56 | 57 | #endif /* EFI_H_INCLUDED */ 58 | -------------------------------------------------------------------------------- /kpartx/kpartx.h: -------------------------------------------------------------------------------- 1 | #ifndef KPARTX_H_INCLUDED 2 | #define KPARTX_H_INCLUDED 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | /* 9 | * For each partition type there is a routine that takes 10 | * a block device and a range, and returns the list of 11 | * slices found there in the supplied array SP that can 12 | * hold NS entries. The return value is the number of 13 | * entries stored, or -1 if the appropriate type is not 14 | * present. 15 | */ 16 | 17 | #define likely(x) __builtin_expect(!!(x), 1) 18 | #define unlikely(x) __builtin_expect(!!(x), 0) 19 | 20 | #define safe_snprintf(var, size, format, args...) \ 21 | ({ \ 22 | size_t __size = size; \ 23 | int __ret; \ 24 | \ 25 | __ret = snprintf(var, __size, format, ##args); \ 26 | __ret < 0 || (size_t)__ret >= __size; \ 27 | }) 28 | 29 | #define safe_sprintf(var, format, args...) \ 30 | safe_snprintf(var, sizeof(var), format, ##args) 31 | 32 | #ifndef BLKSSZGET 33 | #define BLKSSZGET _IO(0x12,104) /* get block device sector size */ 34 | #endif 35 | 36 | int 37 | get_sector_size(int filedes); 38 | 39 | /* 40 | * units: 512 byte sectors 41 | */ 42 | struct slice { 43 | uint64_t start; 44 | uint64_t size; 45 | int container; 46 | unsigned int major; 47 | unsigned int minor; 48 | }; 49 | 50 | typedef int (ptreader)(int fd, struct slice all, struct slice *sp, 51 | unsigned int ns); 52 | 53 | extern int force_gpt; 54 | 55 | extern ptreader read_dos_pt; 56 | extern ptreader read_bsd_pt; 57 | extern ptreader read_solaris_pt; 58 | extern ptreader read_unixware_pt; 59 | extern ptreader read_gpt_pt; 60 | extern ptreader read_dasd_pt; 61 | extern ptreader read_mac_pt; 62 | extern ptreader read_sun_pt; 63 | extern ptreader read_ps3_pt; 64 | 65 | int aligned_malloc(void **mem_p, size_t align, size_t *size_p); 66 | char *getblock(int fd, unsigned int secnr); 67 | 68 | static inline unsigned int 69 | four2int(unsigned char *p) { 70 | return p[0] + (p[1]<<8) + (p[2]<<16) + (p[3]<<24); 71 | } 72 | 73 | #endif /* KPARTX_H_INCLUDED */ 74 | -------------------------------------------------------------------------------- /kpartx/kpartx.rules.in: -------------------------------------------------------------------------------- 1 | # 2 | # persistent links for device-mapper devices 3 | # only hardware-backed device-mapper devices (ie multipath, dmraid, 4 | # and kpartx) have meaningful persistent device names 5 | # 6 | 7 | KERNEL!="dm-*", GOTO="kpartx_end" 8 | ACTION!="add|change", GOTO="kpartx_end" 9 | ENV{DM_UUID}!="?*", GOTO="kpartx_end" 10 | ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}=="1", GOTO="kpartx_end" 11 | 12 | # Create dm tables for partitions on multipath devices. 13 | ENV{DM_UUID}!="mpath-?*", GOTO="mpath_kpartx_end" 14 | 15 | # Ignore RAID members 16 | ENV{ID_FS_TYPE}=="linux_raid_member|isw_raid_member|ddf_raid_member", GOTO="mpath_kpartx_end" 17 | 18 | # DM_SUBSYSTEM_UDEV_FLAG1 is the "skip_kpartx" flag. 19 | # For events not generated by libdevmapper, we need to fetch it from db: 20 | # - "change" events with DM_ACTIVATION!="1" (e.g. partition table changes) 21 | # - "add" events for which rules are not disabled ("coldplug" case) 22 | ENV{DM_ACTIVATION}!="1", IMPORT{db}="DM_SUBSYSTEM_UDEV_FLAG1" 23 | ACTION=="add", IMPORT{db}="DM_SUBSYSTEM_UDEV_FLAG1" 24 | ENV{DM_SUBSYSTEM_UDEV_FLAG1}=="1", GOTO="mpath_kpartx_end" 25 | 26 | # 11-dm-mpath.rules sets MPATH_UNCHANGED for events that can be ignored. 27 | ENV{MPATH_UNCHANGED}=="1", GOTO="mpath_kpartx_end" 28 | 29 | # Don't run kpartx now if we know it will fail or hang. 30 | # This is required for device mapper rules v2 compatibility. 31 | ENV{DM_NOSCAN}=="1", GOTO="mpath_kpartx_end" 32 | 33 | # Run kpartx 34 | GOTO="run_kpartx" 35 | LABEL="mpath_kpartx_end" 36 | 37 | ## Code for other subsystems (non-multipath) could be placed here ## 38 | 39 | GOTO="kpartx_end" 40 | 41 | LABEL="run_kpartx" 42 | RUN+="@BINDIR@/kpartx -un -p -part /dev/$name" 43 | 44 | LABEL="kpartx_end" 45 | -------------------------------------------------------------------------------- /kpartx/kpartx_id: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # kpartx_id 4 | # 5 | # Generates ID information for device-mapper tables. 6 | # 7 | # Copyright (C) 2006 SUSE Linux Products GmbH 8 | # Author: 9 | # Hannes Reinecke 10 | # 11 | # 12 | # This program is free software; you can redistribute it and/or modify it 13 | # under the terms of the GNU General Public License as published by the 14 | # Free Software Foundation version 2 of the License. 15 | # 16 | # This script generates ID information used to generate persistent symlinks. 17 | # It relies on the UUID strings generated by the various programs; the name 18 | # of the tables are of no consequence. 19 | # 20 | # Please note that dmraid does not provide the UUIDs (yet); a patch has been 21 | # sent upstream but has not been accepted yet. 22 | # 23 | 24 | MAJOR=$1 25 | MINOR=$2 26 | UUID=$3 27 | 28 | if [ -z "$MAJOR" -o -z "$MINOR" ]; then 29 | echo "usage: $0 major minor UUID" 30 | exit 1; 31 | fi 32 | 33 | DMSETUP=$(command -v dmsetup) || DMSETUP=/sbin/dmsetup 34 | 35 | # Device-mapper not installed; not an error 36 | if [ ! -x "$DMSETUP" ] ; then 37 | echo "$0: dmsetup not found" >&2 38 | exit 0 39 | fi 40 | 41 | # Table UUIDs are always '-'. 42 | dmuuid=${UUID#*-} 43 | dmtbl=${UUID%%-*} 44 | dmpart=${dmtbl#part} 45 | dmserial= 46 | # kpartx types are 'part' 47 | if [ "$dmpart" = "$dmtbl" ] ; then 48 | dmpart= 49 | else 50 | dmtbl=part 51 | fi 52 | 53 | # Set the name of the table. We're only interested in dmraid, 54 | # multipath, and kpartx tables; everything else is ignored. 55 | if [ "$dmtbl" = "part" ] ; then 56 | dmname=$($DMSETUP info -c --noheadings -o name -u $dmuuid) 57 | echo "DM_MPATH=$dmname" 58 | # We need the dependencies of the parent table to figure out 59 | # the type if the parent is a multipath table 60 | case "$dmuuid" in 61 | mpath-*) 62 | dmdeps=$($DMSETUP deps -u $dmuuid) 63 | dmserial=${dmuuid#mpath-} 64 | ;; 65 | esac 66 | elif [ "$dmtbl" = "mpath" ] ; then 67 | dmname="$dmuuid" 68 | dmserial="$dmuuid" 69 | # We need the dependencies of the table to figure out the type 70 | dmdeps=$($DMSETUP deps -u $UUID) 71 | fi 72 | 73 | [ -n "$dmpart" ] && echo "DM_PART=$dmpart" 74 | 75 | # Figure out the type of the map. For non-multipath maps it's 76 | # always 'raid'. 77 | if [ -n "$dmdeps" ] ; then 78 | case "$dmdeps" in 79 | *\(94,*) 80 | echo "DM_TYPE=ccw" 81 | ;; 82 | *\(104,* | *\(105,* | *\(106,* | *\(107,* | *\(108,* | *\(109,* | *\(110,* | *\(112,*) 83 | echo "DM_TYPE=cciss" 84 | ;; 85 | *\(9*) 86 | echo "DM_TYPE=raid" 87 | ;; 88 | *) 89 | echo "DM_TYPE=scsi" 90 | echo "DM_WWN=0x${dmserial#?}" 91 | ;; 92 | esac 93 | else 94 | echo "DM_TYPE=raid" 95 | fi 96 | if [ -n "$dmserial" ]; then 97 | echo "DM_SERIAL=$dmserial" 98 | fi 99 | 100 | exit 0 101 | -------------------------------------------------------------------------------- /kpartx/lopart.h: -------------------------------------------------------------------------------- 1 | #ifndef LOPART_H_INCLUDED 2 | #define LOPART_H_INCLUDED 3 | extern int verbose; 4 | extern int set_loop (char **, const char *, int, int *); 5 | extern int del_loop (const char *); 6 | extern char * find_loop_by_file (const char *); 7 | #endif 8 | -------------------------------------------------------------------------------- /kpartx/mac.c: -------------------------------------------------------------------------------- 1 | #include "kpartx.h" 2 | #include "byteorder.h" 3 | #include 4 | #include 5 | #include "mac.h" 6 | 7 | int 8 | read_mac_pt(int fd, __attribute__((unused)) struct slice all, 9 | struct slice *sp, unsigned int ns) { 10 | struct mac_driver_desc *md; 11 | struct mac_partition *part; 12 | unsigned secsize; 13 | char *data; 14 | unsigned int blk, blocks_in_map; 15 | int n = 0; 16 | 17 | md = (struct mac_driver_desc *) getblock(fd, 0); 18 | if (md == NULL) 19 | return -1; 20 | 21 | if (be16_to_cpu(md->signature) != MAC_DRIVER_MAGIC) 22 | return -1; 23 | 24 | secsize = be16_to_cpu(md->block_size); 25 | data = getblock(fd, secsize/512); 26 | if (!data) 27 | return -1; 28 | part = (struct mac_partition *) (data + secsize%512); 29 | 30 | if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC) 31 | return -1; 32 | 33 | blocks_in_map = be32_to_cpu(part->map_count); 34 | for (blk = 1; blk <= blocks_in_map && blk <= ns; ++blk, ++n) { 35 | int pos = blk * secsize; 36 | data = getblock(fd, pos/512); 37 | if (!data) 38 | return -1; 39 | 40 | part = (struct mac_partition *) (data + pos%512); 41 | if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC) 42 | break; 43 | 44 | sp[n].start = be32_to_cpu(part->start_block) * (secsize/512); 45 | sp[n].size = be32_to_cpu(part->block_count) * (secsize/512); 46 | } 47 | return n; 48 | } 49 | -------------------------------------------------------------------------------- /kpartx/mac.h: -------------------------------------------------------------------------------- 1 | #ifndef MAC_H_INCLUDED 2 | #define MAC_H_INCLUDED 3 | 4 | #include 5 | 6 | #define MAC_PARTITION_MAGIC 0x504d 7 | 8 | /* type field value for A/UX or other Unix partitions */ 9 | #define APPLE_AUX_TYPE "Apple_UNIX_SVR2" 10 | 11 | struct mac_partition { 12 | uint16_t signature; /* expected to be MAC_PARTITION_MAGIC */ 13 | uint16_t res1; 14 | uint32_t map_count; /* # blocks in partition map */ 15 | uint32_t start_block; /* absolute starting block # of partition */ 16 | uint32_t block_count; /* number of blocks in partition */ 17 | /* there is more stuff after this that we don't need */ 18 | }; 19 | 20 | #define MAC_DRIVER_MAGIC 0x4552 21 | 22 | /* Driver descriptor structure, in block 0 */ 23 | struct mac_driver_desc { 24 | uint16_t signature; /* expected to be MAC_DRIVER_MAGIC */ 25 | uint16_t block_size; 26 | uint32_t block_count; 27 | /* ... more stuff */ 28 | }; 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /kpartx/ps3.c: -------------------------------------------------------------------------------- 1 | #include "kpartx.h" 2 | #include "byteorder.h" 3 | #include 4 | #include 5 | 6 | #define SECTOR_SIZE 512 7 | #define MAX_ACL_ENTRIES 8 8 | #define MAX_PARTITIONS 8 9 | 10 | #define MAGIC1 0x0FACE0FFULL 11 | #define MAGIC2 0xDEADFACEULL 12 | 13 | struct p_acl_entry { 14 | u_int64_t laid; 15 | u_int64_t rights; 16 | }; 17 | 18 | struct d_partition { 19 | u_int64_t p_start; 20 | u_int64_t p_size; 21 | struct p_acl_entry p_acl[MAX_ACL_ENTRIES]; 22 | }; 23 | 24 | struct disklabel { 25 | u_int8_t d_res1[16]; 26 | u_int64_t d_magic1; 27 | u_int64_t d_magic2; 28 | u_int64_t d_res2; 29 | u_int64_t d_res3; 30 | struct d_partition d_partitions[MAX_PARTITIONS]; 31 | u_int8_t d_pad[0x600 - MAX_PARTITIONS * sizeof(struct d_partition) - 0x30]; 32 | }; 33 | 34 | static int 35 | read_disklabel(int fd, struct disklabel *label) { 36 | unsigned char *data; 37 | unsigned int i; 38 | 39 | for (i = 0; i < sizeof(struct disklabel) / SECTOR_SIZE; i++) { 40 | data = (unsigned char *) getblock(fd, i); 41 | if (!data) 42 | return 0; 43 | 44 | memcpy((unsigned char *) label + i * SECTOR_SIZE, data, SECTOR_SIZE); 45 | } 46 | 47 | return 1; 48 | } 49 | 50 | int 51 | read_ps3_pt(int fd, __attribute__((unused)) struct slice all, 52 | struct slice *sp, __attribute__((unused)) unsigned int ns) { 53 | struct disklabel label; 54 | int n = 0; 55 | int i; 56 | 57 | if (!read_disklabel(fd, &label)) 58 | return -1; 59 | 60 | if ((be64_to_cpu(label.d_magic1) != MAGIC1) || 61 | (be64_to_cpu(label.d_magic2) != MAGIC2)) 62 | return -1; 63 | 64 | for (i = 0; i < MAX_PARTITIONS; i++) { 65 | if (label.d_partitions[i].p_start && label.d_partitions[i].p_size) { 66 | sp[n].start = be64_to_cpu(label.d_partitions[i].p_start); 67 | sp[n].size = be64_to_cpu(label.d_partitions[i].p_size); 68 | n++; 69 | } 70 | } 71 | 72 | return n; 73 | } 74 | -------------------------------------------------------------------------------- /kpartx/solaris.c: -------------------------------------------------------------------------------- 1 | #include "kpartx.h" 2 | #include 3 | #include 4 | #include /* time_t */ 5 | 6 | #define SOLARIS_X86_NUMSLICE 8 7 | #define SOLARIS_X86_VTOC_SANE (0x600DDEEEUL) 8 | 9 | struct solaris_x86_slice { 10 | unsigned short s_tag; /* ID tag of partition */ 11 | unsigned short s_flag; /* permission flags */ 12 | __kernel_daddr_t s_start; /* start sector no of partition */ 13 | long s_size; /* # of blocks in partition */ 14 | }; 15 | 16 | struct solaris_x86_vtoc { 17 | unsigned long v_bootinfo[3]; /* info for mboot */ 18 | unsigned long v_sanity; /* to verify vtoc sanity */ 19 | unsigned long v_version; /* layout version */ 20 | char v_volume[8]; /* volume name */ 21 | unsigned short v_sectorsz; /* sector size in bytes */ 22 | unsigned short v_nparts; /* number of partitions */ 23 | unsigned long v_reserved[10]; /* free space */ 24 | struct solaris_x86_slice 25 | v_slice[SOLARIS_X86_NUMSLICE]; /* slice headers */ 26 | time_t timestamp[SOLARIS_X86_NUMSLICE]; /* timestamp */ 27 | char v_asciilabel[128]; /* for compatibility */ 28 | }; 29 | 30 | int 31 | read_solaris_pt(int fd, struct slice all, struct slice *sp, unsigned int ns) { 32 | struct solaris_x86_vtoc *v; 33 | struct solaris_x86_slice *s; 34 | unsigned int offset = all.start; 35 | unsigned int i, n; 36 | char *bp; 37 | 38 | bp = getblock(fd, offset+1); /* 1 sector suffices */ 39 | if (bp == NULL) 40 | return -1; 41 | 42 | v = (struct solaris_x86_vtoc *) bp; 43 | if(v->v_sanity != SOLARIS_X86_VTOC_SANE) 44 | return -1; 45 | 46 | if(v->v_version != 1) { 47 | fprintf(stderr, "Cannot handle solaris version %ld vtoc\n", 48 | v->v_version); 49 | return 0; 50 | } 51 | 52 | for(i=0, n=0; iv_slice[i]; 54 | 55 | if (s->s_size == 0) 56 | continue; 57 | if (n < ns) { 58 | sp[n].start = offset + s->s_start; 59 | sp[n].size = s->s_size; 60 | n++; 61 | } else { 62 | fprintf(stderr, 63 | "solaris_x86_partition: too many slices\n"); 64 | break; 65 | } 66 | } 67 | return n; 68 | } 69 | -------------------------------------------------------------------------------- /kpartx/unixware.c: -------------------------------------------------------------------------------- 1 | #include "kpartx.h" 2 | #include 3 | 4 | #define UNIXWARE_FS_UNUSED 0 5 | #define UNIXWARE_NUMSLICE 16 6 | #define UNIXWARE_DISKMAGIC (0xCA5E600D) 7 | #define UNIXWARE_DISKMAGIC2 (0x600DDEEE) 8 | 9 | struct unixware_slice { 10 | unsigned short s_label; /* label */ 11 | unsigned short s_flags; /* permission flags */ 12 | unsigned int start_sect; /* starting sector */ 13 | unsigned int nr_sects; /* number of sectors in slice */ 14 | }; 15 | 16 | struct unixware_disklabel { 17 | unsigned int d_type; /* drive type */ 18 | unsigned char d_magic[4]; /* the magic number */ 19 | unsigned int d_version; /* version number */ 20 | char d_serial[12]; /* serial number of the device */ 21 | unsigned int d_ncylinders; /* # of data cylinders per device */ 22 | unsigned int d_ntracks; /* # of tracks per cylinder */ 23 | unsigned int d_nsectors; /* # of data sectors per track */ 24 | unsigned int d_secsize; /* # of bytes per sector */ 25 | unsigned int d_part_start; /* # of first sector of this partition */ 26 | unsigned int d_unknown1[12]; /* ? */ 27 | unsigned int d_alt_tbl; /* byte offset of alternate table */ 28 | unsigned int d_alt_len; /* byte length of alternate table */ 29 | unsigned int d_phys_cyl; /* # of physical cylinders per device */ 30 | unsigned int d_phys_trk; /* # of physical tracks per cylinder */ 31 | unsigned int d_phys_sec; /* # of physical sectors per track */ 32 | unsigned int d_phys_bytes; /* # of physical bytes per sector */ 33 | unsigned int d_unknown2; /* ? */ 34 | unsigned int d_unknown3; /* ? */ 35 | unsigned int d_pad[8]; /* pad */ 36 | 37 | struct unixware_vtoc { 38 | unsigned char v_magic[4]; /* the magic number */ 39 | unsigned int v_version; /* version number */ 40 | char v_name[8]; /* volume name */ 41 | unsigned short v_nslices; /* # of slices */ 42 | unsigned short v_unknown1; /* ? */ 43 | unsigned int v_reserved[10]; /* reserved */ 44 | struct unixware_slice 45 | v_slice[UNIXWARE_NUMSLICE]; /* slice headers */ 46 | } vtoc; 47 | 48 | }; /* 408 */ 49 | 50 | int 51 | read_unixware_pt(int fd, struct slice all, struct slice *sp, unsigned int ns) { 52 | struct unixware_disklabel *l; 53 | struct unixware_slice *p; 54 | unsigned int offset = all.start; 55 | char *bp; 56 | unsigned int n = 0; 57 | 58 | bp = getblock(fd, offset+29); /* 1 sector suffices */ 59 | if (bp == NULL) 60 | return -1; 61 | 62 | l = (struct unixware_disklabel *) bp; 63 | if (four2int(l->d_magic) != UNIXWARE_DISKMAGIC || 64 | four2int(l->vtoc.v_magic) != UNIXWARE_DISKMAGIC2) 65 | return -1; 66 | 67 | p = &l->vtoc.v_slice[1]; /* slice 0 is the whole disk. */ 68 | while (p - &l->vtoc.v_slice[0] < UNIXWARE_NUMSLICE) { 69 | if (p->s_label == UNIXWARE_FS_UNUSED) 70 | /* nothing */; 71 | else if (n < ns) { 72 | sp[n].start = p->start_sect; 73 | sp[n].size = p->nr_sects; 74 | n++; 75 | } else { 76 | fprintf(stderr, 77 | "unixware_partition: too many slices\n"); 78 | break; 79 | } 80 | p++; 81 | } 82 | return n; 83 | } 84 | -------------------------------------------------------------------------------- /kpartx/xstrncpy.c: -------------------------------------------------------------------------------- 1 | /* NUL-terminated version of strncpy() */ 2 | #include 3 | #include "xstrncpy.h" 4 | 5 | /* caller guarantees n > 0 */ 6 | void 7 | xstrncpy(char *dest, const char *src, size_t n) { 8 | strncpy(dest, src, n-1); 9 | dest[n-1] = 0; 10 | } 11 | -------------------------------------------------------------------------------- /kpartx/xstrncpy.h: -------------------------------------------------------------------------------- 1 | #ifndef XSTRNCPY_H_INCLUDED 2 | #define XSTRNCPY_H_INCLUDED 3 | extern void xstrncpy(char *dest, const char *src, size_t n); 4 | #endif 5 | -------------------------------------------------------------------------------- /libdmmp/DEV_NOTES: -------------------------------------------------------------------------------- 1 | == Planned features == 2 | * Expose all properties used by /usr/bin/multipath 3 | 4 | == Code style == 5 | * Keep things as simple as possible. 6 | * Linux Kernel code style. 7 | * Don't use typedef. 8 | * Don't use enum. 9 | * We are not smarter than API user, so don't create wrapping function like: 10 | 11 | ``` 12 | dmmp_mpath_search_by_id(struct dmmp_context *ctx, 13 | struct dmmp_mpath **dmmp_mp, 14 | uint32_t dmmp_mp_count, const char *id) 15 | 16 | dmmp_path_group_id_search(struct dmmp_mpath *dmmp_mp, 17 | const char *blk_name) 18 | ``` 19 | * The performance is the same for query single mpath and query all mpaths, 20 | so no `dmmp_mpath_of_wwid(struct dmmp_context *ctx, const char *wwid)` yet. 21 | 22 | == Naming scheme == 23 | * Public constants should be named as `DMMP_XXX_YYY`. 24 | * Public functions should be named as `dmmp__`. 25 | * Private constants should be named as `_DMMP_XXX_YYY`. 26 | * Private functions should be named as `_dmmp__`. 27 | 28 | == Code Layout == 29 | * libdmmp_private.h 30 | Internal functions or macros. 31 | * libdmmp.c 32 | Handling multipathd IPC and generate dmmp_context and 33 | dmmp_mpath_array_get(). 34 | * libdmmp_mp.c 35 | For `struct dmmp_mpath` 36 | * libdmmp_pg.c 37 | For `struct dmmp_path_group` 38 | * libdmmp_path.c 39 | For `struct dmmp_path` 40 | * libdmmp_misc.c 41 | Misc functions. 42 | -------------------------------------------------------------------------------- /libdmmp/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile 2 | # 3 | # Copyright (C) 2015 - 2016 Red Hat, Inc. 4 | # Gris Ge 5 | # 6 | include ../Makefile.inc 7 | 8 | LIBDMMP_VERSION := 0.2.0 9 | SONAME := $(LIBDMMP_VERSION) 10 | DEVLIB := libdmmp.so 11 | PKGFILE := libdmmp.pc 12 | EXTRA_MAN_FILES := libdmmp.h.3 13 | HEADERS := libdmmp/libdmmp.h 14 | 15 | OBJS := libdmmp.o libdmmp_mp.o libdmmp_pg.o libdmmp_path.o libdmmp_misc.o 16 | 17 | CPPFLAGS += -I$(libdmmpdir) -I$(mpathcmddir) $(shell $(PKG_CONFIG) --cflags json-c) 18 | CFLAGS += $(LIB_CFLAGS) -fvisibility=hidden 19 | 20 | LIBDEPS += $(shell $(PKG_CONFIG) --libs json-c) -L$(mpathcmddir) -lmpathcmd -lpthread 21 | 22 | all: $(LIBS) doc 23 | .PHONY: doc clean install uninstall check speed_test dep_clean 24 | 25 | $(LIBS): $(OBJS) 26 | $(Q)$(CC) $(LDFLAGS) $(SHARED_FLAGS) -Wl,-soname=$@ -o $@ $(OBJS) $(LIBDEPS) 27 | 28 | $(DEVLIB): $(LIBS) 29 | $(Q)$(LN) $(LIBS) $@ 30 | 31 | abi: $(DEVLIB:%.so=%.abi) 32 | 33 | install: 34 | @mkdir -p $(DESTDIR)$(usrlibdir) 35 | $(Q)$(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(usrlibdir)/$(LIBS) 36 | $(Q)$(INSTALL_PROGRAM) -m 644 -D \ 37 | $(HEADERS) $(DESTDIR)$(includedir)/$(HEADERS) 38 | $(Q)$(LN) $(LIBS) $(DESTDIR)$(usrlibdir)/$(DEVLIB) 39 | $(Q)$(INSTALL_PROGRAM) -m 644 -D \ 40 | $(PKGFILE).in $(DESTDIR)$(pkgconfdir)/$(PKGFILE) 41 | $(Q)sed -i 's|__VERSION__|$(LIBDMMP_VERSION)|g' \ 42 | $(DESTDIR)$(pkgconfdir)/$(PKGFILE) 43 | $(Q)sed -i 's|__LIBDIR__|$(usrlibdir)|g' \ 44 | $(DESTDIR)$(pkgconfdir)/$(PKGFILE) 45 | $(Q)sed -i 's|__INCLUDEDIR__|$(includedir)|g' \ 46 | $(DESTDIR)$(pkgconfdir)/$(PKGFILE) 47 | $(Q)$(INSTALL_PROGRAM) -m 755 -d $(DESTDIR)$(mandir)/man3 48 | $(Q)$(INSTALL_PROGRAM) -m 644 -t $(DESTDIR)$(mandir)/man3 docs/man/*.3 49 | 50 | uninstall: 51 | $(Q)$(RM) $(DESTDIR)$(usrlibdir)/$(LIBS) 52 | $(Q)$(RM) $(DESTDIR)$(includedir)/$(HEADERS) 53 | $(Q)$(RM) $(DESTDIR)$(usrlibdir)/$(DEVLIB) 54 | @for file in $(DESTDIR)$(mandir)/man3/dmmp_*; do \ 55 | $(RM) $$file; \ 56 | done 57 | $(Q)$(RM) $(DESTDIR)$(mandir)/man3/libdmmp.h* 58 | $(Q)$(RM) $(DESTDIR)$(pkgconfdir)/$(PKGFILE) 59 | 60 | clean: dep_clean 61 | $(Q)$(RM) core *.a *.o *.so *.so.* *.abi $(NV_VERSION_SCRIPT) 62 | @$(MAKE) -C test clean 63 | 64 | include $(wildcard $(OBJS:.o=.d)) 65 | 66 | check: all 67 | @$(MAKE) -C test check 68 | 69 | speed_test: all 70 | @$(MAKE) -C test speed_test 71 | 72 | doc: docs/man/dmmp_strerror.3 73 | 74 | docs/man/dmmp_strerror.3: $(HEADERS) 75 | $(Q)TEMPFILE=$(shell mktemp); \ 76 | cat $^ | perl docs/doc-preclean.pl >$$TEMPFILE; \ 77 | [ "$KBUILD_BUILD_TIMESTAMP" ] || \ 78 | KBUILD_BUILD_TIMESTAMP=`git log -n1 --pretty=%cd --date=iso -- $^`; \ 79 | export KBUILD_BUILD_TIMESTAMP; \ 80 | LC_ALL=C \ 81 | perl docs/kernel-doc -man $$TEMPFILE | \ 82 | perl docs/split-man.pl docs/man; \ 83 | $(RM) -f $$TEMPFILE 84 | 85 | dep_clean: 86 | $(Q)$(RM) $(OBJS:.o=.d) 87 | -------------------------------------------------------------------------------- /libdmmp/docs/doc-preclean.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # Copyright (C) 2016 Red Hat, Inc. 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | # Author: Gris Ge 18 | 19 | use strict; 20 | 21 | my @REMOVE_KEY_LIST=("DMMP_DLL_EXPORT"); 22 | 23 | while (<>) { 24 | for my $key (@REMOVE_KEY_LIST) { 25 | (s/$key//g); 26 | } 27 | print; 28 | } 29 | -------------------------------------------------------------------------------- /libdmmp/docs/man/dmmp_context_free.3: -------------------------------------------------------------------------------- 1 | .TH "dmmp_context_free" 3 "dmmp_context_free" "March 2018" "Device Mapper Multipath API - libdmmp Manual" 2 | .SH NAME 3 | dmmp_context_free \- Release the memory of struct dmmp_context. 4 | .SH SYNOPSIS 5 | .B "void" dmmp_context_free 6 | .BI "(struct dmmp_context *" ctx ");" 7 | .SH ARGUMENTS 8 | .IP "ctx" 12 9 | Pointer of 'struct dmmp_context'. 10 | .SH "DESCRIPTION" 11 | 12 | Release the memory of struct dmmp_context, but the userdata memory defined 13 | via \fBdmmp_context_userdata_set\fP will not be touched. 14 | .SH "RETURN" 15 | void 16 | -------------------------------------------------------------------------------- /libdmmp/docs/man/dmmp_context_log_func_set.3: -------------------------------------------------------------------------------- 1 | .TH "dmmp_context_log_func_set" 3 "dmmp_context_log_func_set" "March 2018" "Device Mapper Multipath API - libdmmp Manual" 2 | .SH NAME 3 | dmmp_context_log_func_set \- Set log handler function. 4 | .SH SYNOPSIS 5 | .B "void" dmmp_context_log_func_set 6 | .BI "(struct dmmp_context *" ctx "," 7 | .BI "void (*" log_func ") (struct dmmp_context *ctx, int priority, const char *file, int line, const char *func_name, const char *format, va_list args));" 8 | .SH ARGUMENTS 9 | .IP "ctx" 12 10 | Pointer of 'struct dmmp_context'. 11 | If this pointer is NULL, your program will be terminated by assert. 12 | .IP "log_func" 12 13 | Pointer of log handler function. If set to NULL, all log will be 14 | ignored. 15 | .SH "DESCRIPTION" 16 | 17 | Set custom log handler. The log handler will be invoked when log message 18 | is equal or more important(less value) than log priority setting. 19 | Please check manpage libdmmp.h(3) for detail usage. 20 | .SH "RETURN" 21 | void 22 | -------------------------------------------------------------------------------- /libdmmp/docs/man/dmmp_context_log_priority_get.3: -------------------------------------------------------------------------------- 1 | .TH "dmmp_context_log_priority_get" 3 "dmmp_context_log_priority_get" "March 2018" "Device Mapper Multipath API - libdmmp Manual" 2 | .SH NAME 3 | dmmp_context_log_priority_get \- Get log priority. 4 | .SH SYNOPSIS 5 | .B "int" dmmp_context_log_priority_get 6 | .BI "(struct dmmp_context *" ctx ");" 7 | .SH ARGUMENTS 8 | .IP "ctx" 12 9 | Pointer of 'struct dmmp_context'. 10 | If this pointer is NULL, your program will be terminated by assert. 11 | .SH "DESCRIPTION" 12 | 13 | Retrieve current log priority. Valid log priority values are: 14 | 15 | * DMMP_LOG_PRIORITY_ERROR -- 3 16 | 17 | * DMMP_LOG_PRIORITY_WARNING -- 4 18 | 19 | * DMMP_LOG_PRIORITY_INFO -- 5 20 | 21 | * DMMP_LOG_PRIORITY_DEBUG -- 7 22 | .SH "RETURN" 23 | int, log priority. 24 | -------------------------------------------------------------------------------- /libdmmp/docs/man/dmmp_context_log_priority_set.3: -------------------------------------------------------------------------------- 1 | .TH "dmmp_context_log_priority_set" 3 "dmmp_context_log_priority_set" "March 2018" "Device Mapper Multipath API - libdmmp Manual" 2 | .SH NAME 3 | dmmp_context_log_priority_set \- Set log priority. 4 | .SH SYNOPSIS 5 | .B "void" dmmp_context_log_priority_set 6 | .BI "(struct dmmp_context *" ctx "," 7 | .BI "int " priority ");" 8 | .SH ARGUMENTS 9 | .IP "ctx" 12 10 | Pointer of 'struct dmmp_context'. 11 | If this pointer is NULL, your program will be terminated by assert. 12 | .IP "priority" 12 13 | int, log priority. 14 | .SH "DESCRIPTION" 15 | 16 | 17 | When library generates log message, only equal or more important(less value) 18 | message will be forwarded to log handler function. Valid log priority values 19 | are: 20 | 21 | * DMMP_LOG_PRIORITY_ERROR -- 3 22 | 23 | * DMMP_LOG_PRIORITY_WARNING -- 4 24 | 25 | * DMMP_LOG_PRIORITY_INFO -- 5 26 | 27 | * DMMP_LOG_PRIORITY_DEBUG -- 7 28 | .SH "RETURN" 29 | void 30 | -------------------------------------------------------------------------------- /libdmmp/docs/man/dmmp_context_new.3: -------------------------------------------------------------------------------- 1 | .TH "dmmp_context_new" 3 "dmmp_context_new" "March 2018" "Device Mapper Multipath API - libdmmp Manual" 2 | .SH NAME 3 | dmmp_context_new \- Create struct dmmp_context. 4 | .SH SYNOPSIS 5 | .B "struct dmmp_context *" dmmp_context_new 6 | .BI "(" void ");" 7 | .SH ARGUMENTS 8 | .IP "void" 12 9 | no arguments 10 | .SH "DESCRIPTION" 11 | 12 | The default logging level (DMMP_LOG_PRIORITY_DEFAULT) is 13 | DMMP_LOG_PRIORITY_WARNING which means only warning and error message will be 14 | forward to log handler function. The default log handler function will print 15 | log message to STDERR, to change so, please use \fBdmmp_context_log_func_set\fP 16 | to set your own log handler, check manpage libdmmp.h(3) for detail. 17 | .SH "RETURN" 18 | Pointer of 'struct dmmp_context'. Should be freed by 19 | \fBdmmp_context_free\fP. 20 | -------------------------------------------------------------------------------- /libdmmp/docs/man/dmmp_context_timeout_get.3: -------------------------------------------------------------------------------- 1 | .TH "dmmp_context_timeout_get" 3 "dmmp_context_timeout_get" "March 2018" "Device Mapper Multipath API - libdmmp Manual" 2 | .SH NAME 3 | dmmp_context_timeout_get \- Get IPC timeout. 4 | .SH SYNOPSIS 5 | .B "unsigned int" dmmp_context_timeout_get 6 | .BI "(struct dmmp_context *" ctx ");" 7 | .SH ARGUMENTS 8 | .IP "ctx" 12 9 | Pointer of 'struct dmmp_context'. 10 | If this pointer is NULL, your program will be terminated by assert. 11 | .SH "DESCRIPTION" 12 | 13 | Retrieve timeout value of IPC connection to multipathd daemon. 14 | .SH "RETURN" 15 | unsigned int. Timeout in milliseconds. 16 | -------------------------------------------------------------------------------- /libdmmp/docs/man/dmmp_context_timeout_set.3: -------------------------------------------------------------------------------- 1 | .TH "dmmp_context_timeout_set" 3 "dmmp_context_timeout_set" "March 2018" "Device Mapper Multipath API - libdmmp Manual" 2 | .SH NAME 3 | dmmp_context_timeout_set \- Set IPC timeout. 4 | .SH SYNOPSIS 5 | .B "void" dmmp_context_timeout_set 6 | .BI "(struct dmmp_context *" ctx "," 7 | .BI "unsigned int " tmo ");" 8 | .SH ARGUMENTS 9 | .IP "ctx" 12 10 | Pointer of 'struct dmmp_context'. 11 | If this pointer is NULL, your program will be terminated by assert. 12 | .IP "tmo" 12 13 | Timeout in milliseconds(1 seconds equal 1000 milliseconds). 14 | 0 means infinite, function only return when error or pass. 15 | .SH "DESCRIPTION" 16 | 17 | By default, the IPC to multipathd daemon will timeout after 60 seconds. 18 | .SH "RETURN" 19 | void 20 | -------------------------------------------------------------------------------- /libdmmp/docs/man/dmmp_context_userdata_get.3: -------------------------------------------------------------------------------- 1 | .TH "dmmp_context_userdata_get" 3 "dmmp_context_userdata_get" "March 2018" "Device Mapper Multipath API - libdmmp Manual" 2 | .SH NAME 3 | dmmp_context_userdata_get \- Get user data pointer. 4 | .SH SYNOPSIS 5 | .B "void *" dmmp_context_userdata_get 6 | .BI "(struct dmmp_context *" ctx ");" 7 | .SH ARGUMENTS 8 | .IP "ctx" 12 9 | Pointer of 'struct dmmp_context'. 10 | If this pointer is NULL, your program will be terminated by assert. 11 | .SH "DESCRIPTION" 12 | 13 | Retrieve user data pointer from 'struct dmmp_context'. 14 | .SH "RETURN" 15 | void *. Pointer of user defined data. 16 | -------------------------------------------------------------------------------- /libdmmp/docs/man/dmmp_context_userdata_set.3: -------------------------------------------------------------------------------- 1 | .TH "dmmp_context_userdata_set" 3 "dmmp_context_userdata_set" "March 2018" "Device Mapper Multipath API - libdmmp Manual" 2 | .SH NAME 3 | dmmp_context_userdata_set \- Set user data pointer. 4 | .SH SYNOPSIS 5 | .B "void" dmmp_context_userdata_set 6 | .BI "(struct dmmp_context *" ctx "," 7 | .BI "void *" userdata ");" 8 | .SH ARGUMENTS 9 | .IP "ctx" 12 10 | Pointer of 'struct dmmp_context'. 11 | If this pointer is NULL, your program will be terminated by assert. 12 | .IP "userdata" 12 13 | Pointer of user defined data. 14 | .SH "DESCRIPTION" 15 | 16 | Store user data pointer into 'struct dmmp_context'. 17 | .SH "RETURN" 18 | void 19 | -------------------------------------------------------------------------------- /libdmmp/docs/man/dmmp_flush_mpath.3: -------------------------------------------------------------------------------- 1 | .TH "dmmp_flush_mpath" 3 "dmmp_flush_mpath" "March 2018" "Device Mapper Multipath API - libdmmp Manual" 2 | .SH NAME 3 | dmmp_flush_mpath \- Flush specified multipath device map if unused. 4 | .SH SYNOPSIS 5 | .B "int" dmmp_flush_mpath 6 | .BI "(struct dmmp_context *" ctx "," 7 | .BI "const char *" mpath_name ");" 8 | .SH ARGUMENTS 9 | .IP "ctx" 12 10 | Pointer of 'struct dmmp_context'. 11 | If this pointer is NULL, your program will be terminated by assert. 12 | .IP "mpath_name" 12 13 | const char *. The name of multipath device map. 14 | .SH "DESCRIPTION" 15 | 16 | Flush a multipath device map specified as parameter, if unused. 17 | .SH "RETURN" 18 | int. Valid error codes are: 19 | 20 | * DMMP_OK 21 | 22 | * DMMP_ERR_BUG 23 | 24 | * DMMP_ERR_NO_MEMORY 25 | 26 | * DMMP_ERR_NO_DAEMON 27 | 28 | * DMMP_ERR_MPATH_BUSY 29 | 30 | * DMMP_ERR_MPATH_NOT_FOUND 31 | 32 | * DMMP_ERR_INVALID_ARGUMENT 33 | 34 | * DMMP_ERR_PERMISSION_DENY 35 | 36 | Error number could be converted to string by \fBdmmp_strerror\fP. 37 | -------------------------------------------------------------------------------- /libdmmp/docs/man/dmmp_last_error_msg.3: -------------------------------------------------------------------------------- 1 | .TH "dmmp_last_error_msg" 3 "dmmp_last_error_msg" "March 2018" "Device Mapper Multipath API - libdmmp Manual" 2 | .SH NAME 3 | dmmp_last_error_msg \- Retrieves the last error message. 4 | .SH SYNOPSIS 5 | .B "const char *" dmmp_last_error_msg 6 | .BI "(struct dmmp_context *" ctx ");" 7 | .SH ARGUMENTS 8 | .IP "ctx" 12 9 | Pointer of 'struct dmmp_context'. 10 | If this pointer is NULL, your program will be terminated by assert. 11 | .SH "DESCRIPTION" 12 | 13 | Retrieves the last error message. 14 | .SH "RETURN" 15 | const char *. No need to free this memory, the resources will get 16 | freed when \fBdmmp_context_free\fP. 17 | -------------------------------------------------------------------------------- /libdmmp/docs/man/dmmp_log_priority_str.3: -------------------------------------------------------------------------------- 1 | .TH "dmmp_log_priority_str" 3 "dmmp_log_priority_str" "March 2018" "Device Mapper Multipath API - libdmmp Manual" 2 | .SH NAME 3 | dmmp_log_priority_str \- Convert log priority to string. 4 | .SH SYNOPSIS 5 | .B "const char *" dmmp_log_priority_str 6 | .BI "(int " priority ");" 7 | .SH ARGUMENTS 8 | .IP "priority" 12 9 | int. Log priority. 10 | .SH "DESCRIPTION" 11 | 12 | Convert log priority to string (const char *). 13 | .SH "RETURN" 14 | const char *. Valid string are: 15 | 16 | * "ERROR" for DMMP_LOG_PRIORITY_ERROR 17 | 18 | * "WARN " for DMMP_LOG_PRIORITY_WARNING 19 | 20 | * "INFO " for DMMP_LOG_PRIORITY_INFO 21 | 22 | * "DEBUG" for DMMP_LOG_PRIORITY_DEBUG 23 | 24 | * "Invalid argument" for invalid log priority. 25 | -------------------------------------------------------------------------------- /libdmmp/docs/man/dmmp_mpath_array_free.3: -------------------------------------------------------------------------------- 1 | .TH "dmmp_mpath_array_free" 3 "dmmp_mpath_array_free" "March 2018" "Device Mapper Multipath API - libdmmp Manual" 2 | .SH NAME 3 | dmmp_mpath_array_free \- Free 'struct dmmp_mpath' pointer array. 4 | .SH SYNOPSIS 5 | .B "void" dmmp_mpath_array_free 6 | .BI "(struct dmmp_mpath **" dmmp_mps "," 7 | .BI "uint32_t " dmmp_mp_count ");" 8 | .SH ARGUMENTS 9 | .IP "dmmp_mps" 12 10 | Pointer of 'struct dmmp_mpath' array. 11 | .IP "dmmp_mp_count" 12 12 | uint32_t, the size of 'dmmp_mps' pointer array. 13 | .SH "DESCRIPTION" 14 | 15 | Free the 'dmmp_mps' pointer array generated by \fBdmmp_mpath_array_get\fP. 16 | If provided 'dmmp_mps' pointer is NULL or dmmp_mp_count == 0, do nothing. 17 | .SH "RETURN" 18 | void 19 | -------------------------------------------------------------------------------- /libdmmp/docs/man/dmmp_mpath_array_get.3: -------------------------------------------------------------------------------- 1 | .TH "dmmp_mpath_array_get" 3 "dmmp_mpath_array_get" "March 2018" "Device Mapper Multipath API - libdmmp Manual" 2 | .SH NAME 3 | dmmp_mpath_array_get \- Query all existing multipath devices. 4 | .SH SYNOPSIS 5 | .B "int" dmmp_mpath_array_get 6 | .BI "(struct dmmp_context *" ctx "," 7 | .BI "struct dmmp_mpath ***" dmmp_mps "," 8 | .BI "uint32_t *" dmmp_mp_count ");" 9 | .SH ARGUMENTS 10 | .IP "ctx" 12 11 | Pointer of 'struct dmmp_context'. 12 | If this pointer is NULL, your program will be terminated by assert. 13 | .IP "dmmp_mps" 12 14 | Output pointer array of 'struct dmmp_mpath'. 15 | If this pointer is NULL, your program will be terminated by assert. 16 | .IP "dmmp_mp_count" 12 17 | Output pointer of uint32_t. Hold the size of 'dmmp_mps' pointer array. 18 | If this pointer is NULL, your program will be terminated by assert. 19 | .SH "DESCRIPTION" 20 | 21 | Query all existing multipath devices and store them into a pointer array. 22 | The memory of 'dmmp_mps' should be freed via \fBdmmp_mpath_array_free\fP. 23 | .SH "RETURN" 24 | int. Valid error codes are: 25 | 26 | * DMMP_OK 27 | 28 | * DMMP_ERR_BUG 29 | 30 | * DMMP_ERR_NO_MEMORY 31 | 32 | * DMMP_ERR_NO_DAEMON 33 | 34 | * DMMP_ERR_INCONSISTENT_DATA 35 | 36 | Error number could be converted to string by \fBdmmp_strerror\fP. 37 | -------------------------------------------------------------------------------- /libdmmp/docs/man/dmmp_mpath_kdev_name_get.3: -------------------------------------------------------------------------------- 1 | .TH "dmmp_mpath_kdev_name_get" 3 "dmmp_mpath_kdev_name_get" "March 2018" "Device Mapper Multipath API - libdmmp Manual" 2 | .SH NAME 3 | dmmp_mpath_kdev_name_get \- Retrieve kernel DEVNAME of certain mpath. 4 | .SH SYNOPSIS 5 | .B "const char *" dmmp_mpath_kdev_name_get 6 | .BI "(struct dmmp_mpath *" dmmp_mp ");" 7 | .SH ARGUMENTS 8 | .IP "dmmp_mp" 12 9 | Pointer of 'struct dmmp_mpath'. 10 | If this pointer is NULL, your program will be terminated by assert. 11 | .SH "DESCRIPTION" 12 | 13 | Retrieve DEVNAME name used by kernel uevent of specified mpath. 14 | For example: 'dm-1'. 15 | .SH "RETURN" 16 | const char *. No need to free this memory, the resources will get 17 | freed when \fBdmmp_mpath_array_free\fP. 18 | -------------------------------------------------------------------------------- /libdmmp/docs/man/dmmp_mpath_name_get.3: -------------------------------------------------------------------------------- 1 | .TH "dmmp_mpath_name_get" 3 "dmmp_mpath_name_get" "March 2018" "Device Mapper Multipath API - libdmmp Manual" 2 | .SH NAME 3 | dmmp_mpath_name_get \- Retrieve name(alias) of certain mpath. 4 | .SH SYNOPSIS 5 | .B "const char *" dmmp_mpath_name_get 6 | .BI "(struct dmmp_mpath *" dmmp_mp ");" 7 | .SH ARGUMENTS 8 | .IP "dmmp_mp" 12 9 | Pointer of 'struct dmmp_mpath'. 10 | If this pointer is NULL, your program will be terminated by assert. 11 | .SH "DESCRIPTION" 12 | 13 | Retrieve the name (also known as alias) of certain mpath. 14 | When the config 'user_friendly_names' been set 'no', the name will be 15 | identical to WWID retrieved by \fBdmmp_mpath_wwid_get\fP. 16 | .SH "RETURN" 17 | const char *. No need to free this memory, the resources will get 18 | freed when \fBdmmp_mpath_array_free\fP. 19 | -------------------------------------------------------------------------------- /libdmmp/docs/man/dmmp_mpath_wwid_get.3: -------------------------------------------------------------------------------- 1 | .TH "dmmp_mpath_wwid_get" 3 "dmmp_mpath_wwid_get" "March 2018" "Device Mapper Multipath API - libdmmp Manual" 2 | .SH NAME 3 | dmmp_mpath_wwid_get \- Retrieve WWID of certain mpath. 4 | .SH SYNOPSIS 5 | .B "const char *" dmmp_mpath_wwid_get 6 | .BI "(struct dmmp_mpath *" dmmp_mp ");" 7 | .SH ARGUMENTS 8 | .IP "dmmp_mp" 12 9 | Pointer of 'struct dmmp_mpath'. 10 | If this pointer is NULL, your program will be terminated by assert. 11 | .SH "RETURN" 12 | const char *. No need to free this memory, the resources will get 13 | freed when \fBdmmp_mpath_array_free\fP. 14 | -------------------------------------------------------------------------------- /libdmmp/docs/man/dmmp_path_array_get.3: -------------------------------------------------------------------------------- 1 | .TH "dmmp_path_array_get" 3 "dmmp_path_array_get" "March 2018" "Device Mapper Multipath API - libdmmp Manual" 2 | .SH NAME 3 | dmmp_path_array_get \- Retrieve path pointer array. 4 | .SH SYNOPSIS 5 | .B "void" dmmp_path_array_get 6 | .BI "(struct dmmp_path_group *" dmmp_pg "," 7 | .BI "struct dmmp_path ***" dmmp_ps "," 8 | .BI "uint32_t *" dmmp_p_count ");" 9 | .SH ARGUMENTS 10 | .IP "dmmp_pg" 12 11 | Pointer of 'struct dmmp_path_group'. 12 | If this pointer is NULL, your program will be terminated by assert. 13 | .IP "dmmp_ps" 12 14 | Output pointer of 'struct dmmp_path' pointer array. 15 | If this pointer is NULL, your program will be terminated by assert. 16 | .IP "dmmp_p_count" 12 17 | Output pointer of uint32_t. Hold the size of 'dmmp_ps' pointer array. 18 | If this pointer is NULL, your program will be terminated by assert. 19 | .SH "DESCRIPTION" 20 | 21 | The memory of output pointer array is hold by 'struct dmmp_mpath', no 22 | need to free this memory, the resources will got freed when 23 | \fBdmmp_mpath_array_free\fP. 24 | .SH "RETURN" 25 | void 26 | -------------------------------------------------------------------------------- /libdmmp/docs/man/dmmp_path_blk_name_get.3: -------------------------------------------------------------------------------- 1 | .TH "dmmp_path_blk_name_get" 3 "dmmp_path_blk_name_get" "March 2018" "Device Mapper Multipath API - libdmmp Manual" 2 | .SH NAME 3 | dmmp_path_blk_name_get \- Retrieve block name. 4 | .SH SYNOPSIS 5 | .B "const char *" dmmp_path_blk_name_get 6 | .BI "(struct dmmp_path *" dmmp_p ");" 7 | .SH ARGUMENTS 8 | .IP "dmmp_p" 12 9 | Pointer of 'struct dmmp_path'. 10 | If this pointer is NULL, your program will be terminated by assert. 11 | .SH "DESCRIPTION" 12 | 13 | Retrieve block name of certain path. The example of block names are "sda", 14 | "nvme0n1". 15 | .SH "RETURN" 16 | const char *. No need to free this memory, the resources will get 17 | freed when \fBdmmp_mpath_array_free\fP. 18 | -------------------------------------------------------------------------------- /libdmmp/docs/man/dmmp_path_group_array_get.3: -------------------------------------------------------------------------------- 1 | .TH "dmmp_path_group_array_get" 3 "dmmp_path_group_array_get" "March 2018" "Device Mapper Multipath API - libdmmp Manual" 2 | .SH NAME 3 | dmmp_path_group_array_get \- Retrieve path groups pointer array. 4 | .SH SYNOPSIS 5 | .B "void" dmmp_path_group_array_get 6 | .BI "(struct dmmp_mpath *" dmmp_mp "," 7 | .BI "struct dmmp_path_group ***" dmmp_pgs "," 8 | .BI "uint32_t *" dmmp_pg_count ");" 9 | .SH ARGUMENTS 10 | .IP "dmmp_mp" 12 11 | Pointer of 'struct dmmp_mpath'. 12 | If this pointer is NULL, your program will be terminated by assert. 13 | .IP "dmmp_pgs" 12 14 | Output pointer of 'struct dmmp_path_group' pointer array. 15 | If this pointer is NULL, your program will be terminated by assert. 16 | .IP "dmmp_pg_count" 12 17 | Output pointer of uint32_t. Hold the size of 'dmmp_pgs' pointer array. 18 | If this pointer is NULL, your program will be terminated by assert. 19 | .SH "DESCRIPTION" 20 | 21 | Retrieve the path groups of certain mpath. 22 | 23 | The memory of output pointer array is hold by 'struct dmmp_mpath', no 24 | need to free this memory, the resources will got freed when 25 | \fBdmmp_mpath_array_free\fP. 26 | .SH "RETURN" 27 | void 28 | -------------------------------------------------------------------------------- /libdmmp/docs/man/dmmp_path_group_id_get.3: -------------------------------------------------------------------------------- 1 | .TH "dmmp_path_group_id_get" 3 "dmmp_path_group_id_get" "March 2018" "Device Mapper Multipath API - libdmmp Manual" 2 | .SH NAME 3 | dmmp_path_group_id_get \- Retrieve path group ID. 4 | .SH SYNOPSIS 5 | .B "uint32_t" dmmp_path_group_id_get 6 | .BI "(struct dmmp_path_group *" dmmp_pg ");" 7 | .SH ARGUMENTS 8 | .IP "dmmp_pg" 12 9 | Pointer of 'struct dmmp_path_group'. 10 | If this pointer is NULL, your program will be terminated by assert. 11 | .SH "DESCRIPTION" 12 | 13 | Retrieve the path group ID which could be used to switch active path group 14 | via command: 15 | 16 | multipathd -k'switch multipath mpathb group $id' 17 | .SH "RETURN" 18 | uint32_t. 19 | -------------------------------------------------------------------------------- /libdmmp/docs/man/dmmp_path_group_priority_get.3: -------------------------------------------------------------------------------- 1 | .TH "dmmp_path_group_priority_get" 3 "dmmp_path_group_priority_get" "March 2018" "Device Mapper Multipath API - libdmmp Manual" 2 | .SH NAME 3 | dmmp_path_group_priority_get \- Retrieve path group priority. 4 | .SH SYNOPSIS 5 | .B "uint32_t" dmmp_path_group_priority_get 6 | .BI "(struct dmmp_path_group *" dmmp_pg ");" 7 | .SH ARGUMENTS 8 | .IP "dmmp_pg" 12 9 | Pointer of 'struct dmmp_path_group'. 10 | If this pointer is NULL, your program will be terminated by assert. 11 | .SH "DESCRIPTION" 12 | 13 | The enabled path group with highest priority will be next active path group 14 | if active path group down. 15 | .SH "RETURN" 16 | uint32_t. 17 | -------------------------------------------------------------------------------- /libdmmp/docs/man/dmmp_path_group_selector_get.3: -------------------------------------------------------------------------------- 1 | .TH "dmmp_path_group_selector_get" 3 "dmmp_path_group_selector_get" "March 2018" "Device Mapper Multipath API - libdmmp Manual" 2 | .SH NAME 3 | dmmp_path_group_selector_get \- Retrieve path group selector. 4 | .SH SYNOPSIS 5 | .B "const char *" dmmp_path_group_selector_get 6 | .BI "(struct dmmp_path_group *" dmmp_pg ");" 7 | .SH ARGUMENTS 8 | .IP "dmmp_pg" 12 9 | Pointer of 'struct dmmp_path_group'. 10 | If this pointer is NULL, your program will be terminated by assert. 11 | .SH "DESCRIPTION" 12 | 13 | Path group selector determine which path in active path group will be 14 | use to next I/O. 15 | .SH "RETURN" 16 | const char *. 17 | -------------------------------------------------------------------------------- /libdmmp/docs/man/dmmp_path_group_status_get.3: -------------------------------------------------------------------------------- 1 | .TH "dmmp_path_group_status_get" 3 "dmmp_path_group_status_get" "March 2018" "Device Mapper Multipath API - libdmmp Manual" 2 | .SH NAME 3 | dmmp_path_group_status_get \- Retrieve path group status. 4 | .SH SYNOPSIS 5 | .B "uint32_t" dmmp_path_group_status_get 6 | .BI "(struct dmmp_path_group *" dmmp_pg ");" 7 | .SH ARGUMENTS 8 | .IP "dmmp_pg" 12 9 | Pointer of 'struct dmmp_path_group'. 10 | If this pointer is NULL, your program will be terminated by assert. 11 | .SH "DESCRIPTION" 12 | 13 | The valid path group statuses are: 14 | 15 | * DMMP_PATH_GROUP_STATUS_UNKNOWN 16 | 17 | * DMMP_PATH_GROUP_STATUS_ENABLED -- standby to be active 18 | 19 | * DMMP_PATH_GROUP_STATUS_DISABLED -- disabled due to all path down 20 | 21 | * DMMP_PATH_GROUP_STATUS_ACTIVE -- selected to handle I/O 22 | .SH "RETURN" 23 | uint32_t. 24 | -------------------------------------------------------------------------------- /libdmmp/docs/man/dmmp_path_group_status_str.3: -------------------------------------------------------------------------------- 1 | .TH "dmmp_path_group_status_str" 3 "dmmp_path_group_status_str" "March 2018" "Device Mapper Multipath API - libdmmp Manual" 2 | .SH NAME 3 | dmmp_path_group_status_str \- Convert path group status to string. 4 | .SH SYNOPSIS 5 | .B "const char *" dmmp_path_group_status_str 6 | .BI "(uint32_t " pg_status ");" 7 | .SH ARGUMENTS 8 | .IP "pg_status" 12 9 | uint32_t. Path group status. 10 | When provided value is not a valid path group status, return "Invalid 11 | argument". 12 | .SH "DESCRIPTION" 13 | 14 | Convert path group status uint32_t to string (const char *). 15 | .SH "RETURN" 16 | const char *. Valid string are: 17 | 18 | * "Invalid argument" 19 | 20 | * "undef" 21 | 22 | * "enabled" 23 | 24 | * "disabled" 25 | 26 | * "active" 27 | -------------------------------------------------------------------------------- /libdmmp/docs/man/dmmp_path_status_get.3: -------------------------------------------------------------------------------- 1 | .TH "dmmp_path_status_get" 3 "dmmp_path_status_get" "March 2018" "Device Mapper Multipath API - libdmmp Manual" 2 | .SH NAME 3 | dmmp_path_status_get \- Retrieve the path status. 4 | .SH SYNOPSIS 5 | .B "uint32_t" dmmp_path_status_get 6 | .BI "(struct dmmp_path *" dmmp_p ");" 7 | .SH ARGUMENTS 8 | .IP "dmmp_p" 12 9 | Pointer of 'struct dmmp_path'. 10 | If this pointer is NULL, your program will be terminated by assert. 11 | .SH "DESCRIPTION" 12 | 13 | The valid path statuses are: 14 | 15 | * DMMP_PATH_STATUS_UNKNOWN 16 | 17 | * DMMP_PATH_STATUS_DOWN 18 | 19 | Path is down and you shouldn't try to send commands to it. 20 | 21 | * DMMP_PATH_STATUS_UP 22 | 23 | Path is up and I/O can be sent to it. 24 | 25 | * DMMP_PATH_STATUS_SHAKY 26 | 27 | Only emc_clariion checker when path not available for "normal" 28 | operations. 29 | 30 | * DMMP_PATH_STATUS_GHOST 31 | 32 | Only hp_sw and rdac checkers. Indicates a "passive/standby" 33 | path on active/passive HP arrays. These paths will return valid 34 | answers to certain SCSI commands (tur, read_capacity, inquiry, 35 | start_stop), but will fail I/O commands. The path needs an 36 | initialization command to be sent to it in order for I/Os to 37 | succeed. 38 | 39 | * DMMP_PATH_STATUS_PENDING 40 | 41 | Available for all async checkers when a check IO is in flight. 42 | 43 | * DMMP_PATH_STATUS_TIMEOUT 44 | 45 | Only tur checker when command timed out. 46 | 47 | * DMMP_PATH_STATUS_DELAYED 48 | 49 | If a path fails after being up for less than delay_watch_checks checks, 50 | when it comes back up again, it will not be marked as up until it has 51 | been up for delay_wait_checks checks. During this time, it is marked as 52 | "delayed". 53 | .SH "RETURN" 54 | uint32_t. 55 | -------------------------------------------------------------------------------- /libdmmp/docs/man/dmmp_path_status_str.3: -------------------------------------------------------------------------------- 1 | .TH "dmmp_path_status_str" 3 "dmmp_path_status_str" "March 2018" "Device Mapper Multipath API - libdmmp Manual" 2 | .SH NAME 3 | dmmp_path_status_str \- Convert path status to string. 4 | .SH SYNOPSIS 5 | .B "const char *" dmmp_path_status_str 6 | .BI "(uint32_t " path_status ");" 7 | .SH ARGUMENTS 8 | .IP "path_status" 12 9 | uint32_t. Path status. 10 | When provided value is not a valid path status, return 11 | "Invalid argument". 12 | .SH "DESCRIPTION" 13 | 14 | Convert path status uint32_t to string (const char *): 15 | 16 | * DMMP_PATH_STATUS_UNKNOWN -- "undef" 17 | 18 | * DMMP_PATH_STATUS_DOWN -- "faulty" 19 | 20 | * DMMP_PATH_STATUS_UP -- "ready" 21 | 22 | * DMMP_PATH_STATUS_SHAKY -- "shaky" 23 | 24 | * DMMP_PATH_STATUS_GHOST -- "ghost" 25 | 26 | * DMMP_PATH_STATUS_PENDING -- "pending" 27 | 28 | * DMMP_PATH_STATUS_TIMEOUT -- "timeout" 29 | 30 | * DMMP_PATH_STATUS_REMOVED -- "removed" 31 | 32 | * DMMP_PATH_STATUS_DELAYED -- "delayed" 33 | .SH "RETURN" 34 | const char *. The meaning of status value. 35 | -------------------------------------------------------------------------------- /libdmmp/docs/man/dmmp_reconfig.3: -------------------------------------------------------------------------------- 1 | .TH "dmmp_reconfig" 3 "dmmp_reconfig" "March 2018" "Device Mapper Multipath API - libdmmp Manual" 2 | .SH NAME 3 | dmmp_reconfig \- Instruct multipathd daemon to do reconfiguration. 4 | .SH SYNOPSIS 5 | .B "int" dmmp_reconfig 6 | .BI "(struct dmmp_context *" ctx ");" 7 | .SH ARGUMENTS 8 | .IP "ctx" 12 9 | Pointer of 'struct dmmp_context'. 10 | If this pointer is NULL, your program will be terminated by assert. 11 | .SH "DESCRIPTION" 12 | 13 | Instruct multipathd daemon to do reconfiguration. 14 | .SH "RETURN" 15 | int. Valid error codes are: 16 | 17 | * DMMP_OK 18 | 19 | * DMMP_ERR_BUG 20 | 21 | * DMMP_ERR_NO_MEMORY 22 | 23 | * DMMP_ERR_NO_DAEMON 24 | 25 | * DMMP_ERR_PERMISSION_DENY 26 | 27 | Error number could be converted to string by \fBdmmp_strerror\fP. 28 | -------------------------------------------------------------------------------- /libdmmp/docs/man/dmmp_strerror.3: -------------------------------------------------------------------------------- 1 | .TH "dmmp_strerror" 3 "dmmp_strerror" "March 2018" "Device Mapper Multipath API - libdmmp Manual" 2 | .SH NAME 3 | dmmp_strerror \- Convert error code to string. 4 | .SH SYNOPSIS 5 | .B "const char *" dmmp_strerror 6 | .BI "(int " rc ");" 7 | .SH ARGUMENTS 8 | .IP "rc" 12 9 | int. Return code by libdmmp functions. When provided error code is not a 10 | valid error code, return "Invalid argument". 11 | .SH "DESCRIPTION" 12 | 13 | Convert error code (int) to string (const char *): 14 | 15 | * DMMP_OK -- "OK" 16 | 17 | * DMMP_ERR_BUG -- "BUG of libdmmp library" 18 | 19 | * DMMP_ERR_NO_MEMORY -- "Out of memory" 20 | 21 | * DMMP_ERR_IPC_TIMEOUT -- "Timeout when communicate with multipathd, 22 | try to set bigger timeout value via dmmp_context_timeout_set ()" 23 | 24 | * DMMP_ERR_IPC_ERROR -- "Error when communicate with multipathd daemon" 25 | 26 | * DMMP_ERR_NO_DAEMON -- "The multipathd daemon not started" 27 | 28 | * DMMP_ERR_INCOMPATIBLE -- "The multipathd daemon version is not 29 | compatible with current library" 30 | 31 | * Other invalid error number -- "Invalid argument" 32 | .SH "RETURN" 33 | const char *. The meaning of provided error code. 34 | -------------------------------------------------------------------------------- /libdmmp/docs/split-man.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # Originally From: 3 | # https://www.kernel.org/doc/Documentation/kernel-doc-nano-HOWTO.txt 4 | # 5 | # Changes: 6 | # * Create manpage section 3 instead of 9. 7 | # * Replace 'Kernel Hackers Manual' to 8 | # 'Device Mapper Multipath API - libdmmp Manual' 9 | # * Remove LINUX from header. 10 | # * Remove DMMP_DLL_EXPORT. 11 | $man_sec_num = 3; 12 | $title = 'Device Mapper Multipath API - libdmmp Manual'; 13 | 14 | if ( $#ARGV < 0 ) { 15 | die "where do I put the results?\n"; 16 | } 17 | 18 | mkdir $ARGV[0], 0777; 19 | $state = 0; 20 | while () { 21 | if (/^\.TH \"[^\"]*\" 9 \"([^\"]*)\"/) { 22 | if ( $state == 1 ) { close OUT } 23 | $state = 1; 24 | $fn = "$ARGV[0]/$1.$man_sec_num"; 25 | print STDERR "Creating $fn\n"; 26 | open OUT, ">$fn" or die "can't open $fn: $!\n"; 27 | 28 | # Change man page code from 9 to $man_sec_num; 29 | s/^\.TH (\"[^\"]*\") 9 \"([^\"]*)\"/\.TH $1 $man_sec_num \"$2\"/; 30 | s/Kernel Hacker's Manual/$title/g; 31 | s/LINUX//g; 32 | 33 | print OUT $_; 34 | } 35 | elsif ( $state != 0 ) { 36 | print OUT $_; 37 | } 38 | } 39 | 40 | close OUT; 41 | -------------------------------------------------------------------------------- /libdmmp/libdmmp.pc.in: -------------------------------------------------------------------------------- 1 | includedir=__INCLUDEDIR__ 2 | libdir=__LIBDIR__ 3 | 4 | Name: libdmmp 5 | Version: __VERSION__ 6 | Description: Device mapper multipath management library 7 | Requires: 8 | Libs: -L${libdir} -ldmmp 9 | Cflags: -I${includedir} 10 | -------------------------------------------------------------------------------- /libdmmp/test/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile 2 | # 3 | # Copyright (C) 2015-2016 Gris Ge 4 | # 5 | TOPDIR := ../.. 6 | include ../../Makefile.inc 7 | 8 | _libdmmpdir=../$(libdmmpdir) 9 | _mpathcmddir=../$(mpathcmddir) 10 | 11 | TEST_EXEC = libdmmp_test 12 | SPD_TEST_EXEC = libdmmp_speed_test 13 | CPPFLAGS += -I$(_libdmmpdir) 14 | LDFLAGS += -L$(_libdmmpdir) -ldmmp 15 | 16 | all: $(TEST_EXEC) $(SPD_TEST_EXEC) 17 | 18 | check: $(TEST_EXEC) $(SPD_TEST_EXEC) 19 | $(Q)sudo env LD_LIBRARY_PATH=$(_libdmmpdir):$(_mpathcmddir) \ 20 | valgrind --quiet --leak-check=full \ 21 | --show-reachable=no --show-possibly-lost=no \ 22 | --trace-children=yes --error-exitcode=1 \ 23 | ./$(TEST_EXEC) 24 | $(MAKE) speed_test 25 | 26 | speed_test: $(SPD_TEST_EXEC) 27 | $(Q)sudo env LD_LIBRARY_PATH=$(_libdmmpdir):$(_mpathcmddir) \ 28 | time -p ./$(SPD_TEST_EXEC) 29 | 30 | clean: dep_clean 31 | $(Q)$(RM) -f $(TEST_EXEC) $(SPD_TEST_EXEC) 32 | 33 | OBJS = $(TEST_EXEC).o $(SPD_TEST_EXEC).o 34 | include $(wildcard $(OBJS:.o=.d)) 35 | 36 | 37 | dep_clean: 38 | $(Q)$(RM) $(OBJS:.o=.d) 39 | -------------------------------------------------------------------------------- /libdmmp/test/libdmmp_speed_test.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015-2016 Red Hat, Inc. 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Author: Gris Ge 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | 30 | int main(void) 31 | { 32 | struct dmmp_context *ctx = NULL; 33 | struct dmmp_mpath **dmmp_mps = NULL; 34 | uint32_t dmmp_mp_count = 0; 35 | int rc = EXIT_SUCCESS; 36 | 37 | ctx = dmmp_context_new(); 38 | dmmp_context_log_priority_set(ctx, DMMP_LOG_PRIORITY_WARNING); 39 | 40 | if (dmmp_mpath_array_get(ctx, &dmmp_mps, &dmmp_mp_count) != 0) { 41 | printf("FAILED\n"); 42 | rc = EXIT_FAILURE; 43 | } else { 44 | printf("Got %" PRIu32 " mpath\n", dmmp_mp_count); 45 | dmmp_mpath_array_free(dmmp_mps, dmmp_mp_count); 46 | } 47 | dmmp_context_free(ctx); 48 | exit(rc); 49 | } 50 | -------------------------------------------------------------------------------- /libmpathcmd/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | DEVLIB := libmpathcmd.so 4 | CFLAGS += $(LIB_CFLAGS) 5 | OBJS := mpath_cmd.o 6 | 7 | all: $(DEVLIB) 8 | 9 | include $(TOPDIR)/rules.mk 10 | 11 | install: all 12 | $(Q)$(INSTALL_PROGRAM) -d $(DESTDIR)$(syslibdir) 13 | $(Q)$(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(syslibdir)/$(LIBS) 14 | $(Q)$(LN) $(LIBS) $(DESTDIR)$(syslibdir)/$(DEVLIB) 15 | $(Q)$(INSTALL_PROGRAM) -d $(DESTDIR)$(includedir) 16 | $(Q)$(INSTALL_PROGRAM) -m 644 mpath_cmd.h $(DESTDIR)$(includedir) 17 | 18 | uninstall: 19 | $(Q)$(RM) $(DESTDIR)$(syslibdir)/$(LIBS) 20 | $(Q)$(RM) $(DESTDIR)$(syslibdir)/$(DEVLIB) 21 | $(Q)$(RM) $(DESTDIR)$(includedir)/mpath_cmd.h 22 | 23 | clean: dep_clean 24 | $(Q)$(RM) core *.a *.o *.so *.so.* *.abi $(NV_VERSION_SCRIPT) 25 | 26 | include $(wildcard $(OBJS:.o=.d)) 27 | 28 | 29 | dep_clean: 30 | $(Q)$(RM) $(OBJS:.o=.d) 31 | -------------------------------------------------------------------------------- /libmpathcmd/libmpathcmd.version: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 SUSE LLC 3 | * SPDX-License-Identifier: GPL-2.0-or-later 4 | * 5 | * libmpathcmd ABI 6 | * 7 | * The ABI of libmpathcmd is supposed to remain stable. Removing symbols 8 | * or altering existing symbols' semantics is not allowed. When changing a 9 | * a symbol, either use a new name, or explicit symver directives. 10 | * 11 | * See libmultipath.version for general policy about version numbers. 12 | */ 13 | 14 | LIBMPATHCMD_1.0.0 { 15 | global: 16 | mpath_connect; 17 | __mpath_connect; 18 | mpath_disconnect; 19 | mpath_process_cmd; 20 | mpath_recv_reply; 21 | mpath_recv_reply_len; 22 | mpath_recv_reply_data; 23 | mpath_send_cmd; 24 | }; 25 | 26 | LIBMPATHCMD_1.1.0 { 27 | global: 28 | mpath_connect__; 29 | } LIBMPATHCMD_1.0.0; 30 | -------------------------------------------------------------------------------- /libmpathpersist/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | DEVLIB := libmpathpersist.so 4 | CFLAGS += $(LIB_CFLAGS) -I$(multipathdir) -I$(mpathutildir) -I$(mpathpersistdir) -I$(mpathcmddir) 5 | LDFLAGS += -L$(multipathdir) -L$(mpathutildir) -L$(mpathcmddir) 6 | LIBDEPS += -lmultipath -lmpathutil -lmpathcmd -ldevmapper -lpthread -ldl 7 | 8 | OBJS := mpath_persist.o mpath_updatepr.o mpath_pr_ioctl.o mpath_persist_int.o 9 | 10 | all: $(DEVLIB) 11 | 12 | include $(TOPDIR)/rules.mk 13 | 14 | install: all 15 | $(Q)$(INSTALL_PROGRAM) -d $(DESTDIR)$(syslibdir) 16 | $(Q)$(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(syslibdir)/$(LIBS) 17 | $(Q)$(INSTALL_PROGRAM) -m 755 -d $(DESTDIR)$(syslibdir) 18 | $(Q)$(INSTALL_PROGRAM) -m 755 -d $(DESTDIR)$(mandir)/man3 19 | $(Q)$(INSTALL_PROGRAM) -m 755 -d $(DESTDIR)$(includedir) 20 | $(Q)$(LN) $(LIBS) $(DESTDIR)$(syslibdir)/$(DEVLIB) 21 | $(Q)$(INSTALL_PROGRAM) -m 644 mpath_persistent_reserve_in.3 $(DESTDIR)$(mandir)/man3 22 | $(Q)$(INSTALL_PROGRAM) -m 644 mpath_persistent_reserve_out.3 $(DESTDIR)$(mandir)/man3 23 | $(Q)$(INSTALL_PROGRAM) -m 644 mpath_persist.h $(DESTDIR)$(includedir) 24 | 25 | uninstall: 26 | $(Q)$(RM) $(DESTDIR)$(syslibdir)/$(LIBS) 27 | $(Q)$(RM) $(DESTDIR)$(mandir)/man3/mpath_persistent_reserve_in.3 28 | $(Q)$(RM) $(DESTDIR)$(mandir)/man3/mpath_persistent_reserve_out.3 29 | $(Q)$(RM) $(DESTDIR)$(includedir)/mpath_persist.h 30 | $(Q)$(RM) $(DESTDIR)$(syslibdir)/$(DEVLIB) 31 | 32 | clean: dep_clean 33 | $(Q)$(RM) core *.a *.o *.so *.so.* *.abi $(NV_VERSION_SCRIPT) 34 | 35 | include $(wildcard $(OBJS:.o=.d)) 36 | 37 | 38 | dep_clean: 39 | $(Q)$(RM) $(OBJS:.o=.d) 40 | -------------------------------------------------------------------------------- /libmpathpersist/libmpathpersist.version: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 SUSE LLC 3 | * SPDX-License-Identifier: GPL-2.0-or-later 4 | * 5 | * libmpathpersist ABI 6 | * 7 | * The ABI of libmpathpersist is supposed to remain stable. Removing symbols 8 | * or altering existing symbols' semantics is not allowed. When changing a 9 | * a symbol, either use a new name, or explicit symver directives. 10 | * 11 | * See libmultipath.version for general policy about version numbers. 12 | */ 13 | /* Previous API for backward compatibility */ 14 | LIBMPATHPERSIST_2.1.0 { 15 | global: 16 | libmpathpersist_exit; 17 | libmpathpersist_init; 18 | mpath_lib_exit; 19 | mpath_lib_init; 20 | mpath_mx_alloc_len; 21 | mpath_persistent_reserve_free_vecs; 22 | __mpath_persistent_reserve_in; 23 | mpath_persistent_reserve_in; 24 | mpath_persistent_reserve_init_vecs; 25 | __mpath_persistent_reserve_out; 26 | mpath_persistent_reserve_out; 27 | local: 28 | *; 29 | }; 30 | 31 | LIBMPATHPERSIST_2.2.0 { 32 | global: 33 | mpath_persistent_reserve_in__; 34 | mpath_persistent_reserve_out__; 35 | } LIBMPATHPERSIST_2.1.0; 36 | 37 | __LIBMPATHPERSIST_INT_1.1.0 { 38 | /* Internal use by multipath-tools */ 39 | dumpHex; 40 | mpath_alloc_prin_response; 41 | prin_do_scsi_ioctl; 42 | prout_do_scsi_ioctl; 43 | update_map_pr; 44 | }; 45 | -------------------------------------------------------------------------------- /libmpathpersist/mpath_persist_int.h: -------------------------------------------------------------------------------- 1 | #ifndef MPATH_PERSIST_INT_H_INCLUDED 2 | #define MPATH_PERSIST_INT_H_INCLUDED 3 | 4 | /* 5 | * This header file contains symbols that are used by multipath-tools 6 | * but aren't part of the public libmpathpersist API. 7 | */ 8 | 9 | void * mpath_alloc_prin_response(int prin_sa); 10 | int do_mpath_persistent_reserve_in(vector curmp, vector pathvec, 11 | int fd, int rq_servact, 12 | struct prin_resp *resp, int noisy); 13 | void *mpath_alloc_prin_response(int prin_sa); 14 | int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd, 15 | int rq_servact, int rq_scope, 16 | unsigned int rq_type, 17 | struct prout_param_descriptor *paramp, 18 | int noisy); 19 | int prin_do_scsi_ioctl(char * dev, int rq_servact, struct prin_resp * resp, int noisy); 20 | int prout_do_scsi_ioctl( char * dev, int rq_servact, int rq_scope, 21 | unsigned int rq_type, struct prout_param_descriptor *paramp, int noisy); 22 | void dumpHex(const char* , int len, int no_ascii); 23 | int update_map_pr(struct multipath *mpp); 24 | 25 | #endif /* MPATH_PERSIST_INT_H_INCLUDED */ 26 | -------------------------------------------------------------------------------- /libmpathpersist/mpath_updatepr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include "debug.h" 16 | #include "mpath_cmd.h" 17 | #include "vector.h" 18 | #include "globals.h" 19 | #include "config.h" 20 | #include "uxsock.h" 21 | #include "mpathpr.h" 22 | 23 | 24 | static int do_update_pr(char *alias, char *cmd, char *key) 25 | { 26 | int fd; 27 | char str[256]; 28 | char *reply; 29 | int ret = 0; 30 | int timeout; 31 | struct config *conf; 32 | 33 | conf = get_multipath_config(); 34 | timeout = conf->uxsock_timeout; 35 | put_multipath_config(conf); 36 | 37 | fd = mpath_connect(); 38 | if (fd == -1) { 39 | condlog (0, "ux socket connect error"); 40 | return -1; 41 | } 42 | 43 | if (key) 44 | snprintf(str,sizeof(str),"%s map %s key %s", cmd, alias, key); 45 | else 46 | snprintf(str,sizeof(str),"%s map %s", cmd, alias); 47 | condlog (2, "%s: pr message=%s", alias, str); 48 | if (send_packet(fd, str) != 0) { 49 | condlog(2, "%s: message=%s send error=%d", alias, str, errno); 50 | mpath_disconnect(fd); 51 | return -1; 52 | } 53 | ret = recv_packet(fd, &reply, timeout); 54 | if (ret < 0) { 55 | condlog(2, "%s: message=%s recv error=%d", alias, str, errno); 56 | ret = -1; 57 | } else { 58 | condlog (2, "%s: message=%s reply=%s", alias, str, reply); 59 | if (reply && strncmp(reply,"ok", 2) == 0) 60 | ret = 0; 61 | else 62 | ret = -1; 63 | } 64 | 65 | free(reply); 66 | mpath_disconnect(fd); 67 | return ret; 68 | } 69 | 70 | int update_prflag(char *mapname, int set) { 71 | return do_update_pr(mapname, (set)? "setprstatus" : "unsetprstatus", 72 | NULL); 73 | } 74 | 75 | int update_prkey_flags(char *mapname, uint64_t prkey, uint8_t sa_flags) { 76 | char str[256]; 77 | 78 | if (!prkey) 79 | return do_update_pr(mapname, "unsetprkey", NULL); 80 | sprintf(str, "%" PRIx64 "%s", prkey, 81 | (sa_flags & MPATH_F_APTPL_MASK) ? ":aptpl" : ""); 82 | return do_update_pr(mapname, "setprkey", str); 83 | } 84 | -------------------------------------------------------------------------------- /libmpathpersist/mpathpr.h: -------------------------------------------------------------------------------- 1 | #ifndef MPATHPR_H_INCLUDED 2 | #define MPATHPR_H_INCLUDED 3 | 4 | /* 5 | * This header file contains symbols that are only used by 6 | * libmpathpersist internally. 7 | */ 8 | 9 | int update_prflag(char *mapname, int set); 10 | int update_prkey_flags(char *mapname, uint64_t prkey, uint8_t sa_flags); 11 | #define update_prkey(mapname, prkey) update_prkey_flags(mapname, prkey, 0) 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /libmpathutil/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2003 Christophe Varoqui, 3 | # 4 | include ../Makefile.inc 5 | 6 | DEVLIB := libmpathutil.so 7 | CPPFLAGS += -I. -I$(multipathdir) -I$(mpathcmddir) $(SYSTEMD_CPPFLAGS) 8 | CFLAGS += $(LIB_CFLAGS) -D_GNU_SOURCE 9 | LIBDEPS += -lpthread -ldl -ludev -L$(mpathcmddir) -lmpathcmd $(SYSTEMD_LIBDEPS) -lrt 10 | 11 | # object files referencing MULTIPATH_DIR or CONFIG_DIR 12 | # they need to be recompiled for unit tests 13 | 14 | # other object files 15 | OBJS := parser.o vector.o util.o debug.o time-util.o \ 16 | uxsock.o log_pthread.o log.o strbuf.o globals.o msort.o 17 | 18 | all: $(DEVLIB) 19 | 20 | include $(TOPDIR)/rules.mk 21 | 22 | install: all 23 | $(Q)$(INSTALL_PROGRAM) -d $(DESTDIR)$(syslibdir) 24 | $(Q)$(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(syslibdir)/$(LIBS) 25 | $(Q)$(LN) $(LIBS) $(DESTDIR)$(syslibdir)/$(DEVLIB) 26 | 27 | uninstall: 28 | $(Q)$(RM) $(DESTDIR)$(syslibdir)/$(LIBS) 29 | $(Q)$(RM) $(DESTDIR)$(syslibdir)/$(DEVLIB) 30 | 31 | clean: dep_clean 32 | $(Q)$(RM) core *.a *.o *.so *.so.* *.abi nvme-ioctl.c nvme-ioctl.h $(NV_VERSION_SCRIPT) 33 | 34 | include $(wildcard $(OBJS:.o=.d)) 35 | 36 | dep_clean: 37 | $(Q)$(RM) $(OBJS:.o=.d) 38 | -------------------------------------------------------------------------------- /libmpathutil/debug.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2005 Christophe Varoqui 3 | */ 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "log_pthread.h" 10 | #include 11 | #include 12 | #include "../third-party/valgrind/drd.h" 13 | #include "vector.h" 14 | #include "config.h" 15 | #include "defaults.h" 16 | #include "debug.h" 17 | #include "time-util.h" 18 | #include "util.h" 19 | 20 | int logsink; 21 | int libmp_verbosity = DEFAULT_VERBOSITY; 22 | 23 | void dlog(int prio, const char * fmt, ...) 24 | { 25 | va_list ap; 26 | 27 | va_start(ap, fmt); 28 | if (logsink != LOGSINK_SYSLOG) { 29 | if (logsink == LOGSINK_STDERR_WITH_TIME) { 30 | struct timespec ts; 31 | char buff[32]; 32 | 33 | get_monotonic_time(&ts); 34 | safe_sprintf(buff, "%ld.%06ld", 35 | (long)ts.tv_sec, 36 | ts.tv_nsec/1000); 37 | fprintf(stderr, "%s | ", buff); 38 | } 39 | vfprintf(stderr, fmt, ap); 40 | } 41 | else 42 | log_safe(prio + 3, fmt, ap); 43 | va_end(ap); 44 | } 45 | -------------------------------------------------------------------------------- /libmpathutil/debug.h: -------------------------------------------------------------------------------- 1 | #ifndef DEBUG_H_INCLUDED 2 | #define DEBUG_H_INCLUDED 3 | void dlog (int prio, const char *fmt, ...) 4 | __attribute__((format(printf, 2, 3))); 5 | 6 | 7 | #include 8 | #include 9 | 10 | #include "log_pthread.h" 11 | 12 | extern int logsink; 13 | extern int libmp_verbosity; 14 | 15 | #ifndef MAX_VERBOSITY 16 | #define MAX_VERBOSITY 4 17 | #endif 18 | 19 | enum { 20 | LOGSINK_STDERR_WITH_TIME = 0, 21 | LOGSINK_STDERR_WITHOUT_TIME = -1, 22 | LOGSINK_SYSLOG = 1, 23 | }; 24 | 25 | #define condlog(prio, fmt, args...) \ 26 | do { \ 27 | int __p = (prio); \ 28 | \ 29 | if (__p <= MAX_VERBOSITY && __p <= libmp_verbosity) \ 30 | dlog(__p, fmt "\n", ##args); \ 31 | } while (0) 32 | #endif /* DEBUG_H_INCLUDED */ 33 | -------------------------------------------------------------------------------- /libmpathutil/globals.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "globals.h" 4 | 5 | __attribute__((weak)) struct config *get_multipath_config(void) 6 | { 7 | return NULL; 8 | } 9 | 10 | __attribute__((weak)) void put_multipath_config(void *p __attribute__((unused))) 11 | {} 12 | -------------------------------------------------------------------------------- /libmpathutil/globals.h: -------------------------------------------------------------------------------- 1 | #ifndef GLOBALS_H_INCLUDED 2 | #define GLOBALS_H_INCLUDED 3 | 4 | struct config; 5 | 6 | /* 7 | * libmultipath provides default implementations of 8 | * get_multipath_config() and put_multipath_config(). 9 | * Applications using these should use init_config(file, NULL) 10 | * to load the configuration, rather than load_config(file). 11 | * Likewise, uninit_config() should be used for teardown, but 12 | * using free_config() for that is supported, too. 13 | * Applications can define their own {get,put}_multipath_config() 14 | * functions, which override the library-internal ones, but 15 | * could still call libmp_{get,put}_multipath_config(). 16 | */ 17 | void put_multipath_config(void *); 18 | struct config *get_multipath_config(void); 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /libmpathutil/log.h: -------------------------------------------------------------------------------- 1 | #ifndef LOG_H_INCLUDED 2 | #define LOG_H_INCLUDED 3 | 4 | #define DEFAULT_AREA_SIZE 16384 5 | #define MAX_MSG_SIZE 256 6 | 7 | #ifndef LOGLEVEL 8 | #define LOGLEVEL 5 9 | #endif 10 | 11 | #if LOGDBG 12 | #define logdbg(file, fmt, args...) fprintf(file, fmt, ##args) 13 | #else 14 | #define logdbg(file, fmt, args...) do {} while (0) 15 | #endif 16 | 17 | struct logmsg { 18 | short int prio; 19 | void * next; 20 | char str[0]; 21 | }; 22 | 23 | struct logarea { 24 | int empty; 25 | void * head; 26 | void * tail; 27 | void * start; 28 | void * end; 29 | char * buff; 30 | }; 31 | 32 | extern struct logarea* la; 33 | 34 | int log_init (char * progname, int size); 35 | void log_close (void); 36 | void log_reset (char * progname); 37 | int log_enqueue (int prio, const char * fmt, va_list ap) 38 | __attribute__((format(printf, 2, 0))); 39 | int log_dequeue (void *); 40 | void log_syslog (void *); 41 | void dump_logmsg (void *); 42 | 43 | #endif /* LOG_H_INCLUDED */ 44 | -------------------------------------------------------------------------------- /libmpathutil/log_pthread.h: -------------------------------------------------------------------------------- 1 | #ifndef LOG_PTHREAD_H_INCLUDED 2 | #define LOG_PTHREAD_H_INCLUDED 3 | 4 | #include 5 | 6 | void log_safe(int prio, const char * fmt, va_list ap) 7 | __attribute__((format(printf, 2, 0))); 8 | void log_thread_start(pthread_attr_t *attr); 9 | void log_thread_reset (void); 10 | void log_thread_stop(void); 11 | 12 | #endif /* LOG_PTHREAD_H_INCLUDED */ 13 | -------------------------------------------------------------------------------- /libmpathutil/msort.h: -------------------------------------------------------------------------------- 1 | #ifndef MSORT_H_INCLUDED 2 | #define MSORT_H_INCLUDED 3 | typedef int(*__compar_fn_t)(const void *, const void *); 4 | void msort (void *b, size_t n, size_t s, __compar_fn_t cmp); 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /libmpathutil/parser.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Soft: Keepalived is a failover program for the LVS project 3 | * . It monitor & manipulate 4 | * a loadbalanced server pool using multi-layer checks. 5 | * 6 | * Part: cfreader.c include file. 7 | * 8 | * Version: $Id: parser.h,v 1.0.3 2003/05/11 02:28:03 acassen Exp $ 9 | * 10 | * Author: Alexandre Cassen, 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 15 | * See the GNU General Public License for more details. 16 | * 17 | * This program is free software; you can redistribute it and/or 18 | * modify it under the terms of the GNU General Public License 19 | * as published by the Free Software Foundation; either version 20 | * 2 of the License, or (at your option) any later version. 21 | */ 22 | 23 | #ifndef PARSER_H_INCLUDED 24 | #define PARSER_H_INCLUDED 25 | 26 | /* system includes */ 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | /* local includes */ 35 | #include "vector.h" 36 | struct strbuf; 37 | struct config; 38 | 39 | /* Global definitions */ 40 | #define EOB "}" 41 | #define MAXBUF 1024 42 | 43 | 44 | /* keyword definition */ 45 | typedef int print_fn(struct config *, struct strbuf *, const void *); 46 | typedef int handler_fn(struct config *, vector, const char *file, int line_nr); 47 | 48 | struct keyword { 49 | char *string; 50 | handler_fn *handler; 51 | print_fn *print; 52 | vector sub; 53 | int unique; 54 | }; 55 | 56 | /* Reloading helpers */ 57 | #define SET_RELOAD (reload = 1) 58 | #define UNSET_RELOAD (reload = 0) 59 | #define RELOAD_DELAY 5 60 | 61 | /* iterator helper */ 62 | #define iterate_sub_keywords(k,p,i) \ 63 | for (i = 0; i < (k)->sub->allocated && ((p) = (k)->sub->slot[i]); i++) 64 | 65 | /* Prototypes */ 66 | int keyword_alloc(vector keywords, char *string, handler_fn *handler, 67 | print_fn *print, int unique); 68 | #define install_keyword_root(str, h) keyword_alloc(keywords, str, h, NULL, 1) 69 | void install_sublevel(void); 70 | void install_sublevel_end(void); 71 | 72 | int install_keyword__(vector keywords, char *string, handler_fn *handler, 73 | print_fn *print, int unique); 74 | #define install_keyword(str, vec, pri) install_keyword__(keywords, str, vec, pri, 1) 75 | #define install_keyword_multi(str, vec, pri) install_keyword__(keywords, str, vec, pri, 0) 76 | void dump_keywords(vector keydump, int level); 77 | void free_keywords(vector keywords); 78 | vector alloc_strvec(char *string); 79 | void *set_value(vector strvec); 80 | int process_file(struct config *conf, const char *conf_file); 81 | struct keyword * find_keyword(vector keywords, vector v, char * name); 82 | int snprint_keyword(struct strbuf *buff, const char *fmt, struct keyword *kw, 83 | const void *data); 84 | bool is_quote(const char* token); 85 | 86 | #endif 87 | -------------------------------------------------------------------------------- /libmpathutil/time-util.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "time-util.h" 5 | 6 | void get_monotonic_time(struct timespec *res) 7 | { 8 | struct timespec ts; 9 | int rv = clock_gettime(CLOCK_MONOTONIC, &ts); 10 | 11 | assert(rv == 0); 12 | *res = ts; 13 | } 14 | 15 | /* Initialize @cond as a condition variable that uses the monotonic clock */ 16 | void pthread_cond_init_mono(pthread_cond_t *cond) 17 | { 18 | pthread_condattr_t attr; 19 | int res; 20 | 21 | res = pthread_condattr_init(&attr); 22 | assert(res == 0); 23 | res = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); 24 | assert(res == 0); 25 | res = pthread_cond_init(cond, &attr); 26 | assert(res == 0); 27 | res = pthread_condattr_destroy(&attr); 28 | assert(res == 0); 29 | } 30 | 31 | /* Ensure that 0 <= ts->tv_nsec && ts->tv_nsec < 1000 * 1000 * 1000. */ 32 | void normalize_timespec(struct timespec *ts) 33 | { 34 | while (ts->tv_nsec < 0) { 35 | ts->tv_nsec += 1000L * 1000 * 1000; 36 | ts->tv_sec--; 37 | } 38 | while (ts->tv_nsec >= 1000L * 1000 * 1000) { 39 | ts->tv_nsec -= 1000L * 1000 * 1000; 40 | ts->tv_sec++; 41 | } 42 | } 43 | 44 | /* Compute *res = *a - *b */ 45 | void timespecsub(const struct timespec *a, const struct timespec *b, 46 | struct timespec *res) 47 | { 48 | res->tv_sec = a->tv_sec - b->tv_sec; 49 | res->tv_nsec = a->tv_nsec - b->tv_nsec; 50 | normalize_timespec(res); 51 | } 52 | 53 | int timespeccmp(const struct timespec *a, const struct timespec *b) 54 | { 55 | struct timespec tmp; 56 | 57 | timespecsub(a, b, &tmp); 58 | if (tmp.tv_sec > 0) 59 | return 1; 60 | if (tmp.tv_sec < 0) 61 | return -1; 62 | return tmp.tv_nsec > 0 ? 1 : (tmp.tv_nsec < 0 ? -1 : 0); 63 | } 64 | -------------------------------------------------------------------------------- /libmpathutil/time-util.h: -------------------------------------------------------------------------------- 1 | #ifndef TIME_UTIL_H_INCLUDED 2 | #define TIME_UTIL_H_INCLUDED 3 | 4 | #include 5 | 6 | struct timespec; 7 | 8 | void get_monotonic_time(struct timespec *res); 9 | void pthread_cond_init_mono(pthread_cond_t *cond); 10 | void normalize_timespec(struct timespec *ts); 11 | void timespecsub(const struct timespec *a, const struct timespec *b, 12 | struct timespec *res); 13 | int timespeccmp(const struct timespec *a, const struct timespec *b); 14 | 15 | #endif /* TIME_UTIL_H_INCLUDED */ 16 | -------------------------------------------------------------------------------- /libmpathutil/uxsock.h: -------------------------------------------------------------------------------- 1 | /* some prototypes */ 2 | #ifndef UXSOCK_H_INCLUDED 3 | #define UXSOCK_H_INCLUDED 4 | 5 | int ux_socket_listen(const char *name); 6 | int send_packet(int fd, const char *buf); 7 | int recv_packet(int fd, char **buf, unsigned int timeout); 8 | 9 | #define MAX_CMD_LEN 512 10 | #endif 11 | -------------------------------------------------------------------------------- /libmpathvalid/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | DEVLIB := libmpathvalid.so 4 | CPPFLAGS += -I$(multipathdir) -I$(mpathutildir) -I$(mpathcmddir) 5 | CFLAGS += $(LIB_CFLAGS) 6 | LIBDEPS += -lpthread -ldevmapper -ldl -L$(multipathdir) -lmultipath \ 7 | -L$(mpathutildir) -lmpathutil -L$(mpathcmddir) -lmpathcmd -ludev 8 | 9 | OBJS := mpath_valid.o 10 | 11 | all: $(DEVLIB) 12 | 13 | include $(TOPDIR)/rules.mk 14 | 15 | install: $(LIBS) 16 | $(Q)$(INSTALL_PROGRAM) -m 755 -d $(DESTDIR)$(syslibdir) 17 | $(Q)$(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(syslibdir)/$(LIBS) 18 | $(Q)$(LN) $(LIBS) $(DESTDIR)$(syslibdir)/$(DEVLIB) 19 | $(Q)$(INSTALL_PROGRAM) -m 755 -d $(DESTDIR)$(includedir) 20 | $(Q)$(INSTALL_PROGRAM) -m 644 mpath_valid.h $(DESTDIR)$(includedir) 21 | 22 | uninstall: 23 | $(Q)$(RM) $(DESTDIR)$(syslibdir)/$(LIBS) 24 | $(Q)$(RM) $(DESTDIR)$(syslibdir)/$(DEVLIB) 25 | $(Q)$(RM) $(DESTDIR)$(includedir)/mpath_valid.h 26 | 27 | clean: dep_clean 28 | $(Q)$(RM) core *.a *.o *.so *.so.* *.abi $(NV_VERSION_SCRIPT) 29 | 30 | include $(wildcard $(OBJS:.o=.d)) 31 | 32 | dep_clean: 33 | $(Q)$(RM) $(OBJS:.o=.d) 34 | -------------------------------------------------------------------------------- /libmpathvalid/libmpathvalid.version: -------------------------------------------------------------------------------- 1 | MPATH_1.0 { 2 | global: 3 | mpathvalid_init; 4 | mpathvalid_reload_config; 5 | mpathvalid_exit; 6 | mpathvalid_is_path; 7 | mpathvalid_get_mode; 8 | local: 9 | *; 10 | }; 11 | -------------------------------------------------------------------------------- /libmultipath/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2003 Christophe Varoqui, 3 | # 4 | include ../Makefile.inc 5 | 6 | DEVLIB := libmultipath.so 7 | CPPFLAGS += -I$(mpathutildir) -I$(mpathcmddir) -I$(nvmedir) -D_GNU_SOURCE $(SYSTEMD_CPPFLAGS) 8 | CFLAGS += $(LIB_CFLAGS) 9 | LIBDEPS += -lpthread -ldl -ldevmapper -ludev -L$(mpathutildir) -lmpathutil -L$(mpathcmddir) -lmpathcmd \ 10 | -lmount -lurcu -laio $(SYSTEMD_LIBDEPS) 11 | 12 | # object files referencing MULTIPATH_DIR or CONFIG_DIR 13 | # they need to be recompiled for unit tests 14 | OBJS-U := prio.o checkers.o foreign.o config.o 15 | OBJS-T := $(patsubst %.o,%-test.o,$(OBJS-U)) 16 | 17 | # other object files 18 | OBJS-O := devmapper.o hwtable.o blacklist.o dmparser.o \ 19 | structs.o discovery.o propsel.o dict.o \ 20 | pgpolicies.o defaults.o uevent.o \ 21 | switchgroup.o print.o alias.o \ 22 | configure.o structs_vec.o sysfs.o \ 23 | lock.o file.o wwids.o prioritizers/alua_rtpg.o prkey.o \ 24 | io_err_stat.o dm-generic.o generic.o nvme-lib.o \ 25 | libsg.o valid.o 26 | 27 | OBJS := $(OBJS-O) $(OBJS-U) 28 | 29 | all: $(DEVLIB) 30 | 31 | include $(TOPDIR)/rules.mk 32 | 33 | nvme-lib.o: nvme-lib.c nvme-ioctl.c nvme-ioctl.h 34 | $(Q)$(CC) $(CPPFLAGS) $(CFLAGS) -Wno-unused-function -c -o $@ $< 35 | 36 | # there are lots of "unused parameters" in dict.c 37 | # because not all handler / snprint methods need all parameters 38 | dict.o: dict.c 39 | $(Q)$(CC) $(CPPFLAGS) $(CFLAGS) -Wno-unused-parameter -c -o $@ $< 40 | 41 | make_static = $(shell sed '/^static/!s/^\([a-z]\{1,\} \)/static \1/' <$1 >$2) 42 | 43 | nvme-ioctl.c: nvme/nvme-ioctl.c 44 | $(Q)$(call make_static,$<,$@) 45 | 46 | nvme-ioctl.h: nvme/nvme-ioctl.h 47 | $(Q)$(call make_static,$<,$@) 48 | 49 | ../tests/$(LIBS): $(OBJS-O) $(OBJS-T) $(VERSION_SCRIPT) 50 | $(Q)$(CC) $(LDFLAGS) $(SHARED_FLAGS) -Wl,-soname=`basename $@` \ 51 | -o $@ $(OBJS-O) $(OBJS-T) $(LIBDEPS) 52 | $(Q)$(LN) $@ ${@:.so.0=.so} 53 | 54 | # This rule is invoked from tests/Makefile, overriding configdir and plugindir 55 | %-test.o: %.c 56 | @echo building $@ because of $? 57 | $(Q)$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $< 58 | 59 | test-lib: ../tests/$(LIBS) 60 | 61 | install: all 62 | $(Q)$(INSTALL_PROGRAM) -d $(DESTDIR)$(syslibdir) 63 | $(Q)$(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(syslibdir)/$(LIBS) 64 | $(Q)$(INSTALL_PROGRAM) -m 755 -d $(DESTDIR)$(plugindir) 65 | $(Q)$(LN) $(LIBS) $(DESTDIR)$(syslibdir)/$(DEVLIB) 66 | 67 | uninstall: 68 | $(Q)$(RM) $(DESTDIR)$(syslibdir)/$(LIBS) 69 | $(Q)$(RM) $(DESTDIR)$(syslibdir)/$(DEVLIB) 70 | 71 | clean: dep_clean 72 | $(Q)$(RM) core *.a *.o *.so *.so.* *.abi nvme-ioctl.c nvme-ioctl.h autoconfig.h $(NV_VERSION_SCRIPT) 73 | 74 | include $(wildcard $(OBJS:.o=.d) $(OBJS-T:.o=.d)) 75 | 76 | dep_clean: 77 | $(Q)$(RM) $(OBJS:.o=.d) $(OBJS-T:.o=.d) 78 | -------------------------------------------------------------------------------- /libmultipath/alias.h: -------------------------------------------------------------------------------- 1 | #ifndef ALIAS_H_INCLUDED 2 | #define ALIAS_H_INCLUDED 3 | 4 | int valid_alias(const char *alias); 5 | int get_user_friendly_wwid(const char *alias, char *buff); 6 | char *get_user_friendly_alias(const char *wwid, const char *alias_old, 7 | const char *prefix, bool bindings_read_only); 8 | 9 | struct config; 10 | int check_alias_settings(const struct config *); 11 | void cleanup_bindings(void); 12 | struct inotify_event; 13 | void handle_bindings_file_inotify(const struct inotify_event *event); 14 | #endif /* ALIAS_H_INCLUDED */ 15 | -------------------------------------------------------------------------------- /libmultipath/blacklist.h: -------------------------------------------------------------------------------- 1 | #ifndef BLACKLIST_H_INCLUDED 2 | #define BLACKLIST_H_INCLUDED 3 | 4 | #include 5 | #include 6 | 7 | #define MATCH_NOTHING 0 8 | #define MATCH_WWID_BLIST 1 9 | #define MATCH_DEVICE_BLIST 2 10 | #define MATCH_DEVNODE_BLIST 3 11 | #define MATCH_PROPERTY_BLIST 4 12 | #define MATCH_PROPERTY_BLIST_MISSING 5 13 | #define MATCH_PROTOCOL_BLIST 6 14 | #define MATCH_WWID_BLIST_EXCEPT -MATCH_WWID_BLIST 15 | #define MATCH_DEVICE_BLIST_EXCEPT -MATCH_DEVICE_BLIST 16 | #define MATCH_DEVNODE_BLIST_EXCEPT -MATCH_DEVNODE_BLIST 17 | #define MATCH_PROPERTY_BLIST_EXCEPT -MATCH_PROPERTY_BLIST 18 | #define MATCH_PROTOCOL_BLIST_EXCEPT -MATCH_PROTOCOL_BLIST 19 | 20 | struct blentry { 21 | char * str; 22 | regex_t regex; 23 | bool invert; 24 | int origin; 25 | }; 26 | 27 | struct blentry_device { 28 | char * vendor; 29 | char * product; 30 | regex_t vendor_reg; 31 | regex_t product_reg; 32 | bool vendor_invert; 33 | bool product_invert; 34 | int origin; 35 | }; 36 | 37 | int setup_default_blist (struct config *); 38 | int alloc_ble_device (vector); 39 | int filter_devnode (const struct vector_s *, const struct vector_s *, 40 | const char *); 41 | int filter_wwid (const struct vector_s *, const struct vector_s *, 42 | const char *, const char *); 43 | int filter_device (const struct vector_s *, const struct vector_s *, 44 | const char *, const char *, const char *); 45 | int filter_path (const struct config *, const struct path *); 46 | int filter_property(const struct config *, struct udev_device *, 47 | int, const char*); 48 | int filter_protocol(const struct vector_s *, const struct vector_s *, 49 | const struct path *); 50 | int store_ble (vector, const char *, int); 51 | int set_ble_device (vector, const char *, const char *, int); 52 | void free_blacklist (vector); 53 | void free_blacklist_device (vector); 54 | void merge_blacklist(vector); 55 | void merge_blacklist_device(vector); 56 | 57 | #endif /* BLACKLIST_H_INCLUDED */ 58 | -------------------------------------------------------------------------------- /libmultipath/byteorder.h: -------------------------------------------------------------------------------- 1 | #ifndef BYTEORDER_H_INCLUDED 2 | #define BYTEORDER_H_INCLUDED 3 | 4 | #ifdef __linux__ 5 | # include 6 | # include 7 | #else 8 | # error unsupported 9 | #endif 10 | 11 | #if BYTE_ORDER == LITTLE_ENDIAN 12 | # define le16_to_cpu(x) (uint16_t)(x) 13 | # define be16_to_cpu(x) bswap_16(x) 14 | # define le32_to_cpu(x) (uint32_t)(x) 15 | # define le64_to_cpu(x) (uint64_t)(x) 16 | # define be32_to_cpu(x) bswap_32(x) 17 | # define be64_to_cpu(x) bswap_64(x) 18 | #elif BYTE_ORDER == BIG_ENDIAN 19 | # define le16_to_cpu(x) bswap_16(x) 20 | # define be16_to_cpu(x) (uint16_t)(x) 21 | # define le32_to_cpu(x) bswap_32(x) 22 | # define le64_to_cpu(x) bswap_64(x) 23 | # define be32_to_cpu(x) (uint32_t)(x) 24 | # define be64_to_cpu(x) (uint64_t)(x) 25 | #else 26 | # error unsupported 27 | #endif 28 | 29 | #define cpu_to_le16(x) le16_to_cpu(x) 30 | #define cpu_to_be16(x) be16_to_cpu(x) 31 | #define cpu_to_le32(x) le32_to_cpu(x) 32 | #define cpu_to_be32(x) be32_to_cpu(x) 33 | #define cpu_to_le64(x) le64_to_cpu(x) 34 | #define cpu_to_be64(x) be64_to_cpu(x) 35 | 36 | struct be64 { 37 | uint64_t _v; 38 | }; 39 | 40 | #define get_be64(x) be64_to_cpu((x)._v) 41 | #define put_be64(x, y) do { (x)._v = cpu_to_be64(y); } while (0) 42 | 43 | 44 | #endif /* BYTEORDER_H_INCLUDED */ 45 | -------------------------------------------------------------------------------- /libmultipath/checkers/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2003 Christophe Varoqui, 3 | # 4 | TOPDIR = ../.. 5 | include ../../Makefile.inc 6 | 7 | CPPFLAGS += -I$(multipathdir) -I$(mpathutildir) 8 | CFLAGS += $(LIB_CFLAGS) 9 | LDFLAGS += -L$(multipathdir) -L$(mpathutildir) 10 | LIBDEPS = -lmultipath -lmpathutil -laio -lpthread -lrt 11 | 12 | # If you add or remove a checker also update multipath/multipath.conf.5 13 | LIBS= \ 14 | libcheckcciss_tur.so \ 15 | libcheckreadsector0.so \ 16 | libchecktur.so \ 17 | libcheckdirectio.so \ 18 | libcheckemc_clariion.so \ 19 | libcheckhp_sw.so \ 20 | libcheckrdac.so 21 | 22 | all: $(LIBS) 23 | 24 | libcheck%.so: %.o 25 | $(Q)$(CC) $(LDFLAGS) $(SHARED_FLAGS) -o $@ $^ $(LIBDEPS) 26 | 27 | install: 28 | $(Q)$(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(plugindir) 29 | 30 | uninstall: 31 | $(Q)for file in $(LIBS); do $(RM) $(DESTDIR)$(plugindir)/$$file; done 32 | 33 | clean: dep_clean 34 | $(Q)$(RM) core *.a *.o *.gz *.so 35 | 36 | OBJS := $(LIBS:libcheck%.so=%.o) 37 | .SECONDARY: $(OBJS) 38 | 39 | include $(wildcard $(OBJS:.o=.d)) 40 | 41 | dep_clean: 42 | $(Q)$(RM) $(OBJS:.o=.d) 43 | -------------------------------------------------------------------------------- /libmultipath/checkers/directio.h: -------------------------------------------------------------------------------- 1 | #ifndef DIRECTIO_H_INCLUDED 2 | #define DIRECTIO_H_INCLUDED 3 | 4 | int directio (struct checker *); 5 | int directio_init (struct checker *); 6 | void directio_free (struct checker *); 7 | 8 | #endif /* DIRECTIO_H_INCLUDED */ 9 | -------------------------------------------------------------------------------- /libmultipath/checkers/emc_clariion.h: -------------------------------------------------------------------------------- 1 | #ifndef EMC_CLARIION_H_INCLUDED 2 | #define EMC_CLARIION_H_INCLUDED 3 | 4 | int emc_clariion (struct checker *); 5 | int emc_clariion_init (struct checker *); 6 | void emc_clariion_free (struct checker *); 7 | 8 | #endif /* EMC_CLARIION_H_INCLUDED */ 9 | -------------------------------------------------------------------------------- /libmultipath/checkers/hp_sw.h: -------------------------------------------------------------------------------- 1 | #ifndef HP_SW_H_INCLUDED 2 | #define HP_SW_H_INCLUDED 3 | 4 | int hp_sw (struct checker *); 5 | int hp_sw_init (struct checker *); 6 | void hp_sw_free (struct checker *); 7 | 8 | #endif /* HP_SW_H_INCLUDED */ 9 | -------------------------------------------------------------------------------- /libmultipath/checkers/rdac.h: -------------------------------------------------------------------------------- 1 | #ifndef RDAC_H_INCLUDED 2 | #define RDAC_H_INCLUDED 3 | 4 | int rdac(struct checker *); 5 | int rdac_init(struct checker *); 6 | void rdac_free(struct checker *); 7 | 8 | #endif /* RDAC_H_INCLUDED */ 9 | -------------------------------------------------------------------------------- /libmultipath/checkers/readsector0.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2004, 2005 Christophe Varoqui 3 | */ 4 | #include 5 | 6 | #include "checkers.h" 7 | #include "libsg.h" 8 | 9 | struct readsector0_checker_context { 10 | void * dummy; 11 | }; 12 | 13 | int libcheck_init (__attribute__((unused)) struct checker * c) 14 | { 15 | return 0; 16 | } 17 | 18 | void libcheck_free (__attribute__((unused)) struct checker * c) 19 | { 20 | return; 21 | } 22 | 23 | int libcheck_check (struct checker * c) 24 | { 25 | unsigned char buf[4096]; 26 | unsigned char sbuf[SENSE_BUFF_LEN]; 27 | int ret; 28 | 29 | ret = sg_read(c->fd, &buf[0], 4096, &sbuf[0], 30 | SENSE_BUFF_LEN, c->timeout); 31 | 32 | switch (ret) 33 | { 34 | case PATH_DOWN: 35 | c->msgid = CHECKER_MSGID_DOWN; 36 | break; 37 | case PATH_UP: 38 | c->msgid = CHECKER_MSGID_UP; 39 | break; 40 | default: 41 | break; 42 | } 43 | return ret; 44 | } 45 | -------------------------------------------------------------------------------- /libmultipath/checkers/readsector0.h: -------------------------------------------------------------------------------- 1 | #ifndef READSECTOR0_H_INCLUDED 2 | #define READSECTOR0_H_INCLUDED 3 | 4 | int readsector0 (struct checker *); 5 | int readsector0_init (struct checker *); 6 | void readsector0_free (struct checker *); 7 | 8 | #endif /* READSECTOR0_H_INCLUDED */ 9 | -------------------------------------------------------------------------------- /libmultipath/checkers/tur.h: -------------------------------------------------------------------------------- 1 | #ifndef TUR_H_INCLUDED 2 | #define TUR_H_INCLUDED 3 | 4 | int tur (struct checker *); 5 | int tur_init (struct checker *); 6 | void tur_free (struct checker *); 7 | 8 | #endif /* TUR_H_INCLUDED */ 9 | -------------------------------------------------------------------------------- /libmultipath/configure.h: -------------------------------------------------------------------------------- 1 | #ifndef CONFIGURE_H_INCLUDED 2 | #define CONFIGURE_H_INCLUDED 3 | 4 | /* 5 | * configurator actions 6 | */ 7 | #define ACT_NOTHING_STR "unchanged" 8 | #define ACT_REJECT_STR "reject" 9 | #define ACT_RELOAD_STR "reload" 10 | #define ACT_SWITCHPG_STR "switchpg" 11 | #define ACT_RENAME_STR "rename" 12 | #define ACT_CREATE_STR "create" 13 | #define ACT_RESIZE_STR "resize" 14 | 15 | enum actions { 16 | ACT_UNDEF, 17 | ACT_NOTHING, 18 | ACT_REJECT, 19 | ACT_RELOAD, 20 | ACT_SWITCHPG, 21 | ACT_RENAME, 22 | ACT_CREATE, 23 | ACT_RESIZE, 24 | ACT_RELOAD_RENAME, 25 | ACT_DRY_RUN, 26 | ACT_IMPOSSIBLE, 27 | ACT_RESIZE_RENAME, 28 | ACT_SWITCHPG_RENAME, 29 | }; 30 | 31 | /* 32 | * Return value of domap() 33 | * DAEMON_RETRY is only used for ACT_CREATE (see domap()). 34 | */ 35 | enum { 36 | DOMAP_RETRY = -1, 37 | DOMAP_FAIL = 0, 38 | DOMAP_OK = 1, 39 | DOMAP_EXIST = 2, 40 | DOMAP_DRY = 3 41 | }; 42 | 43 | /* 44 | * Return value of coalesce_paths() 45 | * CP_RETRY is only used in non-daemon case (multipath). 46 | */ 47 | enum { 48 | CP_OK = 0, 49 | CP_FAIL, 50 | CP_RETRY, 51 | }; 52 | 53 | struct vectors; 54 | 55 | int setup_map (struct multipath * mpp, char **params, struct vectors *vecs); 56 | void select_action (struct multipath *mpp, const struct vector_s *curmp, 57 | int force_reload); 58 | int domap (struct multipath * mpp, char * params, int is_daemon); 59 | int reinstate_paths (struct multipath *mpp); 60 | int coalesce_paths (struct vectors *vecs, vector curmp, char * refwwid, int force_reload, enum mpath_cmds cmd); 61 | int get_refwwid (enum mpath_cmds cmd, const char *dev, enum devtypes dev_type, 62 | vector pathvec, char **wwid); 63 | struct udev_device *get_udev_device(const char *dev, enum devtypes dev_type); 64 | void trigger_path_udev_change(struct path *pp, bool is_mpath); 65 | void trigger_paths_udev_change(struct multipath *mpp, bool is_mpath); 66 | void trigger_partitions_udev_change(struct udev_device *dev, const char *action, 67 | int len); 68 | int check_daemon(void); 69 | #endif 70 | -------------------------------------------------------------------------------- /libmultipath/defaults.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2005 Christophe Varoqui 3 | */ 4 | #include 5 | 6 | #include "defaults.h" 7 | 8 | const char * const default_partition_delim = DEFAULT_PARTITION_DELIM; 9 | -------------------------------------------------------------------------------- /libmultipath/dict.h: -------------------------------------------------------------------------------- 1 | #ifndef DICT_H_INCLUDED 2 | #define DICT_H_INCLUDED 3 | 4 | #include "vector.h" 5 | #include "byteorder.h" 6 | struct strbuf; 7 | 8 | void init_keywords(vector keywords); 9 | int get_sys_max_fds(int *); 10 | int print_rr_weight(struct strbuf *buff, long v); 11 | int print_pgfailback(struct strbuf *buff, long v); 12 | int print_pgpolicy(struct strbuf *buff, long v); 13 | int print_no_path_retry(struct strbuf *buff, long v); 14 | int print_undef_off_zero(struct strbuf *buff, long v); 15 | int print_dev_loss(struct strbuf *buff, unsigned long v); 16 | int print_off_int_undef(struct strbuf *buff, long v); 17 | int print_auto_resize(struct strbuf *buff, long v); 18 | int print_flush_on_last_del(struct strbuf *buff, long v); 19 | #endif /* DICT_H_INCLUDED */ 20 | -------------------------------------------------------------------------------- /libmultipath/discovery.h: -------------------------------------------------------------------------------- 1 | #ifndef DISCOVERY_H_INCLUDED 2 | #define DISCOVERY_H_INCLUDED 3 | 4 | #define SYSFS_PATH_SIZE 255 5 | #define INQUIRY_CMDLEN 6 6 | #define INQUIRY_CMD 0x12 7 | #define SENSE_BUFF_LEN 32 8 | #define RECOVERED_ERROR 0x01 9 | #define MX_ALLOC_LEN 255 10 | #define TUR_CMD_LEN 6 11 | 12 | #ifndef BLKGETSIZE 13 | #define BLKGETSIZE _IO(0x12,96) 14 | #endif 15 | 16 | #ifndef DEF_TIMEOUT 17 | #define DEF_TIMEOUT 30 18 | #endif 19 | 20 | /* 21 | * excerpt from sg_err.h 22 | */ 23 | #define SCSI_CHECK_CONDITION 0x2 24 | #define SCSI_COMMAND_TERMINATED 0x22 25 | #define SG_ERR_DRIVER_SENSE 0x08 26 | 27 | #define PATHINFO_OK 0 28 | #define PATHINFO_FAILED 1 29 | #define PATHINFO_SKIPPED 2 30 | 31 | struct config; 32 | 33 | int path_discovery (vector pathvec, int flag); 34 | int path_get_tpgs(struct path *pp); /* This function never returns TPGS_UNDEF */ 35 | int do_tur (char *); 36 | int path_sysfs_state(struct path *); 37 | int start_checker(struct path * pp, struct config * conf, int daemon, 38 | int state); 39 | int get_state(struct path * pp); 40 | int get_vpd_sgio (int fd, int pg, int vend_id, char * str, int maxlen); 41 | int pathinfo (struct path * pp, struct config * conf, int mask); 42 | int alloc_path_with_pathinfo (struct config *conf, struct udev_device *udevice, 43 | const char *wwid, int flag, struct path **pp_ptr); 44 | int store_pathinfo (vector pathvec, struct config *conf, 45 | struct udev_device *udevice, int flag, 46 | struct path **pp_ptr); 47 | int sysfs_set_scsi_tmo (struct config *conf, struct multipath *mpp); 48 | int sysfs_get_timeout(const struct path *pp, unsigned int *timeout); 49 | int sysfs_get_iscsi_ip_address(const struct path *pp, char *ip_address); 50 | int sysfs_get_host_adapter_name(const struct path *pp, 51 | char *adapter_name); 52 | ssize_t sysfs_get_vpd (struct udev_device *udev, unsigned char pg, 53 | unsigned char *buff, size_t len); 54 | ssize_t sysfs_get_inquiry(struct udev_device *udev, 55 | unsigned char *buff, size_t len); 56 | int sysfs_get_asymmetric_access_state(struct path *pp, 57 | char *buff, int buflen); 58 | bool has_uid_fallback(struct path *pp); 59 | int get_uid(struct path * pp, int path_state, struct udev_device *udev, 60 | int allow_fallback); 61 | bool is_vpd_page_supported(int fd, int pg); 62 | 63 | /* 64 | * discovery bitmask 65 | */ 66 | enum discovery_mode { 67 | DI_SYSFS__, 68 | DI_SERIAL__, 69 | DI_CHECKER__, 70 | DI_PRIO__, 71 | DI_WWID__, 72 | DI_BLACKLIST__, 73 | DI_NOIO__, 74 | DI_NOFALLBACK__, 75 | }; 76 | 77 | #define DI_SYSFS (1 << DI_SYSFS__) 78 | #define DI_SERIAL (1 << DI_SERIAL__) 79 | #define DI_CHECKER (1 << DI_CHECKER__) 80 | #define DI_PRIO (1 << DI_PRIO__) 81 | #define DI_WWID (1 << DI_WWID__) 82 | #define DI_BLACKLIST (1 << DI_BLACKLIST__) 83 | #define DI_NOIO (1 << DI_NOIO__) /* Avoid IO on the device */ 84 | #define DI_NOFALLBACK (1 << DI_NOFALLBACK__) /* do not allow wwid fallback */ 85 | 86 | #define DI_ALL (DI_SYSFS | DI_SERIAL | DI_CHECKER | DI_PRIO | \ 87 | DI_WWID) 88 | 89 | #endif /* DISCOVERY_H_INCLUDED */ 90 | -------------------------------------------------------------------------------- /libmultipath/dm-generic.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2018 Martin Wilck, SUSE Linux GmbH 3 | 4 | This program is free software; you can redistribute it and/or 5 | modify it under the terms of the GNU General Public License 6 | as published by the Free Software Foundation; either version 2 7 | of the License, or (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . 16 | */ 17 | 18 | #include 19 | #include 20 | #include "generic.h" 21 | #include "dm-generic.h" 22 | #include "structs.h" 23 | #include "structs_vec.h" 24 | #include "config.h" 25 | #include "print.h" 26 | 27 | static const struct vector_s* 28 | dm_mp_get_pgs(const struct gen_multipath *gmp) 29 | { 30 | return vector_convert(NULL, gen_multipath_to_dm(gmp)->pg, 31 | struct pathgroup, dm_pathgroup_to_gen); 32 | } 33 | 34 | static void dm_mp_rel_pgs(__attribute__((unused)) 35 | const struct gen_multipath *gmp, 36 | const struct vector_s* v) 37 | { 38 | vector_free_const(v); 39 | } 40 | 41 | static const struct vector_s* 42 | dm_pg_get_paths(const struct gen_pathgroup *gpg) 43 | { 44 | return vector_convert(NULL, gen_pathgroup_to_dm(gpg)->paths, 45 | struct path, dm_path_to_gen); 46 | } 47 | 48 | static void dm_mp_rel_paths(__attribute__((unused)) 49 | const struct gen_pathgroup *gpg, 50 | const struct vector_s* v) 51 | { 52 | vector_free_const(v); 53 | } 54 | 55 | const struct gen_multipath_ops dm_gen_multipath_ops = { 56 | .get_pathgroups = dm_mp_get_pgs, 57 | .rel_pathgroups = dm_mp_rel_pgs, 58 | .snprint = snprint_multipath_attr, 59 | .style = snprint_multipath_style, 60 | }; 61 | 62 | const struct gen_pathgroup_ops dm_gen_pathgroup_ops = { 63 | .get_paths = dm_pg_get_paths, 64 | .rel_paths = dm_mp_rel_paths, 65 | .snprint = snprint_pathgroup_attr, 66 | }; 67 | 68 | const struct gen_path_ops dm_gen_path_ops = { 69 | .snprint = snprint_path_attr, 70 | }; 71 | -------------------------------------------------------------------------------- /libmultipath/dm-generic.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2018 Martin Wilck, SUSE Linux GmbH 3 | 4 | This program is free software; you can redistribute it and/or 5 | modify it under the terms of the GNU General Public License 6 | as published by the Free Software Foundation; either version 2 7 | of the License, or (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . 16 | */ 17 | #ifndef DM_GENERIC_H_INCLUDED 18 | #define DM_GENERIC_H_INCLUDED 19 | #include "generic.h" 20 | #include "list.h" /* for container_of */ 21 | #include "structs.h" 22 | 23 | #define dm_multipath_to_gen(mpp) (&((mpp)->generic_mp)) 24 | #define gen_multipath_to_dm(gm) \ 25 | container_of_const((gm), struct multipath, generic_mp) 26 | 27 | #define dm_pathgroup_to_gen(pg) (&(pg->generic_pg)) 28 | #define gen_pathgroup_to_dm(gpg) \ 29 | container_of_const((gpg), struct pathgroup, generic_pg) 30 | 31 | #define dm_path_to_gen(pp) (&((pp)->generic_path)) 32 | #define gen_path_to_dm(gp) \ 33 | container_of_const((gp), struct path, generic_path) 34 | 35 | extern const struct gen_multipath_ops dm_gen_multipath_ops; 36 | extern const struct gen_pathgroup_ops dm_gen_pathgroup_ops; 37 | extern const struct gen_path_ops dm_gen_path_ops; 38 | 39 | #endif /* DM_GENERIC_H_INCLUDED */ 40 | -------------------------------------------------------------------------------- /libmultipath/dmparser.h: -------------------------------------------------------------------------------- 1 | #ifndef DMPARSER_H_INCLUDED 2 | #define DMPARSER_H_INCLUDED 3 | 4 | int assemble_map (struct multipath *, char **); 5 | int disassemble_map (const struct vector_s *, const char *, struct multipath *); 6 | int disassemble_status (const char *, struct multipath *); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /libmultipath/file.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010 Benjamin Marzinski, Redhat 3 | */ 4 | 5 | #ifndef FILE_H_INCLUDED 6 | #define FILE_H_INCLUDED 7 | 8 | #include 9 | 10 | #define FILE_TIMEOUT 30 11 | int ensure_directories_exist(const char *str, mode_t dir_mode); 12 | int open_file(const char *file, int *can_write, const char *header); 13 | 14 | #endif /* FILE_H_INCLUDED */ 15 | -------------------------------------------------------------------------------- /libmultipath/foreign/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2003 Christophe Varoqui, 3 | # 4 | TOPDIR=../.. 5 | include ../../Makefile.inc 6 | 7 | CPPFLAGS += -I$(multipathdir) -I$(mpathutildir) -I$(nvmedir) 8 | CFLAGS += $(LIB_CFLAGS) 9 | LDFLAGS += -L$(multipathdir) -L$(mpathutildir) 10 | LIBDEPS = -lmultipath -lmpathutil -ludev -lpthread -lrt 11 | 12 | LIBS = libforeign-nvme.so 13 | 14 | all: $(LIBS) 15 | 16 | libforeign-%.so: %.o 17 | $(Q)$(CC) $(LDFLAGS) $(SHARED_FLAGS) -o $@ $^ $(LIBDEPS) 18 | 19 | install: 20 | $(Q)$(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(plugindir) 21 | 22 | uninstall: 23 | $(Q)for file in $(LIBS); do $(RM) $(DESTDIR)$(plugindir)/$$file; done 24 | 25 | clean: dep_clean 26 | $(Q)$(RM) core *.a *.o *.gz *.so 27 | 28 | OBJS := $(LIBS:libforeign-%.so=%.o) 29 | .SECONDARY: $(OBJS) 30 | 31 | include $(wildcard $(OBJS:.o=.d)) 32 | 33 | dep_clean: 34 | $(Q)$(RM) $(OBJS:.o=.d) 35 | -------------------------------------------------------------------------------- /libmultipath/generic.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2018 Martin Wilck, SUSE Linux GmbH 3 | 4 | This program is free software; you can redistribute it and/or 5 | modify it under the terms of the GNU General Public License 6 | as published by the Free Software Foundation; either version 2 7 | of the License, or (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . 16 | */ 17 | 18 | #include "generic.h" 19 | #include "structs.h" 20 | #include "util.h" 21 | #include "strbuf.h" 22 | 23 | int generic_style(const struct gen_multipath* gm, struct strbuf *buf, 24 | __attribute__((unused)) int verbosity) 25 | { 26 | STRBUF_ON_STACK(tmp); 27 | char *alias_buf __attribute__((cleanup(cleanup_charp))); 28 | const char *wwid_buf; 29 | 30 | gm->ops->snprint(gm, &tmp, 'n'); 31 | alias_buf = steal_strbuf_str(&tmp); 32 | gm->ops->snprint(gm, &tmp, 'w'); 33 | wwid_buf = get_strbuf_str(&tmp); 34 | 35 | return print_strbuf(buf, "%%n %s[%%G]:%%d %%s", 36 | strcmp(alias_buf, wwid_buf) ? "(%w) " : ""); 37 | } 38 | -------------------------------------------------------------------------------- /libmultipath/hwtable.h: -------------------------------------------------------------------------------- 1 | #ifndef HWTABLE_H_INCLUDED 2 | #define HWTABLE_H_INCLUDED 3 | 4 | int setup_default_hwtable (vector hw); 5 | 6 | #endif /* HWTABLE_H_INCLUDED */ 7 | -------------------------------------------------------------------------------- /libmultipath/io_err_stat.h: -------------------------------------------------------------------------------- 1 | #ifndef IO_ERR_STAT_H_INCLUDED 2 | #define IO_ERR_STAT_H_INCLUDED 3 | 4 | #include "vector.h" 5 | #include "lock.h" 6 | 7 | 8 | extern pthread_attr_t io_err_stat_attr; 9 | 10 | int start_io_err_stat_thread(void *data); 11 | void stop_io_err_stat_thread(void); 12 | int io_err_stat_handle_pathfail(struct path *path); 13 | int need_io_err_check(struct path *pp); 14 | 15 | #endif /* IO_ERR_STAT_H_INCLUDED */ 16 | -------------------------------------------------------------------------------- /libmultipath/libsg.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2004, 2005 Christophe Varoqui 3 | */ 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "checkers.h" 10 | #include "libsg.h" 11 | #include "../libmultipath/sg_include.h" 12 | 13 | int 14 | sg_read (int sg_fd, unsigned char * buff, int buff_len, 15 | unsigned char * sense, int sense_len, unsigned int timeout) 16 | { 17 | /* defaults */ 18 | int blocks; 19 | long long start_block = 0; 20 | int bs = 512; 21 | int cdbsz = 10; 22 | 23 | unsigned char rdCmd[cdbsz]; 24 | unsigned char *sbb = sense; 25 | struct sg_io_hdr io_hdr; 26 | int res; 27 | int rd_opcode[] = {0x8, 0x28, 0xa8, 0x88}; 28 | int sz_ind; 29 | struct stat filestatus; 30 | int retry_count = 3; 31 | 32 | if (fstat(sg_fd, &filestatus) != 0) 33 | return PATH_DOWN; 34 | bs = (filestatus.st_blksize > 4096)? 4096: filestatus.st_blksize; 35 | blocks = buff_len / bs; 36 | memset(rdCmd, 0, cdbsz); 37 | sz_ind = 1; 38 | rdCmd[0] = rd_opcode[sz_ind]; 39 | rdCmd[2] = (unsigned char)((start_block >> 24) & 0xff); 40 | rdCmd[3] = (unsigned char)((start_block >> 16) & 0xff); 41 | rdCmd[4] = (unsigned char)((start_block >> 8) & 0xff); 42 | rdCmd[5] = (unsigned char)(start_block & 0xff); 43 | rdCmd[7] = (unsigned char)((blocks >> 8) & 0xff); 44 | rdCmd[8] = (unsigned char)(blocks & 0xff); 45 | 46 | memset(&io_hdr, 0, sizeof(struct sg_io_hdr)); 47 | io_hdr.interface_id = 'S'; 48 | io_hdr.cmd_len = cdbsz; 49 | io_hdr.cmdp = rdCmd; 50 | io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; 51 | io_hdr.dxfer_len = bs * blocks; 52 | io_hdr.dxferp = buff; 53 | io_hdr.mx_sb_len = sense_len; 54 | io_hdr.sbp = sense; 55 | io_hdr.timeout = timeout * 1000; 56 | io_hdr.pack_id = (int)start_block; 57 | 58 | retry: 59 | memset(sense, 0, sense_len); 60 | while (((res = ioctl(sg_fd, SG_IO, &io_hdr)) < 0) && (EINTR == errno)); 61 | 62 | if (res < 0) { 63 | if (ENOMEM == errno) { 64 | return PATH_UP; 65 | } 66 | return PATH_DOWN; 67 | } 68 | 69 | if ((0 == io_hdr.status) && 70 | (0 == io_hdr.host_status) && 71 | (0 == io_hdr.driver_status)) { 72 | return PATH_UP; 73 | } else { 74 | int key = 0; 75 | 76 | if (io_hdr.sb_len_wr > 3) { 77 | if (sbb[0] == 0x72 || sbb[0] == 0x73) 78 | key = sbb[1] & 0x0f; 79 | else if (io_hdr.sb_len_wr > 13 && 80 | ((sbb[0] & 0x7f) == 0x70 || 81 | (sbb[0] & 0x7f) == 0x71)) 82 | key = sbb[2] & 0x0f; 83 | } 84 | 85 | /* 86 | * Retry if UNIT_ATTENTION check condition. 87 | */ 88 | if (key == 0x6) { 89 | if (--retry_count) 90 | goto retry; 91 | } 92 | return PATH_DOWN; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /libmultipath/libsg.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBSG_H_INCLUDED 2 | #define LIBSG_H_INCLUDED 3 | 4 | #define SENSE_BUFF_LEN 32 5 | 6 | int sg_read (int sg_fd, unsigned char * buff, int buff_len, 7 | unsigned char * sense, int sense_len, unsigned int timeout); 8 | 9 | #endif /* LIBSG_H_INCLUDED */ 10 | -------------------------------------------------------------------------------- /libmultipath/lock.c: -------------------------------------------------------------------------------- 1 | #include "lock.h" 2 | 3 | void cleanup_lock (void * data) 4 | { 5 | struct mutex_lock *lock = data; 6 | wakeup_fn *fn = lock->wakeup; 7 | 8 | unlock__(lock); 9 | if (fn) 10 | fn(); 11 | } 12 | 13 | void set_wakeup_fn(struct mutex_lock *lck, wakeup_fn *fn) 14 | { 15 | lock(lck); 16 | lck->wakeup = fn; 17 | unlock__(lck); 18 | } 19 | -------------------------------------------------------------------------------- /libmultipath/lock.h: -------------------------------------------------------------------------------- 1 | #ifndef LOCK_H_INCLUDED 2 | #define LOCK_H_INCLUDED 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | typedef void (wakeup_fn)(void); 9 | 10 | struct mutex_lock { 11 | pthread_mutex_t mutex; 12 | wakeup_fn *wakeup; 13 | int waiters; /* uatomic access only */ 14 | }; 15 | 16 | static inline void init_lock(struct mutex_lock *a) 17 | { 18 | pthread_mutex_init(&a->mutex, NULL); 19 | uatomic_set(&a->waiters, 0); 20 | } 21 | 22 | #if defined(__GNUC__) && __GNUC__ == 12 && URCU_VERSION < 0xe00 23 | #pragma GCC diagnostic push 24 | #pragma GCC diagnostic ignored "-Warray-bounds" 25 | #endif 26 | 27 | static inline int uatomic_xchg_int(int *ptr, int val) 28 | { 29 | return uatomic_xchg(ptr, val); 30 | } 31 | 32 | static inline void lock(struct mutex_lock *a) 33 | { 34 | uatomic_inc(&a->waiters); 35 | pthread_mutex_lock(&a->mutex); 36 | uatomic_dec(&a->waiters); 37 | } 38 | 39 | #if defined(__GNUC__) && __GNUC__ == 12 && URCU_VERSION < 0xe00 40 | #pragma GCC diagnostic pop 41 | #endif 42 | 43 | static inline int trylock(struct mutex_lock *a) 44 | { 45 | return pthread_mutex_trylock(&a->mutex); 46 | } 47 | 48 | static inline int timedlock(struct mutex_lock *a, struct timespec *tmo) 49 | { 50 | return pthread_mutex_timedlock(&a->mutex, tmo); 51 | } 52 | 53 | static inline void unlock__(struct mutex_lock *a) 54 | { 55 | pthread_mutex_unlock(&a->mutex); 56 | } 57 | 58 | static inline bool lock_has_waiters(struct mutex_lock *a) 59 | { 60 | return (uatomic_read(&a->waiters) > 0); 61 | } 62 | 63 | #define lock_cleanup_pop(a) pthread_cleanup_pop(1) 64 | 65 | void cleanup_lock (void * data); 66 | void set_wakeup_fn(struct mutex_lock *lock, wakeup_fn *fn); 67 | 68 | #endif /* LOCK_H_INCLUDED */ 69 | -------------------------------------------------------------------------------- /libmultipath/nvme-lib.c: -------------------------------------------------------------------------------- 1 | #include 2 | /* avoid inclusion of standard API */ 3 | #define NVME_LIB_C 1 4 | #include "nvme-lib.h" 5 | #include "nvme-ioctl.c" 6 | #include "debug.h" 7 | 8 | int log_nvme_errcode(int err, const char *dev, const char *msg) 9 | { 10 | if (err > 0) 11 | condlog(3, "%s: %s: NVMe status %d", dev, msg, err); 12 | else if (err < 0) 13 | condlog(3, "%s: %s: %s", dev, msg, strerror(errno)); 14 | return err; 15 | } 16 | 17 | int libmp_nvme_get_nsid(int fd) 18 | { 19 | return nvme_get_nsid(fd); 20 | } 21 | 22 | int libmp_nvme_identify_ctrl(int fd, struct nvme_id_ctrl *ctrl) 23 | { 24 | return nvme_identify_ctrl(fd, ctrl); 25 | } 26 | 27 | int libmp_nvme_identify_ns(int fd, __u32 nsid, bool present, 28 | struct nvme_id_ns *ns) 29 | { 30 | return nvme_identify_ns(fd, nsid, present, ns); 31 | } 32 | 33 | int libmp_nvme_ana_log(int fd, void *ana_log, size_t ana_log_len, int rgo) 34 | { 35 | return nvme_ana_log(fd, ana_log, ana_log_len, rgo); 36 | } 37 | 38 | int nvme_id_ctrl_ana(int fd, struct nvme_id_ctrl *ctrl) 39 | { 40 | int rc; 41 | struct nvme_id_ctrl c; 42 | 43 | rc = nvme_identify_ctrl(fd, &c); 44 | if (rc < 0) 45 | return rc; 46 | if (ctrl) 47 | *ctrl = c; 48 | return c.cmic & (1 << 3) ? 1 : 0; 49 | } 50 | -------------------------------------------------------------------------------- /libmultipath/nvme-lib.h: -------------------------------------------------------------------------------- 1 | #ifndef NVME_LIB_H_INCLUDED 2 | #define NVME_LIB_H_INCLUDED 3 | 4 | #include "nvme.h" 5 | 6 | int log_nvme_errcode(int err, const char *dev, const char *msg); 7 | int libmp_nvme_get_nsid(int fd); 8 | int libmp_nvme_identify_ctrl(int fd, struct nvme_id_ctrl *ctrl); 9 | int libmp_nvme_identify_ns(int fd, __u32 nsid, bool present, 10 | struct nvme_id_ns *ns); 11 | int libmp_nvme_ana_log(int fd, void *ana_log, size_t ana_log_len, int rgo); 12 | /* 13 | * Identify controller, and return true if ANA is supported 14 | * ctrl will be filled in if controller is identified, even w/o ANA 15 | * ctrl may be NULL 16 | */ 17 | int nvme_id_ctrl_ana(int fd, struct nvme_id_ctrl *ctrl); 18 | 19 | #ifndef NVME_LIB_C 20 | /* 21 | * In all files except nvme-lib.c, the nvme functions can be called 22 | * by their usual name. 23 | */ 24 | #define nvme_get_nsid libmp_nvme_get_nsid 25 | #define nvme_identify_ctrl libmp_nvme_identify_ctrl 26 | #define nvme_identify_ns libmp_nvme_identify_ns 27 | #define nvme_ana_log libmp_nvme_ana_log 28 | /* 29 | * Undefine these to avoid clashes with libmultipath's byteorder.h 30 | */ 31 | #undef cpu_to_le16 32 | #undef cpu_to_le32 33 | #undef cpu_to_le64 34 | #undef le16_to_cpu 35 | #undef le32_to_cpu 36 | #undef le64_to_cpu 37 | #endif 38 | 39 | #endif /* NVME_LIB_H_INCLUDED */ 40 | -------------------------------------------------------------------------------- /libmultipath/nvme/json.h: -------------------------------------------------------------------------------- 1 | #ifndef NVME_JSON_H_INCLUDED 2 | #define NVME_JSON_H_INCLUDED 3 | 4 | struct json_object; 5 | struct json_array; 6 | struct json_pair; 7 | 8 | #define JSON_TYPE_STRING 0 9 | #define JSON_TYPE_INTEGER 1 10 | #define JSON_TYPE_FLOAT 2 11 | #define JSON_TYPE_OBJECT 3 12 | #define JSON_TYPE_ARRAY 4 13 | #define JSON_TYPE_UINT 5 14 | #define JSON_PARENT_TYPE_PAIR 0 15 | #define JSON_PARENT_TYPE_ARRAY 1 16 | struct json_value { 17 | int type; 18 | union { 19 | long long integer_number; 20 | unsigned long long uint_number; 21 | long double float_number; 22 | char *string; 23 | struct json_object *object; 24 | struct json_array *array; 25 | }; 26 | int parent_type; 27 | union { 28 | struct json_pair *parent_pair; 29 | struct json_array *parent_array; 30 | }; 31 | }; 32 | 33 | struct json_array { 34 | struct json_value **values; 35 | int value_cnt; 36 | struct json_value *parent; 37 | }; 38 | 39 | struct json_object { 40 | struct json_pair **pairs; 41 | int pair_cnt; 42 | struct json_value *parent; 43 | }; 44 | 45 | struct json_pair { 46 | char *name; 47 | struct json_value *value; 48 | struct json_object *parent; 49 | }; 50 | 51 | struct json_object *json_create_object(void); 52 | struct json_array *json_create_array(void); 53 | 54 | void json_free_object(struct json_object *obj); 55 | 56 | int json_object_add_value_type(struct json_object *obj, const char *name, int type, ...); 57 | #define json_object_add_value_int(obj, name, val) \ 58 | json_object_add_value_type((obj), name, JSON_TYPE_INTEGER, (long long) (val)) 59 | #define json_object_add_value_uint(obj, name, val) \ 60 | json_object_add_value_type((obj), name, JSON_TYPE_UINT, (unsigned long long) (val)) 61 | #define json_object_add_value_float(obj, name, val) \ 62 | json_object_add_value_type((obj), name, JSON_TYPE_FLOAT, (val)) 63 | #define json_object_add_value_string(obj, name, val) \ 64 | json_object_add_value_type((obj), name, JSON_TYPE_STRING, (val)) 65 | #define json_object_add_value_object(obj, name, val) \ 66 | json_object_add_value_type((obj), name, JSON_TYPE_OBJECT, (val)) 67 | #define json_object_add_value_array(obj, name, val) \ 68 | json_object_add_value_type((obj), name, JSON_TYPE_ARRAY, (val)) 69 | int json_array_add_value_type(struct json_array *array, int type, ...); 70 | #define json_array_add_value_int(obj, val) \ 71 | json_array_add_value_type((obj), JSON_TYPE_INTEGER, (val)) 72 | #define json_array_add_value_uint(obj, val) \ 73 | json_array_add_value_type((obj), JSON_TYPE_UINT, (val)) 74 | #define json_array_add_value_float(obj, val) \ 75 | json_array_add_value_type((obj), JSON_TYPE_FLOAT, (val)) 76 | #define json_array_add_value_string(obj, val) \ 77 | json_array_add_value_type((obj), JSON_TYPE_STRING, (val)) 78 | #define json_array_add_value_object(obj, val) \ 79 | json_array_add_value_type((obj), JSON_TYPE_OBJECT, (val)) 80 | #define json_array_add_value_array(obj, val) \ 81 | json_array_add_value_type((obj), JSON_TYPE_ARRAY, (val)) 82 | 83 | #define json_array_last_value_object(obj) \ 84 | (obj->values[obj->value_cnt - 1]->object) 85 | 86 | void json_print_object(struct json_object *obj, void *); 87 | #endif 88 | -------------------------------------------------------------------------------- /libmultipath/nvme/linux/nvme_ioctl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Definitions for the NVM Express ioctl interface 3 | * Copyright (c) 2011-2014, Intel Corporation. 4 | * 5 | * This program is free software; you can redistribute it and/or modify it 6 | * under the terms and conditions of the GNU General Public License, 7 | * version 2, as published by the Free Software Foundation. 8 | * 9 | * This program is distributed in the hope it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 | * more details. 13 | */ 14 | 15 | #ifndef LINUX_NVME_IOCTL_H_INCLUDED 16 | #define LINUX_NVME_IOCTL_H_INCLUDED 17 | 18 | #include 19 | #include 20 | 21 | struct nvme_user_io { 22 | __u8 opcode; 23 | __u8 flags; 24 | __u16 control; 25 | __u16 nblocks; 26 | __u16 rsvd; 27 | __u64 metadata; 28 | __u64 addr; 29 | __u64 slba; 30 | __u32 dsmgmt; 31 | __u32 reftag; 32 | __u16 apptag; 33 | __u16 appmask; 34 | }; 35 | 36 | struct nvme_passthru_cmd { 37 | __u8 opcode; 38 | __u8 flags; 39 | __u16 rsvd1; 40 | __u32 nsid; 41 | __u32 cdw2; 42 | __u32 cdw3; 43 | __u64 metadata; 44 | __u64 addr; 45 | __u32 metadata_len; 46 | __u32 data_len; 47 | __u32 cdw10; 48 | __u32 cdw11; 49 | __u32 cdw12; 50 | __u32 cdw13; 51 | __u32 cdw14; 52 | __u32 cdw15; 53 | __u32 timeout_ms; 54 | __u32 result; 55 | }; 56 | 57 | #define nvme_admin_cmd nvme_passthru_cmd 58 | 59 | #define NVME_IOCTL_ID _IO('N', 0x40) 60 | #define NVME_IOCTL_ADMIN_CMD _IOWR('N', 0x41, struct nvme_admin_cmd) 61 | #define NVME_IOCTL_SUBMIT_IO _IOW('N', 0x42, struct nvme_user_io) 62 | #define NVME_IOCTL_IO_CMD _IOWR('N', 0x43, struct nvme_passthru_cmd) 63 | #define NVME_IOCTL_RESET _IO('N', 0x44) 64 | #define NVME_IOCTL_SUBSYS_RESET _IO('N', 0x45) 65 | #define NVME_IOCTL_RESCAN _IO('N', 0x46) 66 | 67 | #endif /* LINUX_NVME_IOCTL_H_INCLUDED */ 68 | -------------------------------------------------------------------------------- /libmultipath/nvme/plugin.h: -------------------------------------------------------------------------------- 1 | #ifndef NVME_PLUGIN_H_INCLUDED 2 | #define NVME_PLUGIN_H_INCLUDED 3 | 4 | #include 5 | 6 | struct program { 7 | const char *name; 8 | const char *version; 9 | const char *usage; 10 | const char *desc; 11 | const char *more; 12 | struct command **commands; 13 | struct plugin *extensions; 14 | }; 15 | 16 | struct plugin { 17 | const char *name; 18 | const char *desc; 19 | struct command **commands; 20 | struct program *parent; 21 | struct plugin *next; 22 | struct plugin *tail; 23 | }; 24 | 25 | struct command { 26 | char *name; 27 | char *help; 28 | int (*fn)(int argc, char **argv, struct command *command, struct plugin *plugin); 29 | char *alias; 30 | }; 31 | 32 | void usage(struct plugin *plugin); 33 | void general_help(struct plugin *plugin); 34 | int handle_plugin(int argc, char **argv, struct plugin *plugin); 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /libmultipath/pgpolicies.h: -------------------------------------------------------------------------------- 1 | #ifndef PGPOLICIES_H_INCLUDED 2 | #define PGPOLICIES_H_INCLUDED 3 | 4 | #define POLICY_NAME_SIZE 32 5 | 6 | /* Storage controllers capabilities */ 7 | enum iopolicies { 8 | IOPOLICY_UNDEF, 9 | FAILOVER, 10 | MULTIBUS, 11 | GROUP_BY_SERIAL, 12 | GROUP_BY_PRIO, 13 | GROUP_BY_NODE_NAME, 14 | GROUP_BY_TPG, 15 | }; 16 | 17 | int get_pgpolicy_id(char *); 18 | const char *get_pgpolicy_name (int); 19 | int group_paths(struct multipath *, int); 20 | /* 21 | * policies 22 | */ 23 | int one_path_per_group(struct multipath *, vector); 24 | int one_group(struct multipath *, vector); 25 | int group_by_serial(struct multipath *, vector); 26 | int group_by_prio(struct multipath *, vector); 27 | int group_by_node_name(struct multipath *, vector); 28 | int group_by_tpg(struct multipath *, vector); 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /libmultipath/prio.h: -------------------------------------------------------------------------------- 1 | #ifndef PRIO_H_INCLUDED 2 | #define PRIO_H_INCLUDED 3 | 4 | /* 5 | * knowing about path struct gives flexibility to prioritizers 6 | */ 7 | #include "checkers.h" 8 | #include "vector.h" 9 | 10 | /* forward declaration to avoid circular dependency */ 11 | struct path; 12 | 13 | #include "list.h" 14 | #include "defaults.h" 15 | 16 | /* 17 | * Known prioritizers for use in hwtable.c 18 | */ 19 | #define PRIO_ALUA "alua" 20 | #define PRIO_CONST "const" 21 | #define PRIO_DATACORE "datacore" 22 | #define PRIO_EMC "emc" 23 | #define PRIO_HDS "hds" 24 | #define PRIO_HP_SW "hp_sw" 25 | #define PRIO_IET "iet" 26 | #define PRIO_ONTAP "ontap" 27 | #define PRIO_RANDOM "random" 28 | #define PRIO_RDAC "rdac" 29 | #define PRIO_WEIGHTED_PATH "weightedpath" 30 | #define PRIO_SYSFS "sysfs" 31 | #define PRIO_PATH_LATENCY "path_latency" 32 | #define PRIO_ANA "ana" 33 | 34 | /* 35 | * Value used to mark the fact prio was not defined 36 | */ 37 | #define PRIO_UNDEF -1 38 | 39 | /* 40 | * strings lengths 41 | */ 42 | #define LIB_PRIO_NAMELEN 255 43 | #define PRIO_NAME_LEN 16 44 | #define PRIO_ARGS_LEN 255 45 | 46 | struct prio { 47 | void *handle; 48 | int refcount; 49 | struct list_head node; 50 | char name[PRIO_NAME_LEN]; 51 | char args[PRIO_ARGS_LEN]; 52 | int (*getprio)(struct path *, char *); 53 | }; 54 | 55 | unsigned int get_prio_timeout_ms(const struct path *); 56 | int init_prio(void); 57 | void cleanup_prio (void); 58 | struct prio * add_prio (const char *); 59 | int prio_getprio (struct prio *, struct path *); 60 | void prio_get (struct prio *, const char *, const char *); 61 | void prio_put (struct prio *); 62 | int prio_selected (const struct prio *); 63 | const char * prio_name (const struct prio *); 64 | const char * prio_args (const struct prio *); 65 | int prio_set_args (struct prio *, const char *); 66 | 67 | /* The only function exported by prioritizer dynamic libraries (.so) */ 68 | int getprio(struct path *, char *); 69 | 70 | #endif /* PRIO_H_INCLUDED */ 71 | -------------------------------------------------------------------------------- /libmultipath/prioritizers/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2007 Christophe Varoqui, 3 | # 4 | TOPDIR=../.. 5 | 6 | include ../../Makefile.inc 7 | 8 | CPPFLAGS += -I$(multipathdir) -I$(mpathutildir) 9 | CFLAGS += $(LIB_CFLAGS) 10 | LDFLAGS += -L$(multipathdir) -L$(mpathutildir) 11 | LIBDEPS = -lmultipath -lmpathutil -lm -lpthread -lrt 12 | 13 | # If you add or remove a prioritizer also update multipath/multipath.conf.5 14 | LIBS = \ 15 | libprioalua.so \ 16 | libprioconst.so \ 17 | libpriodatacore.so \ 18 | libprioemc.so \ 19 | libpriohds.so \ 20 | libpriohp_sw.so \ 21 | libprioiet.so \ 22 | libprioontap.so \ 23 | libpriorandom.so \ 24 | libpriordac.so \ 25 | libprioweightedpath.so \ 26 | libpriopath_latency.so \ 27 | libpriosysfs.so 28 | 29 | ifeq ($(ANA_SUPPORT),1) 30 | LIBS += libprioana.so 31 | CPPFLAGS += -I../nvme 32 | endif 33 | 34 | all: $(LIBS) 35 | 36 | libprio%.so: %.o 37 | $(Q)$(CC) $(LDFLAGS) $(SHARED_FLAGS) -o $@ $^ $(LIBDEPS) 38 | 39 | install: $(LIBS) 40 | $(Q)$(INSTALL_PROGRAM) -m 755 libprio*.so $(DESTDIR)$(plugindir) 41 | 42 | uninstall: 43 | $(Q)for file in $(LIBS); do $(RM) $(DESTDIR)$(plugindir)/$$file; done 44 | 45 | clean: dep_clean 46 | $(Q)$(RM) core *.a *.o *.gz *.so 47 | 48 | OBJS = $(LIBS:libprio%.so=%.o) alua_rtpg.o 49 | .SECONDARY: $(OBJS) 50 | 51 | include $(wildcard $(OBJS:.o=.d)) 52 | 53 | dep_clean: 54 | $(Q)$(RM) $(OBJS:.o=.d) 55 | -------------------------------------------------------------------------------- /libmultipath/prioritizers/alua.h: -------------------------------------------------------------------------------- 1 | #ifndef ALUA_H_INCLUDED 2 | #define ALUA_H_INCLUDED 3 | 4 | #include "alua_rtpg.h" 5 | 6 | #define PRIO_ALUA "alua" 7 | int prio_alua(struct path * pp); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /libmultipath/prioritizers/alua_rtpg.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright IBM Corp. 2004, 2005 All Rights Reserved. 3 | * 4 | * rtpg.h 5 | * 6 | * Tool to make use of a SCSI-feature called Asymmetric Logical Unit Access. 7 | * It determines the ALUA state of a device and prints a priority value to 8 | * stdout. 9 | * 10 | * Author(s): Jan Kunigk 11 | * S. Bader 12 | * 13 | * This file is released under the GPL. 14 | */ 15 | #ifndef ALUA_RTPG_H_INCLUDED 16 | #define ALUA_RTPG_H_INCLUDED 17 | #include "alua_spc3.h" 18 | 19 | #define RTPG_SUCCESS 0 20 | #define RTPG_INQUIRY_FAILED 1 21 | #define RTPG_NO_TPG_IDENTIFIER 2 22 | #define RTPG_RTPG_FAILED 3 23 | #define RTPG_TPG_NOT_FOUND 4 24 | 25 | int get_target_port_group_support(const struct path *pp); 26 | int get_target_port_group(const struct path *pp); 27 | int get_asymmetric_access_state(const struct path *pp, unsigned int tpg); 28 | 29 | #endif /* ALUA_RTPG_H_INCLUDED */ 30 | -------------------------------------------------------------------------------- /libmultipath/prioritizers/const.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "prio.h" 4 | 5 | int getprio(__attribute__((unused)) struct path * pp, 6 | __attribute__((unused)) char * args) 7 | { 8 | return 1; 9 | } 10 | -------------------------------------------------------------------------------- /libmultipath/prioritizers/datacore.c: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2010 Christophe Varoqui 3 | * (C) 2009 Dembach Goo Informatik GmbH & Co KG 4 | * Manon Goo 5 | * 6 | * datacore.c 7 | * Version 0.9 8 | * 9 | * This program was inspired by work from 10 | * Matthias Rudolph 11 | * 12 | * This work is made available on the basis of the 13 | * GPLv2 for details see . 14 | * 15 | * Manon Goo 2009 16 | * 17 | * 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | #include 24 | #include "sg_include.h" 25 | #include "debug.h" 26 | #include "prio.h" 27 | #include "structs.h" 28 | 29 | #define INQ_REPLY_LEN 255 30 | #define INQ_CMD_CODE 0x12 31 | #define INQ_CMD_LEN 6 32 | 33 | #define dc_log(prio, msg) condlog(prio, "%s: datacore prio: " msg, dev) 34 | 35 | int datacore_prio (const char *dev, int sg_fd, char * args, 36 | unsigned int timeout_ms) 37 | { 38 | int k; 39 | char sdsname[32]; 40 | unsigned char inqCmdBlk[INQ_CMD_LEN] = { INQ_CMD_CODE, 0, 0, 0, INQ_REPLY_LEN, 0 }; 41 | unsigned char inqBuff[INQ_REPLY_LEN]; 42 | unsigned char *inqBuffp = inqBuff; 43 | unsigned char sense_buffer[32]; 44 | sg_io_hdr_t io_hdr; 45 | 46 | char preferredsds_buff[255] = ""; 47 | char * preferredsds = &preferredsds_buff[0]; 48 | 49 | if (!args) { 50 | dc_log(0, "need prio_args with preferredsds set"); 51 | return 0; 52 | } 53 | 54 | if (sscanf(args, "timeout=%i preferredsds=%s", 55 | (int *)&timeout_ms, preferredsds) == 2) {} 56 | else if (sscanf(args, "preferredsds=%s timeout=%i", 57 | preferredsds, (int *)&timeout_ms) == 2) {} 58 | else if (sscanf(args, "preferredsds=%s", 59 | preferredsds) == 1) {} 60 | else { 61 | dc_log(0, "unexpected prio_args format"); 62 | return 0; 63 | } 64 | 65 | // on error just return prio 0 66 | if (strlen(preferredsds) <= 1) { 67 | dc_log(0, "prio args: preferredsds too short (1 character min)"); 68 | return 0; 69 | } 70 | if ((ioctl(sg_fd, SG_GET_VERSION_NUM, &k) < 0) || (k < 30000)) 71 | return 0; 72 | 73 | memset (&io_hdr, 0, sizeof (sg_io_hdr_t)); 74 | io_hdr.interface_id = 'S'; 75 | io_hdr.cmd_len = sizeof (inqCmdBlk); 76 | io_hdr.mx_sb_len = sizeof (sense_buffer); 77 | io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; 78 | io_hdr.dxfer_len = INQ_REPLY_LEN; 79 | io_hdr.dxferp = inqBuff; 80 | io_hdr.cmdp = inqCmdBlk; 81 | io_hdr.sbp = sense_buffer; 82 | io_hdr.timeout = timeout_ms; 83 | 84 | // on error just return prio 0 85 | if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) 86 | return 0; 87 | if ((io_hdr.info & SG_INFO_OK_MASK) != SG_INFO_OK) 88 | return 0; 89 | 90 | snprintf(sdsname, sizeof(sdsname), "%.16s", inqBuffp + 112); 91 | 92 | if (strstr(sdsname , preferredsds)) 93 | return 1; 94 | return 0; 95 | } 96 | 97 | int getprio(struct path * pp, char * args) 98 | { 99 | return datacore_prio(pp->dev, pp->fd, args, get_prio_timeout_ms(pp)); 100 | } 101 | -------------------------------------------------------------------------------- /libmultipath/prioritizers/emc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "sg_include.h" 6 | #include "debug.h" 7 | #include "prio.h" 8 | #include "structs.h" 9 | 10 | #define INQUIRY_CMD 0x12 11 | #define INQUIRY_CMDLEN 6 12 | 13 | #define pp_emc_log(prio, msg) condlog(prio, "%s: emc prio: " msg, dev) 14 | 15 | int emc_clariion_prio(const char *dev, int fd, unsigned int timeout_ms) 16 | { 17 | unsigned char sense_buffer[128]; 18 | unsigned char sb[128]; 19 | unsigned char inqCmdBlk[INQUIRY_CMDLEN] = {INQUIRY_CMD, 1, 0xC0, 0, 20 | sizeof(sense_buffer), 0}; 21 | struct sg_io_hdr io_hdr; 22 | int ret = PRIO_UNDEF; 23 | 24 | memset(&io_hdr, 0, sizeof (struct sg_io_hdr)); 25 | memset(&sense_buffer, 0, 128); 26 | io_hdr.interface_id = 'S'; 27 | io_hdr.cmd_len = sizeof (inqCmdBlk); 28 | io_hdr.mx_sb_len = sizeof (sb); 29 | io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; 30 | io_hdr.dxfer_len = sizeof (sense_buffer); 31 | io_hdr.dxferp = sense_buffer; 32 | io_hdr.cmdp = inqCmdBlk; 33 | io_hdr.sbp = sb; 34 | io_hdr.timeout = timeout_ms; 35 | io_hdr.pack_id = 0; 36 | if (ioctl(fd, SG_IO, &io_hdr) < 0) { 37 | pp_emc_log(0, "sending query command failed"); 38 | goto out; 39 | } 40 | if (io_hdr.info & SG_INFO_OK_MASK) { 41 | pp_emc_log(0, "query command indicates error"); 42 | goto out; 43 | } 44 | 45 | if (/* Verify the code page - right page & revision */ 46 | sense_buffer[1] != 0xc0 || sense_buffer[9] != 0x00) { 47 | pp_emc_log(0, "path unit report page in unknown format"); 48 | goto out; 49 | } 50 | 51 | if ( /* Effective initiator type */ 52 | sense_buffer[27] != 0x03 53 | /* 54 | * Failover mode should be set to 1 (PNR failover mode) 55 | * or 4 (ALUA failover mode). 56 | */ 57 | || (((sense_buffer[28] & 0x07) != 0x04) && 58 | ((sense_buffer[28] & 0x07) != 0x06)) 59 | /* Arraycommpath should be set to 1 */ 60 | || (sense_buffer[30] & 0x04) != 0x04) { 61 | pp_emc_log(0, "path not correctly configured for failover"); 62 | goto out; 63 | } 64 | 65 | if ( /* LUN operations should indicate normal operations */ 66 | sense_buffer[48] != 0x00) { 67 | pp_emc_log(0, "path not available for normal operations"); 68 | goto out; 69 | } 70 | 71 | /* LUN state: unbound, bound, or owned */ 72 | ret = sense_buffer[4]; 73 | 74 | /* Is the default owner equal to this path? */ 75 | /* Note this will switch to the default priority group, even if 76 | * it is not the currently active one. */ 77 | if (sense_buffer[5] == sense_buffer[8]) 78 | ret+=2; 79 | 80 | out: 81 | return(ret); 82 | } 83 | 84 | int getprio (struct path *pp, __attribute__((unused)) char *args) 85 | { 86 | return emc_clariion_prio(pp->dev, pp->fd, get_prio_timeout_ms(pp)); 87 | } 88 | -------------------------------------------------------------------------------- /libmultipath/prioritizers/hp_sw.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Path priority checker for HP active/standby controller 3 | * 4 | * Check the path state and sort them into groups. 5 | * There is actually a preferred path in the controller; 6 | * we should ask HP on how to retrieve that information. 7 | */ 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "sg_include.h" 16 | #include "debug.h" 17 | #include "prio.h" 18 | #include "structs.h" 19 | 20 | #define TUR_CMD_LEN 6 21 | #define SCSI_CHECK_CONDITION 0x2 22 | #define SCSI_COMMAND_TERMINATED 0x22 23 | #define SG_ERR_DRIVER_SENSE 0x08 24 | #define RECOVERED_ERROR 0x01 25 | #define NOT_READY 0x02 26 | #define UNIT_ATTENTION 0x06 27 | 28 | #define HP_PATH_ACTIVE 0x04 29 | #define HP_PATH_STANDBY 0x02 30 | #define HP_PATH_FAILED 0x00 31 | 32 | #define pp_hp_sw_log(prio, fmt, args...) \ 33 | condlog(prio, "%s: hp_sw prio: " fmt, dev, ##args) 34 | 35 | int hp_sw_prio(const char *dev, int fd, unsigned int timeout_ms) 36 | { 37 | unsigned char turCmdBlk[TUR_CMD_LEN] = { 0x00, 0, 0, 0, 0, 0 }; 38 | unsigned char sb[128]; 39 | struct sg_io_hdr io_hdr; 40 | int ret = HP_PATH_FAILED; 41 | 42 | memset(&io_hdr, 0, sizeof (struct sg_io_hdr)); 43 | io_hdr.interface_id = 'S'; 44 | io_hdr.cmd_len = sizeof (turCmdBlk); 45 | io_hdr.mx_sb_len = sizeof (sb); 46 | io_hdr.dxfer_direction = SG_DXFER_NONE; 47 | io_hdr.cmdp = turCmdBlk; 48 | io_hdr.sbp = sb; 49 | io_hdr.timeout = timeout_ms; 50 | io_hdr.pack_id = 0; 51 | retry: 52 | if (ioctl(fd, SG_IO, &io_hdr) < 0) { 53 | pp_hp_sw_log(0, "sending tur command failed"); 54 | goto out; 55 | } 56 | io_hdr.status &= 0x7e; 57 | if ((0 == io_hdr.status) && (0 == io_hdr.host_status) && 58 | (0 == io_hdr.driver_status)) { 59 | /* Command completed normally, path is active */ 60 | ret = HP_PATH_ACTIVE; 61 | } 62 | 63 | if ((SCSI_CHECK_CONDITION == io_hdr.status) || 64 | (SCSI_COMMAND_TERMINATED == io_hdr.status) || 65 | (SG_ERR_DRIVER_SENSE == (0xf & io_hdr.driver_status))) { 66 | if (io_hdr.sbp && (io_hdr.sb_len_wr > 2)) { 67 | int sense_key, asc, asq; 68 | unsigned char * sense_buffer = io_hdr.sbp; 69 | if (sense_buffer[0] & 0x2) { 70 | sense_key = sense_buffer[1] & 0xf; 71 | asc = sense_buffer[2]; 72 | asq = sense_buffer[3]; 73 | } else { 74 | sense_key = sense_buffer[2] & 0xf; 75 | asc = sense_buffer[12]; 76 | asq = sense_buffer[13]; 77 | } 78 | if(RECOVERED_ERROR == sense_key) 79 | ret = HP_PATH_ACTIVE; 80 | if(NOT_READY == sense_key) { 81 | if (asc == 0x04 && asq == 0x02) { 82 | /* This is a standby path */ 83 | ret = HP_PATH_STANDBY; 84 | } 85 | } 86 | if(UNIT_ATTENTION == sense_key) { 87 | if (asc == 0x29) { 88 | /* Retry for device reset */ 89 | goto retry; 90 | } 91 | } 92 | } 93 | } 94 | out: 95 | return(ret); 96 | } 97 | 98 | int getprio (struct path *pp, __attribute__((unused)) char *args) 99 | { 100 | return hp_sw_prio(pp->dev, pp->fd, get_prio_timeout_ms(pp)); 101 | } 102 | -------------------------------------------------------------------------------- /libmultipath/prioritizers/random.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "prio.h" 7 | 8 | int getprio(__attribute__((unused)) struct path *pp, 9 | __attribute__((unused)) char *args) 10 | { 11 | struct timeval tv; 12 | 13 | gettimeofday(&tv, NULL); 14 | srand((unsigned int)tv.tv_usec); 15 | return 1+(int) (10.0*rand()/(RAND_MAX+1.0)); 16 | } 17 | -------------------------------------------------------------------------------- /libmultipath/prioritizers/rdac.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "sg_include.h" 6 | #include "debug.h" 7 | #include "prio.h" 8 | #include "structs.h" 9 | 10 | #define INQUIRY_CMD 0x12 11 | #define INQUIRY_CMDLEN 6 12 | 13 | #define pp_rdac_log(prio, msg) condlog(prio, "%s: rdac prio: " msg, dev) 14 | 15 | int rdac_prio(const char *dev, int fd, unsigned int timeout_ms) 16 | { 17 | unsigned char sense_buffer[128]; 18 | unsigned char sb[128]; 19 | unsigned char inqCmdBlk[INQUIRY_CMDLEN] = {INQUIRY_CMD, 1, 0xC9, 0, 20 | sizeof(sense_buffer), 0}; 21 | struct sg_io_hdr io_hdr; 22 | int ret = 0; 23 | 24 | memset(&io_hdr, 0, sizeof (struct sg_io_hdr)); 25 | memset(sense_buffer, 0, 128); 26 | io_hdr.interface_id = 'S'; 27 | io_hdr.cmd_len = sizeof (inqCmdBlk); 28 | io_hdr.mx_sb_len = sizeof (sb); 29 | io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; 30 | io_hdr.dxfer_len = sizeof (sense_buffer); 31 | io_hdr.dxferp = sense_buffer; 32 | io_hdr.cmdp = inqCmdBlk; 33 | io_hdr.sbp = sb; 34 | io_hdr.timeout = timeout_ms; 35 | io_hdr.pack_id = 0; 36 | if (ioctl(fd, SG_IO, &io_hdr) < 0) { 37 | pp_rdac_log(0, "sending inquiry command failed"); 38 | goto out; 39 | } 40 | if (io_hdr.info & SG_INFO_OK_MASK) { 41 | pp_rdac_log(0, "inquiry command indicates error"); 42 | goto out; 43 | } 44 | 45 | if (/* Verify the code page - right page & page identifier */ 46 | sense_buffer[1] != 0xc9 || 47 | sense_buffer[3] != 0x2c || 48 | sense_buffer[4] != 'v' || 49 | sense_buffer[5] != 'a' || 50 | sense_buffer[6] != 'c' ) { 51 | pp_rdac_log(0, "volume access control page in unknown format"); 52 | goto out; 53 | } 54 | 55 | if ( /* Current Volume Path Bit */ 56 | ( sense_buffer[8] & 0x01) == 0x01 ) { 57 | /* 58 | * This volume was owned by the controller receiving 59 | * the inquiry command. 60 | */ 61 | ret |= 0x02; 62 | } 63 | 64 | /* Volume Preferred Path Priority */ 65 | switch ( sense_buffer[9] & 0x0F ) { 66 | case 0x01: 67 | /* 68 | * Access to this volume is most preferred through 69 | * this path and other paths with this value. 70 | */ 71 | ret |= 0x04; 72 | break; 73 | case 0x02: 74 | /* 75 | * Access to this volume through this path is to be used 76 | * as a secondary path. Typically this path would be used 77 | * for fail-over situations. 78 | */ 79 | ret |= 0x01; 80 | break; 81 | default: 82 | /* Reserved values */ 83 | break; 84 | } 85 | 86 | /* For ioship mode set the bit 3 (00001000) */ 87 | if ((sense_buffer[8] >> 5) & 0x01) 88 | ret |= 0x08; 89 | 90 | out: 91 | return(ret); 92 | } 93 | 94 | int getprio (struct path *pp, __attribute__((unused)) char *args) 95 | { 96 | return rdac_prio(pp->dev, pp->fd, get_prio_timeout_ms(pp)); 97 | } 98 | -------------------------------------------------------------------------------- /libmultipath/prioritizers/sysfs.c: -------------------------------------------------------------------------------- 1 | /* 2 | * sysfs.c 3 | * 4 | * Copyright(c) 2016 Hannes Reinecke, SUSE Linux GmbH 5 | */ 6 | 7 | #include 8 | 9 | #include "structs.h" 10 | #include "discovery.h" 11 | #include "prio.h" 12 | 13 | static const struct { 14 | unsigned char value; 15 | char *name; 16 | } sysfs_access_state_map[] = { 17 | { 50, "active/optimized" }, 18 | { 10, "active/non-optimized" }, 19 | { 5, "lba-dependent" }, 20 | { 1, "standby" }, 21 | }; 22 | 23 | int get_exclusive_pref_arg(char *args) 24 | { 25 | char *ptr; 26 | 27 | if (args == NULL) 28 | return 0; 29 | ptr = strstr(args, "exclusive_pref_bit"); 30 | if (!ptr) 31 | return 0; 32 | if (ptr[18] != '\0' && ptr[18] != ' ' && ptr[18] != '\t') 33 | return 0; 34 | if (ptr != args && ptr[-1] != ' ' && ptr[-1] != '\t') 35 | return 0; 36 | return 1; 37 | } 38 | 39 | int getprio (struct path * pp, char *args) 40 | { 41 | int prio = 0, rc, i; 42 | char buff[512]; 43 | int exclusive_pref; 44 | 45 | exclusive_pref = get_exclusive_pref_arg(args); 46 | rc = sysfs_get_asymmetric_access_state(pp, buff, 512); 47 | if (rc < 0) 48 | return PRIO_UNDEF; 49 | prio = 0; 50 | for (i = 0; i < 4; i++) { 51 | if (!strncmp(buff, sysfs_access_state_map[i].name, 52 | strlen(sysfs_access_state_map[i].name))) { 53 | prio = sysfs_access_state_map[i].value; 54 | break; 55 | } 56 | } 57 | if (rc > 0 && (prio != 50 || exclusive_pref)) 58 | prio += 80; 59 | 60 | return prio; 61 | } 62 | -------------------------------------------------------------------------------- /libmultipath/prioritizers/weightedpath.h: -------------------------------------------------------------------------------- 1 | #ifndef WEIGHTEDPATH_H_INCLUDED 2 | #define WEIGHTEDPATH_H_INCLUDED 3 | 4 | #define PRIO_WEIGHTED_PATH "weightedpath" 5 | #define HBTL "hbtl" 6 | #define DEV_NAME "devname" 7 | #define SERIAL "serial" 8 | #define WWN "wwn" 9 | #define DEFAULT_PRIORITY 0 10 | 11 | int prio_path_weight(struct path *pp, char *prio_args); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /libmultipath/prkey.h: -------------------------------------------------------------------------------- 1 | #ifndef PRKEY_H_INCLUDED 2 | #define PRKEY_H_INCLUDED 3 | 4 | #include "structs.h" 5 | #include 6 | 7 | #define PRKEYS_FILE_HEADER \ 8 | "# Multipath persistent reservation keys, Version : 1.0\n" \ 9 | "# NOTE: this file is automatically maintained by the multipathd program.\n" \ 10 | "# You should not need to edit this file in normal circumstances.\n" \ 11 | "#\n" \ 12 | "# Format:\n" \ 13 | "# prkey wwid\n" \ 14 | "#\n" 15 | 16 | int print_reservation_key(struct strbuf *buff, 17 | struct be64 key, uint8_t flags, int source); 18 | int parse_prkey_flags(const char *ptr, uint64_t *prkey, uint8_t *flags); 19 | int set_prkey(struct config *conf, struct multipath *mpp, 20 | uint64_t prkey, uint8_t sa_flags); 21 | int get_prkey(struct multipath *mpp, uint64_t *prkey, uint8_t *sa_flags); 22 | 23 | #endif /* PRKEY_H_INCLUDED */ 24 | -------------------------------------------------------------------------------- /libmultipath/propsel.h: -------------------------------------------------------------------------------- 1 | #ifndef PROPSEL_H_INCLUDED 2 | #define PROPSEL_H_INCLUDED 3 | int select_rr_weight (struct config *conf, struct multipath * mp); 4 | int select_pgfailback (struct config *conf, struct multipath * mp); 5 | int select_detect_pgpolicy (struct config *conf, struct multipath * mp); 6 | int select_detect_pgpolicy_use_tpg (struct config *conf, struct multipath * mp); 7 | int select_pgpolicy (struct config *conf, struct multipath * mp); 8 | int select_selector (struct config *conf, struct multipath * mp); 9 | int select_alias (struct config *conf, struct multipath * mp); 10 | int select_features (struct config *conf, struct multipath * mp); 11 | int select_hwhandler (struct config *conf, struct multipath * mp); 12 | int select_checker(struct config *conf, struct path *pp); 13 | int select_getuid (struct config *conf, struct path * pp); 14 | int select_recheck_wwid(struct config *conf, struct path * pp); 15 | int select_prio (struct config *conf, struct path * pp); 16 | int select_find_multipaths_timeout(struct config *conf, struct path *pp); 17 | int select_no_path_retry(struct config *conf, struct multipath *mp); 18 | int select_flush_on_last_del(struct config *conf, struct multipath *mp); 19 | int select_minio(struct config *conf, struct multipath *mp); 20 | int select_mode(struct config *conf, struct multipath *mp); 21 | int select_uid(struct config *conf, struct multipath *mp); 22 | int select_gid(struct config *conf, struct multipath *mp); 23 | int select_fast_io_fail(struct config *conf, struct path *pp); 24 | int select_dev_loss(struct config *conf, struct path *pp); 25 | int select_eh_deadline(struct config *conf, struct path *pp); 26 | int select_reservation_key(struct config *conf, struct multipath *mp); 27 | int select_retain_hwhandler (struct config *conf, struct multipath * mp); 28 | int select_detect_prio(struct config *conf, struct path * pp); 29 | int select_detect_checker(struct config *conf, struct path * pp); 30 | int select_deferred_remove(struct config *conf, struct multipath *mp); 31 | int select_delay_checks(struct config *conf, struct multipath * mp); 32 | int select_skip_kpartx (struct config *conf, struct multipath * mp); 33 | int select_max_sectors_kb (struct config *conf, struct multipath * mp); 34 | int select_san_path_err_forget_rate(struct config *conf, struct multipath *mp); 35 | int select_san_path_err_threshold(struct config *conf, struct multipath *mp); 36 | int select_san_path_err_recovery_time(struct config *conf, struct multipath *mp); 37 | int select_marginal_path_err_sample_time(struct config *conf, struct multipath *mp); 38 | int select_marginal_path_err_rate_threshold(struct config *conf, struct multipath *mp); 39 | int select_marginal_path_err_recheck_gap_time(struct config *conf, struct multipath *mp); 40 | int select_marginal_path_double_failed_time(struct config *conf, struct multipath *mp); 41 | int select_ghost_delay(struct config *conf, struct multipath * mp); 42 | void reconcile_features_with_options(const char *id, char **features, 43 | int* no_path_retry, 44 | int *retain_hwhandler); 45 | int select_all_tg_pt (struct config *conf, struct multipath * mp); 46 | int select_vpd_vendor_id (struct path *pp); 47 | #endif 48 | -------------------------------------------------------------------------------- /libmultipath/sg_include.h: -------------------------------------------------------------------------------- 1 | #ifndef SG_INCLUDE_H_INCLUDED 2 | #define SG_INCLUDE_H_INCLUDED 3 | #include 4 | 5 | #ifndef DID_OK 6 | #define DID_OK 0x00 /* NO error */ 7 | #define DID_NO_CONNECT 0x01 /* Couldn't connect before timeout period */ 8 | #define DID_BUS_BUSY 0x02 /* BUS stayed busy through time out period */ 9 | #define DID_TIME_OUT 0x03 /* TIMED OUT for other reason */ 10 | #define DID_BAD_TARGET 0x04 /* BAD target. */ 11 | #define DID_ABORT 0x05 /* Told to abort for some other reason */ 12 | #define DID_PARITY 0x06 /* Parity error */ 13 | #define DID_ERROR 0x07 /* Internal error */ 14 | #define DID_RESET 0x08 /* Reset by somebody. */ 15 | #define DID_BAD_INTR 0x09 /* Got an interrupt we weren't expecting. */ 16 | #define DID_PASSTHROUGH 0x0a /* Force command past mid-layer */ 17 | #define DID_SOFT_ERROR 0x0b /* The low level driver just wish a retry */ 18 | #define DID_IMM_RETRY 0x0c /* Retry without decrementing retry count */ 19 | #define DID_REQUEUE 0x0d /* Requeue command (no immediate retry) also 20 | * without decrementing the retry count */ 21 | #define DID_TRANSPORT_DISRUPTED 0x0e /* Transport error disrupted execution 22 | * and the driver blocked the port to 23 | * recover the link. Transport class will 24 | * retry or fail IO */ 25 | #define DID_TRANSPORT_FAILFAST 0x0f /* Transport class fastfailed the io */ 26 | #endif 27 | #endif 28 | -------------------------------------------------------------------------------- /libmultipath/structs_vec.h: -------------------------------------------------------------------------------- 1 | #ifndef STRUCTS_VEC_H_INCLUDED 2 | #define STRUCTS_VEC_H_INCLUDED 3 | 4 | #include "vector.h" 5 | #include "config.h" 6 | #include "lock.h" 7 | 8 | struct vectors { 9 | vector pathvec; 10 | vector mpvec; 11 | struct mutex_lock lock; /* defined in lock.h */ 12 | }; 13 | 14 | void set_no_path_retry(struct multipath *mpp); 15 | 16 | int adopt_paths (vector pathvec, struct multipath *mpp, 17 | const struct multipath *current_mpp); 18 | void orphan_path (struct path * pp, const char *reason); 19 | void set_path_removed(struct path *pp); 20 | 21 | int verify_paths(struct multipath *mpp); 22 | int update_mpp_paths(struct multipath * mpp, vector pathvec); 23 | int update_multipath_strings (struct multipath *mpp, vector pathvec); 24 | void extract_hwe_from_path(struct multipath * mpp); 25 | 26 | void remove_map (struct multipath *mpp, vector pathvec, vector mpvec); 27 | void remove_map_by_alias(const char *alias, struct vectors * vecs); 28 | void remove_maps (struct vectors * vecs); 29 | 30 | void sync_map_state (struct multipath *); 31 | struct multipath * add_map_with_path (struct vectors * vecs, 32 | struct path * pp, int add_vec, 33 | const struct multipath *current_mpp); 34 | void update_queue_mode_del_path(struct multipath *mpp); 35 | void update_queue_mode_add_path(struct multipath *mpp); 36 | int update_multipath_table__ (struct multipath *mpp, vector pathvec, int flags, 37 | const char *params, const char *status); 38 | int update_multipath_table (struct multipath *mpp, vector pathvec, int flags); 39 | int update_multipath_status (struct multipath *mpp); 40 | vector get_used_hwes(const struct vector_s *pathvec); 41 | 42 | #endif /* STRUCTS_VEC_H_INCLUDED */ 43 | -------------------------------------------------------------------------------- /libmultipath/switchgroup.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2005 Christophe Varoqui 3 | * Copyright (c) 2005 Edward Goggin, EMC 4 | */ 5 | #include "checkers.h" 6 | #include "vector.h" 7 | #include "structs.h" 8 | #include "switchgroup.h" 9 | 10 | void path_group_prio_update(struct pathgroup *pgp) 11 | { 12 | int i; 13 | int priority = 0; 14 | int marginal = 0; 15 | int defined_prios = 0; 16 | struct path * pp; 17 | 18 | pgp->enabled_paths = 0; 19 | if (!pgp->paths) { 20 | pgp->priority = 0; 21 | return; 22 | } 23 | vector_foreach_slot (pgp->paths, pp, i) { 24 | if (pp->marginal) 25 | marginal++; 26 | if (pp->state == PATH_UP || 27 | pp->state == PATH_GHOST) { 28 | if (pp->priority != PRIO_UNDEF) { 29 | defined_prios++; 30 | priority += pp->priority; 31 | } 32 | pgp->enabled_paths++; 33 | } 34 | } 35 | if (defined_prios) 36 | pgp->priority = priority / defined_prios; 37 | else if (pgp->enabled_paths) 38 | pgp->priority = PRIO_UNDEF; 39 | else 40 | pgp->priority = 0; 41 | if (marginal && marginal == i) 42 | pgp->marginal = 1; 43 | } 44 | 45 | int select_path_group(struct multipath *mpp) 46 | { 47 | int i; 48 | int normal_pgp = 0; 49 | int max_priority = 0; 50 | int bestpg = 1; 51 | int max_enabled_paths = 1; 52 | struct pathgroup * pgp; 53 | 54 | if (!mpp->pg) 55 | return 1; 56 | 57 | vector_foreach_slot (mpp->pg, pgp, i) { 58 | if (!pgp->paths) 59 | continue; 60 | 61 | path_group_prio_update(pgp); 62 | if (pgp->marginal && normal_pgp) 63 | continue; 64 | if (pgp->enabled_paths) { 65 | if (!pgp->marginal && !normal_pgp) { 66 | normal_pgp = 1; 67 | max_priority = pgp->priority; 68 | max_enabled_paths = pgp->enabled_paths; 69 | bestpg = i + 1; 70 | } else if (pgp->priority > max_priority) { 71 | max_priority = pgp->priority; 72 | max_enabled_paths = pgp->enabled_paths; 73 | bestpg = i + 1; 74 | } else if (pgp->priority == max_priority) { 75 | if (pgp->enabled_paths > max_enabled_paths) { 76 | max_enabled_paths = pgp->enabled_paths; 77 | bestpg = i + 1; 78 | } 79 | } 80 | } 81 | } 82 | return bestpg; 83 | } 84 | -------------------------------------------------------------------------------- /libmultipath/switchgroup.h: -------------------------------------------------------------------------------- 1 | #ifndef SWITCHGROUP_H_INCLUDED 2 | #define SWITCHGROUP_H_INCLUDED 3 | 4 | void path_group_prio_update (struct pathgroup * pgp); 5 | int select_path_group (struct multipath * mpp); 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /libmultipath/sysfs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * sysfs.h 3 | */ 4 | 5 | #ifndef SYSFS_H_INCLUDED 6 | #define SYSFS_H_INCLUDED 7 | #include 8 | #include "strbuf.h" 9 | 10 | int devt2devname (char *, int, const char *); 11 | ssize_t sysfs_attr_set_value(struct udev_device *dev, const char *attr_name, 12 | const char * value, size_t value_len); 13 | ssize_t sysfs_attr_get_value(struct udev_device *dev, const char *attr_name, 14 | char * value, size_t value_len); 15 | ssize_t sysfs_bin_attr_get_value(struct udev_device *dev, const char *attr_name, 16 | unsigned char * value, size_t value_len); 17 | #define sysfs_attr_value_ok(rc, value_len) \ 18 | ({ \ 19 | ssize_t __r = rc; \ 20 | __r >= 0 && (size_t)__r < (size_t)value_len; \ 21 | }) 22 | 23 | #define sysfs_attr_get_value_ok(dev, attr, val, len) \ 24 | ({ \ 25 | size_t __l = (len); \ 26 | ssize_t __rc = sysfs_attr_get_value(dev, attr, val, __l); \ 27 | sysfs_attr_value_ok(__rc, __l); \ 28 | }) 29 | 30 | #define log_sysfs_attr_set_value(prio, rc, fmt, __args...) \ 31 | do { \ 32 | STRBUF_ON_STACK(__buf); \ 33 | if (print_strbuf(&__buf, fmt, ##__args) >= 0 && \ 34 | print_strbuf(&__buf, ": %s", rc < 0 ? strerror(-rc) : \ 35 | "write underflow") >= 0) \ 36 | condlog(prio, "%s", get_strbuf_str(&__buf)); \ 37 | } while(0) 38 | 39 | int sysfs_get_size (struct path *pp, unsigned long long * size); 40 | int sysfs_check_holders(char * check_devt, char * new_devt); 41 | bool sysfs_is_multipathed(struct path *pp, bool set_wwid); 42 | 43 | struct multipath; 44 | struct udev_device *get_udev_for_mpp(const struct multipath *mpp); 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /libmultipath/uevent.h: -------------------------------------------------------------------------------- 1 | #ifndef UEVENT_H_INCLUDED 2 | #define UEVENT_H_INCLUDED 3 | 4 | /* 5 | * buffer for environment variables, the kernel's size in 6 | * lib/kobject_uevent.c should fit in 7 | */ 8 | #define HOTPLUG_BUFFER_SIZE 2048 9 | #define HOTPLUG_NUM_ENVP 32 10 | #define OBJECT_SIZE 512 11 | 12 | struct udev; 13 | struct config; 14 | 15 | struct uevent { 16 | struct list_head node; 17 | struct list_head merge_node; 18 | struct udev_device *udev; 19 | char buffer[HOTPLUG_BUFFER_SIZE + OBJECT_SIZE]; 20 | char *devpath; 21 | char *action; 22 | char *kernel; 23 | const char *wwid; 24 | unsigned long seqnum; 25 | char *envp[HOTPLUG_NUM_ENVP]; 26 | }; 27 | 28 | struct uevent *alloc_uevent(void); 29 | int is_uevent_busy(void); 30 | 31 | int uevent_listen(struct udev *udev); 32 | int uevent_dispatch(int (*store_uev)(struct uevent *, void * trigger_data), 33 | void * trigger_data); 34 | bool uevent_is_mpath(const struct uevent *uev); 35 | void uevent_get_wwid(struct uevent *uev, const struct config *conf); 36 | 37 | int uevent_get_env_positive_int(const struct uevent *uev, 38 | const char *attr); 39 | 40 | static inline int uevent_get_major(const struct uevent *uev) 41 | { 42 | return uevent_get_env_positive_int(uev, "MAJOR"); 43 | } 44 | 45 | static inline int uevent_get_minor(const struct uevent *uev) 46 | { 47 | return uevent_get_env_positive_int(uev, "MINOR"); 48 | } 49 | 50 | static inline int uevent_get_disk_ro(const struct uevent *uev) 51 | { 52 | return uevent_get_env_positive_int(uev, "DISK_RO"); 53 | } 54 | 55 | char *uevent_get_dm_str(const struct uevent *uev, char *attr); 56 | 57 | static inline char *uevent_get_dm_name(const struct uevent *uev) 58 | { 59 | return uevent_get_dm_str(uev, "DM_NAME"); 60 | } 61 | 62 | static inline char *uevent_get_dm_path(const struct uevent *uev) 63 | { 64 | return uevent_get_dm_str(uev, "DM_PATH"); 65 | } 66 | 67 | static inline char *uevent_get_dm_action(const struct uevent *uev) 68 | { 69 | return uevent_get_dm_str(uev, "DM_ACTION"); 70 | } 71 | 72 | #endif /* UEVENT_H_INCLUDED */ 73 | -------------------------------------------------------------------------------- /libmultipath/unaligned.h: -------------------------------------------------------------------------------- 1 | #ifndef UNALIGNED_H_INCLUDED 2 | #define UNALIGNED_H_INCLUDED 3 | 4 | #include 5 | 6 | static inline uint16_t get_unaligned_be16(const void *ptr) 7 | { 8 | const uint8_t *p = ptr; 9 | 10 | return p[0] << 8 | p[1]; 11 | } 12 | 13 | static inline uint32_t get_unaligned_be32(const void *ptr) 14 | { 15 | const uint8_t *p = ptr; 16 | 17 | return p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; 18 | } 19 | 20 | static inline uint64_t get_unaligned_be64(const void *ptr) 21 | { 22 | uint32_t low = get_unaligned_be32(ptr + 4); 23 | uint64_t high = get_unaligned_be32(ptr); 24 | 25 | return high << 32 | low; 26 | } 27 | 28 | static inline void put_unaligned_be16(uint16_t val, void *ptr) 29 | { 30 | uint8_t *p = ptr; 31 | 32 | p[0] = val >> 8; 33 | p[1] = val; 34 | } 35 | 36 | static inline void put_unaligned_be32(uint32_t val, void *ptr) 37 | { 38 | uint8_t *p = ptr; 39 | 40 | p[0] = val >> 24; 41 | p[1] = val >> 16; 42 | p[2] = val >> 8; 43 | p[3] = val; 44 | } 45 | 46 | static inline void put_unaligned_be64(uint64_t val, void *ptr) 47 | { 48 | uint8_t *p = ptr; 49 | 50 | put_unaligned_be32(val >> 32, p); 51 | put_unaligned_be32(val, p + 4); 52 | } 53 | 54 | #endif /* UNALIGNED_H_INCLUDED */ 55 | -------------------------------------------------------------------------------- /libmultipath/valid.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Benjamin Marzinski, IBM 3 | 4 | This program is free software; you can redistribute it and/or 5 | modify it under the terms of the GNU General Public License 6 | as published by the Free Software Foundation; either version 2 7 | of the License, or (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . 16 | */ 17 | #ifndef VALID_H_INCLUDED 18 | #define VALID_H_INCLUDED 19 | 20 | /* 21 | * PATH_IS_VALID_NO_CHECK is returned when multipath should claim 22 | * the path, regardless of whether is has been released to systemd 23 | * already. 24 | * PATH_IS_VALID is returned by is_path_valid, when the path is 25 | * valid only if it hasn't been released to systemd already. 26 | * PATH_IS_MAYBE_VALID is returned when the path would be valid 27 | * if other paths with the same wwid existed. It is up to the caller 28 | * to check for these other paths. 29 | */ 30 | enum is_path_valid_result { 31 | PATH_IS_ERROR = -1, 32 | PATH_IS_NOT_VALID, 33 | PATH_IS_VALID, 34 | PATH_IS_VALID_NO_CHECK, 35 | PATH_IS_MAYBE_VALID, 36 | PATH_MAX_VALID_RESULT, /* only for bounds checking */ 37 | }; 38 | 39 | int is_path_valid(const char *name, struct config *conf, struct path *pp, 40 | bool check_multipathd); 41 | 42 | #endif /* VALID_H_INCLUDED */ 43 | -------------------------------------------------------------------------------- /libmultipath/version.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Soft: multipath device mapper target autoconfig 3 | * 4 | * Version: $Id: main.h,v 0.0.1 2003/09/18 15:13:38 cvaroqui Exp $ 5 | * 6 | * Author: Christophe Varoqui 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * This program is free software; you can redistribute it and/or 14 | * modify it under the terms of the GNU General Public License 15 | * as published by the Free Software Foundation; either version 16 | * 2 of the License, or (at your option) any later version. 17 | * 18 | * Copyright (c) 2006 Christophe Varoqui 19 | */ 20 | #ifndef VERSION_H_INCLUDED 21 | #define VERSION_H_INCLUDED 22 | 23 | #define VERSION_CODE 0x000B00 24 | /* MMDDYY, in hex */ 25 | #define DATE_CODE 0x110119 26 | 27 | #define PROG "multipath-tools" 28 | 29 | #define MULTIPATH_VERSION(version) \ 30 | (version >> 16) & 0xFF, \ 31 | (version >> 8) & 0xFF, \ 32 | version & 0xFF 33 | 34 | #define VERSION_STRING PROG" v%d.%d.%d (%.2d/%.2d, 20%.2d)\n", \ 35 | MULTIPATH_VERSION(VERSION_CODE), \ 36 | MULTIPATH_VERSION(DATE_CODE) 37 | 38 | #endif /* VERSION_H_INCLUDED */ 39 | -------------------------------------------------------------------------------- /libmultipath/wwids.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010 Benjamin Marzinski, Redhat 3 | */ 4 | 5 | #ifndef WWIDS_H_INCLUDED 6 | #define WWIDS_H_INCLUDED 7 | 8 | #define WWIDS_FILE_HEADER \ 9 | "# Multipath wwids, Version : 1.0\n" \ 10 | "# NOTE: This file is automatically maintained by multipath and multipathd.\n" \ 11 | "# You should not need to edit this file in normal circumstances.\n" \ 12 | "#\n" \ 13 | "# Valid WWIDs:\n" 14 | 15 | int should_multipath(struct path *pp, vector pathvec, vector mpvec); 16 | int remember_wwid(char *wwid); 17 | int check_wwids_file(char *wwid, int write_wwid); 18 | int remove_wwid(char *wwid); 19 | int replace_wwids(vector mp); 20 | 21 | enum { 22 | WWID_IS_NOT_FAILED = 0, 23 | WWID_IS_FAILED, 24 | WWID_FAILED_UNCHANGED, 25 | WWID_FAILED_CHANGED, 26 | WWID_FAILED_ERROR = -1, 27 | }; 28 | 29 | int is_failed_wwid(const char *wwid); 30 | int mark_failed_wwid(const char *wwid); 31 | int unmark_failed_wwid(const char *wwid); 32 | #endif /* WWIDS_H_INCLUDED */ 33 | -------------------------------------------------------------------------------- /mpathpersist/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | CPPFLAGS += -I$(multipathdir) -I$(mpathutildir) -I$(mpathpersistdir) 4 | CFLAGS += $(BIN_CFLAGS) 5 | LDFLAGS += $(BIN_LDFLAGS) 6 | 7 | LIBDEPS += -L$(mpathpersistdir) -lmpathpersist -L$(multipathdir) -lmultipath \ 8 | -L$(mpathutildir) -lmpathutil -L$(mpathcmddir) -lmpathcmd -lpthread -ldevmapper -ludev 9 | 10 | EXEC = mpathpersist 11 | MANPAGES := mpathpersist.8 12 | 13 | OBJS = main.o 14 | 15 | all: $(EXEC) $(MANPAGES) 16 | 17 | $(EXEC): $(OBJS) 18 | $(Q)$(CC) $(OBJS) -o $(EXEC) $(LDFLAGS) $(CFLAGS) $(LIBDEPS) 19 | 20 | install: 21 | $(Q)$(INSTALL_PROGRAM) -d $(DESTDIR)$(bindir) 22 | $(Q)$(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir)/ 23 | $(Q)$(INSTALL_PROGRAM) -d $(DESTDIR)$(mandir)/man8 24 | $(Q)$(INSTALL_PROGRAM) -m 644 $(EXEC).8 $(DESTDIR)$(mandir)/man8 25 | 26 | clean: dep_clean 27 | $(Q)$(RM) core *.o $(EXEC) $(MANPAGES) 28 | 29 | include $(wildcard $(OBJS:.o=.d)) 30 | 31 | uninstall: 32 | $(Q)$(RM) $(DESTDIR)$(bindir)/$(EXEC) 33 | $(Q)$(RM) $(DESTDIR)$(mandir)/man8/$(EXEC).8 34 | 35 | dep_clean: 36 | $(Q)$(RM) $(OBJS:.o=.d) 37 | -------------------------------------------------------------------------------- /mpathpersist/main.h: -------------------------------------------------------------------------------- 1 | #ifndef MPATHPERSIST_MAIN_H_INCLUDED 2 | #define MPATHPERSIST_MAIN_H_INCLUDED 3 | 4 | static struct option long_options[] = { 5 | {"verbose", 1, NULL, 'v'}, 6 | {"clear", 0, NULL, 'C'}, 7 | {"device", 1, NULL, 'd'}, 8 | {"batch-file", 1, NULL, 'f' }, 9 | {"help", 0, NULL, 'h'}, 10 | {"hex", 0, NULL, 'H'}, 11 | {"in", 0, NULL, 'i'}, 12 | {"out", 0, NULL, 'o'}, 13 | {"param-alltgpt", 0, NULL, 'Y'}, 14 | {"param-aptpl", 0, NULL, 'Z'}, 15 | {"param-rk", 1, NULL, 'K'}, 16 | {"param-sark", 1, NULL, 'S'}, 17 | {"preempt", 0, NULL, 'P'}, 18 | {"preempt-abort", 0, NULL, 'A'}, 19 | {"prout-type", 1, NULL, 'T'}, 20 | {"read-full-status", 0, NULL, 's'}, 21 | {"read-keys", 0, NULL, 'k'}, 22 | {"read-reservation", 0, NULL, 'r'}, 23 | {"register", 0, NULL, 'G'}, 24 | {"register-ignore", 0, NULL, 'I'}, 25 | {"release", 0, NULL, 'L'}, 26 | {"report-capabilities", 0, NULL, 'c'}, 27 | {"reserve", 0, NULL, 'R'}, 28 | {"transport-id", 1, NULL, 'X'}, 29 | {"alloc-length", 1, NULL, 'l'}, 30 | {NULL, 0, NULL, 0} 31 | }; 32 | 33 | static void usage(void); 34 | #endif 35 | -------------------------------------------------------------------------------- /multipath/99-z-dm-mpath-late.rules: -------------------------------------------------------------------------------- 1 | # If DM_UDEV_DISABLE_OTHER_RULES_FLAG was modified in 11-dm-mpath.rules, 2 | # restore it here, lest a temporary value be saved in the udev db 3 | ACTION=="add|change", ENV{.MPATH_SAVE_DISABLE_OTHER_RULES_FLAG}=="?*", \ 4 | ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}="$env{.MPATH_SAVE_DISABLE_OTHER_RULES_FLAG}" 5 | -------------------------------------------------------------------------------- /multipath/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2003 Christophe Varoqui, 3 | # 4 | include ../Makefile.inc 5 | 6 | EXEC := multipath 7 | MANPAGES := multipath.8 multipath.conf.5 8 | GENERATED := $(MANPAGES) multipath.rules tmpfiles.conf 11-dm-mpath.rules 9 | 10 | CPPFLAGS += -I$(multipathdir) -I$(mpathutildir) -I$(mpathcmddir) 11 | CFLAGS += $(BIN_CFLAGS) 12 | LDFLAGS += $(BIN_LDFLAGS) 13 | LIBDEPS += -L$(multipathdir) -lmultipath -L$(mpathutildir) -lmpathutil \ 14 | -L$(mpathcmddir) -lmpathcmd -lpthread -ldevmapper -ldl -ludev 15 | 16 | OBJS := main.o 17 | 18 | all: $(EXEC) $(GENERATED) 19 | 20 | $(EXEC): $(OBJS) $(multipathdir)/libmultipath.so $(mpathcmddir)/libmpathcmd.so 21 | @echo building $@ because of $? 22 | $(Q)$(CC) $(CFLAGS) $(OBJS) -o $(EXEC) $(LDFLAGS) $(LIBDEPS) 23 | 24 | install: 25 | $(Q)$(INSTALL_PROGRAM) -d $(DESTDIR)$(bindir) 26 | $(Q)$(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir)/ 27 | $(Q)$(INSTALL_PROGRAM) -d $(DESTDIR)$(udevrulesdir) 28 | $(Q)$(INSTALL_PROGRAM) -m 644 11-dm-mpath.rules $(DESTDIR)$(udevrulesdir) 29 | $(Q)$(INSTALL_PROGRAM) -m 644 99-z-dm-mpath-late.rules $(DESTDIR)$(udevrulesdir) 30 | $(Q)$(INSTALL_PROGRAM) -m 644 multipath.rules $(DESTDIR)$(udevrulesdir)/56-multipath.rules 31 | $(Q)$(INSTALL_PROGRAM) -d $(DESTDIR)$(tmpfilesdir) 32 | $(Q)$(INSTALL_PROGRAM) -m 644 tmpfiles.conf $(DESTDIR)$(tmpfilesdir)/multipath.conf 33 | $(Q)$(INSTALL_PROGRAM) -d $(DESTDIR)$(mandir)/man8 34 | $(Q)$(INSTALL_PROGRAM) -m 644 $(EXEC).8 $(DESTDIR)$(mandir)/man8 35 | $(Q)$(INSTALL_PROGRAM) -d $(DESTDIR)$(mandir)/man5 36 | $(Q)$(INSTALL_PROGRAM) -m 644 $(EXEC).conf.5 $(DESTDIR)$(mandir)/man5 37 | $(Q)$(INSTALL_PROGRAM) -d $(DESTDIR)$(modulesloaddir) 38 | ifeq ($(MODPROBE_UNIT),) 39 | $(Q)$(INSTALL_PROGRAM) -m 644 modules-load.conf $(DESTDIR)$(modulesloaddir)/multipath.conf 40 | endif 41 | ifneq ($(SCSI_DH_MODULES_PRELOAD),) 42 | $(Q)$(INSTALL_PROGRAM) -m 644 scsi_dh.conf $(DESTDIR)$(modulesloaddir)/scsi_dh.conf 43 | $(Q)for _x in $(SCSI_DH_MODULES_PRELOAD); do echo "$$_x"; done \ 44 | >>$(DESTDIR)$(modulesloaddir)/scsi_dh.conf 45 | endif 46 | 47 | uninstall: 48 | $(Q)$(RM) $(DESTDIR)$(bindir)/$(EXEC) 49 | $(Q)$(RM) $(DESTDIR)$(udevrulesdir)/11-dm-mpath.rules 50 | $(Q)$(RM) $(DESTDIR)$(udevrulesdir)/99-z-dm-mpath-late.rules 51 | $(Q)$(RM) $(DESTDIR)$(modulesloaddir)/multipath.conf 52 | $(Q)$(RM) $(DESTDIR)$(modulesloaddir)/scsi_dh.conf 53 | $(Q)$(RM) $(DESTDIR)$(libudevdir)/rules.d/56-multipath.rules 54 | $(Q)$(RM) $(DESTDIR)$(mandir)/man8/$(EXEC).8 55 | $(Q)$(RM) $(DESTDIR)$(mandir)/man5/$(EXEC).conf.5 56 | $(Q)$(RM) $(DESTDIR)$(tmpfilesdir)/multipath.conf 57 | 58 | clean: dep_clean 59 | $(Q)$(RM) core *.o $(EXEC) $(GENERATED) 60 | 61 | include $(wildcard $(OBJS:.o=.d)) 62 | 63 | dep_clean: 64 | $(Q)$(RM) $(OBJS:.o=.d) 65 | -------------------------------------------------------------------------------- /multipath/modules-load.conf: -------------------------------------------------------------------------------- 1 | # load dm-multipath early, both multipathd and multipath depend on it 2 | # (note that multipath may be called from udev rules!) 3 | dm-multipath 4 | -------------------------------------------------------------------------------- /multipath/scsi_dh.conf: -------------------------------------------------------------------------------- 1 | # Load SCSI device handler modules for multipath early 2 | # This file may be empty 3 | -------------------------------------------------------------------------------- /multipath/tmpfiles.conf.in: -------------------------------------------------------------------------------- 1 | d @RUNTIME_DIR@/multipath 0700 root root - 2 | -------------------------------------------------------------------------------- /multipathd/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | EXEC := multipathd 4 | CLI := multipathc 5 | MANPAGES := multipathd.8 6 | 7 | CPPFLAGS += -I$(multipathdir) -I$(mpathutildir) -I$(mpathpersistdir) -I$(mpathcmddir) -I$(thirdpartydir) \ 8 | -DBINDIR='"$(bindir)"' $(SYSTEMD_CPPFLAGS) 9 | 10 | # 11 | # debugging stuff 12 | # 13 | #CPPFLAGS += -DLCKDBG 14 | #CPPFLAGS += -DLOGDBG 15 | 16 | CFLAGS += $(BIN_CFLAGS) 17 | LDFLAGS += $(BIN_LDFLAGS) 18 | 19 | CLI_LIBDEPS := -L$(mpathutildir) -lmpathutil -L$(mpathcmddir) -lmpathcmd \ 20 | -ludev -ldl -lurcu -lpthread $(SYSTEMD_LIBDEPS) 21 | LIBDEPS := -L$(multipathdir) -lmultipath -L$(mpathpersistdir) -lmpathpersist \ 22 | -ldevmapper $(CLI_LIBDEPS) 23 | 24 | ifeq ($(READLINE),libedit) 25 | RL_CPPFLAGS := -DUSE_LIBEDIT 26 | RL_LIBDEPS := -ledit 27 | # See comment in multipathc.c 28 | ifeq ($(shell sed -En 's/.*\ 2 | #include 3 | #include "init_unwinder.h" 4 | 5 | static pthread_mutex_t dummy_mtx = PTHREAD_MUTEX_INITIALIZER; 6 | static pthread_cond_t dummy_cond = PTHREAD_COND_INITIALIZER; 7 | static int dummy_started; 8 | 9 | static void *dummy_thread(void *arg __attribute__((unused))) 10 | { 11 | pthread_mutex_lock(&dummy_mtx); 12 | dummy_started = 1; 13 | pthread_cond_broadcast(&dummy_cond); 14 | pthread_mutex_unlock(&dummy_mtx); 15 | pause(); 16 | return NULL; 17 | } 18 | 19 | int init_unwinder(void) 20 | { 21 | pthread_t dummy; 22 | int rc; 23 | 24 | pthread_mutex_lock(&dummy_mtx); 25 | 26 | rc = pthread_create(&dummy, NULL, dummy_thread, NULL); 27 | if (rc != 0) { 28 | pthread_mutex_unlock(&dummy_mtx); 29 | return rc; 30 | } 31 | 32 | while (!dummy_started) 33 | pthread_cond_wait(&dummy_cond, &dummy_mtx); 34 | 35 | pthread_mutex_unlock(&dummy_mtx); 36 | 37 | return pthread_cancel(dummy); 38 | } 39 | -------------------------------------------------------------------------------- /multipathd/init_unwinder.h: -------------------------------------------------------------------------------- 1 | #ifndef INIT_UNWINDER_H_INCLUDED 2 | #define INIT_UNWINDER_H_INCLUDED 3 | 4 | /* 5 | * init_unwinder(): make sure unwinder symbols are loaded 6 | * 7 | * libc's implementation of pthread_cancel() loads symbols from 8 | * libgcc_s.so using dlopen() when pthread_cancel() is called 9 | * for the first time. This happens even with LD_BIND_NOW=1. 10 | * This may imply the need for file system access when a thread is 11 | * cancelled, which in the case of multipath-tools might be in a 12 | * dangerous situation where multipathd must avoid blocking. 13 | * 14 | * Call load_unwinder() during startup to make sure the dynamic 15 | * linker has all necessary symbols resolved early on. 16 | * 17 | * Return: 0 if successful, an error number otherwise. 18 | */ 19 | int init_unwinder(void); 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /multipathd/main.h: -------------------------------------------------------------------------------- 1 | #ifndef MAIN_H_INCLUDED 2 | #define MAIN_H_INCLUDED 3 | 4 | #define MAPGCINT 5 5 | 6 | enum daemon_status { 7 | DAEMON_INIT = 0, 8 | DAEMON_START, 9 | DAEMON_CONFIGURE, 10 | DAEMON_IDLE, 11 | DAEMON_RUNNING, 12 | DAEMON_SHUTDOWN, 13 | DAEMON_STATUS_SIZE, 14 | }; 15 | 16 | enum remove_path_result { 17 | REMOVE_PATH_FAILURE = 0x0, /* path could not be removed. It is still 18 | * part of the kernel map, but its state 19 | * is set to INIT_REMOVED, and it will be 20 | * removed at the next possible occasion */ 21 | REMOVE_PATH_SUCCESS = 0x1, /* path was removed */ 22 | REMOVE_PATH_DELAY = 0x2, /* path is set to be removed later. it 23 | * currently still exists and is part of the 24 | * kernel map */ 25 | REMOVE_PATH_MAP_ERROR = 0x5, /* map was removed because of error. value 26 | * includes REMOVE_PATH_SUCCESS bit 27 | * because the path was also removed */ 28 | }; 29 | 30 | extern pid_t daemon_pid; 31 | extern int uxsock_timeout; 32 | 33 | void exit_daemon(void); 34 | const char *daemon_status(bool *pending_reconfig); 35 | enum daemon_status wait_for_state_change_if(enum daemon_status oldstate, 36 | unsigned long ms); 37 | void schedule_reconfigure(enum force_reload_types requested_type); 38 | int need_to_delay_reconfig (struct vectors *); 39 | int ev_add_path (struct path *, struct vectors *, int); 40 | int ev_remove_path (struct path *, struct vectors *, int); 41 | int ev_add_map (char *, const char *, struct vectors *); 42 | int flush_map(struct multipath *, struct vectors *); 43 | 44 | void handle_signals(bool); 45 | int refresh_multipath(struct vectors * vecs, struct multipath * mpp); 46 | int setup_multipath(struct vectors * vecs, struct multipath * mpp); 47 | int update_multipath(struct vectors *vecs, char *mapname); 48 | int reload_and_sync_map(struct multipath *mpp, struct vectors *vecs); 49 | 50 | bool handle_path_wwid_change(struct path *pp, struct vectors *vecs); 51 | bool check_path_wwid_change(struct path *pp); 52 | int finish_path_init(struct path *pp, struct vectors * vecs); 53 | int resize_map(struct multipath *mpp, unsigned long long size, 54 | struct vectors *vecs); 55 | #endif /* MAIN_H_INCLUDED */ 56 | -------------------------------------------------------------------------------- /multipathd/multipathc.8: -------------------------------------------------------------------------------- 1 | .\" ---------------------------------------------------------------------------- 2 | .\" Make sure there are no errors with: 3 | .\" groff -z -wall -b -e -t multipathd/multipathc.8 4 | .\" man --warnings -E UTF-8 -l -Tutf8 -Z multipathd/multipathc.8 > /dev/null 5 | .\" 6 | .\" Update the date below if you make any significant change. 7 | .\" ---------------------------------------------------------------------------- 8 | . 9 | .TH MULTIPATHC 8 2022-09-03 Linux 10 | . 11 | . 12 | .\" ---------------------------------------------------------------------------- 13 | .SH NAME 14 | .\" ---------------------------------------------------------------------------- 15 | . 16 | multipathc \- Interactive client for multipathd 17 | . 18 | . 19 | .\" ---------------------------------------------------------------------------- 20 | .SH SYNOPSIS 21 | .\" ---------------------------------------------------------------------------- 22 | . 23 | .B multipathc 24 | .RB [\| 25 | .IR timeout 26 | .RB \|] 27 | . 28 | . 29 | .\" ---------------------------------------------------------------------------- 30 | .SH DESCRIPTION 31 | .\" ---------------------------------------------------------------------------- 32 | . 33 | The \fBmultipathc\fR tool provides an interactive shell for communicating 34 | with the \fBmultipathd\fR daemon. 35 | The command \fBmultipathd -k\fR invokes \fBmultipathc\fR. 36 | .P 37 | All commands documented in \fBmultipathd(8)\fR are supported. 38 | The available commands can be viewed by entering '\fIhelp\fR'. 39 | Use \fIquit\fR, \fIexit\fR, or \fBCTRL-D\fR to exit the shell. 40 | Keywords can be abbreviated with the first letters (for example, 41 | \fIshu\fR for \fIshutdown\fR), if the abbreviation is unique. 42 | Some commands support pretty-printing 43 | using \fBprintf\fR-style format specifiers. The supported format specifiers 44 | can be listed with the command \fBshow wildcards\fR. 45 | Depending on build options, the interactive shell 46 | may provide command completion and history expansion features. 47 | .P 48 | The optional parameter \fBtimeout\fR specifies the timeout to wait for 49 | a reply from \fBmultipathd\fR, in milliseconds. The default is 4000 ms. 50 | . 51 | . 52 | .\" ---------------------------------------------------------------------------- 53 | .SH "SEE ALSO" 54 | .\" ---------------------------------------------------------------------------- 55 | . 56 | .BR multipathd (8) 57 | . 58 | . 59 | .\" ---------------------------------------------------------------------------- 60 | .SH AUTHORS 61 | .\" ---------------------------------------------------------------------------- 62 | . 63 | \fImultipath-tools\fR was developed by Christophe Varoqui 64 | and others. 65 | .\" EOF 66 | -------------------------------------------------------------------------------- /multipathd/multipathd.service.in: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Device-Mapper Multipath Device Controller 3 | Before=lvm2-activation-early.service 4 | Before=local-fs-pre.target blk-availability.service shutdown.target 5 | Wants=systemd-udevd-kernel.socket @MODPROBE_UNIT@ 6 | After=systemd-udevd-kernel.socket @MODPROBE_UNIT@ 7 | After=multipathd.socket systemd-remount-fs.service 8 | Before=initrd-cleanup.service 9 | DefaultDependencies=no 10 | Conflicts=shutdown.target 11 | Conflicts=initrd-cleanup.service 12 | ConditionKernelCommandLine=!nompath 13 | ConditionKernelCommandLine=!multipath=off 14 | ConditionVirtualization=!container 15 | StartLimitIntervalSec=30 16 | StartLimitBurst=3 17 | 18 | [Service] 19 | Type=notify 20 | NotifyAccess=main 21 | ExecStart=@BINDIR@/multipathd -d -s 22 | ExecReload=@BINDIR@/multipathd reconfigure 23 | Restart=on-failure 24 | TasksMax=infinity 25 | LimitRTPRIO=10 26 | CPUWeight=1000 27 | 28 | [Install] 29 | WantedBy=sysinit.target 30 | -------------------------------------------------------------------------------- /multipathd/multipathd.socket: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=multipathd control socket 3 | DefaultDependencies=no 4 | ConditionKernelCommandLine=!nompath 5 | ConditionKernelCommandLine=!multipath=off 6 | ConditionVirtualization=!container 7 | Before=sockets.target 8 | 9 | [Socket] 10 | ListenStream=@/org/kernel/linux/storage/multipathd 11 | 12 | [Install] 13 | # Socket activation for multipathd is disabled by default. 14 | # Activate it here if you find it useful. 15 | # WantedBy=sockets.target 16 | -------------------------------------------------------------------------------- /multipathd/pidfile.c: -------------------------------------------------------------------------------- 1 | #include /* for pid_t */ 2 | #include /* for open */ 3 | #include /* for EACCESS and EAGAIN */ 4 | #include /* for snprintf() */ 5 | #include /* for memset() */ 6 | #include /* for ftruncate() */ 7 | #include /* for fcntl() */ 8 | 9 | #include "debug.h" 10 | 11 | #include "pidfile.h" 12 | 13 | int pidfile_create(const char *pidFile, pid_t pid) 14 | { 15 | char buf[20]; 16 | struct flock lock; 17 | int fd, value; 18 | 19 | if((fd = open(pidFile, O_WRONLY | O_CREAT, 20 | (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) < 0) { 21 | condlog(0, "Cannot open pidfile [%s], error was [%s]", 22 | pidFile, strerror(errno)); 23 | return -errno; 24 | } 25 | lock.l_type = F_WRLCK; 26 | lock.l_start = 0; 27 | lock.l_whence = SEEK_SET; 28 | lock.l_len = 0; 29 | 30 | if (fcntl(fd, F_SETLK, &lock) < 0) { 31 | if (errno != EACCES && errno != EAGAIN) 32 | condlog(0, "Cannot lock pidfile [%s], error was [%s]", 33 | pidFile, strerror(errno)); 34 | else 35 | condlog(0, "process is already running"); 36 | goto fail; 37 | } 38 | if (ftruncate(fd, 0) < 0) { 39 | condlog(0, "Cannot truncate pidfile [%s], error was [%s]", 40 | pidFile, strerror(errno)); 41 | goto fail; 42 | } 43 | memset(buf, 0, sizeof(buf)); 44 | snprintf(buf, sizeof(buf)-1, "%u", pid); 45 | if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf)) { 46 | condlog(0, "Cannot write pid to pidfile [%s], error was [%s]", 47 | pidFile, strerror(errno)); 48 | goto fail; 49 | } 50 | if ((value = fcntl(fd, F_GETFD, 0)) < 0) { 51 | condlog(0, "Cannot get close-on-exec flag from pidfile [%s], " 52 | "error was [%s]", pidFile, strerror(errno)); 53 | goto fail; 54 | } 55 | value |= FD_CLOEXEC; 56 | if (fcntl(fd, F_SETFD, value) < 0) { 57 | condlog(0, "Cannot set close-on-exec flag from pidfile [%s], " 58 | "error was [%s]", pidFile, strerror(errno)); 59 | goto fail; 60 | } 61 | return fd; 62 | fail: 63 | close(fd); 64 | return -errno; 65 | } 66 | -------------------------------------------------------------------------------- /multipathd/pidfile.h: -------------------------------------------------------------------------------- 1 | #ifndef PIDFILE_H_INCLUDED 2 | #define PIDFILE_H_INCLUDED 3 | int pidfile_create(const char *pidFile, pid_t pid); 4 | #endif 5 | 6 | -------------------------------------------------------------------------------- /multipathd/uxclnt.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Original author : tridge@samba.org, January 2002 3 | * 4 | * Copyright (c) 2005 Christophe Varoqui 5 | * Copyright (c) 2005 Benjamin Marzinski, Redhat 6 | */ 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "mpath_cmd.h" 13 | #include "uxsock.h" 14 | #include "uxclnt.h" 15 | 16 | static int process_req(int fd, char * inbuf, unsigned int timeout) 17 | { 18 | char *reply; 19 | int ret; 20 | 21 | if (send_packet(fd, inbuf) != 0) { 22 | printf("cannot send packet\n"); 23 | return 1; 24 | } 25 | ret = recv_packet(fd, &reply, timeout); 26 | if (ret < 0) { 27 | if (ret == -ETIMEDOUT) 28 | printf("timeout receiving packet\n"); 29 | else 30 | printf("error %d receiving packet\n", ret); 31 | return 1; 32 | } else { 33 | ret = (strncmp(reply, "fail\n", 5) == 0); 34 | /* If there is additional failure information, skip the 35 | * initial 'fail' */ 36 | if (ret && strlen(reply) > 5) 37 | printf("%s", reply + 5); 38 | else 39 | printf("%s", reply); 40 | free(reply); 41 | return ret; 42 | } 43 | } 44 | 45 | /* 46 | * entry point 47 | */ 48 | int uxclnt(char * inbuf, unsigned int timeout) 49 | { 50 | int fd, ret = 0; 51 | 52 | if (!inbuf) 53 | return 1; 54 | fd = mpath_connect(); 55 | if (fd == -1) { 56 | fprintf(stderr, "ERROR: failed to connect to multipathd\n"); 57 | return 1; 58 | } 59 | 60 | ret = process_req(fd, inbuf, timeout); 61 | 62 | mpath_disconnect(fd); 63 | return ret; 64 | } 65 | -------------------------------------------------------------------------------- /multipathd/uxclnt.h: -------------------------------------------------------------------------------- 1 | #ifndef UXCLNT_H_INCLUDED 2 | #define UXCLNT_H_INCLUDED 3 | 4 | int uxclnt(char * inbuf, unsigned int timeout); 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /multipathd/uxlsnr.h: -------------------------------------------------------------------------------- 1 | #ifndef UXLSNR_H_INCLUDED 2 | #define UXLSNR_H_INCLUDED 3 | 4 | #include 5 | 6 | bool waiting_clients(void); 7 | void uxsock_cleanup(void *arg); 8 | void *uxsock_listen(long ux_sock, 9 | void * trigger_data); 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /multipathd/waiter.h: -------------------------------------------------------------------------------- 1 | #ifndef WAITER_H_INCLUDED 2 | #define WAITER_H_INCLUDED 3 | 4 | extern pthread_attr_t waiter_attr; 5 | 6 | struct event_thread { 7 | struct dm_task *dmt; 8 | pthread_t thread; 9 | int event_nr; 10 | char mapname[WWID_SIZE]; 11 | struct vectors *vecs; 12 | }; 13 | 14 | void stop_waiter_thread (struct multipath *mpp); 15 | int start_waiter_thread (struct multipath *mpp, struct vectors *vecs); 16 | 17 | #endif /* WAITER_H_INCLUDED */ 18 | -------------------------------------------------------------------------------- /rules.mk: -------------------------------------------------------------------------------- 1 | # Copyright (c) SUSE LLC 2 | # SPDX-License-Identifier: GPL-2.0-or-later 3 | 4 | $(DEVLIB): $(LIBS) 5 | $(Q)$(LN) $(LIBS) $@ 6 | 7 | $(LIBS): $(OBJS) $(VERSION_SCRIPT) 8 | $(Q)$(CC) $(LDFLAGS) $(SHARED_FLAGS) -Wl,-soname=$@ \ 9 | -Wl,--version-script=$(VERSION_SCRIPT) -o $@ $(OBJS) $(LIBDEPS) 10 | 11 | $(LIBS:%.so.$(SONAME)=%-nv.so): $(OBJS) $(NV_VERSION_SCRIPT) 12 | $(Q)$(CC) $(LDFLAGS) $(SHARED_FLAGS) -Wl,-soname=$@ \ 13 | -Wl,--version-script=$(NV_VERSION_SCRIPT) -o $@ $(OBJS) $(LIBDEPS) 14 | 15 | abi: $(LIBS:%.so.$(SONAME)=%-nv.abi) 16 | 17 | $(TOPDIR)/config.mk $(multipathdir)/autoconfig.h: 18 | $(Q)$(MAKE) -C $(TOPDIR) -f create-config.mk 19 | -------------------------------------------------------------------------------- /tests/globals.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "defaults.h" 5 | #include "structs.h" 6 | #include "config.h" 7 | #include "debug.h" 8 | 9 | struct config conf; 10 | 11 | struct config *get_multipath_config(void) 12 | { 13 | return &conf; 14 | } 15 | 16 | void put_multipath_config(void *arg) 17 | {} 18 | 19 | static __attribute__((unused)) void init_test_verbosity(int test_verbosity) 20 | { 21 | char *verb = getenv("MPATHTEST_VERBOSITY"); 22 | 23 | libmp_verbosity = test_verbosity >= 0 ? test_verbosity : 24 | DEFAULT_VERBOSITY; 25 | if (verb && *verb) { 26 | char *c; 27 | int vb; 28 | 29 | vb = strtoul(verb, &c, 10); 30 | if (!*c && vb >= 0 && vb <= 5) 31 | libmp_verbosity = vb; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /tests/test-lib.h: -------------------------------------------------------------------------------- 1 | #ifndef TEST_LIB_H_INCLUDED 2 | #define TEST_LIB_H_INCLUDED 3 | 4 | extern const int default_mask; 5 | extern const char default_devnode[]; 6 | extern const char default_wwid[]; 7 | extern const char default_wwid_1[]; 8 | 9 | enum { 10 | BL_BY_DEVNODE = (1 << 0), 11 | BL_BY_DEVICE = (1 << 1), 12 | BL_BY_WWID = (1 << 2), 13 | BL_BY_PROPERTY = (1 << 3), 14 | BL_MASK = BL_BY_DEVNODE|BL_BY_DEVICE|BL_BY_WWID|BL_BY_PROPERTY, 15 | NEED_SELECT_PRIO = (1 << 8), 16 | NEED_FD = (1 << 9), 17 | USE_VPD_VND = (1 << 10), 18 | DEV_HIDDEN = (1 << 11), 19 | }; 20 | 21 | struct mocked_path { 22 | const char *vendor; 23 | const char *product; 24 | const char *rev; 25 | const char *wwid; 26 | const char *devnode; 27 | unsigned int flags; 28 | }; 29 | 30 | struct mocked_path *fill_mocked_path(struct mocked_path *mp, 31 | const char *vendor, 32 | const char *product, 33 | const char *rev, 34 | const char *wwid, 35 | const char *devnode, 36 | unsigned int flags); 37 | 38 | struct mocked_path *mocked_path_from_path(struct mocked_path *mp, 39 | const struct path *pp); 40 | 41 | void mock_pathinfo(int mask, const struct mocked_path *mp); 42 | void mock_store_pathinfo(int mask, const struct mocked_path *mp); 43 | struct path *mock_path__(vector pathvec, 44 | const char *vnd, const char *prd, 45 | const char *rev, const char *wwid, 46 | const char *dev, 47 | unsigned int flags, int mask); 48 | 49 | #define mock_path(v, p) \ 50 | mock_path__(hwt->vecs->pathvec, (v), (p), "0", NULL, NULL, \ 51 | 0, default_mask) 52 | #define mock_path_flags(v, p, f) \ 53 | mock_path__(hwt->vecs->pathvec, (v), (p), "0", NULL, NULL, \ 54 | (f), default_mask) 55 | #define mock_path_blacklisted(v, p) \ 56 | mock_path__(hwt->vecs->pathvec, (v), (p), "0", NULL, NULL, \ 57 | BL_BY_DEVICE, default_mask) 58 | #define mock_path_wwid(v, p, w) \ 59 | mock_path__(hwt->vecs->pathvec, (v), (p), "0", (w), NULL, \ 60 | 0, default_mask) 61 | #define mock_path_wwid_flags(v, p, w, f) \ 62 | mock_path__(hwt->vecs->pathvec, (v), (p), "0", (w), \ 63 | NULL, (f), default_mask) 64 | 65 | struct multipath *mock_multipath__(struct vectors *vecs, struct path *pp); 66 | #define mock_multipath(pp) mock_multipath__(hwt->vecs, (pp)) 67 | 68 | #endif 69 | -------------------------------------------------------------------------------- /tests/test-log.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "log.h" 8 | #include "test-log.h" 9 | #include "debug.h" 10 | 11 | 12 | __attribute__((format(printf, 2, 0))) 13 | void __wrap_dlog (int prio, const char * fmt, ...) 14 | { 15 | char buff[MAX_MSG_SIZE]; 16 | va_list ap; 17 | char *expected; 18 | 19 | va_start(ap, fmt); 20 | vsnprintf(buff, MAX_MSG_SIZE, fmt, ap); 21 | va_end(ap); 22 | fprintf(stderr, "%s(%d): %s", __func__, prio, buff); 23 | expected = mock_ptr_type(char *); 24 | if (memcmp(expected, buff, strlen(expected))) 25 | fprintf(stderr, "%s(expected): %s", __func__, expected); 26 | check_expected(prio); 27 | assert_memory_equal(buff, expected, strlen(expected)); 28 | } 29 | 30 | void expect_condlog(int prio, char *string) 31 | { 32 | if (prio > MAX_VERBOSITY || prio > libmp_verbosity) 33 | return; 34 | expect_value(__wrap_dlog, prio, prio); 35 | will_return(__wrap_dlog, string); 36 | } 37 | -------------------------------------------------------------------------------- /tests/test-log.h: -------------------------------------------------------------------------------- 1 | #ifndef TEST_LOG_H_INCLUDED 2 | #define TEST_LOG_H_INCLUDED 3 | 4 | __attribute__((format(printf, 2, 0))) 5 | void __wrap_dlog (int prio, const char * fmt, ...); 6 | void expect_condlog(int prio, char *string); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /tests/unaligned.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "unaligned.h" 11 | 12 | #define SIZE 16 13 | static const char memory[8] = { 14 | 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef 15 | }; 16 | 17 | static const uint64_t intval64 = 0x0123456789abcdef; 18 | static const uint32_t intval32 = 0x01234567; 19 | static const uint16_t intval16 = 0x0123; 20 | 21 | #include "globals.c" 22 | 23 | static int setup(void **state) 24 | { 25 | return posix_memalign(state, 16, 2 * SIZE); 26 | } 27 | 28 | static int teardown(void **state) 29 | { 30 | free(*state); 31 | return 0; 32 | } 33 | 34 | 35 | #define make_test(bits, offset) \ 36 | static void test_ ## bits ## _ ## offset(void **state) \ 37 | { \ 38 | int len = bits/8; \ 39 | uint8_t *c = *state; \ 40 | uint8_t *p = *state + SIZE; \ 41 | uint64_t u; \ 42 | \ 43 | assert_in_range(len, 1, SIZE); \ 44 | assert_in_range(offset + len, 1, SIZE); \ 45 | memset(c, 0, 2 * SIZE); \ 46 | memcpy(c + offset, memory, len); \ 47 | \ 48 | u = get_unaligned_be##bits(c + offset); \ 49 | assert_int_equal(u, intval##bits); \ 50 | put_unaligned_be##bits(u, p + offset); \ 51 | assert_memory_equal(c + offset, p + offset, len); \ 52 | } 53 | 54 | make_test(16, 0); 55 | make_test(16, 1); 56 | make_test(32, 0); 57 | make_test(32, 1); 58 | make_test(32, 2); 59 | make_test(32, 3); 60 | make_test(64, 0); 61 | make_test(64, 1); 62 | make_test(64, 2); 63 | make_test(64, 3); 64 | make_test(64, 4); 65 | make_test(64, 5); 66 | make_test(64, 6); 67 | make_test(64, 7); 68 | 69 | int test_unaligned(void) 70 | { 71 | const struct CMUnitTest tests[] = { 72 | cmocka_unit_test(test_16_0), 73 | cmocka_unit_test(test_16_1), 74 | cmocka_unit_test(test_32_0), 75 | cmocka_unit_test(test_32_1), 76 | cmocka_unit_test(test_32_2), 77 | cmocka_unit_test(test_32_3), 78 | cmocka_unit_test(test_64_0), 79 | cmocka_unit_test(test_64_1), 80 | cmocka_unit_test(test_64_2), 81 | cmocka_unit_test(test_64_3), 82 | cmocka_unit_test(test_64_4), 83 | cmocka_unit_test(test_64_5), 84 | cmocka_unit_test(test_64_6), 85 | cmocka_unit_test(test_64_7), 86 | }; 87 | return cmocka_run_group_tests(tests, setup, teardown); 88 | } 89 | 90 | int main(void) 91 | { 92 | int ret = 0; 93 | 94 | init_test_verbosity(-1); 95 | ret += test_unaligned(); 96 | return ret; 97 | } 98 | -------------------------------------------------------------------------------- /third-party/valgrind/mpath-tools.supp: -------------------------------------------------------------------------------- 1 | { 2 | glibc _dlerror_run leak: https://stackoverflow.com/questions/1542457/memory-leak-reported-by-valgrind-in-dlopen 3 | Memcheck:Leak 4 | match-leak-kinds: reachable 5 | fun:calloc 6 | fun:_dlerror_run 7 | fun:dlopen* 8 | } 9 | 10 | { 11 | systemd mempools are never freed: https://bugzilla.redhat.com/show_bug.cgi?id=1215670 12 | Memcheck:Leak 13 | match-leak-kinds: reachable 14 | fun:malloc 15 | fun:mempool_alloc_tile 16 | fun:mempool_alloc0_tile 17 | fun:hashmap_base_new 18 | fun:hashmap_base_ensure_allocated 19 | } 20 | 21 | { 22 | libgcrypt library initialization 23 | Memcheck:Leak 24 | match-leak-kinds: reachable 25 | fun:malloc 26 | ... 27 | fun:_gcry_xmalloc 28 | ... 29 | fun:global_init.* 30 | ... 31 | fun:_dl_init 32 | } 33 | --------------------------------------------------------------------------------