获取CentOS LVM源码

$ which lvmetad
/usr/sbin/lvmetad
$ rpm -qf /usr/sbin/lvmetad
lvm2-2.02.130-5.el7_2.5.x86_64$ which lvmpolld
/usr/sbin/lvmpolld
$ rpm -qf /usr/sbin/lvmpolld
lvm2-2.02.130-5.el7_2.5.x86_64$ cd ~/rpmbuild
$ yumdownloader --source lvm2
$ rpm -ivh lvm2-2.02.130-5.el7_2.5.src.rpm$ rpmbuild -bp SPECS/lvm2.spec
$ mkdir -pv /opt/lvm2
$ cp BUILD/LVM2.2.02.130/ /opt/lvm2/ -rv$ rpmbuild -ba SPECS/lvm2.spec
$ ls RPMS/x86_64/lvm* -l | awk '{print $9}'
RPMS/x86_64/lvm2-2.02.130-5.el7.centos.5.x86_64.rpm
RPMS/x86_64/lvm2-cluster-2.02.130-5.el7.centos.5.x86_64.rpm
RPMS/x86_64/lvm2-cluster-standalone-2.02.130-5.el7.centos.5.x86_64.rpm
RPMS/x86_64/lvm2-debuginfo-2.02.130-5.el7.centos.5.x86_64.rpm
RPMS/x86_64/lvm2-devel-2.02.130-5.el7.centos.5.x86_64.rpm
RPMS/x86_64/lvm2-libs-2.02.130-5.el7.centos.5.x86_64.rpm
RPMS/x86_64/lvm2-lockd-2.02.130-5.el7.centos.5.x86_64.rpm
RPMS/x86_64/lvm2-python-libs-2.02.130-5.el7.centos.5.x86_64.rpm
RPMS/x86_64/lvm2-sysvinit-2.02.130-5.el7.centos.5.x86_64.rpm

获取LVM官方源码

$ mkdir -pv /opt/lvm2
$ cd /opt/lvm2
$ git clone git://git.fedorahosted.org/git/lvm2.git src
$ mkdir -v build target$ yum install dlm-devel pkgconfig systemd-units device-mapper-persistent-data \
corosynclib-devel libblkid-devel
$ cd build
$ ../src/configure --prefix=/opt/lvm2/target/ --enable-applib --enable-cmdlib \
--enable-lvmetad --enable-lvmpolld --enable-cmirrord --enable-debug --enable-lockd-dlm \
--enable-pkgconfig --enable-write_install --enable-dmeventd --enable-nls$ make
$ make install$ export LD_LIBRARY_PATH=/opt/lvm2/target/lib/:$LD_LIBRARY_PATH
$ export PATH=/opt/lvm2/target/sbin:$PATH
$ ./tools/lvm help

查看目标文件

$ cd ../target
$ tree .
.
├── include
│   ├── libdevmapper.h
│   ├── lvm2app.h
│   └── lvm2cmd.h
├── lib
│   ├── device-mapper
│   │   ├── libdevmapper-event-lvm2mirror.so
│   │   ├── libdevmapper-event-lvm2raid.so
│   │   ├── libdevmapper-event-lvm2snapshot.so
│   │   └── libdevmapper-event-lvm2thin.so  │   ├── libdevmapper.so.1.02
│   ├── libdevmapper-event-lvm2.so.2.02
│   ├── libdevmapper-event.so.1.02
│   ├── libdevmapper.so.1.02
│   ├── liblvm2app.so.2.2
│   ├── liblvm2cmd.so.2.02
│   └── ...
├── sbin
│   ├── blkdeactivate   # 去激活块设备
│   ├── cmirrord        # 记录日志
│   ├── dmeventd        # 接收DM事件(比如说精简卷已满的事件)
│   ├── dmsetup         # 配置DM设备用户工具
│   ├── fsadm           # 调整文件系统大小
│   ├── lvm             # LVM命令的最终执行程序
│   ├── lvmconf         # 修改LVM配置
│   ├── lvmdump         # 导出当前LVM信息
│   ├── lvmetad         # 元数据缓存守护进程
│   ├── lvmlockctl      # 操作lvmlockctl的命令
│   ├── lvmlockd        # LVM锁守护进程,可以使用sanlock或者dlm
│   ├── lvmpolld        # LVM命令后台执行进程
│   └── ...
└── share└── man└── man8...
8 directories, 118 files

可见LVM不仅提供LVM命令,还提供与DM驱动进行通信和LVM的编程接口。

查看命令的库依赖

