Merge lp:~xnox/ubuntu/quantal/lvm2/merge95 into lp:ubuntu/quantal/lvm2

Proposed by Dimitri John Ledkov
Status: Merged
Merge reported by: Dimitri John Ledkov
Merged at revision: not available
Proposed branch: lp:~xnox/ubuntu/quantal/lvm2/merge95
Merge into: lp:ubuntu/quantal/lvm2
Diff against target: 85158 lines (+39300/-20331)
513 files modified
.pc/applied-patches (+0/-7)
.pc/avoid-dev-block.patch/lib/device/dev-cache.c (+0/-976)
.pc/dirs.patch/daemons/dmeventd/Makefile.in (+108/-0)
.pc/dirs.patch/daemons/dmeventd/dmeventd.c (+2009/-0)
.pc/dirs.patch/doc/example.conf.in (+0/-662)
.pc/dirs.patch/lib/commands/toolcontext.c (+0/-1513)
.pc/dm-event-api.patch/daemons/dmeventd/.exported_symbols (+4/-0)
.pc/dm-event-api.patch/daemons/dmeventd/dmeventd.c (+2018/-0)
.pc/dm-event-api.patch/daemons/dmeventd/libdevmapper-event.c (+874/-0)
.pc/force-modprobe.patch/configure.in (+0/-1369)
.pc/implicit-pointer.patch/tools/lvm.c (+0/-253)
.pc/install.patch/daemons/dmeventd/plugins/lvm2/Makefile.in (+31/-0)
.pc/install.patch/daemons/dmeventd/plugins/mirror/Makefile.in (+37/-0)
.pc/install.patch/daemons/dmeventd/plugins/raid/Makefile.in (+36/-0)
.pc/install.patch/daemons/dmeventd/plugins/snapshot/Makefile.in (+33/-0)
.pc/install.patch/daemons/dmeventd/plugins/thin/Makefile.in (+36/-0)
.pc/install.patch/make.tmpl.in (+0/-396)
.pc/libs-cleanup.patch/configure.in (+0/-1423)
.pc/monitoring-default-off.patch/doc/example.conf.in (+773/-0)
.pc/monitoring-default-off.patch/lib/config/defaults.h (+0/-165)
.pc/monitoring-default-off.patch/tools/toollib.c (+1637/-0)
Makefile.in (+14/-7)
VERSION (+1/-1)
VERSION_DM (+1/-1)
WHATS_NEW (+273/-1)
WHATS_NEW_DM (+109/-0)
configure (+391/-118)
configure.in (+158/-17)
daemons/Makefile.in (+8/-4)
daemons/clvmd/Makefile.in (+4/-2)
daemons/clvmd/clvm.h (+11/-4)
daemons/clvmd/clvmd-cman.c (+1/-0)
daemons/clvmd/clvmd-command.c (+44/-47)
daemons/clvmd/clvmd-comms.h (+2/-1)
daemons/clvmd/clvmd-corosync.c (+61/-2)
daemons/clvmd/clvmd-openais.c (+1/-0)
daemons/clvmd/clvmd-singlenode.c (+51/-24)
daemons/clvmd/clvmd.c (+158/-103)
daemons/clvmd/lvm-functions.c (+78/-74)
daemons/clvmd/lvm-functions.h (+1/-1)
daemons/clvmd/refresh_clvmd.c (+27/-24)
daemons/cmirrord/clogd.c (+17/-5)
daemons/cmirrord/cluster.c (+120/-25)
daemons/cmirrord/functions.c (+25/-8)
daemons/dmeventd/.exported_symbols (+3/-3)
daemons/dmeventd/Makefile.in (+5/-4)
daemons/dmeventd/dmeventd.c (+165/-133)
daemons/dmeventd/dmeventd.h (+1/-0)
daemons/dmeventd/libdevmapper-event.c (+38/-30)
daemons/dmeventd/libdevmapper-event.h (+3/-0)
daemons/dmeventd/plugins/Makefile.in (+6/-1)
daemons/dmeventd/plugins/lvm2/.exported_symbols (+1/-0)
daemons/dmeventd/plugins/lvm2/Makefile.in (+3/-5)
daemons/dmeventd/plugins/lvm2/dmeventd_lvm.c (+25/-4)
daemons/dmeventd/plugins/lvm2/dmeventd_lvm.h (+3/-0)
daemons/dmeventd/plugins/mirror/Makefile.in (+3/-4)
daemons/dmeventd/plugins/mirror/dmeventd_mirror.c (+16/-26)
daemons/dmeventd/plugins/raid/Makefile.in (+2/-4)
daemons/dmeventd/plugins/raid/dmeventd_raid.c (+30/-3)
daemons/dmeventd/plugins/snapshot/Makefile.in (+3/-4)
daemons/dmeventd/plugins/snapshot/dmeventd_snapshot.c (+60/-38)
daemons/dmeventd/plugins/thin/.exported_symbols (+3/-0)
daemons/dmeventd/plugins/thin/Makefile.in (+37/-0)
daemons/dmeventd/plugins/thin/dmeventd_thin.c (+288/-0)
daemons/lvmetad/Makefile.in (+59/-0)
daemons/lvmetad/lvmetad-client.h (+81/-0)
daemons/lvmetad/lvmetad-core.c (+1126/-0)
daemons/lvmetad/test.sh (+16/-0)
daemons/lvmetad/testclient.c (+127/-0)
debian/changelog (+118/-0)
debian/clvm.init (+6/-4)
debian/clvmd.ra (+2/-2)
debian/control (+22/-10)
debian/dmeventd.install (+2/-0)
debian/libdevmapper-dev.install (+2/-5)
debian/libdevmapper-event1.02.1.install (+1/-1)
debian/libdevmapper-event1.02.1.symbols (+6/-6)
debian/libdevmapper1.02.1.install (+1/-1)
debian/libdevmapper1.02.1.symbols (+66/-0)
debian/liblvm2app2.2.install (+1/-1)
debian/liblvm2cmd2.02.install (+1/-1)
debian/lvm2.init (+6/-6)
debian/lvm2.postinst (+4/-3)
debian/lvm2.postrm (+9/-0)
debian/lvm2.preinst (+4/-0)
debian/patches/dirs.patch (+35/-4)
debian/patches/dm-event-api.patch (+115/-0)
debian/patches/install.patch (+83/-8)
debian/patches/libs-cleanup.patch (+5/-13)
debian/patches/monitoring-default-off.patch (+50/-12)
debian/patches/series (+1/-0)
debian/rules (+55/-43)
doc/example.conf.in (+118/-7)
doc/kernel/crypt.txt (+76/-0)
doc/kernel/delay.txt (+26/-0)
doc/kernel/flakey.txt (+53/-0)
doc/kernel/io.txt (+75/-0)
doc/kernel/kcopyd.txt (+47/-0)
doc/kernel/linear.txt (+61/-0)
doc/kernel/log.txt (+54/-0)
doc/kernel/persistent-data.txt (+84/-0)
doc/kernel/queue-length.txt (+39/-0)
doc/kernel/raid.txt (+108/-0)
doc/kernel/service-time.txt (+91/-0)
doc/kernel/snapshot.txt (+168/-0)
doc/kernel/striped.txt (+58/-0)
doc/kernel/thin-provisioning.txt (+285/-0)
doc/kernel/uevent.txt (+97/-0)
doc/kernel/zero.txt (+37/-0)
doc/lvm2-raid.txt (+197/-20)
doc/lvm_fault_handling.txt (+41/-60)
doc/lvmetad_design.txt (+2/-2)
doc/tagging.txt (+6/-6)
doc/udev_assembly.txt (+2/-2)
include/.symlinks.in (+5/-0)
lib/Makefile.in (+17/-1)
lib/activate/activate.c (+395/-132)
lib/activate/activate.h (+30/-12)
lib/activate/dev_manager.c (+430/-57)
lib/activate/dev_manager.h (+12/-1)
lib/activate/fs.c (+22/-11)
lib/activate/fs.h (+1/-0)
lib/cache/lvmcache.c (+433/-54)
lib/cache/lvmcache.h (+68/-49)
lib/cache/lvmetad.c (+717/-0)
lib/cache/lvmetad.h (+126/-0)
lib/commands/toolcontext.c (+152/-95)
lib/commands/toolcontext.h (+11/-4)
lib/config/config.c (+266/-1207)
lib/config/config.h (+21/-89)
lib/config/defaults.h (+19/-5)
lib/datastruct/str_list.c (+3/-6)
lib/datastruct/str_list.h (+2/-2)
lib/device/dev-cache.c (+87/-45)
lib/device/dev-cache.h (+3/-0)
lib/device/dev-io.c (+7/-20)
lib/display/display.c (+105/-23)
lib/filters/filter-mpath.c (+213/-0)
lib/filters/filter-mpath.h (+23/-0)
lib/filters/filter-persistent.c (+21/-15)
lib/filters/filter-persistent.h (+1/-1)
lib/filters/filter-regex.c (+14/-13)
lib/filters/filter-regex.h (+1/-1)
lib/filters/filter-sysfs.c (+3/-1)
lib/filters/filter.c (+48/-21)
lib/filters/filter.h (+2/-1)
lib/format1/disk-rep.c (+48/-24)
lib/format1/format1.c (+42/-12)
lib/format1/import-extents.c (+4/-4)
lib/format1/lvm1-label.c (+5/-6)
lib/format_pool/disk_rep.c (+106/-76)
lib/format_pool/format_pool.c (+34/-5)
lib/format_pool/import_export.c (+4/-4)
lib/format_text/archive.c (+1/-1)
lib/format_text/archiver.c (+27/-11)
lib/format_text/export.c (+33/-11)
lib/format_text/flags.c (+9/-3)
lib/format_text/format-text.c (+191/-186)
lib/format_text/format-text.h (+12/-0)
lib/format_text/import-export.h (+8/-7)
lib/format_text/import.c (+16/-15)
lib/format_text/import_vsn1.c (+150/-141)
lib/format_text/layout.h (+1/-11)
lib/format_text/tags.c (+3/-3)
lib/format_text/text_export.h (+2/-2)
lib/format_text/text_import.h (+3/-3)
lib/format_text/text_label.c (+117/-94)
lib/label/label.c (+16/-22)
lib/label/label.h (+2/-0)
lib/locking/cluster_locking.c (+36/-30)
lib/locking/external_locking.c (+1/-1)
lib/locking/file_locking.c (+15/-7)
lib/locking/locking.c (+61/-9)
lib/locking/locking.h (+27/-7)
lib/locking/no_locking.c (+2/-2)
lib/log/log.c (+8/-8)
lib/metadata/lv.c (+209/-27)
lib/metadata/lv.h (+11/-1)
lib/metadata/lv_alloc.h (+7/-4)
lib/metadata/lv_manip.c (+693/-255)
lib/metadata/merge.c (+127/-2)
lib/metadata/metadata-exported.h (+123/-87)
lib/metadata/metadata.c (+282/-191)
lib/metadata/metadata.h (+50/-46)
lib/metadata/mirror.c (+144/-93)
lib/metadata/pv.c (+72/-45)
lib/metadata/pv_manip.c (+8/-6)
lib/metadata/pv_map.c (+3/-3)
lib/metadata/pv_map.h (+2/-2)
lib/metadata/raid_manip.c (+654/-22)
lib/metadata/replicator_manip.c (+0/-8)
lib/metadata/segtype.h (+19/-16)
lib/metadata/snapshot_manip.c (+4/-0)
lib/metadata/thin_manip.c (+425/-0)
lib/metadata/vg.c (+22/-3)
lib/metadata/vg.h (+5/-0)
lib/mirror/mirrored.c (+37/-38)
lib/misc/configure.h.in (+15/-0)
lib/misc/lvm-exec.c (+3/-2)
lib/misc/lvm-file.c (+2/-1)
lib/misc/lvm-globals.c (+14/-3)
lib/misc/lvm-globals.h (+3/-0)
lib/misc/lvm-percent.h (+2/-1)
lib/misc/lvm-string.c (+43/-284)
lib/misc/lvm-string.h (+0/-34)
lib/misc/sharedlib.c (+4/-2)
lib/mm/memlock.c (+23/-22)
lib/raid/.exported_symbols (+1/-1)
lib/raid/raid.c (+115/-81)
lib/replicator/replicator.c (+39/-35)
lib/report/columns.h (+12/-1)
lib/report/properties.c (+39/-3)
lib/report/properties.h (+1/-1)
lib/report/report.c (+244/-16)
lib/snapshot/snapshot.c (+10/-8)
lib/striped/striped.c (+13/-11)
lib/thin/.exported_symbols (+1/-0)
lib/thin/Makefile.in (+25/-0)
lib/thin/thin.c (+601/-0)
lib/unknown/unknown.c (+9/-7)
libdaemon/Makefile.in (+29/-0)
libdaemon/client/Makefile.in (+20/-0)
libdaemon/client/daemon-client.c (+118/-0)
libdaemon/client/daemon-client.h (+105/-0)
libdaemon/client/daemon-shared.c (+141/-0)
libdaemon/client/daemon-shared.h (+30/-0)
libdaemon/server/Makefile.in (+22/-0)
libdaemon/server/daemon-server.c (+523/-0)
libdaemon/server/daemon-server.h (+122/-0)
libdm/Makefile.in (+1/-0)
libdm/ioctl/libdm-iface.c (+220/-126)
libdm/ioctl/libdm-targets.h (+3/-0)
libdm/libdevmapper.h (+325/-4)
libdm/libdm-common.c (+760/-104)
libdm/libdm-common.h (+17/-4)
libdm/libdm-config.c (+1174/-0)
libdm/libdm-deptree.c (+1011/-386)
libdm/libdm-file.c (+20/-1)
libdm/libdm-report.c (+3/-0)
libdm/libdm-string.c (+272/-13)
libdm/misc/dm-log-userspace.h (+25/-6)
libdm/mm/dbg_malloc.c (+16/-8)
libdm/mm/dbg_malloc.h (+0/-46)
libdm/mm/pool-fast.c (+13/-2)
libdm/mm/pool.c (+1/-0)
libdm/regex/matcher.c (+108/-68)
liblvm/Makefile.in (+3/-1)
liblvm/lvm2app.h (+2/-1)
liblvm/lvm_base.c (+1/-1)
liblvm/lvm_lv.c (+15/-9)
liblvm/lvm_pv.c (+5/-5)
make.tmpl.in (+40/-30)
man/Makefile.in (+4/-4)
man/clvmd.8.in (+14/-0)
man/dmeventd.8.in (+22/-13)
man/dmsetup.8.in (+472/-258)
man/fsadm.8.in (+59/-45)
man/lvconvert.8.in (+42/-0)
man/lvcreate.8.in (+196/-108)
man/lvextend.8.in (+1/-0)
man/lvm.8.in (+2/-1)
man/lvm.conf.5.in (+16/-4)
man/lvreduce.8.in (+43/-31)
man/lvremove.8.in (+15/-9)
man/lvrename.8.in (+17/-23)
man/lvresize.8.in (+56/-52)
man/lvs.8.in (+68/-33)
man/pvcreate.8.in (+1/-1)
man/pvscan.8.in (+19/-0)
scripts/Makefile.in (+20/-2)
scripts/dm_event_systemd_red_hat.service.in (+3/-1)
scripts/fsadm.sh (+51/-46)
scripts/gdbinit (+68/-43)
scripts/lvm2_lvmetad_init_red_hat.in (+115/-0)
scripts/lvm2_lvmetad_systemd_red_hat.service.in (+17/-0)
scripts/lvm2_lvmetad_systemd_red_hat.socket.in (+10/-0)
scripts/lvm2_monitoring_init_red_hat.in (+4/-4)
scripts/lvm2_monitoring_init_rhel4 (+4/-4)
scripts/lvm2_monitoring_systemd_red_hat.service.in (+1/-2)
scripts/lvm2_tmpfiles_red_hat.conf.in (+2/-0)
scripts/lvm2create_initrd/lvm2create_initrd (+3/-3)
scripts/lvm2create_initrd/lvm2create_initrd.8 (+53/-44)
scripts/lvm2create_initrd/lvm2create_initrd.pod (+5/-5)
scripts/vgimportclone.sh (+7/-5)
test/Makefile.in (+46/-40)
test/api/Makefile.in (+15/-34)
test/api/percent.sh (+2/-0)
test/lib/aux.sh (+75/-11)
test/lib/check.sh (+4/-4)
test/lib/harness.c (+20/-9)
test/lib/test.sh (+12/-3)
test/shell/000-basic.sh (+28/-0)
test/shell/activate-missing.sh (+87/-0)
test/shell/activate-partial.sh (+30/-0)
test/shell/clvmd-restart.sh (+53/-0)
test/shell/covercmd.sh (+82/-0)
test/shell/dmeventd-restart.sh (+42/-0)
test/shell/dumpconfig.sh (+35/-0)
test/shell/fsadm.sh (+128/-0)
test/shell/inconsistent-metadata.sh (+78/-0)
test/shell/listings.sh (+83/-0)
test/shell/lock-blocking.sh (+41/-0)
test/shell/lvchange-mirror.sh (+28/-0)
test/shell/lvconvert-mirror-basic-0.sh (+12/-0)
test/shell/lvconvert-mirror-basic-1.sh (+12/-0)
test/shell/lvconvert-mirror-basic-2.sh (+12/-0)
test/shell/lvconvert-mirror-basic-3.sh (+12/-0)
test/shell/lvconvert-mirror-basic.sh (+143/-0)
test/shell/lvconvert-mirror.sh (+259/-0)
test/shell/lvconvert-raid.sh (+215/-0)
test/shell/lvconvert-repair-dmeventd.sh (+26/-0)
test/shell/lvconvert-repair-policy.sh (+91/-0)
test/shell/lvconvert-repair-replace.sh (+93/-0)
test/shell/lvconvert-repair-snapshot.sh (+27/-0)
test/shell/lvconvert-repair-transient-dmeventd.sh (+27/-0)
test/shell/lvconvert-repair-transient.sh (+26/-0)
test/shell/lvconvert-repair.sh (+114/-0)
test/shell/lvconvert-twostep.sh (+26/-0)
test/shell/lvcreate-large.sh (+40/-0)
test/shell/lvcreate-mirror.sh (+41/-0)
test/shell/lvcreate-operation.sh (+43/-0)
test/shell/lvcreate-pvtags.sh (+47/-0)
test/shell/lvcreate-raid.sh (+95/-0)
test/shell/lvcreate-repair.sh (+100/-0)
test/shell/lvcreate-small-snap.sh (+30/-0)
test/shell/lvcreate-striped-mirror.sh (+65/-0)
test/shell/lvcreate-thin.sh (+216/-0)
test/shell/lvcreate-usage.sh (+152/-0)
test/shell/lvextend-percent-extents.sh (+106/-0)
test/shell/lvextend-snapshot-dmeventd.sh (+62/-0)
test/shell/lvextend-snapshot-policy.sh (+47/-0)
test/shell/lvm-init.sh (+21/-0)
test/shell/lvmcache-exercise.sh (+22/-0)
test/shell/lvmetad-pvs.sh (+20/-0)
test/shell/lvresize-mirror.sh (+38/-0)
test/shell/lvresize-rounding.sh (+25/-0)
test/shell/lvresize-usage.sh (+20/-0)
test/shell/mdata-strings.sh (+39/-0)
test/shell/metadata-balance.sh (+232/-0)
test/shell/metadata-dirs.sh (+43/-0)
test/shell/metadata.sh (+80/-0)
test/shell/mirror-names.sh (+156/-0)
test/shell/mirror-vgreduce-removemissing.sh (+424/-0)
test/shell/name-mangling.sh (+230/-0)
test/shell/nomda-missing.sh (+83/-0)
test/shell/pool-labels.sh (+40/-0)
test/shell/pv-duplicate.sh (+25/-0)
test/shell/pv-min-size.sh (+31/-0)
test/shell/pv-range-overflow.sh (+32/-0)
test/shell/pvchange-usage.sh (+66/-0)
test/shell/pvcreate-metadata0.sh (+32/-0)
test/shell/pvcreate-operation-md.sh (+147/-0)
test/shell/pvcreate-operation.sh (+121/-0)
test/shell/pvcreate-usage.sh (+192/-0)
test/shell/pvmove-basic.sh (+385/-0)
test/shell/pvremove-usage.sh (+68/-0)
test/shell/read-ahead.sh (+62/-0)
test/shell/snapshot-autoumount-dmeventd.sh (+39/-0)
test/shell/snapshot-merge.sh (+134/-0)
test/shell/snapshots-of-mirrors.sh (+44/-0)
test/shell/tags.sh (+74/-0)
test/shell/test-partition.sh (+30/-0)
test/shell/topology-support.sh (+106/-0)
test/shell/unknown-segment.sh (+34/-0)
test/shell/unlost-pv.sh (+38/-0)
test/shell/vgcfgbackup-usage.sh (+54/-0)
test/shell/vgchange-maxlv.sh (+31/-0)
test/shell/vgchange-sysinit.sh (+51/-0)
test/shell/vgchange-usage.sh (+44/-0)
test/shell/vgcreate-usage.sh (+163/-0)
test/shell/vgextend-restoremissing.sh (+30/-0)
test/shell/vgextend-usage.sh (+129/-0)
test/shell/vgimportclone.sh (+38/-0)
test/shell/vgmerge-operation.sh (+81/-0)
test/shell/vgmerge-usage.sh (+67/-0)
test/shell/vgreduce-removemissing-snapshot.sh (+26/-0)
test/shell/vgreduce-usage.sh (+87/-0)
test/shell/vgrename-usage.sh (+41/-0)
test/shell/vgsplit-operation.sh (+295/-0)
test/shell/vgsplit-stacked.sh (+29/-0)
test/shell/vgsplit-usage.sh (+168/-0)
test/t-000-basic.sh (+0/-30)
test/t-activate-missing.sh (+0/-87)
test/t-activate-partial.sh (+0/-30)
test/t-covercmd.sh (+0/-82)
test/t-dmeventd-restart.sh (+0/-40)
test/t-fsadm.sh (+0/-123)
test/t-inconsistent-metadata.sh (+0/-75)
test/t-listings.sh (+0/-83)
test/t-lock-blocking.sh (+0/-41)
test/t-lvchange-mirror.sh (+0/-28)
test/t-lvconvert-mirror-basic-0.sh (+0/-12)
test/t-lvconvert-mirror-basic-1.sh (+0/-12)
test/t-lvconvert-mirror-basic-2.sh (+0/-12)
test/t-lvconvert-mirror-basic-3.sh (+0/-12)
test/t-lvconvert-mirror-basic.sh (+0/-142)
test/t-lvconvert-mirror.sh (+0/-255)
test/t-lvconvert-raid.sh (+0/-158)
test/t-lvconvert-repair-dmeventd.sh (+0/-26)
test/t-lvconvert-repair-policy.sh (+0/-91)
test/t-lvconvert-repair-replace.sh (+0/-93)
test/t-lvconvert-repair-snapshot.sh (+0/-27)
test/t-lvconvert-repair-transient-dmeventd.sh (+0/-27)
test/t-lvconvert-repair-transient.sh (+0/-26)
test/t-lvconvert-repair.sh (+0/-108)
test/t-lvconvert-twostep.sh (+0/-26)
test/t-lvcreate-mirror.sh (+0/-41)
test/t-lvcreate-operation.sh (+0/-43)
test/t-lvcreate-pvtags.sh (+0/-45)
test/t-lvcreate-raid.sh (+0/-113)
test/t-lvcreate-repair.sh (+0/-97)
test/t-lvcreate-small-snap.sh (+0/-30)
test/t-lvcreate-usage.sh (+0/-152)
test/t-lvextend-percent-extents.sh (+0/-106)
test/t-lvextend-snapshot-dmeventd.sh (+0/-51)
test/t-lvextend-snapshot-policy.sh (+0/-47)
test/t-lvm-init.sh (+0/-21)
test/t-lvmcache-exercise.sh (+0/-23)
test/t-lvresize-mirror.sh (+0/-38)
test/t-lvresize-usage.sh (+0/-20)
test/t-mdata-strings.sh (+0/-33)
test/t-metadata-balance.sh (+0/-232)
test/t-metadata-dirs.sh (+0/-43)
test/t-metadata.sh (+0/-80)
test/t-mirror-names.sh (+0/-156)
test/t-mirror-vgreduce-removemissing.sh (+0/-424)
test/t-nomda-missing.sh (+0/-83)
test/t-pool-labels.sh (+0/-39)
test/t-pv-duplicate.sh (+0/-25)
test/t-pv-min-size.sh (+0/-31)
test/t-pv-range-overflow.sh (+0/-32)
test/t-pvchange-usage.sh (+0/-66)
test/t-pvcreate-metadata0.sh (+0/-32)
test/t-pvcreate-operation-md.sh (+0/-147)
test/t-pvcreate-operation.sh (+0/-121)
test/t-pvcreate-usage.sh (+0/-192)
test/t-pvmove-basic.sh (+0/-378)
test/t-pvremove-usage.sh (+0/-68)
test/t-read-ahead.sh (+0/-62)
test/t-snapshot-autoumount-dmeventd.sh (+0/-39)
test/t-snapshot-merge.sh (+0/-133)
test/t-snapshots-of-mirrors.sh (+0/-44)
test/t-tags.sh (+0/-74)
test/t-test-partition.sh (+0/-30)
test/t-topology-support.sh (+0/-106)
test/t-unknown-segment.sh (+0/-34)
test/t-unlost-pv.sh (+0/-38)
test/t-vgcfgbackup-usage.sh (+0/-54)
test/t-vgchange-maxlv.sh (+0/-31)
test/t-vgchange-sysinit.sh (+0/-51)
test/t-vgchange-usage.sh (+0/-44)
test/t-vgcreate-usage.sh (+0/-163)
test/t-vgextend-restoremissing.sh (+0/-30)
test/t-vgextend-usage.sh (+0/-129)
test/t-vgimportclone.sh (+0/-36)
test/t-vgmerge-operation.sh (+0/-81)
test/t-vgmerge-usage.sh (+0/-67)
test/t-vgreduce-removemissing-snapshot.sh (+0/-26)
test/t-vgreduce-usage.sh (+0/-87)
test/t-vgrename-usage.sh (+0/-41)
test/t-vgsplit-operation.sh (+0/-290)
test/t-vgsplit-stacked.sh (+0/-29)
test/t-vgsplit-usage.sh (+0/-168)
test/unit/Makefile.in (+33/-0)
test/unit/bitset_t.c (+133/-0)
test/unit/config_t.c (+156/-0)
test/unit/matcher_data.h (+1013/-0)
test/unit/matcher_t.c (+85/-0)
test/unit/run.c (+29/-0)
test/unit/string_t.c (+83/-0)
tools/Makefile.in (+2/-4)
tools/args.h (+7/-2)
tools/commands.h (+16/-7)
tools/dmsetup.c (+378/-71)
tools/dumpconfig.c (+1/-1)
tools/lvchange.c (+45/-17)
tools/lvconvert.c (+144/-23)
tools/lvcreate.c (+582/-156)
tools/lvm.c (+1/-2)
tools/lvm2cmd.h (+6/-0)
tools/lvmcmdlib.c (+4/-0)
tools/lvmcmdline.c (+28/-16)
tools/lvmdiskscan.c (+7/-4)
tools/lvrename.c (+15/-0)
tools/lvresize.c (+128/-31)
tools/polldaemon.c (+24/-7)
tools/polldaemon.h (+3/-3)
tools/pvchange.c (+1/-1)
tools/pvck.c (+1/-1)
tools/pvcreate.c (+3/-3)
tools/pvmove.c (+32/-29)
tools/pvremove.c (+9/-6)
tools/pvresize.c (+1/-1)
tools/pvscan.c (+146/-7)
tools/reporter.c (+3/-0)
tools/toollib.c (+57/-39)
tools/toollib.h (+0/-1)
tools/tools.h (+3/-0)
tools/vgcfgbackup.c (+1/-1)
tools/vgcfgrestore.c (+2/-0)
tools/vgchange.c (+17/-10)
tools/vgconvert.c (+1/-5)
tools/vgcreate.c (+2/-0)
tools/vgmerge.c (+2/-1)
tools/vgreduce.c (+4/-4)
tools/vgremove.c (+1/-1)
tools/vgrename.c (+8/-3)
tools/vgscan.c (+8/-1)
tools/vgsplit.c (+16/-3)
udev/13-dm-disk.rules (+0/-27)
udev/13-dm-disk.rules.in (+38/-0)
udev/69-dm-lvm-metad.rules (+25/-0)
udev/Makefile.in (+12/-2)
To merge this branch: bzr merge lp:~xnox/ubuntu/quantal/lvm2/merge95
Reviewer Review Type Date Requested Status
Steve Langasek Needs Fixing
Kees Cook Pending
Canonical Foundations Team Pending
Ubuntu branches Pending
Review via email: mp+119696@code.launchpad.net

Description of the change

* Debian accepted some of the event manager packaging
* Debian multiarched libdevmapper libs, but not the libdevmapper-dev
* Ubuntu's "Don't install documentation in udebs" vanished and there are no traces of it
* Ubuntu's "don't ship lvm2 init script" transformed into "don't ship clvm init script" see bug 1037033
* I added libdevmapper-dev multiarching
* It looks like Debian refreshed api patch, which is now different to Ubuntu's. Since the 'new' api was only in quantal so far, I am tempted to switch for Debian's API instead & recompile. See $ bzr log -p debian/*.symbols

The rest stayed the same.

To post a comment you must log in.
Revision history for this message
Steve Langasek (vorlon) wrote :

> - debian/{clvmd.ra,clvm.init}:
> - create /var/run/lvm if it doesn't exist.

debian/rules now points at /run/lvm; this should be updated to match.

--- debian/libdevmapper-dev.install 2010-12-07 08:08:45 +0000
+++ debian/libdevmapper-dev.install 2012-08-18 04:00:45 +0000
@@ -1,5 +1,2 @@
-usr/include/libdevmapper.h
-usr/include/libdevmapper-event.h
-usr/lib/libdevmapper.so
-usr/lib/pkgconfig/devmapper.pc
-usr/lib/pkgconfig/devmapper-event.pc
+usr/include/libdevmapper*
+usr/lib/*/pkgconfig/devmapper*

Hmm, good catch. I think you should call this out as a separate change in the changelog, since this isn't just a "remaining change" but a fix to multiarch support for the runtime lib package.

--- debian/lvm2.postinst 2009-10-08 18:17:43 +0000
+++ debian/lvm2.postinst 2012-08-15 17:05:32 +0000
@@ -5,7 +5,9 @@
 case "$1" in
     configure)
         vgcfgbackup >/dev/null 2>&1 || :
- invoke-rc.d lvm2 start || :
+ if [ -x /etc/init.d/lvm2 ]; then
+ invoke-rc.d lvm2 start || :
+ fi
         if [ -x /usr/sbin/update-initramfs ]; then
             update-initramfs -u
         fi

Since the lvm2.init is being dropped, this probably shouldn't be conditional - it should probably be removed entirely. In fact, when this regression was introduced during the lucid merge, the previous postinst was doing this:

    if test -f /etc/init.d/lvm2; then
        update-rc.d -f lvm2 remove >/dev/null 2>&1 || true
       rm -f /etc/init.d/lvm2
    fi

We probably want to be doing that again, possibly with better handling of modified conffiles.

BTW, perhaps it's worth checking with Kees to see if there was a reason he thought this init script should be restored when merging.

--- debian/libdevmapper-event1.02.1.symbols 2012-04-14 03:19:00 +0000
+++ debian/libdevmapper-event1.02.1.symbols 2012-08-18 04:00:45 +0000
@@ -1,11 +1,13 @@
 libdevmapper-event.so.1.02.1 libdevmapper-event1.02.1 #MINVER#
  Base@Base 2:1.02.20
- daemon_talk@Base 2:1.02.67
+ dm_event_daemon_fini_fifos@Base 2:1.02.74
+ dm_event_daemon_init_fifos@Base 2:1.02.74
+ dm_event_daemon_talk@Base 2:1.02.74

This is unfortunate, but it happens... In this case, it appears that dmeventd used the old symbol, so we want to have a Breaks against the old version of dmeventd. No other packages in Ubuntu that depend on libdevmapper-event1.02.1 appear to use that symbol, so this Breaks is the only fix needed.

- dm_event_get_version@Base 2:1.02.67
+ dm_event_get_version@Base 2:1.02.74
  dm_event_handler_create@Base 2:1.02.20
  dm_event_handler_destroy@Base 2:1.02.20
- dm_event_handler_get_dev_name@Base 2:1.02.67
+ dm_event_handler_get_dev_name@Base 2:1.02.74

Those version bumps are unnecessary in Ubuntu, but mostly harmless.

@@ -22,5 +24,3 @@
  dm_event_handler_set_uuid@Base 2:1.02.20
  dm_event_register_handler@Base 2:1.02.20
  dm_event_unregister_handler@Base 2:1.02.20
- fini_fifos@Base 2:1.02.67
- init_fifos@Base 2:1.02.67

These symbols are also only used by dmeventd. (This makes sense, as all three symbols appear to be due to a Debian-specific patch for dmeventd.)

The rest looks good to me.

review: Needs Fixing
lp:~xnox/ubuntu/quantal/lvm2/merge95 updated
79. By Dimitri John Ledkov

Note additional multi-arch changes only once.

80. By Dimitri John Ledkov

(omit leading /var/): create /run/lvm if it doesn't exist.

81. By Dimitri John Ledkov

 * debian/lvm2.{preinst,postinst,postrm}:
  - Implement removal of obsolete /etc/init.d/lvm2 conffile, which
    should not have been re-introduced in Quantal.

82. By Dimitri John Ledkov

minimise diff

83. By Dimitri John Ledkov

 * libdevmapper-event1.02.1:
  - Add Breaks: dmeventd (<< 2.02.95-4ubuntu1) due to debian symbol rename

Revision history for this message
Dimitri John Ledkov (xnox) wrote :