$ find sbin -type f | xargs ldd
sbin/lvmlockd:linux-vdso.so.1 =>  (0x00007fff3b197000)libdl.so.2 => /lib64/libdl.so.2 (0x00007f83e7977000)libdevmapper.so.1.02 => /opt/lvm2/target/lib/libdevmapper.so.1.02 (0x00007f83e7707000)librt.so.1 => /lib64/librt.so.1 (0x00007f83e74ff000)libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f83e72e3000)libdlm_lt.so.3 => /lib64/libdlm_lt.so.3 (0x00007f83e70dd000)libc.so.6 => /lib64/libc.so.6 (0x00007f83e6d1b000)/lib64/ld-linux-x86-64.so.2 (0x00007f83e7bae000)libselinux.so.1 => /lib64/libselinux.so.1 (0x00007f83e6af6000)libsepol.so.1 => /lib64/libsepol.so.1 (0x00007f83e68b0000)libm.so.6 => /lib64/libm.so.6 (0x00007f83e65ae000)libpcre.so.1 => /lib64/libpcre.so.1 (0x00007f83e634d000)liblzma.so.5 => /lib64/liblzma.so.5 (0x00007f83e6127000)
sbin/lvmconf:不是动态可执行文件
sbin/lvmetad:linux-vdso.so.1 =>  (0x00007fff5af8c000)libdl.so.2 => /lib64/libdl.so.2 (0x00007f84a23e9000)libdevmapper.so.1.02 => /opt/lvm2/target/lib/libdevmapper.so.1.02 (0x00007f84a2179000)librt.so.1 => /lib64/librt.so.1 (0x00007f84a1f71000)libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f84a1d55000)libc.so.6 => /lib64/libc.so.6 (0x00007f84a1992000)/lib64/ld-linux-x86-64.so.2 (0x00007f84a2834000)libselinux.so.1 => /lib64/libselinux.so.1 (0x00007f84a176d000)libsepol.so.1 => /lib64/libsepol.so.1 (0x00007f84a1528000)libm.so.6 => /lib64/libm.so.6 (0x00007f84a1225000)libpcre.so.1 => /lib64/libpcre.so.1 (0x00007f84a0fc4000)liblzma.so.5 => /lib64/liblzma.so.5 (0x00007f84a0d9f000)sbin/lvm:linux-vdso.so.1 =>  (0x00007ffe85933000)libdl.so.2 => /lib64/libdl.so.2 (0x00007ff248621000)libdevmapper-event.so.1.02 => /opt/lvm2/target/lib/libdevmapper-event.so.1.02 (0x00007ff248418000)libdevmapper.so.1.02 => /opt/lvm2/target/lib/libdevmapper.so.1.02 (0x00007ff2481a9000)libreadline.so.6 => /lib64/libreadline.so.6 (0x00007ff247f63000)librt.so.1 => /lib64/librt.so.1 (0x00007ff247d5a000)libc.so.6 => /lib64/libc.so.6 (0x00007ff247998000)/lib64/ld-linux-x86-64.so.2 (0x00007ff248c54000)libselinux.so.1 => /lib64/libselinux.so.1 (0x00007ff247773000)libsepol.so.1 => /lib64/libsepol.so.1 (0x00007ff24752d000)libpthread.so.0 => /lib64/libpthread.so.0 (0x00007ff247311000)libm.so.6 => /lib64/libm.so.6 (0x00007ff24700f000)libtinfo.so.5 => /lib64/libtinfo.so.5 (0x00007ff246de4000)libpcre.so.1 => /lib64/libpcre.so.1 (0x00007ff246b83000)liblzma.so.5 => /lib64/liblzma.so.5 (0x00007ff24695e000)
sbin/lvmlockctl:linux-vdso.so.1 =>  (0x00007ffeca352000)libdl.so.2 => /lib64/libdl.so.2 (0x00007f7b56c09000)libdevmapper.so.1.02 => /opt/lvm2/target/lib/libdevmapper.so.1.02 (0x00007f7b56999000)libc.so.6 => /lib64/libc.so.6 (0x00007f7b565d7000)/lib64/ld-linux-x86-64.so.2 (0x00007f7b56e40000)librt.so.1 => /lib64/librt.so.1 (0x00007f7b563cf000)libselinux.so.1 => /lib64/libselinux.so.1 (0x00007f7b561a9000)libsepol.so.1 => /lib64/libsepol.so.1 (0x00007f7b55f64000)libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f7b55d48000)libm.so.6 => /lib64/libm.so.6 (0x00007f7b55a45000)libpcre.so.1 => /lib64/libpcre.so.1 (0x00007f7b557e4000)liblzma.so.5 => /lib64/liblzma.so.5 (0x00007f7b555bf000)
sbin/blkdeactivate:不是动态可执行文件
sbin/lvmpolld:linux-vdso.so.1 =>  (0x00007ffc0df4d000)libdl.so.2 => /lib64/libdl.so.2 (0x00007f36a272f000)libdevmapper.so.1.02 => /opt/lvm2/target/lib/libdevmapper.so.1.02 (0x00007f36a24bf000)librt.so.1 => /lib64/librt.so.1 (0x00007f36a22b7000)libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f36a209b000)libc.so.6 => /lib64/libc.so.6 (0x00007f36a1cd8000)/lib64/ld-linux-x86-64.so.2 (0x00007f36a2966000)libselinux.so.1 => /lib64/libselinux.so.1 (0x00007f36a1ab3000)libsepol.so.1 => /lib64/libsepol.so.1 (0x00007f36a186e000)libm.so.6 => /lib64/libm.so.6 (0x00007f36a156b000)libpcre.so.1 => /lib64/libpcre.so.1 (0x00007f36a130a000)liblzma.so.5 => /lib64/liblzma.so.5 (0x00007f36a10e5000)
sbin/fsadm:不是动态可执行文件
sbin/dmsetup:linux-vdso.so.1 =>  (0x00007ffd7b9d4000)libdevmapper.so.1.02 => /opt/lvm2/target/lib/libdevmapper.so.1.02 (0x00007efe39d14000)librt.so.1 => /lib64/librt.so.1 (0x00007efe39ad9000)libc.so.6 => /lib64/libc.so.6 (0x00007efe39717000)libselinux.so.1 => /lib64/libselinux.so.1 (0x00007efe394f2000)libsepol.so.1 => /lib64/libsepol.so.1 (0x00007efe392ac000)libpthread.so.0 => /lib64/libpthread.so.0 (0x00007efe39090000)libm.so.6 => /lib64/libm.so.6 (0x00007efe38d8e000)/lib64/ld-linux-x86-64.so.2 (0x00007efe3a1ad000)libpcre.so.1 => /lib64/libpcre.so.1 (0x00007efe38b2c000)liblzma.so.5 => /lib64/liblzma.so.5 (0x00007efe38907000)libdl.so.2 => /lib64/libdl.so.2 (0x00007efe38703000)
sbin/lvmdump:不是动态可执行文件
sbin/dmeventd:linux-vdso.so.1 =>  (0x00007ffd2c59b000)libdl.so.2 => /lib64/libdl.so.2 (0x00007fecfe2a3000)libdevmapper-event.so.1.02 => /opt/lvm2/target/lib/libdevmapper-event.so.1.02 (0x00007fecfe09a000)libpthread.so.0 => /lib64/libpthread.so.0 (0x00007fecfde7e000)librt.so.1 => /lib64/librt.so.1 (0x00007fecfdc76000)libdevmapper.so.1.02 => /opt/lvm2/target/lib/libdevmapper.so.1.02 (0x00007fecfda06000)libc.so.6 => /lib64/libc.so.6 (0x00007fecfd644000)/lib64/ld-linux-x86-64.so.2 (0x00007fecfe6e8000)libselinux.so.1 => /lib64/libselinux.so.1 (0x00007fecfd41f000)libsepol.so.1 => /lib64/libsepol.so.1 (0x00007fecfd1d9000)libm.so.6 => /lib64/libm.so.6 (0x00007fecfced7000)libpcre.so.1 => /lib64/libpcre.so.1 (0x00007fecfcc76000)liblzma.so.5 => /lib64/liblzma.so.5 (0x00007fecfca50000)
sbin/cmirrord:linux-vdso.so.1 =>  (0x00007ffe1adf1000)libcpg.so.4 => /lib64/libcpg.so.4 (0x00007f3d3bdd0000)librt.so.1 => /lib64/librt.so.1 (0x00007f3d3bbc7000)libdevmapper.so.1.02 => /opt/lvm2/target/lib/libdevmapper.so.1.02 (0x00007f3d3b958000)libc.so.6 => /lib64/libc.so.6 (0x00007f3d3b596000)libcorosync_common.so.4 => /lib64/libcorosync_common.so.4 (0x00007f3d3b392000)libqb.so.0 => /lib64/libqb.so.0 (0x00007f3d3b12d000)libdl.so.2 => /lib64/libdl.so.2 (0x00007f3d3af29000)libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f3d3ad0c000)/lib64/ld-linux-x86-64.so.2 (0x00007f3d3c22f000)libselinux.so.1 => /lib64/libselinux.so.1 (0x00007f3d3aae7000)libsepol.so.1 => /lib64/libsepol.so.1 (0x00007f3d3a8a2000)libm.so.6 => /lib64/libm.so.6 (0x00007f3d3a59f000)libpcre.so.1 => /lib64/libpcre.so.1 (0x00007f3d3a33e000)liblzma.so.5 => /lib64/liblzma.so.5 (0x00007f3d3a119000)

他们全部依赖libdevmapper库来与DM驱动进行通信。

查看CentOS LVM的服务

$ systemctl list-units | grep lvm
lvm2-lvmetad.service                                            loaded active running   LVM2 metadata daemon
lvm2-monitor.service                                            loaded active exited    Monitoring of LVM2 mirrors, snapshots etc. using  dmeventd or progress polling
lvm2-pvscan@253:0.service                                       loaded active exited    LVM2 PV scan on device 253:0
system-lvm2\x2dpvscan.slice                                     loaded active active    system-lvm2\x2dpvscan.slice
lvm2-lvmetad.socket                                              loaded active running   LVM2 metadata daemon socket
lvm2-lvmpolld.socket                                            loaded active listening LVM2 poll daemon socket$ ls /usr/lib/systemd/system/*lvm*
/usr/lib/systemd/system/lvm2-lvmetad.service
/usr/lib/systemd/system/lvm2-lvmpolld.service
/usr/lib/systemd/system/lvm2-monitor.service
/usr/lib/systemd/system/lvm2-lvmetad.socket
/usr/lib/systemd/system/lvm2-lvmpolld.socket
/usr/lib/systemd/system/lvm2-pvscan@.service$ find /usr/lib/systemd/system -name *lvm* -exec cat {} \;
[Unit]
Description=Monitoring of LVM2 mirrors, snapshots etc. using dmeventd or progress polling
Documentation=man:dmeventd(8) man:lvcreate(8) man:lvchange(8) man:vgchange(8)
Requires=dm-event.socket lvm2-lvmetad.socket
After=dm-event.socket dm-event.service lvm2-lvmetad.socket lvm2-activation.service lvm2-lvmetad.service
Before=local-fs.target
DefaultDependencies=no
Conflicts=shutdown.target[Service]
Type=oneshot
Environment=LVM_SUPPRESS_LOCKING_FAILURE_MESSAGES=1
ExecStart=/usr/sbin/lvm vgchange --monitor y --ignoreskippedcluster
ExecStop=/usr/sbin/lvm vgchange --monitor n --ignoreskippedcluster
RemainAfterExit=yes[Install]
WantedBy=sysinit.target[Unit]
Description=LVM2 poll daemon socket
Documentation=man:lvmpolld(8)
DefaultDependencies=no[Socket]
ListenStream=/run/lvm/lvmpolld.socket
SocketMode=0600
RemoveOnStop=true[Install]
WantedBy=sysinit.target[Unit]
Description=LVM2 PV scan on device %i
Documentation=man:pvscan(8)
DefaultDependencies=no
BindsTo=dev-block-%i.device
Requires=lvm2-lvmetad.socket
After=lvm2-lvmetad.socket lvm2-lvmetad.service
Before=shutdown.target
Conflicts=shutdown.target[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/sbin/lvm pvscan --cache --activate ay %i
ExecStop=/usr/sbin/lvm pvscan --cache %i[Unit]
Description=LVM2 poll daemon
Documentation=man:lvmpolld(8)
Requires=lvm2-lvmpolld.socket
After=lvm2-lvmpolld.socket
DefaultDependencies=no
Conflicts=shutdown.target[Service]
Type=simple
NonBlocking=true
ExecStart=/usr/sbin/lvmpolld -t 60 -f
Environment=SD_ACTIVATION=1
PIDFile=/run/lvmpolld.pid[Install]
WantedBy=sysinit.target[Unit]
Description=LVM2 metadata daemon
Documentation=man:lvmetad(8)
Requires=lvm2-lvmetad.socket
After=lvm2-lvmetad.socket
DefaultDependencies=no
Conflicts=shutdown.target[Service]
Type=simple
NonBlocking=true
ExecStart=/usr/sbin/lvmetad -f
Environment=SD_ACTIVATION=1
Restart=on-abort
PIDFile=/run/lvmetad.pid[Install]
WantedBy=sysinit.target[Unit]
Description=LVM2 metadata daemon socket
Documentation=man:lvmetad(8)
DefaultDependencies=no[Socket]
ListenStream=/run/lvm/lvmetad.socket
SocketMode=0600
RemoveOnStop=true[Install]
WantedBy=sysinit.target

这些服务主要使用了如下命令:vgchange、lvmpolld、pvscan、lvmetad。

简要分析lvscan命令

tools/lvscan.c

 #include "tools.h"// 使用lvmetad处理单个LV信息。static int _lvscan_single_lvmetad(struct cmd_context *cmd, struct logical_volume *lv){struct pv_list *pvl;struct dm_list all_pvs;char pvid_s[64] __attribute__((aligned(8)));if (!lvmetad_used())return ECMD_PROCESSED;dm_list_init(&all_pvs);if (!get_pv_list_for_lv(lv->vg->vgmem, lv, &all_pvs))return ECMD_FAILED;dm_list_iterate_items(pvl, &all_pvs) {if (!pvl->pv->dev) {if (!id_write_format(&pvl->pv->id, pvid_s, sizeof(pvid_s)))stack;elselog_warn("WARNING: Device for PV %s already missing, skipping.",pvid_s);continue;}if (!lvmetad_pvscan_single(cmd, pvl->pv->dev, NULL, NULL))return ECMD_FAILED;}return ECMD_PROCESSED;}// 不使用lvmetad处理单个LV信息。static int lvscan_single(struct cmd_context *cmd, struct logical_volume *lv,struct processing_handle *handle __attribute__((unused))){struct lvinfo info;int inkernel, snap_active = 1;dm_percent_t snap_percent;     /* fused, fsize; */const char *active_str, *snapshot_str;if (arg_is_set(cmd, cache_long_ARG))return _lvscan_single_lvmetad(cmd, lv);if (!arg_is_set(cmd, all_ARG) && !lv_is_visible(lv))return ECMD_PROCESSED;// 获取LV信息inkernel = lv_info(cmd, lv, 0, &info, 0, 0) && info.exists;if (lv_is_cow(lv)) {if (inkernel &&(snap_active = lv_snapshot_percent(lv, &snap_percent)))if (snap_percent == DM_PERCENT_INVALID)snap_active = 0;}// 打印LV信息/* FIXME Add -D arg to skip this! */if (inkernel && snap_active)active_str = "ACTIVE   ";elseactive_str = "inactive ";if (lv_is_origin(lv))snapshot_str = "Original";else if (lv_is_cow(lv))snapshot_str = "Snapshot";elsesnapshot_str = "        ";log_print_unless_silent("%s%s '%s%s/%s' [%s] %s", active_str, snapshot_str,cmd->dev_dir, lv->vg->name, lv->name,display_size(cmd, lv->size),get_alloc_string(lv->alloc));return ECMD_PROCESSED;}int lvscan(struct cmd_context *cmd, int argc, char **argv){const char *reason = NULL;if (argc && !arg_is_set(cmd, cache_long_ARG)) {log_error("No additional command line arguments allowed");return EINVALID_CMD_LINE;}if (!lvmetad_used() && arg_is_set(cmd, cache_long_ARG))log_verbose("Ignoring lvscan --cache because lvmetad is not in use.");/* Needed because this command has NO_LVMETAD_AUTOSCAN. */if (lvmetad_used() && (!lvmetad_token_matches(cmd) || lvmetad_is_disabled(cmd, &reason))) {if (lvmetad_used() && !lvmetad_pvscan_all_devs(cmd, 0)) {log_warn("WARNING: Not using lvmetad because cache update failed.");lvmetad_make_unused(cmd);}if (lvmetad_used() && lvmetad_is_disabled(cmd, &reason)) {log_warn("WARNING: Not using lvmetad because %s.", reason);lvmetad_make_unused(cmd);}/** FIXME: doing lvscan --cache after a full scan is pointless.* Should the cache case just exit here?*/}return process_each_lv(cmd, argc, argv, NULL, NULL, 0, NULL, &lvscan_single);}

tools/command.h

    xx(lvscan,"List all logical volumes in all volume groups",PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | NO_LVMETAD_AUTOSCAN,"lvscan\n""\t[-a|--all]\n""\t[-b|--blockdevice]\n""\t[--cache]\n""\t[--commandprofile ProfileName]\n""\t[-d|--debug]\n""\t[-h|-?|--help]\n""\t[--ignorelockingfailure]\n""\t[-P|--partial]\n""\t[--readonly]\n""\t[--reportformat {basic|json}]\n""\t[-v|--verbose]\n""\t[--version]\n",all_ARG, blockdevice_ARG, ignorelockingfailure_ARG, partial_ARG,readonly_ARG, reportformat_ARG, cache_long_ARG)

tools/lvmcmdline.c

 void lvm_register_commands(void){#define xx(a, b, c, d...) _register_command(# a, a, b, c, ## d, \driverloaded_ARG, \debug_ARG, help_ARG, help2_ARG, \version_ARG, verbose_ARG, \yes_ARG, \quiet_ARG, config_ARG, \commandprofile_ARG, \profile_ARG, -1);#include "commands.h"#undef xx}

tools/cmdnames.h

#define xx(a, b, c...) a#include "commands.h"

tools/Makefile.in

install_tools_dynamic: lvm .commands$(INSTALL_PROGRAM) -D lvm $(sbindir)/lvm@echo Creating symbolic links for individual commands in $(sbindir)@for v in `cat .commands`; do \echo "$(LN_S) -f lvm $(sbindir)/$$v"; \$(LN_S) -f lvm $(sbindir)/$$v; \done;.commands: $(srcdir)/commands.h $(srcdir)/cmdnames.h Makefile$(CC) -E -P $(srcdir)/cmdnames.h 2> /dev/null | \egrep -v '^ *(|#.*|config|devtypes|dumpconfig|formats|fullreport|help\|lastlog|lvpoll|pvdata|segtypes|systemid|tags|version) *$$' > .commands

跟踪process_each_lv函数

根据命令行参数,遍历所有LV (tools/toollib.c : process_single_lv)

 /** Call process_single_lv() for each LV selected by the command line arguments.*/int process_each_lv(struct cmd_context *cmd,int argc, char **argv,const char *one_vgname, const char *one_lvname,uint32_t read_flags,struct processing_handle *handle,process_single_lv_fn_t process_single_lv){log_report_t saved_log_report_state = log_get_report_state();int handle_supplied = handle != NULL;struct dm_list arg_tags;     /* str_list */struct dm_list arg_vgnames;       /* str_list */struct dm_list arg_lvnames;       /* str_list */struct dm_list vgnameids_on_system;   /* vgnameid_list */struct dm_list vgnameids_to_process; /* vgnameid_list */int enable_all_vgs = (cmd->command->flags & ALL_VGS_IS_DEFAULT);int process_all_vgs_on_system = 0;int ret_max = ECMD_PROCESSED;int ret;log_set_report_object_type(LOG_REPORT_OBJECT_TYPE_LV);/* Disable error in vg_read so we can print it from ignore_vg. */cmd->vg_read_print_access_error = 0;dm_list_init(&arg_tags);dm_list_init(&arg_vgnames);dm_list_init(&arg_lvnames);dm_list_init(&vgnameids_on_system);dm_list_init(&vgnameids_to_process);// 根据命令行参数生成VG列表/** Find any LVs, VGs or tags explicitly provided on the command line.*/if ((ret = _get_arg_lvnames(cmd, argc, argv, one_vgname, one_lvname, &arg_vgnames, &arg_lvnames, &arg_tags) != ECMD_PROCESSED)){ret_max = ret;goto_out;}if (!handle && !(handle = init_processing_handle(cmd, NULL))) {ret_max = ECMD_FAILED;goto_out;}if (handle->internal_report_for_select && !handle->selection_handle &&!init_selection_handle(cmd, handle, LVS)) {ret_max = ECMD_FAILED;goto_out;}/** Process all VGs on the system when:* . tags are specified and all VGs need to be read to*   look for matching tags.* . no VG names are specified and the command defaults*   to processing all VGs when none are specified.* . no VG names are specified and the select option needs*   resolving.*/if (!dm_list_empty(&arg_tags))process_all_vgs_on_system = 1;else if (dm_list_empty(&arg_vgnames) && enable_all_vgs)process_all_vgs_on_system = 1;else if (dm_list_empty(&arg_vgnames) && handle->internal_report_for_select)process_all_vgs_on_system = 1;/** Needed for a current listing of the global VG namespace.*/if (process_all_vgs_on_system && !lockd_gl(cmd, "sh", 0)) {ret_max = ECMD_FAILED;goto_out;}/** A list of all VGs on the system is needed when:* . processing all VGs on the system* . A VG name is specified which may refer to one*   of multiple VGs on the system with that name.*/log_debug("Get list of VGs on system");// 从DM获取VG列表if (!get_vgnameids(cmd, &vgnameids_on_system, NULL, 0)) {ret_max = ECMD_FAILED;goto_out;}if (!dm_list_empty(&arg_vgnames)) {/* This may remove entries from arg_vgnames or vgnameids_on_system. */ret = _resolve_duplicate_vgnames(cmd, &arg_vgnames, &vgnameids_on_system);if (ret > ret_max)ret_max = ret;if (dm_list_empty(&arg_vgnames) && dm_list_empty(&arg_tags)) {ret_max = ECMD_FAILED;goto out;}}if (dm_list_empty(&arg_vgnames) && dm_list_empty(&vgnameids_on_system)) {/* FIXME Should be log_print, but suppressed for reporting cmds */log_verbose("No volume groups found.");ret_max = ECMD_PROCESSED;goto out;}if (dm_list_empty(&arg_vgnames))read_flags |= READ_OK_NOTFOUND;/** When processing all VGs, vgnameids_on_system simply becomes* vgnameids_to_process.* When processing only specified VGs, then for each item in* arg_vgnames, move the corresponding entry from* vgnameids_on_system to vgnameids_to_process.*/if (process_all_vgs_on_system)    // 把系统所有的VG列表添加进待处理的VG列表。dm_list_splice(&vgnameids_to_process, &vgnameids_on_system);else_choose_vgs_to_process(cmd, &arg_vgnames, &vgnameids_on_system, &vgnameids_to_process);// 遍历VG列表ret = _process_lv_vgnameid_list(cmd, read_flags, &vgnameids_to_process, &arg_vgnames, &arg_lvnames,&arg_tags, handle, process_single_lv);if (ret > ret_max)ret_max = ret;out:if (!handle_supplied)destroy_processing_handle(cmd, handle);log_restore_report_state(saved_log_report_state);return ret_max;}

获取系统中的VG列表 (lib/metadata/metadata.c)

   int get_vgnameids(struct cmd_context *cmd, struct dm_list *vgnameids,const char *only_this_vgname, int include_internal){struct vgnameid_list *vgnl;struct format_type *fmt;if (only_this_vgname) {if (!(vgnl = dm_pool_alloc(cmd->mem, sizeof(*vgnl)))) {log_error("vgnameid_list allocation failed.");return 0;}vgnl->vg_name = dm_pool_strdup(cmd->mem, only_this_vgname);vgnl->vgid = NULL;dm_list_add(vgnameids, &vgnl->list);return 1;}// 从lvmetad获取元数据if (lvmetad_used()) {/** This just gets the list of names/ids from lvmetad* and does not populate lvmcache.*/lvmetad_get_vgnameids(cmd, vgnameids);if (include_internal) {dm_list_iterate_items(fmt, &cmd->formats) {if (!(vgnl = dm_pool_alloc(cmd->mem, sizeof(*vgnl)))) {log_error("vgnameid_list allocation failed.");return 0;}vgnl->vg_name = dm_pool_strdup(cmd->mem, fmt->orphan_vg_name);vgnl->vgid = NULL;dm_list_add(vgnameids, &vgnl->list);}}} else {// 从缓存获取元数据/** The non-lvmetad case. This function begins by calling* lvmcache_label_scan() to populate lvmcache.*/lvmcache_get_vgnameids(cmd, include_internal, vgnameids);}return 1;}

从缓存获取元数据 (lib/cache/lvmcache.c)

    int lvmcache_get_vgnameids(struct cmd_context *cmd, int include_internal,struct dm_list *vgnameids){struct vgnameid_list *vgnl;struct lvmcache_vginfo *vginfo;lvmcache_label_scan(cmd);// 遍历元数据缓存dm_list_iterate_items(vginfo, &_vginfos) {if (!include_internal && is_orphan_vg(vginfo->vgname))continue;if (!(vgnl = dm_pool_alloc(cmd->mem, sizeof(*vgnl)))) {log_error("vgnameid_list allocation failed.");return 0;}vgnl->vgid = dm_pool_strdup(cmd->mem, vginfo->vgid);vgnl->vg_name = dm_pool_strdup(cmd->mem, vginfo->vgname);if (!vgnl->vgid || !vgnl->vg_name) {log_error("vgnameid_list member allocation failed.");return 0;}dm_list_add(vgnameids, &vgnl->list);}return 1;}

根据VG遍历每个LV (tools/toollib.c : _process_lv_vgnameid_list)

   static int _process_lv_vgnameid_list(struct cmd_context *cmd, uint32_t read_flags,struct dm_list *vgnameids_to_process,struct dm_list *arg_vgnames,struct dm_list *arg_lvnames,struct dm_list *arg_tags,struct processing_handle *handle,process_single_lv_fn_t process_single_lv){log_report_t saved_log_report_state = log_get_report_state();char uuid[64] __attribute__((aligned(8)));struct volume_group *vg;struct vgnameid_list *vgnl;struct dm_str_list *sl;struct dm_list *tags_arg;struct dm_list lvnames;uint32_t lockd_state = 0;const char *vg_name;const char *vg_uuid;const char *vgn;const char *lvn;int ret_max = ECMD_PROCESSED;int ret;int skip;int notfound;int already_locked;int do_report_ret_code = 1;log_set_report_object_type(LOG_REPORT_OBJECT_TYPE_VG);// 遍历每个VGdm_list_iterate_items(vgnl, vgnameids_to_process) {vg_name = vgnl->vg_name;vg_uuid = vgnl->vgid;skip = 0;notfound = 0;uuid[0] = '\0';if (vg_uuid && !id_write_format((const struct id*)vg_uuid, uuid, sizeof(uuid)))stack;log_set_report_object_name_and_id(vg_name, uuid);if (sigint_caught()) {ret_max = ECMD_FAILED;goto_out;}/** arg_lvnames contains some elements that are just "vgname"* which means process all lvs in the vg.  Other elements* are "vgname/lvname" which means process only the select* lvs in the vg.*/tags_arg = arg_tags;dm_list_init(&lvnames);    /* LVs to be processed in this VG */dm_list_iterate_items(sl, arg_lvnames) {vgn = sl->str;lvn = strchr(vgn, '/');if (!lvn && !strcmp(vgn, vg_name)) {/* Process all LVs in this VG */tags_arg = NULL;dm_list_init(&lvnames);break;}if (lvn && !strncmp(vgn, vg_name, strlen(vg_name)) &&strlen(vg_name) == (size_t) (lvn - vgn)) {if (!str_list_add(cmd->mem, &lvnames,dm_pool_strdup(cmd->mem, lvn + 1))) {log_error("strlist allocation failed.");ret_max = ECMD_FAILED;goto out;}}}log_very_verbose("Processing VG %s %s", vg_name, vg_uuid ? uuid : "");if (!lockd_vg(cmd, vg_name, NULL, 0, &lockd_state)) {ret_max = ECMD_FAILED;report_log_ret_code(ret_max);continue;}already_locked = lvmcache_vgname_is_locked(vg_name);// 读取VG的元数据vg = vg_read(cmd, vg_name, vg_uuid, read_flags, lockd_state);if (_ignore_vg(vg, vg_name, arg_vgnames, read_flags, &skip, &notfound)) {stack;ret_max = ECMD_FAILED;report_log_ret_code(ret_max);goto endvg;}if (skip || notfound)goto endvg;// 遍历并处理每个LVret = process_each_lv_in_vg(cmd, vg, &lvnames, tags_arg, 0,handle, process_single_lv);if (ret != ECMD_PROCESSED)stack;report_log_ret_code(ret);if (ret > ret_max)ret_max = ret;if (!already_locked)unlock_vg(cmd, vg, vg_name);endvg:release_vg(vg);if (!lockd_vg(cmd, vg_name, "un", 0, &lockd_state))stack;log_set_report_object_name_and_id(NULL, NULL);}do_report_ret_code = 0;out:if (do_report_ret_code)report_log_ret_code(ret_max);log_restore_report_state(saved_log_report_state);return ret_max;}

读取VG元数据 (lib/metadata/metadata.c)

  /** vg_read: High-level volume group metadata read function.** vg_read_error() must be used on any handle returned to check for errors.**  - metadata inconsistent and automatic correction failed: FAILED_INCONSISTENT*  - VG is read-only: FAILED_READ_ONLY*  - VG is EXPORTED, unless flags has READ_ALLOW_EXPORTED: FAILED_EXPORTED*  - VG is not RESIZEABLE: FAILED_RESIZEABLE*  - locking failed: FAILED_LOCKING** On failures, all locks are released, unless one of the following applies:*  - vgname_is_locked(lock_name) is true* FIXME: remove the above 2 conditions if possible and make an error always* release the lock.** Volume groups are opened read-only unless flags contains READ_FOR_UPDATE.** Checking for VG existence:** FIXME: We want vg_read to attempt automatic recovery after acquiring a* temporary write lock: if that fails, we bail out as usual, with failed &* FAILED_INCONSISTENT. If it works, we are good to go. Code that's been in* toollib just set lock_flags to LCK_VG_WRITE and called vg_read_internal with* *consistent = 1.*/struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name,const char *vgid, uint32_t read_flags, uint32_t lockd_state){uint64_t status_flags = UINT64_C(0);uint32_t lock_flags = LCK_VG_READ;if (read_flags & READ_FOR_UPDATE) {status_flags |= EXPORTED_VG | LVM_WRITE;lock_flags = LCK_VG_WRITE;}if (read_flags & READ_ALLOW_EXPORTED)status_flags &= ~EXPORTED_VG;// 解析PV和VG的元数据,并更新缓存。return _vg_lock_and_read(cmd, vg_name, vgid, lock_flags, status_flags, read_flags, lockd_state);}

_vg_lock_and_read最终会调用_vg_read进行相关的源数据解析 (lib/metadata/metadata.c)

关键数据结构

format_type (lib/metadata/metadata-export.h)

   struct format_type {struct dm_list list;struct cmd_context *cmd;struct format_handler *ops;struct dm_list mda_ops; /* List of permissible mda ops. */struct labeller *labeller;const char *name;const char *alias;const char *orphan_vg_name;struct volume_group *orphan_vg; /* Only one ever exists. */uint32_t features;void *library;void *private;};

format_handler (lib/metadata/metadata.h)

   /** Ownership of objects passes to caller.*/struct format_handler {/** Scan any metadata areas that aren't referenced in PV labels*/int (*scan) (const struct format_type * fmt, const char *vgname);/** Return PV with given path.*/int (*pv_read) (const struct format_type * fmt, const char *pv_name,struct physical_volume * pv, int scan_label_only);/** Initialise a new PV.*/int (*pv_initialise) (const struct format_type * fmt,struct pv_create_args *pva,struct physical_volume * pv);/** Tweak an already filled out a pv ready for importing into a* vg.  eg. pe_count is format specific.*/int (*pv_setup) (const struct format_type * fmt,struct physical_volume * pv,struct volume_group * vg);/** Add metadata area to a PV. Changes will take effect on pv_write.*/int (*pv_add_metadata_area) (const struct format_type * fmt,struct physical_volume * pv,int pe_start_locked,unsigned metadata_index,uint64_t metadata_size,unsigned metadata_ignored);/** Remove metadata area from a PV. Changes will take effect on pv_write.*/int (*pv_remove_metadata_area) (const struct format_type *fmt,struct physical_volume *pv,unsigned metadata_index);/** Recalculate the PV size taking into account any existing metadata areas.*/int (*pv_resize) (const struct format_type *fmt,struct physical_volume *pv,struct volume_group *vg,uint64_t size);/** Write a PV structure to disk. Fails if the PV is in a VG ie* pv->vg_name must be a valid orphan VG name*/int (*pv_write) (const struct format_type * fmt,struct physical_volume * pv);/** Check if PV needs rewriting. This is used to check whether there are any* format-specific changes  before actually writing the PV (by calling pv_write).* With this, we can call pv_write conditionally only if it's really needed.*/int (*pv_needs_rewrite) (const struct format_type *fmt,struct physical_volume *pv,int *needs_rewrite);/** Tweak an already filled out a lv eg, check there* aren't too many extents.*/int (*lv_setup) (struct format_instance * fi,struct logical_volume * lv);/** Tweak an already filled out vg.  eg, max_pv is format* specific.*/int (*vg_setup) (struct format_instance * fi, struct volume_group * vg);/** Check whether particular segment type is supported.*/int (*segtype_supported) (struct format_instance *fid,const struct segment_type *segtype);/** Create format instance with a particular metadata area*/struct format_instance *(*create_instance) (const struct format_type *fmt,const struct format_instance_ctx *fic);/** Destructor for format instance*/void (*destroy_instance) (struct format_instance * fid);/** Destructor for format type*/void (*destroy) (struct format_type * fmt);};

format_instance (lib/metadata/metadata-export.h)

   struct format_instance {unsigned ref_count; /* Refs to this fid from VG and PV structs */struct dm_pool *mem;uint32_t type;const struct format_type *fmt;/** Each mda in a vg is on exactly one of the below lists.* MDAs on the 'in_use' list will be read from / written to* disk, while MDAs on the 'ignored' list will not be read* or written to.*//* FIXME: Try to use the index only. Remove these lists. */struct dm_list metadata_areas_in_use;struct dm_list metadata_areas_ignored;struct dm_hash_table *metadata_areas_index;void *private;};

LVM源码分析1-概览相关推荐

  1. Retrofit源码分析一 概览

    Retrofit源码分析一 概览 Retrofit的本质和与Okhttp的关系 ​ 说到Retrofit,免不了要提起Okhttp,因为二者通常是绑定到一起使用的.那么我们首先要明确一点Retrofi ...

  2. android 日历源码解析,Android 4.0日历(calendar)源码分析之概览

    Calendar 从4.0开始,谷歌android系统有了脱碳换骨的改变,相应的日历应用的代码架构也跟2.*完全不同.代码更规范,当然也更复杂,且涉及到了android开发的方方面面. 如果你熟悉了i ...

  3. LVM源码分析2-libdaemon

    2019独角兽企业重金招聘Python工程师标准>>> LVM的libdaemon库实现了守护进程与命令工具之间使用UNIX本地套接字进行CS通信的基础模型. 报文 配置树结构 $ ...

  4. LVM源码分析3-lvextend

    2019独角兽企业重金招聘Python工程师标准>>> 命令参数定义: $ cat tools/command.h ...xx(lvextend,"Add space to ...

  5. Dubbo服务注册源码分析

    本代码版本基于Dubbo2.7.8版本进行源码分析 注册概览 扫描所有@DubboService注解, 加载配置文件, 装载注解中的所有属性, 把每个服务都封装成一个ServiceBean, 注入到S ...

  6. xf86-video-intel源码分析1 —— 源码目录结构概览

    在<Spectacle/Flameshot/X11 Xlib截屏问题现象及解决方法>一文(链接如下)中提到, Spectacle/Flameshot/X11 Xlib截屏问题现象及解决方法 ...

  7. 【Spring源码分析】Bean加载流程概览

    代码入口 之前写文章都会啰啰嗦嗦一大堆再开始,进入[Spring源码分析]这个板块就直接切入正题了. 很多朋友可能想看Spring源码,但是不知道应当如何入手去看,这个可以理解:Java开发者通常从事 ...

  8. beaninfo详解源码解析 java_【Spring源码分析】Bean加载流程概览

    代码入口 之前写文章都会啰啰嗦嗦一大堆再开始,进入[Spring源码分析]这个板块就直接切入正题了. 很多朋友可能想看Spring源码,但是不知道应当如何入手去看,这个可以理解:Java开发者通常从事 ...

  9. EOS智能合约:system系统合约源码分析

    链客,专为开发者而生,有问必答! 此文章来自区块链技术社区,未经允许拒绝转载. eosio.system 概览 笔者使用的IDE是VScode,首先来看eosio.system的源码结构.如下图所示. ...

最新文章

  1. Java中string字符串的值_Java中的字符串(String)
  2. play!框架_在Play上使用twitter4j! 框架和安全社交很容易
  3. 面对imbalance data的时候
  4. java数据类型double保留两位小数
  5. 托微软的福,谷歌把GitLab捧成了独角兽
  6. python 局域网服务器_Python一秒搭建ftp服务器,帮助你在局域网共享文件
  7. Atitit 2017年第68界机器视觉图像处理学术大会会议记要attilax总结自建学院自颁学位理论
  8. 黑莓9900 java应用,黑莓9900怎么用 黑莓9900使用技巧【图文详解】
  9. 虚拟机及CentOS7各个版本镜像下载地址
  10. 闭包及作用域销毁练习
  11. 利用栈来完成表达式求值
  12. 如何听懂画外音-《用事实说话》:听懂“暗语”,让沟通透明化
  13. ffmpeg视频裁剪,切割,crop裁剪相关
  14. 腾讯企业邮箱 java_java发送腾讯企业邮件-可用于发送邮箱验证码
  15. 记录一些遇见的bug——Lombok和Mapstruct的冲突导致,A component required a bean of type ‘com.XXX.controller.converter.
  16. 2018上海居住证续签
  17. 连玉君链接-Stata连享会
  18. python 爬取《延禧攻略》所有的演员参演的电视剧
  19. Inline Hook 钩子编写技巧
  20. 数据仓库项目需求分析

热门文章

  1. 【杂文随笔】2020年总结 送自己一个字
  2. [Network Analysis] 复杂网络分析总结
  3. 解决电脑打不开问题,滴滴滴的响
  4. 我国量子态隐形传输获突破 超越时空或成真
  5. 喝什么茶保肝又护肾?
  6. Cesium无需KEY调用Bing地图
  7. asp.net923-学生健康档案管理系统
  8. 决策树与随机森林(DecisionTree_RandomForest)
  9. Linux下 XordDos(BillGates)木马查杀记录
  10. ES6代理器Proxy简介