Address all comments.
/etc/init.d/lvm2 was only reintroduced in quantal, added rm_conffile snippets for it which can be removed in R.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added file '.pc/applied-patches'
--- .pc/applied-patches 1970-01-01 00:00:00 +0000
+++ .pc/applied-patches 2012-08-21 10:18:22 +0000
@@ -0,0 +1,8 @@
1install.patch
2libs-cleanup.patch
3dirs.patch
4force-modprobe.patch
5implicit-pointer.patch
6avoid-dev-block.patch
7dm-event-api.patch
8monitoring-default-off.patch
09
=== removed file '.pc/applied-patches'
--- .pc/applied-patches 2012-04-14 02:57:53 +0000
+++ .pc/applied-patches 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1install.patch
2libs-cleanup.patch
3dirs.patch
4force-modprobe.patch
5implicit-pointer.patch
6avoid-dev-block.patch
7monitoring-default-off.patch
80
=== added directory '.pc/avoid-dev-block.patch'
=== removed directory '.pc/avoid-dev-block.patch'
=== added directory '.pc/avoid-dev-block.patch/lib'
=== removed directory '.pc/avoid-dev-block.patch/lib'
=== added directory '.pc/avoid-dev-block.patch/lib/device'
=== removed directory '.pc/avoid-dev-block.patch/lib/device'
=== added file '.pc/avoid-dev-block.patch/lib/device/dev-cache.c'
--- .pc/avoid-dev-block.patch/lib/device/dev-cache.c 1970-01-01 00:00:00 +0000
+++ .pc/avoid-dev-block.patch/lib/device/dev-cache.c 2012-08-21 10:18:22 +0000
@@ -0,0 +1,1018 @@
1/*
2 * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
3 * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
4 *
5 * This file is part of LVM2.
6 *
7 * This copyrighted material is made available to anyone wishing to use,
8 * modify, copy, or redistribute it subject to the terms and conditions
9 * of the GNU Lesser General Public License v.2.1.
10 *
11 * You should have received a copy of the GNU Lesser General Public License
12 * along with this program; if not, write to the Free Software Foundation,
13 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
14 */
15
16#include "lib.h"
17#include "dev-cache.h"
18#include "lvm-types.h"
19#include "btree.h"
20#include "filter.h"
21#include "filter-persistent.h"
22#include "toolcontext.h"
23
24#include <unistd.h>
25#include <sys/param.h>
26#include <dirent.h>
27
28struct dev_iter {
29 struct btree_iter *current;
30 struct dev_filter *filter;
31};
32
33struct dir_list {
34 struct dm_list list;
35 char dir[0];
36};
37
38static struct {
39 struct dm_pool *mem;
40 struct dm_hash_table *names;
41 struct btree *devices;
42 struct dm_regex *preferred_names_matcher;
43 const char *dev_dir;
44
45 int has_scanned;
46 struct dm_list dirs;
47 struct dm_list files;
48
49} _cache;
50
51#define _zalloc(x) dm_pool_zalloc(_cache.mem, (x))
52#define _free(x) dm_pool_free(_cache.mem, (x))
53#define _strdup(x) dm_pool_strdup(_cache.mem, (x))
54
55static int _insert(const char *path, int rec, int check_with_udev_db);
56
57/* Setup non-zero members of passed zeroed 'struct device' */
58static void _dev_init(struct device *dev, int max_error_count)
59{
60 dev->block_size = -1;
61 dev->fd = -1;
62 dev->read_ahead = -1;
63 dev->max_error_count = max_error_count;
64
65 dm_list_init(&dev->aliases);
66 dm_list_init(&dev->open_list);
67}
68
69struct device *dev_create_file(const char *filename, struct device *dev,
70 struct str_list *alias, int use_malloc)
71{
72 int allocate = !dev;
73
74 if (allocate) {
75 if (use_malloc) {
76 if (!(dev = dm_zalloc(sizeof(*dev)))) {
77 log_error("struct device allocation failed");
78 return NULL;
79 }
80 if (!(alias = dm_zalloc(sizeof(*alias)))) {
81 log_error("struct str_list allocation failed");
82 dm_free(dev);
83 return NULL;
84 }
85 if (!(alias->str = dm_strdup(filename))) {
86 log_error("filename strdup failed");
87 dm_free(dev);
88 dm_free(alias);
89 return NULL;
90 }
91 } else {
92 if (!(dev = _zalloc(sizeof(*dev)))) {
93 log_error("struct device allocation failed");
94 return NULL;
95 }
96 if (!(alias = _zalloc(sizeof(*alias)))) {
97 log_error("struct str_list allocation failed");
98 _free(dev);
99 return NULL;
100 }
101 if (!(alias->str = _strdup(filename))) {
102 log_error("filename strdup failed");
103 return NULL;
104 }
105 }
106 } else if (!(alias->str = dm_strdup(filename))) {
107 log_error("filename strdup failed");
108 return NULL;
109 }
110
111 _dev_init(dev, NO_DEV_ERROR_COUNT_LIMIT);
112 dev->flags = DEV_REGULAR | ((use_malloc) ? DEV_ALLOCED : 0);
113 dm_list_add(&dev->aliases, &alias->list);
114
115 return dev;
116}
117
118static struct device *_dev_create(dev_t d)
119{
120 struct device *dev;
121
122 if (!(dev = _zalloc(sizeof(*dev)))) {
123 log_error("struct device allocation failed");
124 return NULL;
125 }
126
127 _dev_init(dev, dev_disable_after_error_count());
128 dev->dev = d;
129
130 return dev;
131}
132
133void dev_set_preferred_name(struct str_list *sl, struct device *dev)
134{
135 /*
136 * Don't interfere with ordering specified in config file.
137 */
138 if (_cache.preferred_names_matcher)
139 return;
140
141 log_debug("%s: New preferred name", sl->str);
142 dm_list_del(&sl->list);
143 dm_list_add_h(&dev->aliases, &sl->list);
144}
145
146/*
147 * Check whether path0 or path1 contains the subpath. The path that
148 * *does not* contain the subpath wins (return 0 or 1). If both paths
149 * contain the subpath, return -1. If none of them contains the subpath,
150 * return -2.
151 */
152static int _builtin_preference(const char *path0, const char *path1,
153 size_t skip_prefix_count, const char *subpath)
154{
155 size_t subpath_len;
156 int r0, r1;
157
158 subpath_len = strlen(subpath);
159
160 r0 = !strncmp(path0 + skip_prefix_count, subpath, subpath_len);
161 r1 = !strncmp(path1 + skip_prefix_count, subpath, subpath_len);
162
163 if (!r0 && r1)
164 /* path0 does not have the subpath - it wins */
165 return 0;
166 else if (r0 && !r1)
167 /* path1 does not have the subpath - it wins */
168 return 1;
169 else if (r0 && r1)
170 /* both of them have the subpath */
171 return -1;
172
173 /* no path has the subpath */
174 return -2;
175}
176
177static int _apply_builtin_path_preference_rules(const char *path0, const char *path1)
178{
179 size_t devdir_len;
180 int r;
181
182 devdir_len = strlen(_cache.dev_dir);
183
184 if (!strncmp(path0, _cache.dev_dir, devdir_len) &&
185 !strncmp(path1, _cache.dev_dir, devdir_len)) {
186 /*
187 * We're trying to achieve the ordering:
188 * /dev/block/ < /dev/dm-* < /dev/disk/ < /dev/mapper/ < anything else
189 */
190
191 /* Prefer any other path over /dev/block/ path. */
192 if ((r = _builtin_preference(path0, path1, devdir_len, "block/")) >= -1)
193 return r;
194
195 /* Prefer any other path over /dev/dm-* path. */
196 if ((r = _builtin_preference(path0, path1, devdir_len, "dm-")) >= -1)
197 return r;
198
199 /* Prefer any other path over /dev/disk/ path. */
200 if ((r = _builtin_preference(path0, path1, devdir_len, "disk/")) >= -1)
201 return r;
202
203 /* Prefer any other path over /dev/mapper/ path. */
204 if ((r = _builtin_preference(path0, path1, 0, dm_dir())) >= -1)
205 return r;
206 }
207
208 return -1;
209}
210
211/* Return 1 if we prefer path1 else return 0 */
212static int _compare_paths(const char *path0, const char *path1)
213{
214 int slash0 = 0, slash1 = 0;
215 int m0, m1;
216 const char *p;
217 char p0[PATH_MAX], p1[PATH_MAX];
218 char *s0, *s1;
219 struct stat stat0, stat1;
220 int r;
221
222 /*
223 * FIXME Better to compare patterns one-at-a-time against all names.
224 */
225 if (_cache.preferred_names_matcher) {
226 m0 = dm_regex_match(_cache.preferred_names_matcher, path0);
227 m1 = dm_regex_match(_cache.preferred_names_matcher, path1);
228
229 if (m0 != m1) {
230 if (m0 < 0)
231 return 1;
232 if (m1 < 0)
233 return 0;
234 if (m0 < m1)
235 return 1;
236 if (m1 < m0)
237 return 0;
238 }
239 }
240
241 /* Apply built-in preference rules first. */
242 if ((r = _apply_builtin_path_preference_rules(path0, path1)) >= 0)
243 return r;
244
245 /* Return the path with fewer slashes */
246 for (p = path0; p++; p = (const char *) strchr(p, '/'))
247 slash0++;
248
249 for (p = path1; p++; p = (const char *) strchr(p, '/'))
250 slash1++;
251
252 if (slash0 < slash1)
253 return 0;
254 if (slash1 < slash0)
255 return 1;
256
257 strncpy(p0, path0, sizeof(p0) - 1);
258 p0[sizeof(p0) - 1] = '\0';
259 strncpy(p1, path1, sizeof(p1) - 1);
260 p1[sizeof(p1) - 1] = '\0';
261 s0 = p0 + 1;
262 s1 = p1 + 1;
263
264 /*
265 * If we reach here, both paths are the same length.
266 * Now skip past identical path components.
267 */
268 while (*s0 && *s0 == *s1)
269 s0++, s1++;
270
271 /* We prefer symlinks - they exist for a reason!
272 * So we prefer a shorter path before the first symlink in the name.
273 * FIXME Configuration option to invert this? */
274 while (s0) {
275 s0 = strchr(s0, '/');
276 s1 = strchr(s1, '/');
277 if (s0) {
278 *s0 = '\0';
279 *s1 = '\0';
280 }
281 if (lstat(p0, &stat0)) {
282 log_sys_very_verbose("lstat", p0);
283 return 1;
284 }
285 if (lstat(p1, &stat1)) {
286 log_sys_very_verbose("lstat", p1);
287 return 0;
288 }
289 if (S_ISLNK(stat0.st_mode) && !S_ISLNK(stat1.st_mode))
290 return 0;
291 if (!S_ISLNK(stat0.st_mode) && S_ISLNK(stat1.st_mode))
292 return 1;
293 if (s0) {
294 *s0++ = '/';
295 *s1++ = '/';
296 }
297 }
298
299 /* ASCII comparison */
300 if (strcmp(path0, path1) < 0)
301 return 0;
302 else
303 return 1;
304}
305
306static int _add_alias(struct device *dev, const char *path)
307{
308 struct str_list *sl = _zalloc(sizeof(*sl));
309 struct str_list *strl;
310 const char *oldpath;
311 int prefer_old = 1;
312
313 if (!sl)
314 return_0;
315
316 /* Is name already there? */
317 dm_list_iterate_items(strl, &dev->aliases) {
318 if (!strcmp(strl->str, path)) {
319 log_debug("%s: Already in device cache", path);
320 return 1;
321 }
322 }
323
324 sl->str = path;
325
326 if (!dm_list_empty(&dev->aliases)) {
327 oldpath = dm_list_item(dev->aliases.n, struct str_list)->str;
328 prefer_old = _compare_paths(path, oldpath);
329 log_debug("%s: Aliased to %s in device cache%s",
330 path, oldpath, prefer_old ? "" : " (preferred name)");
331
332 } else
333 log_debug("%s: Added to device cache", path);
334
335 if (prefer_old)
336 dm_list_add(&dev->aliases, &sl->list);
337 else
338 dm_list_add_h(&dev->aliases, &sl->list);
339
340 return 1;
341}
342
343/*
344 * Either creates a new dev, or adds an alias to
345 * an existing dev.
346 */
347static int _insert_dev(const char *path, dev_t d)
348{
349 struct device *dev;
350 static dev_t loopfile_count = 0;
351 int loopfile = 0;
352 char *path_copy;
353
354 /* Generate pretend device numbers for loopfiles */
355 if (!d) {
356 if (dm_hash_lookup(_cache.names, path))
357 return 1;
358 d = ++loopfile_count;
359 loopfile = 1;
360 }
361
362 /* is this device already registered ? */
363 if (!(dev = (struct device *) btree_lookup(_cache.devices,
364 (uint32_t) d))) {
365 /* create new device */
366 if (loopfile) {
367 if (!(dev = dev_create_file(path, NULL, NULL, 0)))
368 return_0;
369 } else if (!(dev = _dev_create(d)))
370 return_0;
371
372 if (!(btree_insert(_cache.devices, (uint32_t) d, dev))) {
373 log_error("Couldn't insert device into binary tree.");
374 _free(dev);
375 return 0;
376 }
377 }
378
379 if (!(path_copy = dm_pool_strdup(_cache.mem, path))) {
380 log_error("Failed to duplicate path string.");
381 return 0;
382 }
383
384 if (!loopfile && !_add_alias(dev, path_copy)) {
385 log_error("Couldn't add alias to dev cache.");
386 return 0;
387 }
388
389 if (!dm_hash_insert(_cache.names, path_copy, dev)) {
390 log_error("Couldn't add name to hash in dev cache.");
391 return 0;
392 }
393
394 return 1;
395}
396
397static char *_join(const char *dir, const char *name)
398{
399 size_t len = strlen(dir) + strlen(name) + 2;
400 char *r = dm_malloc(len);
401 if (r)
402 snprintf(r, len, "%s/%s", dir, name);
403
404 return r;
405}
406
407/*
408 * Get rid of extra slashes in the path string.
409 */
410static void _collapse_slashes(char *str)
411{
412 char *ptr;
413 int was_slash = 0;
414
415 for (ptr = str; *ptr; ptr++) {
416 if (*ptr == '/') {
417 if (was_slash)
418 continue;
419
420 was_slash = 1;
421 } else
422 was_slash = 0;
423 *str++ = *ptr;
424 }
425
426 *str = *ptr;
427}
428
429static int _insert_dir(const char *dir)
430{
431 int n, dirent_count, r = 1;
432 struct dirent **dirent;
433 char *path;
434
435 dirent_count = scandir(dir, &dirent, NULL, alphasort);
436 if (dirent_count > 0) {
437 for (n = 0; n < dirent_count; n++) {
438 if (dirent[n]->d_name[0] == '.') {
439 free(dirent[n]);
440 continue;
441 }
442
443 if (!(path = _join(dir, dirent[n]->d_name)))
444 return_0;
445
446 _collapse_slashes(path);
447 r &= _insert(path, 1, 0);
448 dm_free(path);
449
450 free(dirent[n]);
451 }
452 free(dirent);
453 }
454
455 return r;
456}
457
458static int _insert_file(const char *path)
459{
460 struct stat info;
461
462 if (stat(path, &info) < 0) {
463 log_sys_very_verbose("stat", path);
464 return 0;
465 }
466
467 if (!S_ISREG(info.st_mode)) {
468 log_debug("%s: Not a regular file", path);
469 return 0;
470 }
471
472 if (!_insert_dev(path, 0))
473 return_0;
474
475 return 1;
476}
477
478#ifdef UDEV_SYNC_SUPPORT
479
480static int _device_in_udev_db(const dev_t d)
481{
482 struct udev *udev;
483 struct udev_device *udev_device;
484
485 if (!(udev = udev_get_library_context()))
486 return_0;
487
488 if ((udev_device = udev_device_new_from_devnum(udev, 'b', d))) {
489 udev_device_unref(udev_device);
490 return 1;
491 }
492
493 return 0;
494}
495
496static int _insert_udev_dir(struct udev *udev, const char *dir)
497{
498 struct udev_enumerate *udev_enum = NULL;
499 struct udev_list_entry *device_entry, *symlink_entry;
500 const char *node_name, *symlink_name;
501 struct udev_device *device;
502 int r = 1;
503
504 if (!(udev_enum = udev_enumerate_new(udev)))
505 goto bad;
506
507 if (udev_enumerate_add_match_subsystem(udev_enum, "block") ||
508 udev_enumerate_scan_devices(udev_enum))
509 goto bad;
510
511 udev_list_entry_foreach(device_entry, udev_enumerate_get_list_entry(udev_enum)) {
512 if (!(device = udev_device_new_from_syspath(udev, udev_list_entry_get_name(device_entry)))) {
513 log_warn("WARNING: udev failed to return a device entry.");
514 continue;
515 }
516
517 if (!(node_name = udev_device_get_devnode(device)))
518 log_warn("WARNING: udev failed to return a device node.");
519 else
520 r &= _insert(node_name, 0, 0);
521
522 udev_list_entry_foreach(symlink_entry, udev_device_get_devlinks_list_entry(device)) {
523 if (!(symlink_name = udev_list_entry_get_name(symlink_entry)))
524 log_warn("WARNING: udev failed to return a symlink name.");
525 else
526 r &= _insert(symlink_name, 0, 0);
527 }
528
529 udev_device_unref(device);
530 }
531
532 udev_enumerate_unref(udev_enum);
533 return r;
534
535bad:
536 log_error("Failed to enumerate udev device list.");
537 udev_enumerate_unref(udev_enum);
538 return 0;
539}
540
541static void _insert_dirs(struct dm_list *dirs)
542{
543 struct dir_list *dl;
544 struct udev *udev;
545 int with_udev;
546
547 with_udev = obtain_device_list_from_udev() &&
548 (udev = udev_get_library_context());
549
550 dm_list_iterate_items(dl, &_cache.dirs) {
551 if (with_udev) {
552 if (!_insert_udev_dir(udev, dl->dir))
553 log_debug("%s: Failed to insert devices from "
554 "udev-managed directory to device "
555 "cache fully", dl->dir);
556 }
557 else if (!_insert_dir(dl->dir))
558 log_debug("%s: Failed to insert devices to "
559 "device cache fully", dl->dir);
560 }
561}
562
563#else /* UDEV_SYNC_SUPPORT */
564
565static int _device_in_udev_db(const dev_t d)
566{
567 return 0;
568}
569
570static void _insert_dirs(struct dm_list *dirs)
571{
572 struct dir_list *dl;
573
574 dm_list_iterate_items(dl, &_cache.dirs)
575 _insert_dir(dl->dir);
576}
577
578#endif /* UDEV_SYNC_SUPPORT */
579
580static int _insert(const char *path, int rec, int check_with_udev_db)
581{
582 struct stat info;
583 int r = 0;
584
585 if (stat(path, &info) < 0) {
586 log_sys_very_verbose("stat", path);
587 return 0;
588 }
589
590 if (check_with_udev_db && !_device_in_udev_db(info.st_rdev)) {
591 log_very_verbose("%s: Not in udev db", path);
592 return 0;
593 }
594
595 if (S_ISDIR(info.st_mode)) { /* add a directory */
596 /* check it's not a symbolic link */
597 if (lstat(path, &info) < 0) {
598 log_sys_very_verbose("lstat", path);
599 return 0;
600 }
601
602 if (S_ISLNK(info.st_mode)) {
603 log_debug("%s: Symbolic link to directory", path);
604 return 0;
605 }
606
607 if (rec)
608 r = _insert_dir(path);
609
610 } else { /* add a device */
611 if (!S_ISBLK(info.st_mode)) {
612 log_debug("%s: Not a block device", path);
613 return 0;
614 }
615
616 if (!_insert_dev(path, info.st_rdev))
617 return_0;
618
619 r = 1;
620 }
621
622 return r;
623}
624
625static void _full_scan(int dev_scan)
626{
627 struct dir_list *dl;
628
629 if (_cache.has_scanned && !dev_scan)
630 return;
631
632 _insert_dirs(&_cache.dirs);
633
634 dm_list_iterate_items(dl, &_cache.files)
635 _insert_file(dl->dir);
636
637 _cache.has_scanned = 1;
638 init_full_scan_done(1);
639}
640
641int dev_cache_has_scanned(void)
642{
643 return _cache.has_scanned;
644}
645
646void dev_cache_scan(int do_scan)
647{
648 if (!do_scan)
649 _cache.has_scanned = 1;
650 else
651 _full_scan(1);
652}
653
654static int _init_preferred_names(struct cmd_context *cmd)
655{
656 const struct dm_config_node *cn;
657 const struct dm_config_value *v;
658 struct dm_pool *scratch = NULL;
659 const char **regex;
660 unsigned count = 0;
661 int i, r = 0;
662
663 _cache.preferred_names_matcher = NULL;
664
665 if (!(cn = find_config_tree_node(cmd, "devices/preferred_names")) ||
666 cn->v->type == DM_CFG_EMPTY_ARRAY) {
667 log_very_verbose("devices/preferred_names not found in config file: "
668 "using built-in preferences");
669 return 1;
670 }
671
672 for (v = cn->v; v; v = v->next) {
673 if (v->type != DM_CFG_STRING) {
674 log_error("preferred_names patterns must be enclosed in quotes");
675 return 0;
676 }
677
678 count++;
679 }
680
681 if (!(scratch = dm_pool_create("preferred device name matcher", 1024)))
682 return_0;
683
684 if (!(regex = dm_pool_alloc(scratch, sizeof(*regex) * count))) {
685 log_error("Failed to allocate preferred device name "
686 "pattern list.");
687 goto out;
688 }
689
690 for (v = cn->v, i = count - 1; v; v = v->next, i--) {
691 if (!(regex[i] = dm_pool_strdup(scratch, v->v.str))) {
692 log_error("Failed to allocate a preferred device name "
693 "pattern.");
694 goto out;
695 }
696 }
697
698 if (!(_cache.preferred_names_matcher =
699 dm_regex_create(_cache.mem, regex, count))) {
700 log_error("Preferred device name pattern matcher creation failed.");
701 goto out;
702 }
703
704 r = 1;
705
706out:
707 dm_pool_destroy(scratch);
708
709 return r;
710}
711
712int dev_cache_init(struct cmd_context *cmd)
713{
714 _cache.names = NULL;
715 _cache.has_scanned = 0;
716
717 if (!(_cache.mem = dm_pool_create("dev_cache", 10 * 1024)))
718 return_0;
719
720 if (!(_cache.names = dm_hash_create(128))) {
721 dm_pool_destroy(_cache.mem);
722 _cache.mem = 0;
723 return_0;
724 }
725
726 if (!(_cache.devices = btree_create(_cache.mem))) {
727 log_error("Couldn't create binary tree for dev-cache.");
728 goto bad;
729 }
730
731 if (!(_cache.dev_dir = _strdup(cmd->dev_dir))) {
732 log_error("strdup dev_dir failed.");
733 goto bad;
734 }
735
736 dm_list_init(&_cache.dirs);
737 dm_list_init(&_cache.files);
738
739 if (!_init_preferred_names(cmd))
740 goto_bad;
741
742 return 1;
743
744 bad:
745 dev_cache_exit();
746 return 0;
747}
748
749static void _check_closed(struct device *dev)
750{
751 if (dev->fd >= 0)
752 log_error("Device '%s' has been left open.", dev_name(dev));
753}
754
755static void _check_for_open_devices(void)
756{
757 dm_hash_iter(_cache.names, (dm_hash_iterate_fn) _check_closed);
758}
759
760void dev_cache_exit(void)
761{
762 if (_cache.names)
763 _check_for_open_devices();
764
765 if (_cache.preferred_names_matcher)
766 _cache.preferred_names_matcher = NULL;
767
768 if (_cache.mem) {
769 dm_pool_destroy(_cache.mem);
770 _cache.mem = NULL;
771 }
772
773 if (_cache.names) {
774 dm_hash_destroy(_cache.names);
775 _cache.names = NULL;
776 }
777
778 _cache.devices = NULL;
779 _cache.has_scanned = 0;
780 dm_list_init(&_cache.dirs);
781 dm_list_init(&_cache.files);
782}
783
784int dev_cache_add_dir(const char *path)
785{
786 struct dir_list *dl;
787 struct stat st;
788
789 if (stat(path, &st)) {
790 log_error("Ignoring %s: %s", path, strerror(errno));
791 /* But don't fail */
792 return 1;
793 }
794
795 if (!S_ISDIR(st.st_mode)) {
796 log_error("Ignoring %s: Not a directory", path);
797 return 1;
798 }
799
800 if (!(dl = _zalloc(sizeof(*dl) + strlen(path) + 1))) {
801 log_error("dir_list allocation failed");
802 return 0;
803 }
804
805 strcpy(dl->dir, path);
806 dm_list_add(&_cache.dirs, &dl->list);
807 return 1;
808}
809
810int dev_cache_add_loopfile(const char *path)
811{
812 struct dir_list *dl;
813 struct stat st;
814
815 if (stat(path, &st)) {
816 log_error("Ignoring %s: %s", path, strerror(errno));
817 /* But don't fail */
818 return 1;
819 }
820
821 if (!S_ISREG(st.st_mode)) {
822 log_error("Ignoring %s: Not a regular file", path);
823 return 1;
824 }
825
826 if (!(dl = _zalloc(sizeof(*dl) + strlen(path) + 1))) {
827 log_error("dir_list allocation failed for file");
828 return 0;
829 }
830
831 strcpy(dl->dir, path);
832 dm_list_add(&_cache.files, &dl->list);
833 return 1;
834}
835
836/* Check cached device name is still valid before returning it */
837/* This should be a rare occurrence */
838/* set quiet if the cache is expected to be out-of-date */
839/* FIXME Make rest of code pass/cache struct device instead of dev_name */
840const char *dev_name_confirmed(struct device *dev, int quiet)
841{
842 struct stat buf;
843 const char *name;
844 int r;
845
846 if ((dev->flags & DEV_REGULAR))
847 return dev_name(dev);
848
849 while ((r = stat(name = dm_list_item(dev->aliases.n,
850 struct str_list)->str, &buf)) ||
851 (buf.st_rdev != dev->dev)) {
852 if (r < 0) {
853 if (quiet)
854 log_sys_debug("stat", name);
855 else
856 log_sys_error("stat", name);
857 }
858 if (quiet)
859 log_debug("Path %s no longer valid for device(%d,%d)",
860 name, (int) MAJOR(dev->dev),
861 (int) MINOR(dev->dev));
862 else
863 log_error("Path %s no longer valid for device(%d,%d)",
864 name, (int) MAJOR(dev->dev),
865 (int) MINOR(dev->dev));
866
867 /* Remove the incorrect hash entry */
868 dm_hash_remove(_cache.names, name);
869
870 /* Leave list alone if there isn't an alternative name */
871 /* so dev_name will always find something to return. */
872 /* Otherwise add the name to the correct device. */
873 if (dm_list_size(&dev->aliases) > 1) {
874 dm_list_del(dev->aliases.n);
875 if (!r)
876 _insert(name, 0, obtain_device_list_from_udev());
877 continue;
878 }
879
880 /* Scanning issues this inappropriately sometimes. */
881 log_debug("Aborting - please provide new pathname for what "
882 "used to be %s", name);
883 return NULL;
884 }
885
886 return dev_name(dev);
887}
888
889struct device *dev_cache_get(const char *name, struct dev_filter *f)
890{
891 struct stat buf;
892 struct device *d = (struct device *) dm_hash_lookup(_cache.names, name);
893
894 if (d && (d->flags & DEV_REGULAR))
895 return d;
896
897 /* If the entry's wrong, remove it */
898 if (d && (stat(name, &buf) || (buf.st_rdev != d->dev))) {
899 dm_hash_remove(_cache.names, name);
900 d = NULL;
901 }
902
903 if (!d) {
904 _insert(name, 0, obtain_device_list_from_udev());
905 d = (struct device *) dm_hash_lookup(_cache.names, name);
906 if (!d) {
907 _full_scan(0);
908 d = (struct device *) dm_hash_lookup(_cache.names, name);
909 }
910 }
911
912 return (d && (!f || (d->flags & DEV_REGULAR) ||
913 f->passes_filter(f, d))) ? d : NULL;
914}
915
916static struct device *_dev_cache_seek_devt(dev_t dev)
917{
918 struct device *d = NULL;
919 struct dm_hash_node *n = dm_hash_get_first(_cache.names);
920 while (n) {
921 d = dm_hash_get_data(_cache.names, n);
922 if (d->dev == dev)
923 return d;
924 n = dm_hash_get_next(_cache.names, n);
925 }
926 return NULL;
927}
928
929/*
930 * TODO This is very inefficient. We probably want a hash table indexed by
931 * major:minor for keys to speed up these lookups.
932 */
933struct device *dev_cache_get_by_devt(dev_t dev, struct dev_filter *f)
934{
935 struct device *d = _dev_cache_seek_devt(dev);
936
937 if (d && (d->flags & DEV_REGULAR))
938 return d;
939
940 if (!d) {
941 _full_scan(0);
942 d = _dev_cache_seek_devt(dev);
943 }
944
945 return (d && (!f || (d->flags & DEV_REGULAR) ||
946 f->passes_filter(f, d))) ? d : NULL;
947}
948
949struct dev_iter *dev_iter_create(struct dev_filter *f, int dev_scan)
950{
951 struct dev_iter *di = dm_malloc(sizeof(*di));
952
953 if (!di) {
954 log_error("dev_iter allocation failed");
955 return NULL;
956 }
957
958 if (dev_scan && !trust_cache()) {
959 /* Flag gets reset between each command */
960 if (!full_scan_done())
961 persistent_filter_wipe(f); /* Calls _full_scan(1) */
962 } else
963 _full_scan(0);
964
965 di->current = btree_first(_cache.devices);
966 di->filter = f;
967 di->filter->use_count++;
968
969 return di;
970}
971
972void dev_iter_destroy(struct dev_iter *iter)
973{
974 iter->filter->use_count--;
975 dm_free(iter);
976}
977
978static struct device *_iter_next(struct dev_iter *iter)
979{
980 struct device *d = btree_get_data(iter->current);
981 iter->current = btree_next(iter->current);
982 return d;
983}
984
985struct device *dev_iter_get(struct dev_iter *iter)
986{
987 while (iter->current) {
988 struct device *d = _iter_next(iter);
989 if (!iter->filter || (d->flags & DEV_REGULAR) ||
990 iter->filter->passes_filter(iter->filter, d))
991 return d;
992 }
993
994 return NULL;
995}
996
997void dev_reset_error_count(struct cmd_context *cmd)
998{
999 struct dev_iter iter;
1000
1001 if (!_cache.devices)
1002 return;
1003
1004 iter.current = btree_first(_cache.devices);
1005 while (iter.current)
1006 _iter_next(&iter)->error_count = 0;
1007}
1008
1009int dev_fd(struct device *dev)
1010{
1011 return dev->fd;
1012}
1013
1014const char *dev_name(const struct device *dev)
1015{
1016 return (dev) ? dm_list_item(dev->aliases.n, struct str_list)->str :
1017 "unknown device";
1018}
01019
=== removed file '.pc/avoid-dev-block.patch/lib/device/dev-cache.c'
--- .pc/avoid-dev-block.patch/lib/device/dev-cache.c 2012-04-14 02:57:53 +0000
+++ .pc/avoid-dev-block.patch/lib/device/dev-cache.c 1970-01-01 00:00:00 +0000
@@ -1,976 +0,0 @@
1/*
2 * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
3 * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
4 *
5 * This file is part of LVM2.
6 *
7 * This copyrighted material is made available to anyone wishing to use,
8 * modify, copy, or redistribute it subject to the terms and conditions
9 * of the GNU Lesser General Public License v.2.1.
10 *
11 * You should have received a copy of the GNU Lesser General Public License
12 * along with this program; if not, write to the Free Software Foundation,
13 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
14 */
15
16#include "lib.h"
17#include "dev-cache.h"
18#include "lvm-types.h"
19#include "btree.h"
20#include "filter.h"
21#include "filter-persistent.h"
22#include "toolcontext.h"
23
24#include <unistd.h>
25#include <sys/param.h>
26#include <dirent.h>
27
28struct dev_iter {
29 struct btree_iter *current;
30 struct dev_filter *filter;
31};
32
33struct dir_list {
34 struct dm_list list;
35 char dir[0];
36};
37
38static struct {
39 struct dm_pool *mem;
40 struct dm_hash_table *names;
41 struct btree *devices;
42 struct dm_regex *preferred_names_matcher;
43 const char *dev_dir;
44
45 int has_scanned;
46 struct dm_list dirs;
47 struct dm_list files;
48
49} _cache;
50
51#define _alloc(x) dm_pool_zalloc(_cache.mem, (x))
52#define _free(x) dm_pool_free(_cache.mem, (x))
53#define _strdup(x) dm_pool_strdup(_cache.mem, (x))
54
55static int _insert(const char *path, int rec, int check_with_udev_db);
56
57struct device *dev_create_file(const char *filename, struct device *dev,
58 struct str_list *alias, int use_malloc)
59{
60 int allocate = !dev;
61
62 if (allocate) {
63 if (use_malloc) {
64 if (!(dev = dm_malloc(sizeof(*dev)))) {
65 log_error("struct device allocation failed");
66 return NULL;
67 }
68 if (!(alias = dm_malloc(sizeof(*alias)))) {
69 log_error("struct str_list allocation failed");
70 dm_free(dev);
71 return NULL;
72 }
73 if (!(alias->str = dm_strdup(filename))) {
74 log_error("filename strdup failed");
75 dm_free(dev);
76 dm_free(alias);
77 return NULL;
78 }
79 dev->flags = DEV_ALLOCED;
80 } else {
81 if (!(dev = _alloc(sizeof(*dev)))) {
82 log_error("struct device allocation failed");
83 return NULL;
84 }
85 if (!(alias = _alloc(sizeof(*alias)))) {
86 log_error("struct str_list allocation failed");
87 _free(dev);
88 return NULL;
89 }
90 if (!(alias->str = _strdup(filename))) {
91 log_error("filename strdup failed");
92 return NULL;
93 }
94 }
95 } else if (!(alias->str = dm_strdup(filename))) {
96 log_error("filename strdup failed");
97 return NULL;
98 }
99
100 dev->flags |= DEV_REGULAR;
101 dm_list_init(&dev->aliases);
102 dm_list_add(&dev->aliases, &alias->list);
103 dev->end = UINT64_C(0);
104 dev->dev = 0;
105 dev->fd = -1;
106 dev->open_count = 0;
107 dev->error_count = 0;
108 dev->max_error_count = NO_DEV_ERROR_COUNT_LIMIT;
109 dev->block_size = -1;
110 dev->read_ahead = -1;
111 memset(dev->pvid, 0, sizeof(dev->pvid));
112 dm_list_init(&dev->open_list);
113
114 return dev;
115}
116
117static struct device *_dev_create(dev_t d)
118{
119 struct device *dev;
120
121 if (!(dev = _alloc(sizeof(*dev)))) {
122 log_error("struct device allocation failed");
123 return NULL;
124 }
125 dev->flags = 0;
126 dm_list_init(&dev->aliases);
127 dev->dev = d;
128 dev->fd = -1;
129 dev->open_count = 0;
130 dev->max_error_count = dev_disable_after_error_count();
131 dev->block_size = -1;
132 dev->read_ahead = -1;
133 dev->end = UINT64_C(0);
134 memset(dev->pvid, 0, sizeof(dev->pvid));
135 dm_list_init(&dev->open_list);
136
137 return dev;
138}
139
140void dev_set_preferred_name(struct str_list *sl, struct device *dev)
141{
142 /*
143 * Don't interfere with ordering specified in config file.
144 */
145 if (_cache.preferred_names_matcher)
146 return;
147
148 log_debug("%s: New preferred name", sl->str);
149 dm_list_del(&sl->list);
150 dm_list_add_h(&dev->aliases, &sl->list);
151}
152
153/*
154 * Check whether path0 or path1 contains the subpath. The path that
155 * *does not* contain the subpath wins (return 0 or 1). If both paths
156 * contain the subpath, return -1. If none of them contains the subpath,
157 * return -2.
158 */
159static int _builtin_preference(const char *path0, const char *path1,
160 size_t skip_prefix_count, const char *subpath)
161{
162 size_t subpath_len;
163 int r0, r1;
164
165 subpath_len = strlen(subpath);
166
167 r0 = !strncmp(path0 + skip_prefix_count, subpath, subpath_len);
168 r1 = !strncmp(path1 + skip_prefix_count, subpath, subpath_len);
169
170 if (!r0 && r1)
171 /* path0 does not have the subpath - it wins */
172 return 0;
173 else if (r0 && !r1)
174 /* path1 does not have the subpath - it wins */
175 return 1;
176 else if (r0 && r1)
177 /* both of them have the subpath */
178 return -1;
179
180 /* no path has the subpath */
181 return -2;
182}
183
184static int _apply_builtin_path_preference_rules(const char *path0, const char *path1)
185{
186 size_t devdir_len;
187 int r;
188
189 devdir_len = strlen(_cache.dev_dir);
190
191 if (!strncmp(path0, _cache.dev_dir, devdir_len) &&
192 !strncmp(path1, _cache.dev_dir, devdir_len)) {
193 /*
194 * We're trying to achieve the ordering:
195 * /dev/block/ < /dev/dm-* < /dev/disk/ < /dev/mapper/ < anything else
196 */
197
198 /* Prefer any other path over /dev/block/ path. */
199 if ((r = _builtin_preference(path0, path1, devdir_len, "block/")) >= -1)
200 return r;
201
202 /* Prefer any other path over /dev/dm-* path. */
203 if ((r = _builtin_preference(path0, path1, devdir_len, "dm-")) >= -1)
204 return r;
205
206 /* Prefer any other path over /dev/disk/ path. */
207 if ((r = _builtin_preference(path0, path1, devdir_len, "disk/")) >= -1)
208 return r;
209
210 /* Prefer any other path over /dev/mapper/ path. */
211 if ((r = _builtin_preference(path0, path1, 0, dm_dir())) >= -1)
212 return r;
213 }
214
215 return -1;
216}
217
218/* Return 1 if we prefer path1 else return 0 */
219static int _compare_paths(const char *path0, const char *path1)
220{
221 int slash0 = 0, slash1 = 0;
222 int m0, m1;
223 const char *p;
224 char p0[PATH_MAX], p1[PATH_MAX];
225 char *s0, *s1;
226 struct stat stat0, stat1;
227 int r;
228
229 /*
230 * FIXME Better to compare patterns one-at-a-time against all names.
231 */
232 if (_cache.preferred_names_matcher) {
233 m0 = dm_regex_match(_cache.preferred_names_matcher, path0);
234 m1 = dm_regex_match(_cache.preferred_names_matcher, path1);
235
236 if (m0 != m1) {
237 if (m0 < 0)
238 return 1;
239 if (m1 < 0)
240 return 0;
241 if (m0 < m1)
242 return 1;
243 if (m1 < m0)
244 return 0;
245 }
246 }
247
248 /* Apply built-in preference rules first. */
249 if ((r = _apply_builtin_path_preference_rules(path0, path1)) >= 0)
250 return r;
251
252 /* Return the path with fewer slashes */
253 for (p = path0; p++; p = (const char *) strchr(p, '/'))
254 slash0++;
255
256 for (p = path1; p++; p = (const char *) strchr(p, '/'))
257 slash1++;
258
259 if (slash0 < slash1)
260 return 0;
261 if (slash1 < slash0)
262 return 1;
263
264 strncpy(p0, path0, PATH_MAX);
265 strncpy(p1, path1, PATH_MAX);
266 s0 = &p0[0] + 1;
267 s1 = &p1[0] + 1;
268
269 /* We prefer symlinks - they exist for a reason!
270 * So we prefer a shorter path before the first symlink in the name.
271 * FIXME Configuration option to invert this? */
272 while (s0) {
273 s0 = strchr(s0, '/');
274 s1 = strchr(s1, '/');
275 if (s0) {
276 *s0 = '\0';
277 *s1 = '\0';
278 }
279 if (lstat(p0, &stat0)) {
280 log_sys_very_verbose("lstat", p0);
281 return 1;
282 }
283 if (lstat(p1, &stat1)) {
284 log_sys_very_verbose("lstat", p1);
285 return 0;
286 }
287 if (S_ISLNK(stat0.st_mode) && !S_ISLNK(stat1.st_mode))
288 return 0;
289 if (!S_ISLNK(stat0.st_mode) && S_ISLNK(stat1.st_mode))
290 return 1;
291 if (s0) {
292 *s0++ = '/';
293 *s1++ = '/';
294 }
295 }
296
297 /* ASCII comparison */
298 if (strcmp(path0, path1) < 0)
299 return 0;
300 else
301 return 1;
302}
303
304static int _add_alias(struct device *dev, const char *path)
305{
306 struct str_list *sl = _alloc(sizeof(*sl));
307 struct str_list *strl;
308 const char *oldpath;
309 int prefer_old = 1;
310
311 if (!sl)
312 return_0;
313
314 /* Is name already there? */
315 dm_list_iterate_items(strl, &dev->aliases) {
316 if (!strcmp(strl->str, path)) {
317 log_debug("%s: Already in device cache", path);
318 return 1;
319 }
320 }
321
322 sl->str = path;
323
324 if (!dm_list_empty(&dev->aliases)) {
325 oldpath = dm_list_item(dev->aliases.n, struct str_list)->str;
326 prefer_old = _compare_paths(path, oldpath);
327 log_debug("%s: Aliased to %s in device cache%s",
328 path, oldpath, prefer_old ? "" : " (preferred name)");
329
330 } else
331 log_debug("%s: Added to device cache", path);
332
333 if (prefer_old)
334 dm_list_add(&dev->aliases, &sl->list);
335 else
336 dm_list_add_h(&dev->aliases, &sl->list);
337
338 return 1;
339}
340
341/*
342 * Either creates a new dev, or adds an alias to
343 * an existing dev.
344 */
345static int _insert_dev(const char *path, dev_t d)
346{
347 struct device *dev;
348 static dev_t loopfile_count = 0;
349 int loopfile = 0;
350 char *path_copy;
351
352 /* Generate pretend device numbers for loopfiles */
353 if (!d) {
354 if (dm_hash_lookup(_cache.names, path))
355 return 1;
356 d = ++loopfile_count;
357 loopfile = 1;
358 }
359
360 /* is this device already registered ? */
361 if (!(dev = (struct device *) btree_lookup(_cache.devices,
362 (uint32_t) d))) {
363 /* create new device */
364 if (loopfile) {
365 if (!(dev = dev_create_file(path, NULL, NULL, 0)))
366 return_0;
367 } else if (!(dev = _dev_create(d)))
368 return_0;
369
370 if (!(btree_insert(_cache.devices, (uint32_t) d, dev))) {
371 log_error("Couldn't insert device into binary tree.");
372 _free(dev);
373 return 0;
374 }
375 }
376
377 if (!(path_copy = dm_pool_strdup(_cache.mem, path))) {
378 log_error("Failed to duplicate path string.");
379 return 0;
380 }
381
382 if (!loopfile && !_add_alias(dev, path_copy)) {
383 log_error("Couldn't add alias to dev cache.");
384 return 0;
385 }
386
387 if (!dm_hash_insert(_cache.names, path_copy, dev)) {
388 log_error("Couldn't add name to hash in dev cache.");
389 return 0;
390 }
391
392 return 1;
393}
394
395static char *_join(const char *dir, const char *name)
396{
397 size_t len = strlen(dir) + strlen(name) + 2;
398 char *r = dm_malloc(len);
399 if (r)
400 snprintf(r, len, "%s/%s", dir, name);
401
402 return r;
403}
404
405/*
406 * Get rid of extra slashes in the path string.
407 */
408static void _collapse_slashes(char *str)
409{
410 char *ptr;
411 int was_slash = 0;
412
413 for (ptr = str; *ptr; ptr++) {
414 if (*ptr == '/') {
415 if (was_slash)
416 continue;
417
418 was_slash = 1;
419 } else
420 was_slash = 0;
421 *str++ = *ptr;
422 }
423
424 *str = *ptr;
425}
426
427static int _insert_dir(const char *dir)
428{
429 int n, dirent_count, r = 1;
430 struct dirent **dirent;
431 char *path;
432
433 dirent_count = scandir(dir, &dirent, NULL, alphasort);
434 if (dirent_count > 0) {
435 for (n = 0; n < dirent_count; n++) {
436 if (dirent[n]->d_name[0] == '.') {
437 free(dirent[n]);
438 continue;
439 }
440
441 if (!(path = _join(dir, dirent[n]->d_name)))
442 return_0;
443
444 _collapse_slashes(path);
445 r &= _insert(path, 1, 0);
446 dm_free(path);
447
448 free(dirent[n]);
449 }
450 free(dirent);
451 }
452
453 return r;
454}
455
456static int _insert_file(const char *path)
457{
458 struct stat info;
459
460 if (stat(path, &info) < 0) {
461 log_sys_very_verbose("stat", path);
462 return 0;
463 }
464
465 if (!S_ISREG(info.st_mode)) {
466 log_debug("%s: Not a regular file", path);
467 return 0;
468 }
469
470 if (!_insert_dev(path, 0))
471 return_0;
472
473 return 1;
474}
475
476#ifdef UDEV_SYNC_SUPPORT
477
478static int _device_in_udev_db(const dev_t d)
479{
480 struct udev *udev;
481 struct udev_device *udev_device;
482
483 if (!(udev = udev_get_library_context()))
484 return_0;
485
486 if ((udev_device = udev_device_new_from_devnum(udev, 'b', d))) {
487 udev_device_unref(udev_device);
488 return 1;
489 }
490
491 return 0;
492}
493
494static int _insert_udev_dir(struct udev *udev, const char *dir)
495{
496 struct udev_enumerate *udev_enum = NULL;
497 struct udev_list_entry *device_entry, *symlink_entry;
498 const char *node_name, *symlink_name;
499 struct udev_device *device;
500 int r = 1;
501
502 if (!(udev_enum = udev_enumerate_new(udev)))
503 goto bad;
504
505 if (udev_enumerate_add_match_subsystem(udev_enum, "block") ||
506 udev_enumerate_scan_devices(udev_enum))
507 goto bad;
508
509 udev_list_entry_foreach(device_entry, udev_enumerate_get_list_entry(udev_enum)) {
510 device = udev_device_new_from_syspath(udev, udev_list_entry_get_name(device_entry));
511
512 node_name = udev_device_get_devnode(device);
513 r &= _insert(node_name, 0, 0);
514
515 udev_list_entry_foreach(symlink_entry, udev_device_get_devlinks_list_entry(device)) {
516 symlink_name = udev_list_entry_get_name(symlink_entry);
517 r &= _insert(symlink_name, 0, 0);
518 }
519
520 udev_device_unref(device);
521 }
522
523 udev_enumerate_unref(udev_enum);
524 return r;
525
526bad:
527 log_error("Failed to enumerate udev device list.");
528 udev_enumerate_unref(udev_enum);
529 return 0;
530}
531
532static void _insert_dirs(struct dm_list *dirs)
533{
534 struct dir_list *dl;
535 struct udev *udev;
536 int with_udev;
537
538 with_udev = obtain_device_list_from_udev() &&
539 (udev = udev_get_library_context());
540
541 dm_list_iterate_items(dl, &_cache.dirs) {
542 if (with_udev) {
543 if (!_insert_udev_dir(udev, dl->dir))
544 log_debug("%s: Failed to insert devices from "
545 "udev-managed directory to device "
546 "cache fully", dl->dir);
547 }
548 else if (!_insert_dir(dl->dir))
549 log_debug("%s: Failed to insert devices to "
550 "device cache fully", dl->dir);
551 }
552}
553
554#else /* UDEV_SYNC_SUPPORT */
555
556static int _device_in_udev_db(const dev_t d)
557{
558 return 0;
559}
560
561static void _insert_dirs(struct dm_list *dirs)
562{
563 struct dir_list *dl;
564
565 dm_list_iterate_items(dl, &_cache.dirs)
566 _insert_dir(dl->dir);
567}
568
569#endif /* UDEV_SYNC_SUPPORT */
570
571static int _insert(const char *path, int rec, int check_with_udev_db)
572{
573 struct stat info;
574 int r = 0;
575
576 if (stat(path, &info) < 0) {
577 log_sys_very_verbose("stat", path);
578 return 0;
579 }
580
581 if (check_with_udev_db && !_device_in_udev_db(info.st_rdev)) {
582 log_very_verbose("%s: Not in udev db", path);
583 return 0;
584 }
585
586 if (S_ISDIR(info.st_mode)) { /* add a directory */
587 /* check it's not a symbolic link */
588 if (lstat(path, &info) < 0) {
589 log_sys_very_verbose("lstat", path);
590 return 0;
591 }
592
593 if (S_ISLNK(info.st_mode)) {
594 log_debug("%s: Symbolic link to directory", path);
595 return 0;
596 }
597
598 if (rec)
599 r = _insert_dir(path);
600
601 } else { /* add a device */
602 if (!S_ISBLK(info.st_mode)) {
603 log_debug("%s: Not a block device", path);
604 return 0;
605 }
606
607 if (!_insert_dev(path, info.st_rdev))
608 return_0;
609
610 r = 1;
611 }
612
613 return r;
614}
615
616static void _full_scan(int dev_scan)
617{
618 struct dir_list *dl;
619
620 if (_cache.has_scanned && !dev_scan)
621 return;
622
623 _insert_dirs(&_cache.dirs);
624
625 dm_list_iterate_items(dl, &_cache.files)
626 _insert_file(dl->dir);
627
628 _cache.has_scanned = 1;
629 init_full_scan_done(1);
630}
631
632int dev_cache_has_scanned(void)
633{
634 return _cache.has_scanned;
635}
636
637void dev_cache_scan(int do_scan)
638{
639 if (!do_scan)
640 _cache.has_scanned = 1;
641 else
642 _full_scan(1);
643}
644
645static int _init_preferred_names(struct cmd_context *cmd)
646{
647 const struct config_node *cn;
648 const struct config_value *v;
649 struct dm_pool *scratch = NULL;
650 const char **regex;
651 unsigned count = 0;
652 int i, r = 0;
653
654 _cache.preferred_names_matcher = NULL;
655
656 if (!(cn = find_config_tree_node(cmd, "devices/preferred_names")) ||
657 cn->v->type == CFG_EMPTY_ARRAY) {
658 log_very_verbose("devices/preferred_names not found in config file: "
659 "using built-in preferences");
660 return 1;
661 }
662
663 for (v = cn->v; v; v = v->next) {
664 if (v->type != CFG_STRING) {
665 log_error("preferred_names patterns must be enclosed in quotes");
666 return 0;
667 }
668
669 count++;
670 }
671
672 if (!(scratch = dm_pool_create("preferred device name matcher", 1024)))
673 return_0;
674
675 if (!(regex = dm_pool_alloc(scratch, sizeof(*regex) * count))) {
676 log_error("Failed to allocate preferred device name "
677 "pattern list.");
678 goto out;
679 }
680
681 for (v = cn->v, i = count - 1; v; v = v->next, i--) {
682 if (!(regex[i] = dm_pool_strdup(scratch, v->v.str))) {
683 log_error("Failed to allocate a preferred device name "
684 "pattern.");
685 goto out;
686 }
687 }
688
689 if (!(_cache.preferred_names_matcher =
690 dm_regex_create(_cache.mem, regex, count))) {
691 log_error("Preferred device name pattern matcher creation failed.");
692 goto out;
693 }
694
695 r = 1;
696
697out:
698 dm_pool_destroy(scratch);
699
700 return r;
701}
702
703int dev_cache_init(struct cmd_context *cmd)
704{
705 _cache.names = NULL;
706 _cache.has_scanned = 0;
707
708 if (!(_cache.mem = dm_pool_create("dev_cache", 10 * 1024)))
709 return_0;
710
711 if (!(_cache.names = dm_hash_create(128))) {
712 dm_pool_destroy(_cache.mem);
713 _cache.mem = 0;
714 return_0;
715 }
716
717 if (!(_cache.devices = btree_create(_cache.mem))) {
718 log_error("Couldn't create binary tree for dev-cache.");
719 goto bad;
720 }
721
722 if (!(_cache.dev_dir = _strdup(cmd->dev_dir))) {
723 log_error("strdup dev_dir failed.");
724 goto bad;
725 }
726
727 dm_list_init(&_cache.dirs);
728 dm_list_init(&_cache.files);
729
730 if (!_init_preferred_names(cmd))
731 goto_bad;
732
733 return 1;
734
735 bad:
736 dev_cache_exit();
737 return 0;
738}
739
740static void _check_closed(struct device *dev)
741{
742 if (dev->fd >= 0)
743 log_error("Device '%s' has been left open.", dev_name(dev));
744}
745
746static void _check_for_open_devices(void)
747{
748 dm_hash_iter(_cache.names, (dm_hash_iterate_fn) _check_closed);
749}
750
751void dev_cache_exit(void)
752{
753 if (_cache.names)
754 _check_for_open_devices();
755
756 if (_cache.preferred_names_matcher)
757 _cache.preferred_names_matcher = NULL;
758
759 if (_cache.mem) {
760 dm_pool_destroy(_cache.mem);
761 _cache.mem = NULL;
762 }
763
764 if (_cache.names) {
765 dm_hash_destroy(_cache.names);
766 _cache.names = NULL;
767 }
768
769 _cache.devices = NULL;
770 _cache.has_scanned = 0;
771 dm_list_init(&_cache.dirs);
772 dm_list_init(&_cache.files);
773}
774
775int dev_cache_add_dir(const char *path)
776{
777 struct dir_list *dl;
778 struct stat st;
779
780 if (stat(path, &st)) {
781 log_error("Ignoring %s: %s", path, strerror(errno));
782 /* But don't fail */
783 return 1;
784 }
785
786 if (!S_ISDIR(st.st_mode)) {
787 log_error("Ignoring %s: Not a directory", path);
788 return 1;
789 }
790
791 if (!(dl = _alloc(sizeof(*dl) + strlen(path) + 1))) {
792 log_error("dir_list allocation failed");
793 return 0;
794 }
795
796 strcpy(dl->dir, path);
797 dm_list_add(&_cache.dirs, &dl->list);
798 return 1;
799}
800
801int dev_cache_add_loopfile(const char *path)
802{
803 struct dir_list *dl;
804 struct stat st;
805
806 if (stat(path, &st)) {
807 log_error("Ignoring %s: %s", path, strerror(errno));
808 /* But don't fail */
809 return 1;
810 }
811
812 if (!S_ISREG(st.st_mode)) {
813 log_error("Ignoring %s: Not a regular file", path);
814 return 1;
815 }
816
817 if (!(dl = _alloc(sizeof(*dl) + strlen(path) + 1))) {
818 log_error("dir_list allocation failed for file");
819 return 0;
820 }
821
822 strcpy(dl->dir, path);
823 dm_list_add(&_cache.files, &dl->list);
824 return 1;
825}
826
827/* Check cached device name is still valid before returning it */
828/* This should be a rare occurrence */
829/* set quiet if the cache is expected to be out-of-date */
830/* FIXME Make rest of code pass/cache struct device instead of dev_name */
831const char *dev_name_confirmed(struct device *dev, int quiet)
832{
833 struct stat buf;
834 const char *name;
835 int r;
836
837 if ((dev->flags & DEV_REGULAR))
838 return dev_name(dev);
839
840 while ((r = stat(name = dm_list_item(dev->aliases.n,
841 struct str_list)->str, &buf)) ||
842 (buf.st_rdev != dev->dev)) {
843 if (r < 0) {
844 if (quiet)
845 log_sys_debug("stat", name);
846 else
847 log_sys_error("stat", name);
848 }
849 if (quiet)
850 log_debug("Path %s no longer valid for device(%d,%d)",
851 name, (int) MAJOR(dev->dev),
852 (int) MINOR(dev->dev));
853 else
854 log_error("Path %s no longer valid for device(%d,%d)",
855 name, (int) MAJOR(dev->dev),
856 (int) MINOR(dev->dev));
857
858 /* Remove the incorrect hash entry */
859 dm_hash_remove(_cache.names, name);
860
861 /* Leave list alone if there isn't an alternative name */
862 /* so dev_name will always find something to return. */
863 /* Otherwise add the name to the correct device. */
864 if (dm_list_size(&dev->aliases) > 1) {
865 dm_list_del(dev->aliases.n);
866 if (!r)
867 _insert(name, 0, obtain_device_list_from_udev());
868 continue;
869 }
870
871 /* Scanning issues this inappropriately sometimes. */
872 log_debug("Aborting - please provide new pathname for what "
873 "used to be %s", name);
874 return NULL;
875 }
876
877 return dev_name(dev);
878}
879
880struct device *dev_cache_get(const char *name, struct dev_filter *f)
881{
882 struct stat buf;
883 struct device *d = (struct device *) dm_hash_lookup(_cache.names, name);
884
885 if (d && (d->flags & DEV_REGULAR))
886 return d;
887
888 /* If the entry's wrong, remove it */
889 if (d && (stat(name, &buf) || (buf.st_rdev != d->dev))) {
890 dm_hash_remove(_cache.names, name);
891 d = NULL;
892 }
893
894 if (!d) {
895 _insert(name, 0, obtain_device_list_from_udev());
896 d = (struct device *) dm_hash_lookup(_cache.names, name);
897 if (!d) {
898 _full_scan(0);
899 d = (struct device *) dm_hash_lookup(_cache.names, name);
900 }
901 }
902
903 return (d && (!f || (d->flags & DEV_REGULAR) ||
904 f->passes_filter(f, d))) ? d : NULL;
905}
906
907struct dev_iter *dev_iter_create(struct dev_filter *f, int dev_scan)
908{
909 struct dev_iter *di = dm_malloc(sizeof(*di));
910
911 if (!di) {
912 log_error("dev_iter allocation failed");
913 return NULL;
914 }
915
916 if (dev_scan && !trust_cache()) {
917 /* Flag gets reset between each command */
918 if (!full_scan_done())
919 persistent_filter_wipe(f); /* Calls _full_scan(1) */
920 } else
921 _full_scan(0);
922
923 di->current = btree_first(_cache.devices);
924 di->filter = f;
925 di->filter->use_count++;
926
927 return di;
928}
929
930void dev_iter_destroy(struct dev_iter *iter)
931{
932 iter->filter->use_count--;
933 dm_free(iter);
934}
935
936static struct device *_iter_next(struct dev_iter *iter)
937{
938 struct device *d = btree_get_data(iter->current);
939 iter->current = btree_next(iter->current);
940 return d;
941}
942
943struct device *dev_iter_get(struct dev_iter *iter)
944{
945 while (iter->current) {
946 struct device *d = _iter_next(iter);
947 if (!iter->filter || (d->flags & DEV_REGULAR) ||
948 iter->filter->passes_filter(iter->filter, d))
949 return d;
950 }
951
952 return NULL;
953}
954
955void dev_reset_error_count(struct cmd_context *cmd)
956{
957 struct dev_iter iter;
958
959 if (!_cache.devices)
960 return;
961
962 iter.current = btree_first(_cache.devices);
963 while (iter.current)
964 _iter_next(&iter)->error_count = 0;
965}
966
967int dev_fd(struct device *dev)
968{
969 return dev->fd;
970}
971
972const char *dev_name(const struct device *dev)
973{
974 return (dev) ? dm_list_item(dev->aliases.n, struct str_list)->str :
975 "unknown device";
976}
9770
=== added directory '.pc/dirs.patch'
=== removed directory '.pc/dirs.patch'
=== added directory '.pc/dirs.patch/daemons'
=== added directory '.pc/dirs.patch/daemons/dmeventd'
=== added file '.pc/dirs.patch/daemons/dmeventd/Makefile.in'
--- .pc/dirs.patch/daemons/dmeventd/Makefile.in 1970-01-01 00:00:00 +0000
+++ .pc/dirs.patch/daemons/dmeventd/Makefile.in 2012-08-21 10:18:22 +0000
@@ -0,0 +1,108 @@
1#
2# Copyright (C) 2005-2011 Red Hat, Inc. All rights reserved.
3#
4# This file is part of the device-mapper userspace tools.
5#
6# This copyrighted material is made available to anyone wishing to use,
7# modify, copy, or redistribute it subject to the terms and conditions
8# of the GNU Lesser General Public License v.2.1.
9#
10# You should have received a copy of the GNU Lesser General Public License
11# along with this program; if not, write to the Free Software Foundation,
12# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
13
14srcdir = @srcdir@
15top_srcdir = @top_srcdir@
16top_builddir = @top_builddir@
17
18SOURCES = libdevmapper-event.c
19SOURCES2 = dmeventd.c
20
21TARGETS = dmeventd
22
23.PHONY: install_lib_dynamic install_lib_static install_include \
24 install_pkgconfig install_dmeventd_dynamic install_dmeventd_static \
25 install_lib install_dmeventd
26
27INSTALL_DMEVENTD_TARGETS = install_dmeventd_dynamic
28INSTALL_LIB_TARGETS = install_lib_dynamic
29
30LIB_NAME = libdevmapper-event
31ifeq ("@STATIC_LINK@", "yes")
32 LIB_STATIC = $(LIB_NAME).a
33 TARGETS += $(LIB_STATIC) dmeventd.static
34 INSTALL_DMEVENTD_TARGETS += install_dmeventd_static
35 INSTALL_LIB_TARGETS += install_lib_static
36endif
37
38LIB_VERSION = $(LIB_VERSION_DM)
39LIB_SHARED = $(LIB_NAME).$(LIB_SUFFIX)
40
41CLEAN_TARGETS = dmeventd.static $(LIB_NAME).a
42
43ifneq ($(MAKECMDGOALS),device-mapper)
44 SUBDIRS+=plugins
45endif
46
47CFLOW_LIST = $(SOURCES)
48CFLOW_LIST_TARGET = $(LIB_NAME).cflow
49CFLOW_TARGET = dmeventd
50
51EXPORTED_HEADER = $(srcdir)/libdevmapper-event.h
52EXPORTED_FN_PREFIX = dm_event
53
54include $(top_builddir)/make.tmpl
55
56all: device-mapper
57device-mapper: $(TARGETS)
58
59LIBS += -ldevmapper
60LVMLIBS += -ldevmapper-event $(PTHREAD_LIBS)
61
62dmeventd: $(LIB_SHARED) dmeventd.o
63 $(CC) $(CFLAGS) $(LDFLAGS) $(ELDFLAGS) -L. -o $@ dmeventd.o \
64 $(DL_LIBS) $(LVMLIBS) $(LIBS) -rdynamic
65
66dmeventd.static: $(LIB_STATIC) dmeventd.o $(interfacebuilddir)/libdevmapper.a
67 $(CC) $(CFLAGS) $(LDFLAGS) $(ELDFLAGS) -static -L. -L$(interfacebuilddir) -o $@ \
68 dmeventd.o $(DL_LIBS) $(LVMLIBS) $(LIBS) $(STATIC_LIBS)
69
70ifeq ("@PKGCONFIG@", "yes")
71 INSTALL_LIB_TARGETS += install_pkgconfig
72endif
73
74ifneq ("$(CFLOW_CMD)", "")
75CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES))
76-include $(top_builddir)/libdm/libdevmapper.cflow
77-include $(top_builddir)/lib/liblvm-internal.cflow
78-include $(top_builddir)/lib/liblvm2cmd.cflow
79-include $(top_builddir)/daemons/dmeventd/$(LIB_NAME).cflow
80-include $(top_builddir)/daemons/dmeventd/plugins/mirror/$(LIB_NAME)-lvm2mirror.cflow
81endif
82
83install_include: $(srcdir)/libdevmapper-event.h
84 $(INSTALL_DATA) -D $< $(includedir)/$(<F)
85
86install_pkgconfig: libdevmapper-event.pc
87 $(INSTALL_DATA) -D $< $(pkgconfigdir)/devmapper-event.pc
88
89install_lib_dynamic: install_lib_shared
90
91install_lib_static: $(LIB_STATIC)
92 $(INSTALL_DATA) -D $< $(usrlibdir)/$(<F)
93
94install_lib: $(INSTALL_LIB_TARGETS)
95
96install_dmeventd_dynamic: dmeventd
97 $(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
98
99install_dmeventd_static: dmeventd.static
100 $(INSTALL_PROGRAM) -D $< $(staticdir)/$(<F)
101
102install_dmeventd: $(INSTALL_DMEVENTD_TARGETS)
103
104install: install_include install_lib install_dmeventd
105
106install_device-mapper: install_include install_lib install_dmeventd
107
108DISTCLEAN_TARGETS += libdevmapper-event.pc
0109
=== added file '.pc/dirs.patch/daemons/dmeventd/dmeventd.c'
--- .pc/dirs.patch/daemons/dmeventd/dmeventd.c 1970-01-01 00:00:00 +0000
+++ .pc/dirs.patch/daemons/dmeventd/dmeventd.c 2012-08-21 10:18:22 +0000
@@ -0,0 +1,2009 @@
1/*
2 * Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved.
3 *
4 * This file is part of the device-mapper userspace tools.
5 *
6 * This copyrighted material is made available to anyone wishing to use,
7 * modify, copy, or redistribute it subject to the terms and conditions
8 * of the GNU Lesser General Public License v.2.1.
9 *
10 * You should have received a copy of the GNU Lesser General Public License
11 * along with this program; if not, write to the Free Software Foundation,
12 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
13 */
14
15/*
16 * dmeventd - dm event daemon to monitor active mapped devices
17 */
18
19#define _GNU_SOURCE
20#define _FILE_OFFSET_BITS 64
21
22#include "configure.h"
23#include "libdevmapper.h"
24#include "libdevmapper-event.h"
25#include "dmeventd.h"
26//#include "libmultilog.h"
27#include "dm-logging.h"
28
29#include <dlfcn.h>
30#include <errno.h>
31#include <pthread.h>
32#include <sys/file.h>
33#include <sys/stat.h>
34#include <sys/wait.h>
35#include <sys/time.h>
36#include <sys/resource.h>
37#include <unistd.h>
38#include <signal.h>
39#include <arpa/inet.h> /* for htonl, ntohl */
40
41#ifdef linux
42# include <malloc.h>
43
44/*
45 * Kernel version 2.6.36 and higher has
46 * new OOM killer adjustment interface.
47 */
48# define OOM_ADJ_FILE_OLD "/proc/self/oom_adj"
49# define OOM_ADJ_FILE "/proc/self/oom_score_adj"
50
51/* From linux/oom.h */
52/* Old interface */
53# define OOM_DISABLE (-17)
54# define OOM_ADJUST_MIN (-16)
55/* New interface */
56# define OOM_SCORE_ADJ_MIN (-1000)
57
58/* Systemd on-demand activation support */
59# define SD_LISTEN_PID_ENV_VAR_NAME "LISTEN_PID"
60# define SD_LISTEN_FDS_ENV_VAR_NAME "LISTEN_FDS"
61# define SD_LISTEN_FDS_START 3
62# define SD_FD_FIFO_SERVER SD_LISTEN_FDS_START
63# define SD_FD_FIFO_CLIENT (SD_LISTEN_FDS_START + 1)
64
65#endif
66
67/* FIXME We use syslog for now, because multilog is not yet implemented */
68#include <syslog.h>
69
70static volatile sig_atomic_t _exit_now = 0; /* set to '1' when signal is given to exit */
71static volatile sig_atomic_t _thread_registries_empty = 1; /* registries are empty initially */
72
73/* List (un)link macros. */
74#define LINK(x, head) dm_list_add(head, &(x)->list)
75#define LINK_DSO(dso) LINK(dso, &_dso_registry)
76#define LINK_THREAD(thread) LINK(thread, &_thread_registry)
77
78#define UNLINK(x) dm_list_del(&(x)->list)
79#define UNLINK_DSO(x) UNLINK(x)
80#define UNLINK_THREAD(x) UNLINK(x)
81
82#define DAEMON_NAME "dmeventd"
83
84/*
85 Global mutex for thread list access. Has to be held when:
86 - iterating thread list
87 - adding or removing elements from thread list
88 - changing or reading thread_status's fields:
89 processing, status, events
90 Use _lock_mutex() and _unlock_mutex() to hold/release it
91*/
92static pthread_mutex_t _global_mutex;
93
94/*
95 There are three states a thread can attain (see struct
96 thread_status, field int status):
97
98 - DM_THREAD_RUNNING: thread has started up and is either working or
99 waiting for events... transitions to either SHUTDOWN or DONE
100 - DM_THREAD_SHUTDOWN: thread is still doing something, but it is
101 supposed to terminate (and transition to DONE) as soon as it
102 finishes whatever it was doing at the point of flipping state to
103 SHUTDOWN... the thread is still on the thread list
104 - DM_THREAD_DONE: thread has terminated and has been moved over to
105 unused thread list, cleanup pending
106 */
107#define DM_THREAD_RUNNING 0
108#define DM_THREAD_SHUTDOWN 1
109#define DM_THREAD_DONE 2
110
111#define THREAD_STACK_SIZE (300*1024)
112
113int dmeventd_debug = 0;
114static int _systemd_activation = 0;
115static int _foreground = 0;
116static int _restart = 0;
117static char **_initial_registrations = 0;
118
119/* Data kept about a DSO. */
120struct dso_data {
121 struct dm_list list;
122
123 char *dso_name; /* DSO name (eg, "evms", "dmraid", "lvm2"). */
124
125 void *dso_handle; /* Opaque handle as returned from dlopen(). */
126 unsigned int ref_count; /* Library reference count. */
127
128 /*
129 * Event processing.
130 *
131 * The DSO can do whatever appropriate steps if an event
132 * happens such as changing the mapping in case a mirror
133 * fails, update the application metadata etc.
134 *
135 * This function gets a dm_task that is a result of
136 * DM_DEVICE_WAITEVENT ioctl (results equivalent to
137 * DM_DEVICE_STATUS). It should not destroy it.
138 * The caller must dispose of the task.
139 */
140 void (*process_event)(struct dm_task *dmt, enum dm_event_mask event, void **user);
141
142 /*
143 * Device registration.
144 *
145 * When an application registers a device for an event, the DSO
146 * can carry out appropriate steps so that a later call to
147 * the process_event() function is sane (eg, read metadata
148 * and activate a mapping).
149 */
150 int (*register_device)(const char *device, const char *uuid, int major,
151 int minor, void **user);
152
153 /*
154 * Device unregistration.
155 *
156 * In case all devices of a mapping (eg, RAID10) are unregistered
157 * for events, the DSO can recognize this and carry out appropriate
158 * steps (eg, deactivate mapping, metadata update).
159 */
160 int (*unregister_device)(const char *device, const char *uuid,
161 int major, int minor, void **user);
162};
163static DM_LIST_INIT(_dso_registry);
164
165/* Structure to keep parsed register variables from client message. */
166struct message_data {
167 char *id;
168 char *dso_name; /* Name of DSO. */
169 char *device_uuid; /* Mapped device path. */
170 union {
171 char *str; /* Events string as fetched from message. */
172 enum dm_event_mask field; /* Events bitfield. */
173 } events;
174 union {
175 char *str;
176 uint32_t secs;
177 } timeout;
178 struct dm_event_daemon_message *msg; /* Pointer to message buffer. */
179};
180
181/*
182 * Housekeeping of thread+device states.
183 *
184 * One thread per mapped device which can block on it until an event
185 * occurs and the event processing function of the DSO gets called.
186 */
187struct thread_status {
188 struct dm_list list;
189
190 pthread_t thread;
191
192 struct dso_data *dso_data; /* DSO this thread accesses. */
193
194 struct {
195 char *uuid;
196 char *name;
197 int major, minor;
198 } device;
199 uint32_t event_nr; /* event number */
200 int processing; /* Set when event is being processed */
201
202 int status; /* see DM_THREAD_{RUNNING,SHUTDOWN,DONE}
203 constants above */
204 enum dm_event_mask events; /* bitfield for event filter. */
205 enum dm_event_mask current_events; /* bitfield for occured events. */
206 struct dm_task *current_task;
207 time_t next_time;
208 uint32_t timeout;
209 struct dm_list timeout_list;
210 void *dso_private; /* dso per-thread status variable */
211};
212static DM_LIST_INIT(_thread_registry);
213static DM_LIST_INIT(_thread_registry_unused);
214
215static int _timeout_running;
216static DM_LIST_INIT(_timeout_registry);
217static pthread_mutex_t _timeout_mutex = PTHREAD_MUTEX_INITIALIZER;
218static pthread_cond_t _timeout_cond = PTHREAD_COND_INITIALIZER;
219
220/* Allocate/free the status structure for a monitoring thread. */
221static struct thread_status *_alloc_thread_status(struct message_data *data,
222 struct dso_data *dso_data)
223{
224 struct thread_status *ret = (typeof(ret)) dm_zalloc(sizeof(*ret));
225
226 if (!ret)
227 return NULL;
228
229 if (!(ret->device.uuid = dm_strdup(data->device_uuid))) {
230 dm_free(ret);
231 return NULL;
232 }
233
234 ret->current_task = NULL;
235 ret->device.name = NULL;
236 ret->device.major = ret->device.minor = 0;
237 ret->dso_data = dso_data;
238 ret->events = data->events.field;
239 ret->timeout = data->timeout.secs;
240 dm_list_init(&ret->timeout_list);
241
242 return ret;
243}
244
245static void _lib_put(struct dso_data *data);
246static void _free_thread_status(struct thread_status *thread)
247{
248 _lib_put(thread->dso_data);
249 if (thread->current_task)
250 dm_task_destroy(thread->current_task);
251 dm_free(thread->device.uuid);
252 dm_free(thread->device.name);
253 dm_free(thread);
254}
255
256/* Allocate/free DSO data. */
257static struct dso_data *_alloc_dso_data(struct message_data *data)
258{
259 struct dso_data *ret = (typeof(ret)) dm_zalloc(sizeof(*ret));
260
261 if (!ret)
262 return NULL;
263
264 if (!(ret->dso_name = dm_strdup(data->dso_name))) {
265 dm_free(ret);
266 return NULL;
267 }
268
269 return ret;
270}
271
272/* Create a device monitoring thread. */
273static int _pthread_create_smallstack(pthread_t *t, void *(*fun)(void *), void *arg)
274{
275 pthread_attr_t attr;
276 pthread_attr_init(&attr);
277 /*
278 * We use a smaller stack since it gets preallocated in its entirety
279 */
280 pthread_attr_setstacksize(&attr, THREAD_STACK_SIZE);
281 return pthread_create(t, &attr, fun, arg);
282}
283
284static void _free_dso_data(struct dso_data *data)
285{
286 dm_free(data->dso_name);
287 dm_free(data);
288}
289
290/*
291 * Fetch a string off src and duplicate it into *ptr.
292 * Pay attention to zero-length strings.
293 */
294/* FIXME? move to libdevmapper to share with the client lib (need to
295 make delimiter a parameter then) */
296static int _fetch_string(char **ptr, char **src, const int delimiter)
297{
298 int ret = 0;
299 char *p;
300 size_t len;
301
302 if ((p = strchr(*src, delimiter)))
303 *p = 0;
304
305 if ((*ptr = dm_strdup(*src))) {
306 if ((len = strlen(*ptr)))
307 *src += len;
308 else {
309 dm_free(*ptr);
310 *ptr = NULL;
311 }
312
313 (*src)++;
314 ret = 1;
315 }
316
317 if (p)
318 *p = delimiter;
319
320 return ret;
321}
322
323/* Free message memory. */
324static void _free_message(struct message_data *message_data)
325{
326 dm_free(message_data->id);
327 dm_free(message_data->dso_name);
328
329 dm_free(message_data->device_uuid);
330
331}
332
333/* Parse a register message from the client. */
334static int _parse_message(struct message_data *message_data)
335{
336 int ret = 0;
337 char *p = message_data->msg->data;
338 struct dm_event_daemon_message *msg = message_data->msg;
339
340 if (!msg->data)
341 return 0;
342
343 /*
344 * Retrieve application identifier, mapped device
345 * path and events # string from message.
346 */
347 if (_fetch_string(&message_data->id, &p, ' ') &&
348 _fetch_string(&message_data->dso_name, &p, ' ') &&
349 _fetch_string(&message_data->device_uuid, &p, ' ') &&
350 _fetch_string(&message_data->events.str, &p, ' ') &&
351 _fetch_string(&message_data->timeout.str, &p, ' ')) {
352 if (message_data->events.str) {
353 enum dm_event_mask i = atoi(message_data->events.str);
354
355 /*
356 * Free string representaion of events.
357 * Not needed an more.
358 */
359 dm_free(message_data->events.str);
360 message_data->events.field = i;
361 }
362 if (message_data->timeout.str) {
363 uint32_t secs = atoi(message_data->timeout.str);
364 dm_free(message_data->timeout.str);
365 message_data->timeout.secs = secs ? secs :
366 DM_EVENT_DEFAULT_TIMEOUT;
367 }
368
369 ret = 1;
370 }
371
372 dm_free(msg->data);
373 msg->data = NULL;
374 msg->size = 0;
375 return ret;
376};
377
378/* Global mutex to lock access to lists et al. See _global_mutex
379 above. */
380static int _lock_mutex(void)
381{
382 return pthread_mutex_lock(&_global_mutex);
383}
384
385static int _unlock_mutex(void)
386{
387 return pthread_mutex_unlock(&_global_mutex);
388}
389
390/* Check, if a device exists. */
391static int _fill_device_data(struct thread_status *ts)
392{
393 struct dm_task *dmt;
394 struct dm_info dmi;
395
396 if (!ts->device.uuid)
397 return 0;
398
399 ts->device.name = NULL;
400 ts->device.major = ts->device.minor = 0;
401
402 dmt = dm_task_create(DM_DEVICE_INFO);
403 if (!dmt)
404 return 0;
405
406 if (!dm_task_set_uuid(dmt, ts->device.uuid))
407 goto fail;
408
409 if (!dm_task_run(dmt))
410 goto fail;
411
412 ts->device.name = dm_strdup(dm_task_get_name(dmt));
413 if (!ts->device.name)
414 goto fail;
415
416 if (!dm_task_get_info(dmt, &dmi))
417 goto fail;
418
419 ts->device.major = dmi.major;
420 ts->device.minor = dmi.minor;
421
422 dm_task_destroy(dmt);
423 return 1;
424
425 fail:
426 dm_task_destroy(dmt);
427 dm_free(ts->device.name);
428 return 0;
429}
430
431/*
432 * Find an existing thread for a device.
433 *
434 * Mutex must be held when calling this.
435 */
436static struct thread_status *_lookup_thread_status(struct message_data *data)
437{
438 struct thread_status *thread;
439
440 dm_list_iterate_items(thread, &_thread_registry)
441 if (!strcmp(data->device_uuid, thread->device.uuid))
442 return thread;
443
444 return NULL;
445}
446
447static int _get_status(struct message_data *message_data)
448{
449 struct dm_event_daemon_message *msg = message_data->msg;
450 struct thread_status *thread;
451 int i, j;
452 int ret = -1;
453 int count = dm_list_size(&_thread_registry);
454 int size = 0, current = 0;
455 char *buffers[count];
456 char *message;
457
458 dm_free(msg->data);
459
460 for (i = 0; i < count; ++i)
461 buffers[i] = NULL;
462
463 i = 0;
464 _lock_mutex();
465 dm_list_iterate_items(thread, &_thread_registry) {
466 if ((current = dm_asprintf(buffers + i, "0:%d %s %s %u %" PRIu32 ";",
467 i, thread->dso_data->dso_name,
468 thread->device.uuid, thread->events,
469 thread->timeout)) < 0) {
470 _unlock_mutex();
471 goto out;
472 }
473 ++ i;
474 size += current;
475 }
476 _unlock_mutex();
477
478 msg->size = size + strlen(message_data->id) + 1;
479 msg->data = dm_malloc(msg->size);
480 if (!msg->data)
481 goto out;
482 *msg->data = 0;
483
484 message = msg->data;
485 strcpy(message, message_data->id);
486 message += strlen(message_data->id);
487 *message = ' ';
488 message ++;
489 for (j = 0; j < i; ++j) {
490 strcpy(message, buffers[j]);
491 message += strlen(buffers[j]);
492 }
493
494 ret = 0;
495 out:
496 for (j = 0; j < i; ++j)
497 dm_free(buffers[j]);
498 return ret;
499
500}
501
502/* Cleanup at exit. */
503static void _exit_dm_lib(void)
504{
505 dm_lib_release();
506 dm_lib_exit();
507}
508
509static void _exit_timeout(void *unused __attribute__((unused)))
510{
511 _timeout_running = 0;
512 pthread_mutex_unlock(&_timeout_mutex);
513}
514
515/* Wake up monitor threads every so often. */
516static void *_timeout_thread(void *unused __attribute__((unused)))
517{
518 struct timespec timeout;
519 time_t curr_time;
520
521 timeout.tv_nsec = 0;
522 pthread_cleanup_push(_exit_timeout, NULL);
523 pthread_mutex_lock(&_timeout_mutex);
524
525 while (!dm_list_empty(&_timeout_registry)) {
526 struct thread_status *thread;
527
528 timeout.tv_sec = 0;
529 curr_time = time(NULL);
530
531 dm_list_iterate_items_gen(thread, &_timeout_registry, timeout_list) {
532 if (thread->next_time <= curr_time) {
533 thread->next_time = curr_time + thread->timeout;
534 pthread_kill(thread->thread, SIGALRM);
535 }
536
537 if (thread->next_time < timeout.tv_sec || !timeout.tv_sec)
538 timeout.tv_sec = thread->next_time;
539 }
540
541 pthread_cond_timedwait(&_timeout_cond, &_timeout_mutex,
542 &timeout);
543 }
544
545 pthread_cleanup_pop(1);
546
547 return NULL;
548}
549
550static int _register_for_timeout(struct thread_status *thread)
551{
552 int ret = 0;
553
554 pthread_mutex_lock(&_timeout_mutex);
555
556 thread->next_time = time(NULL) + thread->timeout;
557
558 if (dm_list_empty(&thread->timeout_list)) {
559 dm_list_add(&_timeout_registry, &thread->timeout_list);
560 if (_timeout_running)
561 pthread_cond_signal(&_timeout_cond);
562 }
563
564 if (!_timeout_running) {
565 pthread_t timeout_id;
566
567 if (!(ret = -_pthread_create_smallstack(&timeout_id, _timeout_thread, NULL)))
568 _timeout_running = 1;
569 }
570
571 pthread_mutex_unlock(&_timeout_mutex);
572
573 return ret;
574}
575
576static void _unregister_for_timeout(struct thread_status *thread)
577{
578 pthread_mutex_lock(&_timeout_mutex);
579 if (!dm_list_empty(&thread->timeout_list)) {
580 dm_list_del(&thread->timeout_list);
581 dm_list_init(&thread->timeout_list);
582 }
583 pthread_mutex_unlock(&_timeout_mutex);
584}
585
586__attribute__((format(printf, 4, 5)))
587static void _no_intr_log(int level, const char *file, int line,
588 const char *f, ...)
589{
590 va_list ap;
591
592 if (errno == EINTR)
593 return;
594 if (level > _LOG_WARN)
595 return;
596
597 va_start(ap, f);
598
599 if (level < _LOG_WARN)
600 vfprintf(stderr, f, ap);
601 else
602 vprintf(f, ap);
603
604 va_end(ap);
605
606 if (level < _LOG_WARN)
607 fprintf(stderr, "\n");
608 else
609 fprintf(stdout, "\n");
610}
611
612static sigset_t _unblock_sigalrm(void)
613{
614 sigset_t set, old;
615
616 sigemptyset(&set);
617 sigaddset(&set, SIGALRM);
618 pthread_sigmask(SIG_UNBLOCK, &set, &old);
619 return old;
620}
621
622#define DM_WAIT_RETRY 0
623#define DM_WAIT_INTR 1
624#define DM_WAIT_FATAL 2
625
626/* Wait on a device until an event occurs. */
627static int _event_wait(struct thread_status *thread, struct dm_task **task)
628{
629 sigset_t set;
630 int ret = DM_WAIT_RETRY;
631 struct dm_task *dmt;
632 struct dm_info info;
633
634 *task = 0;
635
636 if (!(dmt = dm_task_create(DM_DEVICE_WAITEVENT)))
637 return DM_WAIT_RETRY;
638
639 thread->current_task = dmt;
640
641 if (!dm_task_set_uuid(dmt, thread->device.uuid) ||
642 !dm_task_set_event_nr(dmt, thread->event_nr))
643 goto out;
644
645 /*
646 * This is so that you can break out of waiting on an event,
647 * either for a timeout event, or to cancel the thread.
648 */
649 set = _unblock_sigalrm();
650 dm_log_init(_no_intr_log);
651 errno = 0;
652 if (dm_task_run(dmt)) {
653 thread->current_events |= DM_EVENT_DEVICE_ERROR;
654 ret = DM_WAIT_INTR;
655
656 if ((ret = dm_task_get_info(dmt, &info)))
657 thread->event_nr = info.event_nr;
658 } else if (thread->events & DM_EVENT_TIMEOUT && errno == EINTR) {
659 thread->current_events |= DM_EVENT_TIMEOUT;
660 ret = DM_WAIT_INTR;
661 } else if (thread->status == DM_THREAD_SHUTDOWN && errno == EINTR) {
662 ret = DM_WAIT_FATAL;
663 } else {
664 syslog(LOG_NOTICE, "dm_task_run failed, errno = %d, %s",
665 errno, strerror(errno));
666 if (errno == ENXIO) {
667 syslog(LOG_ERR, "%s disappeared, detaching",
668 thread->device.name);
669 ret = DM_WAIT_FATAL;
670 }
671 }
672
673 pthread_sigmask(SIG_SETMASK, &set, NULL);
674 dm_log_init(NULL);
675
676 out:
677 if (ret == DM_WAIT_FATAL || ret == DM_WAIT_RETRY) {
678 dm_task_destroy(dmt);
679 thread->current_task = NULL;
680 } else
681 *task = dmt;
682
683 return ret;
684}
685
686/* Register a device with the DSO. */
687static int _do_register_device(struct thread_status *thread)
688{
689 return thread->dso_data->register_device(thread->device.name,
690 thread->device.uuid,
691 thread->device.major,
692 thread->device.minor,
693 &(thread->dso_private));
694}
695
696/* Unregister a device with the DSO. */
697static int _do_unregister_device(struct thread_status *thread)
698{
699 return thread->dso_data->unregister_device(thread->device.name,
700 thread->device.uuid,
701 thread->device.major,
702 thread->device.minor,
703 &(thread->dso_private));
704}
705
706/* Process an event in the DSO. */
707static void _do_process_event(struct thread_status *thread, struct dm_task *task)
708{
709 thread->dso_data->process_event(task, thread->current_events, &(thread->dso_private));
710}
711
712/* Thread cleanup handler to unregister device. */
713static void _monitor_unregister(void *arg)
714{
715 struct thread_status *thread = arg, *thread_iter;
716
717 if (!_do_unregister_device(thread))
718 syslog(LOG_ERR, "%s: %s unregister failed\n", __func__,
719 thread->device.name);
720 if (thread->current_task)
721 dm_task_destroy(thread->current_task);
722 thread->current_task = NULL;
723
724 _lock_mutex();
725 if (thread->events & DM_EVENT_TIMEOUT) {
726 /* _unregister_for_timeout locks another mutex, we
727 don't want to deadlock so we release our mutex for
728 a bit */
729 _unlock_mutex();
730 _unregister_for_timeout(thread);
731 _lock_mutex();
732 }
733 /* we may have been relinked to unused registry since we were
734 called, so check that */
735 dm_list_iterate_items(thread_iter, &_thread_registry_unused)
736 if (thread_iter == thread) {
737 thread->status = DM_THREAD_DONE;
738 _unlock_mutex();
739 return;
740 }
741 thread->status = DM_THREAD_DONE;
742 pthread_mutex_lock(&_timeout_mutex);
743 UNLINK_THREAD(thread);
744 LINK(thread, &_thread_registry_unused);
745 pthread_mutex_unlock(&_timeout_mutex);
746 _unlock_mutex();
747}
748
749static struct dm_task *_get_device_status(struct thread_status *ts)
750{
751 struct dm_task *dmt = dm_task_create(DM_DEVICE_STATUS);
752
753 if (!dmt)
754 return NULL;
755
756 if (!dm_task_set_uuid(dmt, ts->device.uuid)) {
757 dm_task_destroy(dmt);
758 return NULL;
759 }
760
761 if (!dm_task_run(dmt)) {
762 dm_task_destroy(dmt);
763 return NULL;
764 }
765
766 return dmt;
767}
768
769/* Device monitoring thread. */
770static void *_monitor_thread(void *arg)
771{
772 struct thread_status *thread = arg;
773 int wait_error = 0;
774 struct dm_task *task;
775
776 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
777 pthread_cleanup_push(_monitor_unregister, thread);
778
779 /* Wait for do_process_request() to finish its task. */
780 _lock_mutex();
781 thread->status = DM_THREAD_RUNNING;
782 _unlock_mutex();
783
784 /* Loop forever awaiting/analyzing device events. */
785 while (1) {
786 thread->current_events = 0;
787
788 wait_error = _event_wait(thread, &task);
789 if (wait_error == DM_WAIT_RETRY)
790 continue;
791
792 if (wait_error == DM_WAIT_FATAL)
793 break;
794
795 /* Timeout occurred, task is not filled properly.
796 * We get device status here for processing it in DSO.
797 */
798 if (wait_error == DM_WAIT_INTR &&
799 thread->current_events & DM_EVENT_TIMEOUT) {
800 dm_task_destroy(task);
801 task = _get_device_status(thread);
802 /* FIXME: syslog fail here ? */
803 if (!(thread->current_task = task))
804 continue;
805 }
806
807 /*
808 * We know that wait succeeded and stored a
809 * pointer to dm_task with device status into task.
810 */
811
812 /*
813 * Check against filter.
814 *
815 * If there's current events delivered from _event_wait() AND
816 * the device got registered for those events AND
817 * those events haven't been processed yet, call
818 * the DSO's process_event() handler.
819 */
820 _lock_mutex();
821 if (thread->status == DM_THREAD_SHUTDOWN) {
822 _unlock_mutex();
823 break;
824 }
825 _unlock_mutex();
826
827 if (thread->events & thread->current_events) {
828 _lock_mutex();
829 thread->processing = 1;
830 _unlock_mutex();
831
832 _do_process_event(thread, task);
833 dm_task_destroy(task);
834 thread->current_task = NULL;
835
836 _lock_mutex();
837 thread->processing = 0;
838 _unlock_mutex();
839 } else {
840 dm_task_destroy(task);
841 thread->current_task = NULL;
842 }
843 }
844
845 pthread_cleanup_pop(1);
846
847 return NULL;
848}
849
850/* Create a device monitoring thread. */
851static int _create_thread(struct thread_status *thread)
852{
853 return _pthread_create_smallstack(&thread->thread, _monitor_thread, thread);
854}
855
856static int _terminate_thread(struct thread_status *thread)
857{
858 return pthread_kill(thread->thread, SIGALRM);
859}
860
861/* DSO reference counting. Call with _global_mutex locked! */
862static void _lib_get(struct dso_data *data)
863{
864 data->ref_count++;
865}
866
867static void _lib_put(struct dso_data *data)
868{
869 if (!--data->ref_count) {
870 dlclose(data->dso_handle);
871 UNLINK_DSO(data);
872 _free_dso_data(data);
873 }
874}
875
876/* Find DSO data. */
877static struct dso_data *_lookup_dso(struct message_data *data)
878{
879 struct dso_data *dso_data, *ret = NULL;
880
881 dm_list_iterate_items(dso_data, &_dso_registry)
882 if (!strcmp(data->dso_name, dso_data->dso_name)) {
883 _lib_get(dso_data);
884 ret = dso_data;
885 break;
886 }
887
888 return ret;
889}
890
891/* Lookup DSO symbols we need. */
892static int _lookup_symbol(void *dl, void **symbol, const char *name)
893{
894 if ((*symbol = dlsym(dl, name)))
895 return 1;
896
897 return 0;
898}
899
900static int lookup_symbols(void *dl, struct dso_data *data)
901{
902 return _lookup_symbol(dl, (void *) &data->process_event,
903 "process_event") &&
904 _lookup_symbol(dl, (void *) &data->register_device,
905 "register_device") &&
906 _lookup_symbol(dl, (void *) &data->unregister_device,
907 "unregister_device");
908}
909
910/* Load an application specific DSO. */
911static struct dso_data *_load_dso(struct message_data *data)
912{
913 void *dl;
914 struct dso_data *ret = NULL;
915
916 if (!(dl = dlopen(data->dso_name, RTLD_NOW))) {
917 const char *dlerr = dlerror();
918 syslog(LOG_ERR, "dmeventd %s dlopen failed: %s", data->dso_name,
919 dlerr);
920 data->msg->size =
921 dm_asprintf(&(data->msg->data), "%s %s dlopen failed: %s",
922 data->id, data->dso_name, dlerr);
923 return NULL;
924 }
925
926 if (!(ret = _alloc_dso_data(data))) {
927 dlclose(dl);
928 return NULL;
929 }
930
931 if (!(lookup_symbols(dl, ret))) {
932 _free_dso_data(ret);
933 dlclose(dl);
934 return NULL;
935 }
936
937 /*
938 * Keep handle to close the library once
939 * we've got no references to it any more.
940 */
941 ret->dso_handle = dl;
942 _lib_get(ret);
943
944 _lock_mutex();
945 LINK_DSO(ret);
946 _unlock_mutex();
947
948 return ret;
949}
950
951/* Return success on daemon active check. */
952static int _active(struct message_data *message_data)
953{
954 return 0;
955}
956
957/*
958 * Register for an event.
959 *
960 * Only one caller at a time here, because we use
961 * a FIFO and lock it against multiple accesses.
962 */
963static int _register_for_event(struct message_data *message_data)
964{
965 int ret = 0;
966 struct thread_status *thread, *thread_new = NULL;
967 struct dso_data *dso_data;
968
969 if (!(dso_data = _lookup_dso(message_data)) &&
970 !(dso_data = _load_dso(message_data))) {
971 stack;
972#ifdef ELIBACC
973 ret = -ELIBACC;
974#else
975 ret = -ENODEV;
976#endif
977 goto out;
978 }
979
980 /* Preallocate thread status struct to avoid deadlock. */
981 if (!(thread_new = _alloc_thread_status(message_data, dso_data))) {
982 stack;
983 ret = -ENOMEM;
984 goto out;
985 }
986
987 if (!_fill_device_data(thread_new)) {
988 stack;
989 ret = -ENODEV;
990 goto out;
991 }
992
993 _lock_mutex();
994
995 /* If creation of timeout thread fails (as it may), we fail
996 here completely. The client is responsible for either
997 retrying later or trying to register without timeout
998 events. However, if timeout thread cannot be started, it
999 usually means we are so starved on resources that we are
1000 almost as good as dead already... */
1001 if (thread_new->events & DM_EVENT_TIMEOUT) {
1002 ret = -_register_for_timeout(thread_new);
1003 if (ret)
1004 goto outth;
1005 }
1006
1007 if (!(thread = _lookup_thread_status(message_data))) {
1008 _unlock_mutex();
1009
1010 if (!(ret = _do_register_device(thread_new)))
1011 goto out;
1012
1013 thread = thread_new;
1014 thread_new = NULL;
1015
1016 /* Try to create the monitoring thread for this device. */
1017 _lock_mutex();
1018 if ((ret = -_create_thread(thread))) {
1019 _unlock_mutex();
1020 _do_unregister_device(thread);
1021 _free_thread_status(thread);
1022 goto out;
1023 } else
1024 LINK_THREAD(thread);
1025 }
1026
1027 /* Or event # into events bitfield. */
1028 thread->events |= message_data->events.field;
1029
1030 outth:
1031 _unlock_mutex();
1032
1033 out:
1034 /*
1035 * Deallocate thread status after releasing
1036 * the lock in case we haven't used it.
1037 */
1038 if (thread_new)
1039 _free_thread_status(thread_new);
1040
1041 return ret;
1042}
1043
1044/*
1045 * Unregister for an event.
1046 *
1047 * Only one caller at a time here as with register_for_event().
1048 */
1049static int _unregister_for_event(struct message_data *message_data)
1050{
1051 int ret = 0;
1052 struct thread_status *thread;
1053
1054 /*
1055 * Clear event in bitfield and deactivate
1056 * monitoring thread in case bitfield is 0.
1057 */
1058 _lock_mutex();
1059
1060 if (!(thread = _lookup_thread_status(message_data))) {
1061 _unlock_mutex();
1062 ret = -ENODEV;
1063 goto out;
1064 }
1065
1066 if (thread->status == DM_THREAD_DONE) {
1067 /* the thread has terminated while we were not
1068 watching */
1069 _unlock_mutex();
1070 return 0;
1071 }
1072
1073 thread->events &= ~message_data->events.field;
1074
1075 if (!(thread->events & DM_EVENT_TIMEOUT))
1076 _unregister_for_timeout(thread);
1077 /*
1078 * In case there's no events to monitor on this device ->
1079 * unlink and terminate its monitoring thread.
1080 */
1081 if (!thread->events) {
1082 pthread_mutex_lock(&_timeout_mutex);
1083 UNLINK_THREAD(thread);
1084 LINK(thread, &_thread_registry_unused);
1085 pthread_mutex_unlock(&_timeout_mutex);
1086 }
1087 _unlock_mutex();
1088
1089 out:
1090 return ret;
1091}
1092
1093/*
1094 * Get registered device.
1095 *
1096 * Only one caller at a time here as with register_for_event().
1097 */
1098static int _registered_device(struct message_data *message_data,
1099 struct thread_status *thread)
1100{
1101 struct dm_event_daemon_message *msg = message_data->msg;
1102
1103 const char *fmt = "%s %s %s %u";
1104 const char *id = message_data->id;
1105 const char *dso = thread->dso_data->dso_name;
1106 const char *dev = thread->device.uuid;
1107 int r;
1108 unsigned events = ((thread->status == DM_THREAD_RUNNING)
1109 && (thread->events)) ? thread->events : thread->
1110 events | DM_EVENT_REGISTRATION_PENDING;
1111
1112 dm_free(msg->data);
1113
1114 if ((r = dm_asprintf(&(msg->data), fmt, id, dso, dev, events)) < 0) {
1115 msg->size = 0;
1116 return -ENOMEM;
1117 }
1118
1119 msg->size = (uint32_t) r;
1120
1121 return 0;
1122}
1123
1124static int _want_registered_device(char *dso_name, char *device_uuid,
1125 struct thread_status *thread)
1126{
1127 /* If DSO names and device paths are equal. */
1128 if (dso_name && device_uuid)
1129 return !strcmp(dso_name, thread->dso_data->dso_name) &&
1130 !strcmp(device_uuid, thread->device.uuid) &&
1131 (thread->status == DM_THREAD_RUNNING ||
1132 (thread->events & DM_EVENT_REGISTRATION_PENDING));
1133
1134 /* If DSO names are equal. */
1135 if (dso_name)
1136 return !strcmp(dso_name, thread->dso_data->dso_name) &&
1137 (thread->status == DM_THREAD_RUNNING ||
1138 (thread->events & DM_EVENT_REGISTRATION_PENDING));
1139
1140 /* If device paths are equal. */
1141 if (device_uuid)
1142 return !strcmp(device_uuid, thread->device.uuid) &&
1143 (thread->status == DM_THREAD_RUNNING ||
1144 (thread->events & DM_EVENT_REGISTRATION_PENDING));
1145
1146 return 1;
1147}
1148
1149static int _get_registered_dev(struct message_data *message_data, int next)
1150{
1151 struct thread_status *thread, *hit = NULL;
1152 int ret = -ENOENT;
1153
1154 _lock_mutex();
1155
1156 /* Iterate list of threads checking if we want a particular one. */
1157 dm_list_iterate_items(thread, &_thread_registry)
1158 if (_want_registered_device(message_data->dso_name,
1159 message_data->device_uuid,
1160 thread)) {
1161 hit = thread;
1162 break;
1163 }
1164
1165 /*
1166 * If we got a registered device and want the next one ->
1167 * fetch next conforming element off the list.
1168 */
1169 if (hit && !next)
1170 goto reg;
1171
1172 if (!hit)
1173 goto out;
1174
1175 while (1) {
1176 if (dm_list_end(&_thread_registry, &thread->list))
1177 goto out;
1178
1179 thread = dm_list_item(thread->list.n, struct thread_status);
1180 if (_want_registered_device(message_data->dso_name, NULL, thread)) {
1181 hit = thread;
1182 break;
1183 }
1184 }
1185
1186 reg:
1187 ret = _registered_device(message_data, hit);
1188
1189 out:
1190 _unlock_mutex();
1191
1192 return ret;
1193}
1194
1195static int _get_registered_device(struct message_data *message_data)
1196{
1197 return _get_registered_dev(message_data, 0);
1198}
1199
1200static int _get_next_registered_device(struct message_data *message_data)
1201{
1202 return _get_registered_dev(message_data, 1);
1203}
1204
1205static int _set_timeout(struct message_data *message_data)
1206{
1207 struct thread_status *thread;
1208
1209 _lock_mutex();
1210 if ((thread = _lookup_thread_status(message_data)))
1211 thread->timeout = message_data->timeout.secs;
1212 _unlock_mutex();
1213
1214 return thread ? 0 : -ENODEV;
1215}
1216
1217static int _get_timeout(struct message_data *message_data)
1218{
1219 struct thread_status *thread;
1220 struct dm_event_daemon_message *msg = message_data->msg;
1221
1222 dm_free(msg->data);
1223
1224 _lock_mutex();
1225 if ((thread = _lookup_thread_status(message_data))) {
1226 msg->size =
1227 dm_asprintf(&(msg->data), "%s %" PRIu32, message_data->id,
1228 thread->timeout);
1229 } else {
1230 msg->data = NULL;
1231 msg->size = 0;
1232 }
1233 _unlock_mutex();
1234
1235 return thread ? 0 : -ENODEV;
1236}
1237
1238/* Initialize a fifos structure with path names. */
1239static void _init_fifos(struct dm_event_fifos *fifos)
1240{
1241 memset(fifos, 0, sizeof(*fifos));
1242
1243 fifos->client_path = DM_EVENT_FIFO_CLIENT;
1244 fifos->server_path = DM_EVENT_FIFO_SERVER;
1245}
1246
1247/* Open fifos used for client communication. */
1248static int _open_fifos(struct dm_event_fifos *fifos)
1249{
1250 struct stat st;
1251
1252 /* Create client fifo. */
1253 (void) dm_prepare_selinux_context(fifos->client_path, S_IFIFO);
1254 if ((mkfifo(fifos->client_path, 0600) == -1) && errno != EEXIST) {
1255 syslog(LOG_ERR, "%s: Failed to create client fifo %s: %m.\n",
1256 __func__, fifos->client_path);
1257 (void) dm_prepare_selinux_context(NULL, 0);
1258 return 0;
1259 }
1260
1261 /* Create server fifo. */
1262 (void) dm_prepare_selinux_context(fifos->server_path, S_IFIFO);
1263 if ((mkfifo(fifos->server_path, 0600) == -1) && errno != EEXIST) {
1264 syslog(LOG_ERR, "%s: Failed to create server fifo %s: %m.\n",
1265 __func__, fifos->server_path);
1266 (void) dm_prepare_selinux_context(NULL, 0);
1267 return 0;
1268 }
1269
1270 (void) dm_prepare_selinux_context(NULL, 0);
1271
1272 /* Warn about wrong permissions if applicable */
1273 if ((!stat(fifos->client_path, &st)) && (st.st_mode & 0777) != 0600)
1274 syslog(LOG_WARNING, "Fixing wrong permissions on %s: %m.\n",
1275 fifos->client_path);
1276
1277 if ((!stat(fifos->server_path, &st)) && (st.st_mode & 0777) != 0600)
1278 syslog(LOG_WARNING, "Fixing wrong permissions on %s: %m.\n",
1279 fifos->server_path);
1280
1281 /* If they were already there, make sure permissions are ok. */
1282 if (chmod(fifos->client_path, 0600)) {
1283 syslog(LOG_ERR, "Unable to set correct file permissions on %s: %m.\n",
1284 fifos->client_path);
1285 return 0;
1286 }
1287
1288 if (chmod(fifos->server_path, 0600)) {
1289 syslog(LOG_ERR, "Unable to set correct file permissions on %s: %m.\n",
1290 fifos->server_path);
1291 return 0;
1292 }
1293
1294 /* Need to open read+write or we will block or fail */
1295 if ((fifos->server = open(fifos->server_path, O_RDWR)) < 0) {
1296 syslog(LOG_ERR, "Failed to open fifo server %s: %m.\n",
1297 fifos->server_path);
1298 return 0;
1299 }
1300
1301 /* Need to open read+write for select() to work. */
1302 if ((fifos->client = open(fifos->client_path, O_RDWR)) < 0) {
1303 syslog(LOG_ERR, "Failed to open fifo client %s: %m", fifos->client_path);
1304 if (close(fifos->server))
1305 syslog(LOG_ERR, "Failed to close fifo server %s: %m", fifos->server_path);
1306 return 0;
1307 }
1308
1309 return 1;
1310}
1311
1312/*
1313 * Read message from client making sure that data is available
1314 * and a complete message is read. Must not block indefinitely.
1315 */
1316static int _client_read(struct dm_event_fifos *fifos,
1317 struct dm_event_daemon_message *msg)
1318{
1319 struct timeval t;
1320 unsigned bytes = 0;
1321 int ret = 0;
1322 fd_set fds;
1323 size_t size = 2 * sizeof(uint32_t); /* status + size */
1324 uint32_t *header = alloca(size);
1325 char *buf = (char *)header;
1326
1327 msg->data = NULL;
1328
1329 errno = 0;
1330 while (bytes < size && errno != EOF) {
1331 /* Watch client read FIFO for input. */
1332 FD_ZERO(&fds);
1333 FD_SET(fifos->client, &fds);
1334 t.tv_sec = 1;
1335 t.tv_usec = 0;
1336 ret = select(fifos->client + 1, &fds, NULL, NULL, &t);
1337
1338 if (!ret && !bytes) /* nothing to read */
1339 return 0;
1340
1341 if (!ret) /* trying to finish read */
1342 continue;
1343
1344 if (ret < 0) /* error */
1345 return 0;
1346
1347 ret = read(fifos->client, buf + bytes, size - bytes);
1348 bytes += ret > 0 ? ret : 0;
1349 if (header && (bytes == 2 * sizeof(uint32_t))) {
1350 msg->cmd = ntohl(header[0]);
1351 msg->size = ntohl(header[1]);
1352 buf = msg->data = dm_malloc(msg->size);
1353 size = msg->size;
1354 bytes = 0;
1355 header = 0;
1356 }
1357 }
1358
1359 if (bytes != size) {
1360 dm_free(msg->data);
1361 msg->data = NULL;
1362 msg->size = 0;
1363 }
1364
1365 return bytes == size;
1366}
1367
1368/*
1369 * Write a message to the client making sure that it is ready to write.
1370 */
1371static int _client_write(struct dm_event_fifos *fifos,
1372 struct dm_event_daemon_message *msg)
1373{
1374 unsigned bytes = 0;
1375 int ret = 0;
1376 fd_set fds;
1377
1378 size_t size = 2 * sizeof(uint32_t) + msg->size;
1379 uint32_t *header = alloca(size);
1380 char *buf = (char *)header;
1381
1382 header[0] = htonl(msg->cmd);
1383 header[1] = htonl(msg->size);
1384 if (msg->data)
1385 memcpy(buf + 2 * sizeof(uint32_t), msg->data, msg->size);
1386
1387 errno = 0;
1388 while (bytes < size && errno != EIO) {
1389 do {
1390 /* Watch client write FIFO to be ready for output. */
1391 FD_ZERO(&fds);
1392 FD_SET(fifos->server, &fds);
1393 } while (select(fifos->server + 1, NULL, &fds, NULL, NULL) !=
1394 1);
1395
1396 ret = write(fifos->server, buf + bytes, size - bytes);
1397 bytes += ret > 0 ? ret : 0;
1398 }
1399
1400 return bytes == size;
1401}
1402
1403/*
1404 * Handle a client request.
1405 *
1406 * We put the request handling functions into
1407 * a list because of the growing number.
1408 */
1409static int _handle_request(struct dm_event_daemon_message *msg,
1410 struct message_data *message_data)
1411{
1412 static struct request {
1413 unsigned int cmd;
1414 int (*f)(struct message_data *);
1415 } requests[] = {
1416 { DM_EVENT_CMD_REGISTER_FOR_EVENT, _register_for_event},
1417 { DM_EVENT_CMD_UNREGISTER_FOR_EVENT, _unregister_for_event},
1418 { DM_EVENT_CMD_GET_REGISTERED_DEVICE, _get_registered_device},
1419 { DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE,
1420 _get_next_registered_device},
1421 { DM_EVENT_CMD_SET_TIMEOUT, _set_timeout},
1422 { DM_EVENT_CMD_GET_TIMEOUT, _get_timeout},
1423 { DM_EVENT_CMD_ACTIVE, _active},
1424 { DM_EVENT_CMD_GET_STATUS, _get_status},
1425 }, *req;
1426
1427 for (req = requests; req < requests + sizeof(requests) / sizeof(struct request); req++)
1428 if (req->cmd == msg->cmd)
1429 return req->f(message_data);
1430
1431 return -EINVAL;
1432}
1433
1434/* Process a request passed from the communication thread. */
1435static int _do_process_request(struct dm_event_daemon_message *msg)
1436{
1437 int ret;
1438 char *answer;
1439 static struct message_data message_data;
1440
1441 /* Parse the message. */
1442 memset(&message_data, 0, sizeof(message_data));
1443 message_data.msg = msg;
1444 if (msg->cmd == DM_EVENT_CMD_HELLO || msg->cmd == DM_EVENT_CMD_DIE) {
1445 ret = 0;
1446 answer = msg->data;
1447 if (answer) {
1448 msg->size = dm_asprintf(&(msg->data), "%s %s %d", answer,
1449 msg->cmd == DM_EVENT_CMD_DIE ? "DYING" : "HELLO",
1450 DM_EVENT_PROTOCOL_VERSION);
1451 dm_free(answer);
1452 } else {
1453 msg->size = 0;
1454 msg->data = NULL;
1455 }
1456 } else if (msg->cmd != DM_EVENT_CMD_ACTIVE && !_parse_message(&message_data)) {
1457 stack;
1458 ret = -EINVAL;
1459 } else
1460 ret = _handle_request(msg, &message_data);
1461
1462 msg->cmd = ret;
1463 if (!msg->data)
1464 msg->size = dm_asprintf(&(msg->data), "%s %s", message_data.id, strerror(-ret));
1465
1466 _free_message(&message_data);
1467
1468 return ret;
1469}
1470
1471/* Only one caller at a time. */
1472static void _process_request(struct dm_event_fifos *fifos)
1473{
1474 int die = 0;
1475 struct dm_event_daemon_message msg;
1476
1477 memset(&msg, 0, sizeof(msg));
1478
1479 /*
1480 * Read the request from the client (client_read, client_write
1481 * give true on success and false on failure).
1482 */
1483 if (!_client_read(fifos, &msg))
1484 return;
1485
1486 if (msg.cmd == DM_EVENT_CMD_DIE)
1487 die = 1;
1488
1489 /* _do_process_request fills in msg (if memory allows for
1490 data, otherwise just cmd and size = 0) */
1491 _do_process_request(&msg);
1492
1493 if (!_client_write(fifos, &msg))
1494 stack;
1495
1496 dm_free(msg.data);
1497
1498 if (die) raise(9);
1499}
1500
1501static void _process_initial_registrations(void)
1502{
1503 int i = 0;
1504 char *reg;
1505 struct dm_event_daemon_message msg = { 0, 0, NULL };
1506
1507 while ((reg = _initial_registrations[i])) {
1508 msg.cmd = DM_EVENT_CMD_REGISTER_FOR_EVENT;
1509 if ((msg.size = strlen(reg))) {
1510 msg.data = reg;
1511 _do_process_request(&msg);
1512 }
1513 ++ i;
1514 }
1515}
1516
1517static void _cleanup_unused_threads(void)
1518{
1519 int ret;
1520 struct dm_list *l;
1521 struct thread_status *thread;
1522 int join_ret = 0;
1523
1524 _lock_mutex();
1525 while ((l = dm_list_first(&_thread_registry_unused))) {
1526 thread = dm_list_item(l, struct thread_status);
1527 if (thread->processing)
1528 break; /* cleanup on the next round */
1529
1530 if (thread->status == DM_THREAD_RUNNING) {
1531 thread->status = DM_THREAD_SHUTDOWN;
1532 break;
1533 }
1534
1535 if (thread->status == DM_THREAD_SHUTDOWN) {
1536 if (!thread->events) {
1537 /* turn codes negative -- should we be returning this? */
1538 ret = _terminate_thread(thread);
1539
1540 if (ret == ESRCH) {
1541 thread->status = DM_THREAD_DONE;
1542 } else if (ret) {
1543 syslog(LOG_ERR,
1544 "Unable to terminate thread: %s\n",
1545 strerror(-ret));
1546 stack;
1547 }
1548 break;
1549 }
1550
1551 dm_list_del(l);
1552 syslog(LOG_ERR,
1553 "thread can't be on unused list unless !thread->events");
1554 thread->status = DM_THREAD_RUNNING;
1555 LINK_THREAD(thread);
1556
1557 continue;
1558 }
1559
1560 if (thread->status == DM_THREAD_DONE) {
1561 dm_list_del(l);
1562 join_ret = pthread_join(thread->thread, NULL);
1563 _free_thread_status(thread);
1564 }
1565 }
1566
1567 _unlock_mutex();
1568
1569 if (join_ret)
1570 syslog(LOG_ERR, "Failed pthread_join: %s\n", strerror(join_ret));
1571}
1572
1573static void _sig_alarm(int signum __attribute__((unused)))
1574{
1575 pthread_testcancel();
1576}
1577
1578/* Init thread signal handling. */
1579static void _init_thread_signals(void)
1580{
1581 sigset_t my_sigset;
1582 struct sigaction act;
1583
1584 memset(&act, 0, sizeof(act));
1585 act.sa_handler = _sig_alarm;
1586 sigaction(SIGALRM, &act, NULL);
1587 sigfillset(&my_sigset);
1588
1589 /* These are used for exiting */
1590 sigdelset(&my_sigset, SIGTERM);
1591 sigdelset(&my_sigset, SIGINT);
1592 sigdelset(&my_sigset, SIGHUP);
1593 sigdelset(&my_sigset, SIGQUIT);
1594
1595 pthread_sigmask(SIG_BLOCK, &my_sigset, NULL);
1596}
1597
1598/*
1599 * exit_handler
1600 * @sig
1601 *
1602 * Set the global variable which the process should
1603 * be watching to determine when to exit.
1604 */
1605static void _exit_handler(int sig __attribute__((unused)))
1606{
1607 /*
1608 * We exit when '_exit_now' is set.
1609 * That is, when a signal has been received.
1610 *
1611 * We can not simply set '_exit_now' unless all
1612 * threads are done processing.
1613 */
1614 if (!_thread_registries_empty) {
1615 syslog(LOG_ERR, "There are still devices being monitored.");
1616 syslog(LOG_ERR, "Refusing to exit.");
1617 } else
1618 _exit_now = 1;
1619
1620}
1621
1622#ifdef linux
1623static int _set_oom_adj(const char *oom_adj_path, int val)
1624{
1625 FILE *fp;
1626
1627 if (!(fp = fopen(oom_adj_path, "w"))) {
1628 perror("oom_adj: fopen failed");
1629 return 0;
1630 }
1631
1632 fprintf(fp, "%i", val);
1633
1634 if (dm_fclose(fp))
1635 perror("oom_adj: fclose failed");
1636
1637 return 1;
1638}
1639
1640/*
1641 * Protection against OOM killer if kernel supports it
1642 */
1643static int _protect_against_oom_killer(void)
1644{
1645 struct stat st;
1646
1647 if (stat(OOM_ADJ_FILE, &st) == -1) {
1648 if (errno != ENOENT)
1649 perror(OOM_ADJ_FILE ": stat failed");
1650
1651 /* Try old oom_adj interface as a fallback */
1652 if (stat(OOM_ADJ_FILE_OLD, &st) == -1) {
1653 if (errno == ENOENT)
1654 perror(OOM_ADJ_FILE_OLD " not found");
1655 else
1656 perror(OOM_ADJ_FILE_OLD ": stat failed");
1657 return 1;
1658 }
1659
1660 return _set_oom_adj(OOM_ADJ_FILE_OLD, OOM_DISABLE) ||
1661 _set_oom_adj(OOM_ADJ_FILE_OLD, OOM_ADJUST_MIN);
1662 }
1663
1664 return _set_oom_adj(OOM_ADJ_FILE, OOM_SCORE_ADJ_MIN);
1665}
1666
1667static int _handle_preloaded_fifo(int fd, const char *path)
1668{
1669 struct stat st_fd, st_path;
1670 int flags;
1671
1672 if ((flags = fcntl(fd, F_GETFD)) < 0)
1673 return 0;
1674
1675 if (flags & FD_CLOEXEC)
1676 return 0;
1677
1678 if (fstat(fd, &st_fd) < 0 || !S_ISFIFO(st_fd.st_mode))
1679 return 0;
1680
1681 if (stat(path, &st_path) < 0 ||
1682 st_path.st_dev != st_fd.st_dev ||
1683 st_path.st_ino != st_fd.st_ino)
1684 return 0;
1685
1686 if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0)
1687 return 0;
1688
1689 return 1;
1690}
1691
1692static int _systemd_handover(struct dm_event_fifos *fifos)
1693{
1694 const char *e;
1695 char *p;
1696 unsigned long env_pid, env_listen_fds;
1697 int r = 0;
1698
1699 memset(fifos, 0, sizeof(*fifos));
1700
1701 /* LISTEN_PID must be equal to our PID! */
1702 if (!(e = getenv(SD_LISTEN_PID_ENV_VAR_NAME)))
1703 goto out;
1704
1705 errno = 0;
1706 env_pid = strtoul(e, &p, 10);
1707 if (errno || !p || *p || env_pid <= 0 ||
1708 getpid() != (pid_t) env_pid)
1709 goto out;
1710
1711 /* LISTEN_FDS must be 2 and the fds must be FIFOSs! */
1712 if (!(e = getenv(SD_LISTEN_FDS_ENV_VAR_NAME)))
1713 goto out;
1714
1715 errno = 0;
1716 env_listen_fds = strtoul(e, &p, 10);
1717 if (errno || !p || *p || env_listen_fds != 2)
1718 goto out;
1719
1720 /* Check and handle the FIFOs passed in */
1721 r = (_handle_preloaded_fifo(SD_FD_FIFO_SERVER, DM_EVENT_FIFO_SERVER) &&
1722 _handle_preloaded_fifo(SD_FD_FIFO_CLIENT, DM_EVENT_FIFO_CLIENT));
1723
1724 if (r) {
1725 fifos->server = SD_FD_FIFO_SERVER;
1726 fifos->server_path = DM_EVENT_FIFO_SERVER;
1727 fifos->client = SD_FD_FIFO_CLIENT;
1728 fifos->client_path = DM_EVENT_FIFO_CLIENT;
1729 }
1730
1731out:
1732 unsetenv(SD_LISTEN_PID_ENV_VAR_NAME);
1733 unsetenv(SD_LISTEN_FDS_ENV_VAR_NAME);
1734 return r;
1735}
1736#endif
1737
1738static void remove_lockfile(void)
1739{
1740 if (unlink(DMEVENTD_PIDFILE))
1741 perror(DMEVENTD_PIDFILE ": unlink failed");
1742}
1743
1744static void _daemonize(void)
1745{
1746 int child_status;
1747 int fd;
1748 pid_t pid;
1749 struct rlimit rlim;
1750 struct timeval tval;
1751 sigset_t my_sigset;
1752
1753 sigemptyset(&my_sigset);
1754 if (sigprocmask(SIG_SETMASK, &my_sigset, NULL) < 0) {
1755 fprintf(stderr, "Unable to restore signals.\n");
1756 exit(EXIT_FAILURE);
1757 }
1758 signal(SIGTERM, &_exit_handler);
1759
1760 switch (pid = fork()) {
1761 case -1:
1762 perror("fork failed:");
1763 exit(EXIT_FAILURE);
1764
1765 case 0: /* Child */
1766 break;
1767
1768 default:
1769 /* Wait for response from child */
1770 while (!waitpid(pid, &child_status, WNOHANG) && !_exit_now) {
1771 tval.tv_sec = 0;
1772 tval.tv_usec = 250000; /* .25 sec */
1773 select(0, NULL, NULL, NULL, &tval);
1774 }
1775
1776 if (_exit_now) /* Child has signaled it is ok - we can exit now */
1777 exit(EXIT_SUCCESS);
1778
1779 /* Problem with child. Determine what it is by exit code */
1780 switch (WEXITSTATUS(child_status)) {
1781 case EXIT_DESC_CLOSE_FAILURE:
1782 case EXIT_DESC_OPEN_FAILURE:
1783 case EXIT_FIFO_FAILURE:
1784 case EXIT_CHDIR_FAILURE:
1785 default:
1786 fprintf(stderr, "Child exited with code %d\n", WEXITSTATUS(child_status));
1787 break;
1788 }
1789
1790 exit(WEXITSTATUS(child_status));
1791 }
1792
1793 if (chdir("/"))
1794 exit(EXIT_CHDIR_FAILURE);
1795
1796 if (getrlimit(RLIMIT_NOFILE, &rlim) < 0)
1797 fd = 256; /* just have to guess */
1798 else
1799 fd = rlim.rlim_cur;
1800
1801 for (--fd; fd >= 0; fd--) {
1802#ifdef linux
1803 /* Do not close fds preloaded by systemd! */
1804 if (_systemd_activation &&
1805 (fd == SD_FD_FIFO_SERVER || fd == SD_FD_FIFO_CLIENT))
1806 continue;
1807#endif
1808 (void) close(fd);
1809 }
1810
1811 if ((open("/dev/null", O_RDONLY) < 0) ||
1812 (open("/dev/null", O_WRONLY) < 0) ||
1813 (open("/dev/null", O_WRONLY) < 0))
1814 exit(EXIT_DESC_OPEN_FAILURE);
1815
1816 setsid();
1817}
1818
1819static void restart(void)
1820{
1821 struct dm_event_fifos fifos;
1822 struct dm_event_daemon_message msg = { 0, 0, NULL };
1823 int i, count = 0;
1824 char *message;
1825 int length;
1826 int version;
1827
1828 /* Get the list of registrations from the running daemon. */
1829
1830 if (!init_fifos(&fifos)) {
1831 fprintf(stderr, "WARNING: Could not initiate communication with existing dmeventd.\n");
1832 return;
1833 }
1834
1835 if (!dm_event_get_version(&fifos, &version)) {
1836 fprintf(stderr, "WARNING: Could not communicate with existing dmeventd.\n");
1837 fini_fifos(&fifos);
1838 return;
1839 }
1840
1841 if (version < 1) {
1842 fprintf(stderr, "WARNING: The running dmeventd instance is too old.\n"
1843 "Protocol version %d (required: 1). Action cancelled.\n",
1844 version);
1845 exit(EXIT_FAILURE);
1846 }
1847
1848 if (daemon_talk(&fifos, &msg, DM_EVENT_CMD_GET_STATUS, "-", "-", 0, 0)) {
1849 exit(EXIT_FAILURE);
1850 }
1851
1852 message = msg.data;
1853 message = strchr(message, ' ');
1854 ++ message;
1855 length = strlen(msg.data);
1856 for (i = 0; i < length; ++i) {
1857 if (msg.data[i] == ';') {
1858 msg.data[i] = 0;
1859 ++count;
1860 }
1861 }
1862
1863 if (!(_initial_registrations = dm_malloc(sizeof(char*) * (count + 1)))) {
1864 fprintf(stderr, "Memory allocation registration failed.\n");
1865 exit(EXIT_FAILURE);
1866 }
1867
1868 for (i = 0; i < count; ++i) {
1869 if (!(_initial_registrations[i] = dm_strdup(message))) {
1870 fprintf(stderr, "Memory allocation for message failed.\n");
1871 exit(EXIT_FAILURE);
1872 }
1873 message += strlen(message) + 1;
1874 }
1875 _initial_registrations[count] = 0;
1876
1877 if (daemon_talk(&fifos, &msg, DM_EVENT_CMD_DIE, "-", "-", 0, 0)) {
1878 fprintf(stderr, "Old dmeventd refused to die.\n");
1879 exit(EXIT_FAILURE);
1880 }
1881
1882 fini_fifos(&fifos);
1883}
1884
1885static void usage(char *prog, FILE *file)
1886{
1887 fprintf(file, "Usage:\n"
1888 "%s [-d [-d [-d]]] [-f] [-h] [-R] [-V] [-?]\n\n"
1889 " -d Log debug messages to syslog (-d, -dd, -ddd)\n"
1890 " -f Don't fork, run in the foreground\n"
1891 " -h -? Show this help information\n"
1892 " -R Restart dmeventd\n"
1893 " -V Show version of dmeventd\n\n", prog);
1894}
1895
1896int main(int argc, char *argv[])
1897{
1898 signed char opt;
1899 struct dm_event_fifos fifos;
1900 //struct sys_log logdata = {DAEMON_NAME, LOG_DAEMON};
1901
1902 opterr = 0;
1903 optind = 0;
1904
1905 while ((opt = getopt(argc, argv, "?fhVdR")) != EOF) {
1906 switch (opt) {
1907 case 'h':
1908 usage(argv[0], stdout);
1909 exit(0);
1910 case '?':
1911 usage(argv[0], stderr);
1912 exit(0);
1913 case 'R':
1914 _restart++;
1915 break;
1916 case 'f':
1917 _foreground++;
1918 break;
1919 case 'd':
1920 dmeventd_debug++;
1921 break;
1922 case 'V':
1923 printf("dmeventd version: %s\n", DM_LIB_VERSION);
1924 exit(1);
1925 }
1926 }
1927
1928 /*
1929 * Switch to C locale to avoid reading large locale-archive file
1930 * used by some glibc (on some distributions it takes over 100MB).
1931 * Daemon currently needs to use mlockall().
1932 */
1933 if (setenv("LANG", "C", 1))
1934 perror("Cannot set LANG to C");
1935
1936 if (_restart)
1937 restart();
1938
1939#ifdef linux
1940 _systemd_activation = _systemd_handover(&fifos);
1941#endif
1942
1943 if (!_foreground)
1944 _daemonize();
1945
1946 openlog("dmeventd", LOG_PID, LOG_DAEMON);
1947
1948 (void) dm_prepare_selinux_context(DMEVENTD_PIDFILE, S_IFREG);
1949 if (dm_create_lockfile(DMEVENTD_PIDFILE) == 0)
1950 exit(EXIT_FAILURE);
1951
1952 atexit(remove_lockfile);
1953 (void) dm_prepare_selinux_context(NULL, 0);
1954
1955 /* Set the rest of the signals to cause '_exit_now' to be set */
1956 signal(SIGINT, &_exit_handler);
1957 signal(SIGHUP, &_exit_handler);
1958 signal(SIGQUIT, &_exit_handler);
1959
1960#ifdef linux
1961 /* Systemd has adjusted oom killer for us already */
1962 if (!_systemd_activation && !_protect_against_oom_killer())
1963 syslog(LOG_ERR, "Failed to protect against OOM killer");
1964#endif
1965
1966 _init_thread_signals();
1967
1968 //multilog_clear_logging();
1969 //multilog_add_type(std_syslog, &logdata);
1970 //multilog_init_verbose(std_syslog, _LOG_DEBUG);
1971 //multilog_async(1);
1972
1973 if (!_systemd_activation)
1974 _init_fifos(&fifos);
1975
1976 pthread_mutex_init(&_global_mutex, NULL);
1977
1978 if (!_systemd_activation && !_open_fifos(&fifos))
1979 exit(EXIT_FIFO_FAILURE);
1980
1981 /* Signal parent, letting them know we are ready to go. */
1982 if (!_foreground)
1983 kill(getppid(), SIGTERM);
1984 syslog(LOG_NOTICE, "dmeventd ready for processing.");
1985
1986 if (_initial_registrations)
1987 _process_initial_registrations();
1988
1989 while (!_exit_now) {
1990 _process_request(&fifos);
1991 _cleanup_unused_threads();
1992 _lock_mutex();
1993 if (!dm_list_empty(&_thread_registry)
1994 || !dm_list_empty(&_thread_registry_unused))
1995 _thread_registries_empty = 0;
1996 else
1997 _thread_registries_empty = 1;
1998 _unlock_mutex();
1999 }
2000
2001 _exit_dm_lib();
2002
2003 pthread_mutex_destroy(&_global_mutex);
2004
2005 syslog(LOG_NOTICE, "dmeventd shutting down.");
2006 closelog();
2007
2008 exit(EXIT_SUCCESS);
2009}
02010
=== added directory '.pc/dirs.patch/doc'
=== removed directory '.pc/dirs.patch/doc'
=== added file '.pc/dirs.patch/doc/example.conf.in'
--- .pc/dirs.patch/doc/example.conf.in 1970-01-01 00:00:00 +0000
+++ .pc/dirs.patch/doc/example.conf.in 2012-08-21 10:18:22 +0000
@@ -0,0 +1,773 @@
1# This is an example configuration file for the LVM2 system.
2# It contains the default settings that would be used if there was no
3# @DEFAULT_SYS_DIR@/lvm.conf file.
4#
5# Refer to 'man lvm.conf' for further information including the file layout.
6#
7# To put this file in a different directory and override @DEFAULT_SYS_DIR@ set
8# the environment variable LVM_SYSTEM_DIR before running the tools.
9#
10# N.B. Take care that each setting only appears once if uncommenting
11# example settings in this file.
12
13
14# This section allows you to configure which block devices should
15# be used by the LVM system.
16devices {
17
18 # Where do you want your volume groups to appear ?
19 dir = "/dev"
20
21 # An array of directories that contain the device nodes you wish
22 # to use with LVM2.
23 scan = [ "/dev" ]
24
25 # If set, the cache of block device nodes with all associated symlinks
26 # will be constructed out of the existing udev database content.
27 # This avoids using and opening any inapplicable non-block devices or
28 # subdirectories found in the device directory. This setting is applied
29 # to udev-managed device directory only, other directories will be scanned
30 # fully. LVM2 needs to be compiled with udev support for this setting to
31 # take effect. N.B. Any device node or symlink not managed by udev in
32 # udev directory will be ignored with this setting on.
33 obtain_device_list_from_udev = 1
34
35 # If several entries in the scanned directories correspond to the
36 # same block device and the tools need to display a name for device,
37 # all the pathnames are matched against each item in the following
38 # list of regular expressions in turn and the first match is used.
39 preferred_names = [ ]
40
41 # Try to avoid using undescriptive /dev/dm-N names, if present.
42 # preferred_names = [ "^/dev/mpath/", "^/dev/mapper/mpath", "^/dev/[hs]d" ]
43
44 # A filter that tells LVM2 to only use a restricted set of devices.
45 # The filter consists of an array of regular expressions. These
46 # expressions can be delimited by a character of your choice, and
47 # prefixed with either an 'a' (for accept) or 'r' (for reject).
48 # The first expression found to match a device name determines if
49 # the device will be accepted or rejected (ignored). Devices that
50 # don't match any patterns are accepted.
51
52 # Be careful if there there are symbolic links or multiple filesystem
53 # entries for the same device as each name is checked separately against
54 # the list of patterns. The effect is that if the first pattern in the
55 # list to match a name is an 'a' pattern for any of the names, the device
56 # is accepted; otherwise if the first pattern in the list to match a name
57 # is an 'r' pattern for any of the names it is rejected; otherwise it is
58 # accepted.
59
60 # Don't have more than one filter line active at once: only one gets used.
61
62 # Run vgscan after you change this parameter to ensure that
63 # the cache file gets regenerated (see below).
64 # If it doesn't do what you expect, check the output of 'vgscan -vvvv'.
65
66
67 # By default we accept every block device:
68 filter = [ "a/.*/" ]
69
70 # Exclude the cdrom drive
71 # filter = [ "r|/dev/cdrom|" ]
72
73 # When testing I like to work with just loopback devices:
74 # filter = [ "a/loop/", "r/.*/" ]
75
76 # Or maybe all loops and ide drives except hdc:
77 # filter =[ "a|loop|", "r|/dev/hdc|", "a|/dev/ide|", "r|.*|" ]
78
79 # Use anchors if you want to be really specific
80 # filter = [ "a|^/dev/hda8$|", "r/.*/" ]
81
82 # The results of the filtering are cached on disk to avoid
83 # rescanning dud devices (which can take a very long time).
84 # By default this cache is stored in the @DEFAULT_SYS_DIR@/@DEFAULT_CACHE_SUBDIR@ directory
85 # in a file called '.cache'.
86 # It is safe to delete the contents: the tools regenerate it.
87 # (The old setting 'cache' is still respected if neither of
88 # these new ones is present.)
89 cache_dir = "@DEFAULT_SYS_DIR@/@DEFAULT_CACHE_SUBDIR@"
90 cache_file_prefix = ""
91
92 # You can turn off writing this cache file by setting this to 0.
93 write_cache_state = 1
94
95 # Advanced settings.
96
97 # List of pairs of additional acceptable block device types found
98 # in /proc/devices with maximum (non-zero) number of partitions.
99 # types = [ "fd", 16 ]
100
101 # If sysfs is mounted (2.6 kernels) restrict device scanning to
102 # the block devices it believes are valid.
103 # 1 enables; 0 disables.
104 sysfs_scan = 1
105
106 # By default, LVM2 will ignore devices used as component paths
107 # of device-mapper multipath devices.
108 # 1 enables; 0 disables.
109 multipath_component_detection = 1
110
111 # By default, LVM2 will ignore devices used as components of
112 # software RAID (md) devices by looking for md superblocks.
113 # 1 enables; 0 disables.
114 md_component_detection = 1
115
116 # By default, if a PV is placed directly upon an md device, LVM2
117 # will align its data blocks with the md device's stripe-width.
118 # 1 enables; 0 disables.
119 md_chunk_alignment = 1
120
121 # Default alignment of the start of a data area in MB. If set to 0,
122 # a value of 64KB will be used. Set to 1 for 1MiB, 2 for 2MiB, etc.
123 # default_data_alignment = @DEFAULT_DATA_ALIGNMENT@
124
125 # By default, the start of a PV's data area will be a multiple of
126 # the 'minimum_io_size' or 'optimal_io_size' exposed in sysfs.
127 # - minimum_io_size - the smallest request the device can perform
128 # w/o incurring a read-modify-write penalty (e.g. MD's chunk size)
129 # - optimal_io_size - the device's preferred unit of receiving I/O
130 # (e.g. MD's stripe width)
131 # minimum_io_size is used if optimal_io_size is undefined (0).
132 # If md_chunk_alignment is enabled, that detects the optimal_io_size.
133 # This setting takes precedence over md_chunk_alignment.
134 # 1 enables; 0 disables.
135 data_alignment_detection = 1
136
137 # Alignment (in KB) of start of data area when creating a new PV.
138 # md_chunk_alignment and data_alignment_detection are disabled if set.
139 # Set to 0 for the default alignment (see: data_alignment_default)
140 # or page size, if larger.
141 data_alignment = 0
142
143 # By default, the start of the PV's aligned data area will be shifted by
144 # the 'alignment_offset' exposed in sysfs. This offset is often 0 but
145 # may be non-zero; e.g.: certain 4KB sector drives that compensate for
146 # windows partitioning will have an alignment_offset of 3584 bytes
147 # (sector 7 is the lowest aligned logical block, the 4KB sectors start
148 # at LBA -1, and consequently sector 63 is aligned on a 4KB boundary).
149 # But note that pvcreate --dataalignmentoffset will skip this detection.
150 # 1 enables; 0 disables.
151 data_alignment_offset_detection = 1
152
153 # If, while scanning the system for PVs, LVM2 encounters a device-mapper
154 # device that has its I/O suspended, it waits for it to become accessible.
155 # Set this to 1 to skip such devices. This should only be needed
156 # in recovery situations.
157 ignore_suspended_devices = 0
158
159 # During each LVM operation errors received from each device are counted.
160 # If the counter of a particular device exceeds the limit set here, no
161 # further I/O is sent to that device for the remainder of the respective
162 # operation. Setting the parameter to 0 disables the counters altogether.
163 disable_after_error_count = 0
164
165 # Allow use of pvcreate --uuid without requiring --restorefile.
166 require_restorefile_with_uuid = 1
167
168 # Minimum size (in KB) of block devices which can be used as PVs.
169 # In a clustered environment all nodes must use the same value.
170 # Any value smaller than 512KB is ignored.
171
172 # Ignore devices smaller than 2MB such as floppy drives.
173 pv_min_size = 2048
174
175 # The original built-in setting was 512 up to and including version 2.02.84.
176 # pv_min_size = 512
177
178 # Issue discards to a logical volumes's underlying physical volume(s) when
179 # the logical volume is no longer using the physical volumes' space (e.g.
180 # lvremove, lvreduce, etc). Discards inform the storage that a region is
181 # no longer in use. Storage that supports discards advertise the protocol
182 # specific way discards should be issued by the kernel (TRIM, UNMAP, or
183 # WRITE SAME with UNMAP bit set). Not all storage will support or benefit
184 # from discards but SSDs and thinly provisioned LUNs generally do. If set
185 # to 1, discards will only be issued if both the storage and kernel provide
186 # support.
187 # 1 enables; 0 disables.
188 issue_discards = 0
189}
190
191# This section allows you to configure the way in which LVM selects
192# free space for its Logical Volumes.
193#allocation {
194# When searching for free space to extend an LV, the "cling"
195# allocation policy will choose space on the same PVs as the last
196# segment of the existing LV. If there is insufficient space and a
197# list of tags is defined here, it will check whether any of them are
198# attached to the PVs concerned and then seek to match those PV tags
199# between existing extents and new extents.
200# Use the special tag "@*" as a wildcard to match any PV tag.
201#
202# Example: LVs are mirrored between two sites within a single VG.
203# PVs are tagged with either @site1 or @site2 to indicate where
204# they are situated.
205#
206# cling_tag_list = [ "@site1", "@site2" ]
207# cling_tag_list = [ "@*" ]
208#
209# Changes made in version 2.02.85 extended the reach of the 'cling'
210# policies to detect more situations where data can be grouped
211# onto the same disks. Set this to 0 to revert to the previous
212# algorithm.
213#
214# maximise_cling = 1
215#
216# Set to 1 to guarantee that mirror logs will always be placed on
217# different PVs from the mirror images. This was the default
218# until version 2.02.85.
219#
220# mirror_logs_require_separate_pvs = 0
221#
222# Set to 1 to guarantee that thin pool metadata will always
223# be placed on different PVs from the pool data.
224#
225# thin_pool_metadata_require_separate_pvs = 0
226#}
227
228# This section that allows you to configure the nature of the
229# information that LVM2 reports.
230log {
231
232 # Controls the messages sent to stdout or stderr.
233 # There are three levels of verbosity, 3 being the most verbose.
234 verbose = 0
235
236 # Should we send log messages through syslog?
237 # 1 is yes; 0 is no.
238 syslog = 1
239
240 # Should we log error and debug messages to a file?
241 # By default there is no log file.
242 #file = "/var/log/lvm2.log"
243
244 # Should we overwrite the log file each time the program is run?
245 # By default we append.
246 overwrite = 0
247
248 # What level of log messages should we send to the log file and/or syslog?
249 # There are 6 syslog-like log levels currently in use - 2 to 7 inclusive.
250 # 7 is the most verbose (LOG_DEBUG).
251 level = 0
252
253 # Format of output messages
254 # Whether or not (1 or 0) to indent messages according to their severity
255 indent = 1
256
257 # Whether or not (1 or 0) to display the command name on each line output
258 command_names = 0
259
260 # A prefix to use before the message text (but after the command name,
261 # if selected). Default is two spaces, so you can see/grep the severity
262 # of each message.
263 prefix = " "
264
265 # To make the messages look similar to the original LVM tools use:
266 # indent = 0
267 # command_names = 1
268 # prefix = " -- "
269
270 # Set this if you want log messages during activation.
271 # Don't use this in low memory situations (can deadlock).
272 # activation = 0
273}
274
275# Configuration of metadata backups and archiving. In LVM2 when we
276# talk about a 'backup' we mean making a copy of the metadata for the
277# *current* system. The 'archive' contains old metadata configurations.
278# Backups are stored in a human readeable text format.
279backup {
280
281 # Should we maintain a backup of the current metadata configuration ?
282 # Use 1 for Yes; 0 for No.
283 # Think very hard before turning this off!
284 backup = 1
285
286 # Where shall we keep it ?
287 # Remember to back up this directory regularly!
288 backup_dir = "@DEFAULT_SYS_DIR@/@DEFAULT_BACKUP_SUBDIR@"
289
290 # Should we maintain an archive of old metadata configurations.
291 # Use 1 for Yes; 0 for No.
292 # On by default. Think very hard before turning this off.
293 archive = 1
294
295 # Where should archived files go ?
296 # Remember to back up this directory regularly!
297 archive_dir = "@DEFAULT_SYS_DIR@/@DEFAULT_ARCHIVE_SUBDIR@"
298
299 # What is the minimum number of archive files you wish to keep ?
300 retain_min = 10
301
302 # What is the minimum time you wish to keep an archive file for ?
303 retain_days = 30
304}
305
306# Settings for the running LVM2 in shell (readline) mode.
307shell {
308
309 # Number of lines of history to store in ~/.lvm_history
310 history_size = 100
311}
312
313
314# Miscellaneous global LVM2 settings
315global {
316
317 # The file creation mask for any files and directories created.
318 # Interpreted as octal if the first digit is zero.
319 umask = 077
320
321 # Allow other users to read the files
322 #umask = 022
323
324 # Enabling test mode means that no changes to the on disk metadata
325 # will be made. Equivalent to having the -t option on every
326 # command. Defaults to off.
327 test = 0
328
329 # Default value for --units argument
330 units = "h"
331
332 # Since version 2.02.54, the tools distinguish between powers of
333 # 1024 bytes (e.g. KiB, MiB, GiB) and powers of 1000 bytes (e.g.
334 # KB, MB, GB).
335 # If you have scripts that depend on the old behaviour, set this to 0
336 # temporarily until you update them.
337 si_unit_consistency = 1
338
339 # Whether or not to communicate with the kernel device-mapper.
340 # Set to 0 if you want to use the tools to manipulate LVM metadata
341 # without activating any logical volumes.
342 # If the device-mapper kernel driver is not present in your kernel
343 # setting this to 0 should suppress the error messages.
344 activation = 1
345
346 # If we can't communicate with device-mapper, should we try running
347 # the LVM1 tools?
348 # This option only applies to 2.4 kernels and is provided to help you
349 # switch between device-mapper kernels and LVM1 kernels.
350 # The LVM1 tools need to be installed with .lvm1 suffices
351 # e.g. vgscan.lvm1 and they will stop working after you start using
352 # the new lvm2 on-disk metadata format.
353 # The default value is set when the tools are built.
354 # fallback_to_lvm1 = 0
355
356 # The default metadata format that commands should use - "lvm1" or "lvm2".
357 # The command line override is -M1 or -M2.
358 # Defaults to "lvm2".
359 # format = "lvm2"
360
361 # Location of proc filesystem
362 proc = "/proc"
363
364 # Type of locking to use. Defaults to local file-based locking (1).
365 # Turn locking off by setting to 0 (dangerous: risks metadata corruption
366 # if LVM2 commands get run concurrently).
367 # Type 2 uses the external shared library locking_library.
368 # Type 3 uses built-in clustered locking.
369 # Type 4 uses read-only locking which forbids any operations that might
370 # change metadata.
371 locking_type = 1
372
373 # Set to 0 to fail when a lock request cannot be satisfied immediately.
374 wait_for_locks = 1
375
376 # If using external locking (type 2) and initialisation fails,
377 # with this set to 1 an attempt will be made to use the built-in
378 # clustered locking.
379 # If you are using a customised locking_library you should set this to 0.
380 fallback_to_clustered_locking = 1
381
382 # If an attempt to initialise type 2 or type 3 locking failed, perhaps
383 # because cluster components such as clvmd are not running, with this set
384 # to 1 an attempt will be made to use local file-based locking (type 1).
385 # If this succeeds, only commands against local volume groups will proceed.
386 # Volume Groups marked as clustered will be ignored.
387 fallback_to_local_locking = 1
388
389 # Local non-LV directory that holds file-based locks while commands are
390 # in progress. A directory like /tmp that may get wiped on reboot is OK.
391 locking_dir = "@DEFAULT_LOCK_DIR@"
392
393 # Whenever there are competing read-only and read-write access requests for
394 # a volume group's metadata, instead of always granting the read-only
395 # requests immediately, delay them to allow the read-write requests to be
396 # serviced. Without this setting, write access may be stalled by a high
397 # volume of read-only requests.
398 # NB. This option only affects locking_type = 1 viz. local file-based
399 # locking.
400 prioritise_write_locks = 1
401
402 # Other entries can go here to allow you to load shared libraries
403 # e.g. if support for LVM1 metadata was compiled as a shared library use
404 # format_libraries = "liblvm2format1.so"
405 # Full pathnames can be given.
406
407 # Search this directory first for shared libraries.
408 # library_dir = "/lib"
409
410 # The external locking library to load if locking_type is set to 2.
411 # locking_library = "liblvm2clusterlock.so"
412
413 # Treat any internal errors as fatal errors, aborting the process that
414 # encountered the internal error. Please only enable for debugging.
415 abort_on_internal_errors = 0
416
417 # Check whether CRC is matching when parsed VG is used multiple times.
418 # This is useful to catch unexpected internal cached volume group
419 # structure modification. Please only enable for debugging.
420 detect_internal_vg_cache_corruption = 0
421
422 # If set to 1, no operations that change on-disk metadata will be permitted.
423 # Additionally, read-only commands that encounter metadata in need of repair
424 # will still be allowed to proceed exactly as if the repair had been
425 # performed (except for the unchanged vg_seqno).
426 # Inappropriate use could mess up your system, so seek advice first!
427 metadata_read_only = 0
428
429 # 'mirror_segtype_default' defines which segtype will be used when the
430 # shorthand '-m' option is used for mirroring. The possible options are:
431 #
432 # "mirror" - The original RAID1 implementation provided by LVM2/DM. It is
433 # characterized by a flexible log solution (core, disk, mirrored)
434 # and by the necessity to block I/O while reconfiguring in the
435 # event of a failure. Snapshots of this type of RAID1 can be
436 # problematic.
437 #
438 # "raid1" - This implementation leverages MD's RAID1 personality through
439 # device-mapper. It is characterized by a lack of log options.
440 # (A log is always allocated for every device and they are placed
441 # on the same device as the image - no separate devices are
442 # required.) This mirror implementation does not require I/O
443 # to be blocked in the kernel in the event of a failure.
444 #
445 # Specify the '--type <mirror|raid1>' option to override this default
446 # setting.
447 mirror_segtype_default = "mirror"
448
449 # The default format for displaying LV names in lvdisplay was changed
450 # in version 2.02.89 to show the LV name and path separately.
451 # Previously this was always shown as /dev/vgname/lvname even when that
452 # was never a valid path in the /dev filesystem.
453 # Set to 1 to reinstate the previous format.
454 #
455 # lvdisplay_shows_full_device_path = 0
456
457 # Whether to use (trust) a running instance of lvmetad. If this is set to
458 # 0, all commands fall back to the usual scanning mechanisms. When set to 1
459 # *and* when lvmetad is running (it is not auto-started), the volume group
460 # metadata and PV state flags are obtained from the lvmetad instance and no
461 # scanning is done by the individual commands. In a setup with lvmetad,
462 # lvmetad udev rules *must* be set up for LVM to work correctly. Without
463 # proper udev rules, all changes in block device configuration will be
464 # *ignored* until a manual 'vgscan' is performed.
465 use_lvmetad = 0
466}
467
468activation {
469 # Set to 1 to perform internal checks on the operations issued to
470 # libdevmapper. Useful for debugging problems with activation.
471 # Some of the checks may be expensive, so it's best to use this
472 # only when there seems to be a problem.
473 checks = 0
474
475 # Set to 0 to disable udev synchronisation (if compiled into the binaries).
476 # Processes will not wait for notification from udev.
477 # They will continue irrespective of any possible udev processing
478 # in the background. You should only use this if udev is not running
479 # or has rules that ignore the devices LVM2 creates.
480 # The command line argument --nodevsync takes precedence over this setting.
481 # If set to 1 when udev is not running, and there are LVM2 processes
482 # waiting for udev, run 'dmsetup udevcomplete_all' manually to wake them up.
483 udev_sync = 1
484
485 # Set to 0 to disable the udev rules installed by LVM2 (if built with
486 # --enable-udev_rules). LVM2 will then manage the /dev nodes and symlinks
487 # for active logical volumes directly itself.
488 # N.B. Manual intervention may be required if this setting is changed
489 # while any logical volumes are active.
490 udev_rules = 1
491
492 # Set to 1 for LVM2 to verify operations performed by udev. This turns on
493 # additional checks (and if necessary, repairs) on entries in the device
494 # directory after udev has completed processing its events.
495 # Useful for diagnosing problems with LVM2/udev interactions.
496 verify_udev_operations = 0
497
498 # If set to 1 and if deactivation of an LV fails, perhaps because
499 # a process run from a quick udev rule temporarily opened the device,
500 # retry the operation for a few seconds before failing.
501 retry_deactivation = 1
502
503 # How to fill in missing stripes if activating an incomplete volume.
504 # Using "error" will make inaccessible parts of the device return
505 # I/O errors on access. You can instead use a device path, in which
506 # case, that device will be used to in place of missing stripes.
507 # But note that using anything other than "error" with mirrored
508 # or snapshotted volumes is likely to result in data corruption.
509 missing_stripe_filler = "error"
510
511 # The linear target is an optimised version of the striped target
512 # that only handles a single stripe. Set this to 0 to disable this
513 # optimisation and always use the striped target.
514 use_linear_target = 1
515
516 # How much stack (in KB) to reserve for use while devices suspended
517 # Prior to version 2.02.89 this used to be set to 256KB
518 reserved_stack = 64
519
520 # How much memory (in KB) to reserve for use while devices suspended
521 reserved_memory = 8192
522
523 # Nice value used while devices suspended
524 process_priority = -18
525
526 # If volume_list is defined, each LV is only activated if there is a
527 # match against the list.
528 # "vgname" and "vgname/lvname" are matched exactly.
529 # "@tag" matches any tag set in the LV or VG.
530 # "@*" matches if any tag defined on the host is also set in the LV or VG
531 #
532 # volume_list = [ "vg1", "vg2/lvol1", "@tag1", "@*" ]
533
534 # If read_only_volume_list is defined, each LV that is to be activated
535 # is checked against the list, and if it matches, it as activated
536 # in read-only mode. (This overrides '--permission rw' stored in the
537 # metadata.)
538 # "vgname" and "vgname/lvname" are matched exactly.
539 # "@tag" matches any tag set in the LV or VG.
540 # "@*" matches if any tag defined on the host is also set in the LV or VG
541 #
542 # read_only_volume_list = [ "vg1", "vg2/lvol1", "@tag1", "@*" ]
543
544 # Size (in KB) of each copy operation when mirroring
545 mirror_region_size = 512
546
547 # Setting to use when there is no readahead value stored in the metadata.
548 #
549 # "none" - Disable readahead.
550 # "auto" - Use default value chosen by kernel.
551 readahead = "auto"
552
553 # 'raid_fault_policy' defines how a device failure in a RAID logical
554 # volume is handled. This includes logical volumes that have the following
555 # segment types: raid1, raid4, raid5*, and raid6*.
556 #
557 # In the event of a failure, the following policies will determine what
558 # actions are performed during the automated response to failures (when
559 # dmeventd is monitoring the RAID logical volume) and when 'lvconvert' is
560 # called manually with the options '--repair' and '--use-policies'.
561 #
562 # "warn" - Use the system log to warn the user that a device in the RAID
563 # logical volume has failed. It is left to the user to run
564 # 'lvconvert --repair' manually to remove or replace the failed
565 # device. As long as the number of failed devices does not
566 # exceed the redundancy of the logical volume (1 device for
567 # raid4/5, 2 for raid6, etc) the logical volume will remain
568 # usable.
569 #
570 # "allocate" - Attempt to use any extra physical volumes in the volume
571 # group as spares and replace faulty devices.
572 #
573 raid_fault_policy = "warn"
574
575 # 'mirror_image_fault_policy' and 'mirror_log_fault_policy' define
576 # how a device failure affecting a mirror (of "mirror" segment type) is
577 # handled. A mirror is composed of mirror images (copies) and a log.
578 # A disk log ensures that a mirror does not need to be re-synced
579 # (all copies made the same) every time a machine reboots or crashes.
580 #
581 # In the event of a failure, the specified policy will be used to determine
582 # what happens. This applies to automatic repairs (when the mirror is being
583 # monitored by dmeventd) and to manual lvconvert --repair when
584 # --use-policies is given.
585 #
586 # "remove" - Simply remove the faulty device and run without it. If
587 # the log device fails, the mirror would convert to using
588 # an in-memory log. This means the mirror will not
589 # remember its sync status across crashes/reboots and
590 # the entire mirror will be re-synced. If a
591 # mirror image fails, the mirror will convert to a
592 # non-mirrored device if there is only one remaining good
593 # copy.
594 #
595 # "allocate" - Remove the faulty device and try to allocate space on
596 # a new device to be a replacement for the failed device.
597 # Using this policy for the log is fast and maintains the
598 # ability to remember sync state through crashes/reboots.
599 # Using this policy for a mirror device is slow, as it
600 # requires the mirror to resynchronize the devices, but it
601 # will preserve the mirror characteristic of the device.
602 # This policy acts like "remove" if no suitable device and
603 # space can be allocated for the replacement.
604 #
605 # "allocate_anywhere" - Not yet implemented. Useful to place the log device
606 # temporarily on same physical volume as one of the mirror
607 # images. This policy is not recommended for mirror devices
608 # since it would break the redundant nature of the mirror. This
609 # policy acts like "remove" if no suitable device and space can
610 # be allocated for the replacement.
611
612 mirror_log_fault_policy = "allocate"
613 mirror_image_fault_policy = "remove"
614
615 # 'snapshot_autoextend_threshold' and 'snapshot_autoextend_percent' define
616 # how to handle automatic snapshot extension. The former defines when the
617 # snapshot should be extended: when its space usage exceeds this many
618 # percent. The latter defines how much extra space should be allocated for
619 # the snapshot, in percent of its current size.
620 #
621 # For example, if you set snapshot_autoextend_threshold to 70 and
622 # snapshot_autoextend_percent to 20, whenever a snapshot exceeds 70% usage,
623 # it will be extended by another 20%. For a 1G snapshot, using up 700M will
624 # trigger a resize to 1.2G. When the usage exceeds 840M, the snapshot will
625 # be extended to 1.44G, and so on.
626 #
627 # Setting snapshot_autoextend_threshold to 100 disables automatic
628 # extensions. The minimum value is 50 (A setting below 50 will be treated
629 # as 50).
630
631 snapshot_autoextend_threshold = 100
632 snapshot_autoextend_percent = 20
633
634 # 'thin_pool_autoextend_threshold' and 'thin_pool_autoextend_percent' define
635 # how to handle automatic pool extension. The former defines when the
636 # pool should be extended: when its space usage exceeds this many
637 # percent. The latter defines how much extra space should be allocated for
638 # the pool, in percent of its current size.
639 #
640 # For example, if you set thin_pool_autoextend_threshold to 70 and
641 # thin_pool_autoextend_percent to 20, whenever a pool exceeds 70% usage,
642 # it will be extended by another 20%. For a 1G pool, using up 700M will
643 # trigger a resize to 1.2G. When the usage exceeds 840M, the pool will
644 # be extended to 1.44G, and so on.
645 #
646 # Setting thin_pool_autoextend_threshold to 100 disables automatic
647 # extensions. The minimum value is 50 (A setting below 50 will be treated
648 # as 50).
649
650 thin_pool_autoextend_threshold = 100
651 thin_pool_autoextend_percent = 20
652
653 # Full path of the utility called to check that a thin metadata device
654 # is in a state that allows it to be used.
655 # Each time a thin pool needs to be activated, this utility is executed.
656 # The activation will only proceed if the utility has an exit status of 0.
657 # Set to "" to skip this check. (Not recommended.)
658 # The thin tools are available as part of the device-mapper-persistent-data
659 # package from https://github.com/jthornber/thin-provisioning-tools.
660 #
661 thin_check_executable = "/sbin/thin_check -q"
662
663 # While activating devices, I/O to devices being (re)configured is
664 # suspended, and as a precaution against deadlocks, LVM2 needs to pin
665 # any memory it is using so it is not paged out. Groups of pages that
666 # are known not to be accessed during activation need not be pinned
667 # into memory. Each string listed in this setting is compared against
668 # each line in /proc/self/maps, and the pages corresponding to any
669 # lines that match are not pinned. On some systems locale-archive was
670 # found to make up over 80% of the memory used by the process.
671 # mlock_filter = [ "locale/locale-archive", "gconv/gconv-modules.cache" ]
672
673 # Set to 1 to revert to the default behaviour prior to version 2.02.62
674 # which used mlockall() to pin the whole process's memory while activating
675 # devices.
676 use_mlockall = 0
677
678 # Monitoring is enabled by default when activating logical volumes.
679 # Set to 0 to disable monitoring or use the --ignoremonitoring option.
680 monitoring = 1
681
682 # When pvmove or lvconvert must wait for the kernel to finish
683 # synchronising or merging data, they check and report progress
684 # at intervals of this number of seconds. The default is 15 seconds.
685 # If this is set to 0 and there is only one thing to wait for, there
686 # are no progress reports, but the process is awoken immediately the
687 # operation is complete.
688 polling_interval = 15
689}
690
691
692####################
693# Advanced section #
694####################
695
696# Metadata settings
697#
698# metadata {
699 # Default number of copies of metadata to hold on each PV. 0, 1 or 2.
700 # You might want to override it from the command line with 0
701 # when running pvcreate on new PVs which are to be added to large VGs.
702
703 # pvmetadatacopies = 1
704
705 # Default number of copies of metadata to maintain for each VG.
706 # If set to a non-zero value, LVM automatically chooses which of
707 # the available metadata areas to use to achieve the requested
708 # number of copies of the VG metadata. If you set a value larger
709 # than the the total number of metadata areas available then
710 # metadata is stored in them all.
711 # The default value of 0 ("unmanaged") disables this automatic
712 # management and allows you to control which metadata areas
713 # are used at the individual PV level using 'pvchange
714 # --metadataignore y/n'.
715
716 # vgmetadatacopies = 0
717
718 # Approximate default size of on-disk metadata areas in sectors.
719 # You should increase this if you have large volume groups or
720 # you want to retain a large on-disk history of your metadata changes.
721
722 # pvmetadatasize = 255
723
724 # List of directories holding live copies of text format metadata.
725 # These directories must not be on logical volumes!
726 # It's possible to use LVM2 with a couple of directories here,
727 # preferably on different (non-LV) filesystems, and with no other
728 # on-disk metadata (pvmetadatacopies = 0). Or this can be in
729 # addition to on-disk metadata areas.
730 # The feature was originally added to simplify testing and is not
731 # supported under low memory situations - the machine could lock up.
732 #
733 # Never edit any files in these directories by hand unless you
734 # you are absolutely sure you know what you are doing! Use
735 # the supplied toolset to make changes (e.g. vgcfgrestore).
736
737 # dirs = [ "/etc/lvm/metadata", "/mnt/disk2/lvm/metadata2" ]
738#}
739
740# Event daemon
741#
742dmeventd {
743 # mirror_library is the library used when monitoring a mirror device.
744 #
745 # "libdevmapper-event-lvm2mirror.so" attempts to recover from
746 # failures. It removes failed devices from a volume group and
747 # reconfigures a mirror as necessary. If no mirror library is
748 # provided, mirrors are not monitored through dmeventd.
749
750 mirror_library = "libdevmapper-event-lvm2mirror.so"
751
752 # snapshot_library is the library used when monitoring a snapshot device.
753 #
754 # "libdevmapper-event-lvm2snapshot.so" monitors the filling of
755 # snapshots and emits a warning through syslog when the use of
756 # the snapshot exceeds 80%. The warning is repeated when 85%, 90% and
757 # 95% of the snapshot is filled.
758
759 snapshot_library = "libdevmapper-event-lvm2snapshot.so"
760
761 # thin_library is the library used when monitoring a thin device.
762 #
763 # "libdevmapper-event-lvm2thin.so" monitors the filling of
764 # pool and emits a warning through syslog when the use of
765 # the pool exceeds 80%. The warning is repeated when 85%, 90% and
766 # 95% of the pool is filled.
767
768 thin_library = "libdevmapper-event-lvm2thin.so"
769
770 # Full path of the dmeventd binary.
771 #
772 # executable = "@DMEVENTD_PATH@"
773}
0774
=== removed file '.pc/dirs.patch/doc/example.conf.in'
--- .pc/dirs.patch/doc/example.conf.in 2012-04-14 02:57:53 +0000
+++ .pc/dirs.patch/doc/example.conf.in 1970-01-01 00:00:00 +0000
@@ -1,662 +0,0 @@
1# This is an example configuration file for the LVM2 system.
2# It contains the default settings that would be used if there was no
3# @DEFAULT_SYS_DIR@/lvm.conf file.
4#
5# Refer to 'man lvm.conf' for further information including the file layout.
6#
7# To put this file in a different directory and override @DEFAULT_SYS_DIR@ set
8# the environment variable LVM_SYSTEM_DIR before running the tools.
9#
10# N.B. Take care that each setting only appears once if uncommenting
11# example settings in this file.
12
13
14# This section allows you to configure which block devices should
15# be used by the LVM system.
16devices {
17
18 # Where do you want your volume groups to appear ?
19 dir = "/dev"
20
21 # An array of directories that contain the device nodes you wish
22 # to use with LVM2.
23 scan = [ "/dev" ]
24
25 # If set, the cache of block device nodes with all associated symlinks
26 # will be constructed out of the existing udev database content.
27 # This avoids using and opening any inapplicable non-block devices or
28 # subdirectories found in the device directory. This setting is applied
29 # to udev-managed device directory only, other directories will be scanned
30 # fully. LVM2 needs to be compiled with udev support for this setting to
31 # take effect. N.B. Any device node or symlink not managed by udev in
32 # udev directory will be ignored with this setting on.
33 obtain_device_list_from_udev = 1
34
35 # If several entries in the scanned directories correspond to the
36 # same block device and the tools need to display a name for device,
37 # all the pathnames are matched against each item in the following
38 # list of regular expressions in turn and the first match is used.
39 preferred_names = [ ]
40
41 # Try to avoid using undescriptive /dev/dm-N names, if present.
42 # preferred_names = [ "^/dev/mpath/", "^/dev/mapper/mpath", "^/dev/[hs]d" ]
43
44 # A filter that tells LVM2 to only use a restricted set of devices.
45 # The filter consists of an array of regular expressions. These
46 # expressions can be delimited by a character of your choice, and
47 # prefixed with either an 'a' (for accept) or 'r' (for reject).
48 # The first expression found to match a device name determines if
49 # the device will be accepted or rejected (ignored). Devices that
50 # don't match any patterns are accepted.
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches