drbd-utils-8.9.6/0000755000175000017500000000000012654475367013526 5ustar apoikosapoikosdrbd-utils-8.9.6/.gitmodules0000644000175000017500000000013512477305373015672 0ustar apoikosapoikos[submodule "drbd-headers"] path = drbd-headers url = git://git.linbit.com/drbd-headers.git drbd-utils-8.9.6/documentation/0000755000175000017500000000000012654475367016377 5ustar apoikosapoikosdrbd-utils-8.9.6/documentation/aspell.en.per0000644000175000017500000000374212466702073020762 0ustar apoikosapoikospersonal_ws-1.1 en 285 ArbitraryCnt BIOs BLKFLSBUF BLKGETSIZE BLKSSZGET BarrierAck Bitmap's BrokenPipe ConnectedCnt ConnectedInd DRBD's DUnknown EAGAIN EBUSY EINVAL ENOMEM EOPNOTSUPP Ellenberg FIXME GBit GCs GPL GmbH HumanCnt IDE JFS KDIR KOBJ LANANA LBD LINBIT MDF NIC NICs NUL NUM NetworkFailure PausedSyncS PausedSyncT Philipp PingAck ProtocolError RAIDs RHEL RLE ReIsErFs Reisner SETLKW SIGALRM SVN SWAPSPACE StandAlone StartingSync StartingSyncS StartingSyncT SyncParam SyncSource SyncTarget SyncUUID TCQ TK TODO TearDown TimeoutCnt UI UUIDs UnknownMandatoryTag UpToDate VerifyS VerifyT WFBitMapS WFBitMapT WFConnection WFReportParams WFSyncUUID WantFullSync ack acked acks actlog addr adm al alg api argc args argv asbp asender asprintf bm bmbv bnum boolean bsize buildtag bvec cB calloc canonicalize cfg cgi chdir checksum cmd cmdname cn conf config conv cpu crypto cstate ctl degr dereference dev devfs devname diskless diskstats dont dopd drbd drbdX drbdadm drbdmeta drbdsetup drbdtool ds dstate dt endian endianness enums etext evictable exa extraversion fcntl fd fdopen fgets filesystem fprintf fs fstat fstype gc gcc gethostbyname gi goto haclient hacluster hdr hexdump hmac hostname http idx incon init inline io ip ipv irq kb kmalloc ko lastState len lge libdisk linux lld llu ln longjmp longoptions lookup lr lru lu lvm malloc md mem memalign memset metadata mkdir modprobe multihomed mutex netlink nodenames noheadings nop nosuffix nv ok online oopsie optind ord outdate outdating pagesize param parms pathname pid plaintext posix pre prepends pri printf proc pv pvs recurse recurses recv refcnt refcount reiser reiserfs resize resync resynced rr runlength sb sbin scmd sendpage sizeof sndbuf spinlock ssocks startup stderr stdout stonith str strtoll struct subcommand sublevel superblock suse symlinks syncer sys syscall sysconf tl toc tracepoint tri tty udev unconfigure unconfigured uniq urandom userland userspace usr uuid uuids varname vasprintf vmalloc wfc wget writeout xfs xfsprogs xml yylval drbd-utils-8.9.6/documentation/fencing-by-constraints.txt0000644000175000017500000001002712466702073023512 0ustar apoikosapoikos# vim: set foldenable foldmethod=indent sw=4 ts=8 : # Copyright 2013 Linbit HA Solutions GmbH # Lars Ellenberg @ linbit.com TODO: someone convert this into proper ascii doc please ;-) ... and draw some pictures ... How crm-fence-peer.sh, pacemaker, and the OCF Linbit DRBD resource agent are supposed to work together. Two node cluster is the trickier one, because it has not real quorum. Relative Timeouts --dc-timeout > dead-time resp. stonith-timeout if stonith enabled, --timeout >= --dc-timeout if no stonith, then timeout may be small. Pacemaker operations timeouts monitor and promote action timeout > max(dc_timeout, timeout) Node reboot, possibly because of crash or stonith due to communication loss no peer reachable [no delay] crm may decide to elect itself, shoot the peer, and start services. If DRBD peer disk state is known Outdated or worse, DRBD will switch itself to UpToDate, allowing it to be promoted, without further fencing actions. If DRBD peer disk state is DUnknown, DRBD will be only Consistent. In case crm decides to promote this instance, the fence-peer callback runs, finds the peer "unreachable", finds itself Consistent only, does NOT set any constraint, and DRBD refuses to be promoted. CRM will now try in an endless loop to promote this instance. Avoid this by adding param adjust_master_score="0 10 1000 10000" to the DRBD resource definition. no replication link CRM can see both nodes. [delay: crmadmin -S $peer] If currently both nodes are Secondary Consistent, CRM will decide to promote one instance. The fence-peer callback will find the other node still reachable after timeout, and set the constraint. If there is already one Primary, and this is a node rejoining the cluster, there should already be a constraint preventing this node from being promoted. Only Replication link breaks during normal operation Single Primary [delay: crmadmin -S $peer] fence-peer callback finds DC, crmadmin -S confirms peer still "reachable", and sets contraint. Dual Primary both fence-peer callbacks find DC, both see node_state "reachable", optionaly delay for --network-hickup timeout, and if DRBD is still disconnected, both try to set the constraint. Only one succeeds. The loser should probably commit suicide, to reduce the overall recovery time. --suicide-on-failure-if-primary Node crash surviving node is Secondary, [no delay] If not DC, triggers DC election, elects itself. Is DC now. If stonith enabled, shoots the peer. Promotes this node. During promotion, fenc-peer callback finds a DC, and a node_state "unreachable", so sets the constraint "immediately". surviving node is Primary (DC) [delay up to timeout] If stonith enabled, shoots the peer. fence-peer callback finds DC, after some time sees node_state "unreachable", or times out while node_state is still "reachable". Either way still sets the constraint. surviving node is Primary (not DC) [delay up to mac(dc_timeout,timeout)] fence-peer callback loops trying to contact DC. eventually this node is elected DC. If stonith enabled, shoots the peer. Fence-peer callback either times out while no DC is available, thus fails. Make sure you chose a suitable --dc-timeout. Or it finds the other node "unreachable", and sets the constraint. Total communication loss To the single node, this looks like node crash, so see above. The difference is the potential of data divergence. If DRBD was configured for "fencing resource-and-stonith", IO on any Primary is frozen while the fence-peer callback runs. If stonith is enabled, timeouts should be selected so that we are shot while waiting for the DC to confirm node_state "unreachable" of the peer, thus combined with freezing IO, no harmful data diversion can happen at this time. If there is no stonith enabled, data divergence is unavoidable. ==> Multi-Primary *requires* both node level fencing (stonith) AND drbd resource level fencing Again: Multi-Primary REQUIRES stonith enabled and working. drbd-utils-8.9.6/documentation/v84/0000755000175000017500000000000012654475367017020 5ustar apoikosapoikosdrbd-utils-8.9.6/documentation/v84/drbdmeta.80000644000175000017500000001432412654452472020667 0ustar apoikosapoikos'\" t .\" Title: drbdmeta .\" Author: [see the "Author" section] .\" Generator: DocBook XSL Stylesheets v1.75.2 .\" Date: 15 Oct 2008 .\" Manual: System Administration .\" Source: DRBD 8.3.2 .\" Language: English .\" .TH "DRBDMETA" "8" "15 Oct 2008" "DRBD 8.3.2" "System Administration" .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" drbdmeta \- DRBD\'s meta data management tool .\" drbdmeta .SH "SYNOPSIS" .HP \w'\fBdrbdmeta\fR\ 'u \fBdrbdmeta\fR [\-\-force] [\-\-ignore\-sanity\-checks] {\fIdevice\fR} {v06\ \fIminor\fR | v07\ \fImeta_dev\ index\fR | v08\ \fImeta_dev\ index\fR} {\fIcommand\fR} [\fIcmd\ args\fR...] .SH "DESCRIPTION" .PP Drbdmeta is used to create, display and modify the contents of DRBD\'s meta data storage\&. Usually you do not want to use this command directly, but start it via the frontend \fBdrbdadm\fR(8)\&. .PP This command only works if the DRBD resource is currently down, or at least detached from its backing storage\&. The first parameter is the device node associated to the resource\&. With the second parameter you can select the version of the meta data\&. Currently all major DRBD releases (0\&.6, 0\&.7 and 8) are supported\&. .SH "OPTIONS" .PP \-\-force .RS 4 .\" drbdmeta: --force All questions that get asked by drbdmeta are treated as if the user answered \'yes\'\&. .RE .PP \-\-ignore\-sanity\-checks .RS 4 .\" drbdmeta: --ignore-sanity-checks Some sanity checks cause drbdmeta to terminate\&. E\&.g\&. if a file system image would get destroyed by creating the meta data\&. By using that option you can force drbdmeta to ignore these checks\&. .RE .SH "COMMANDS" .PP create\-md \fB\-\-peer\-max\-bio\-size \fR\fB\fIval\fR\fR \fB\-\-al\-stripes \fR\fB\fIval\fR\fR \fB\-\-al\-stripe\-size\-kB \fR\fB\fIval\fR\fR .RS 4 .\" drbdmeta: create-md Create\-md initializes the meta data storage\&. This needs to be done before a DRBD resource can be taken online for the first time\&. In case there is already a meta data signature of an older format in place, drbdmeta will ask you if it should convert the older format to the selected format\&. .sp If you will use the resource before it is connected to its peer for the first time DRBD may perform better if you use the \fB\-\-peer\-max\-bio\-size\fR option\&. For DRBD versions of the peer use up to these values: <8\&.3\&.7 \-> 4k, 8\&.3\&.8 \-> 32k, 8\&.3\&.9 \-> 128k, 8\&.4\&.0 \-> 1M\&. .sp If you want to use more than 6433 activity log extents, or live on top of a spriped RAID, you may specify the number of stripes (\fB\-\-al\-stripes\fR, default 1), and the stripe size (\fB\-\-al\-stripe\-size\-kB\fR, default 32)\&. To just use a larger linear on\-disk ring\-buffer, leave the number of stripes at 1, and increase the size only: \fBdrbdmeta 0 v08 /dev/vg23/lv42 internal create\-md \-\-al\-stripe\-size 1M\fR .sp To avoid a single "spindle" from becoming a bottleneck, increase the number of stripes, to achieve an interleaved layout of the on\-disk activity\-log transactions\&. What you give as "stripe\-size" should be what is a\&.k\&.a\&. "chunk size" or "granularity" or "strip unit": the minimum skip to the next "spindle"\&. \fBdrbdmeta 0 v08 /dev/vg23/lv42 internal create\-md \-\-al\-stripes 7 \-\-al\-stripe\-size 64k\fR .RE .PP get\-gi .RS 4 .\" drbdmeta: get-gi Get\-gi shows a short textual representation of the data generation identifier\&. In version 0\&.6 and 0\&.7 these are generation counters, while in version 8 it is a set of UUIDs\&. .RE .PP show\-gi .RS 4 .\" drbdmeta: show-gi Show\-gi prints a textual representation of the data generation identifiers including explanatory information\&. .RE .PP dump\-md .RS 4 .\" drbdmeta: dump-md Dumps the whole contents of the meta data storage including the stored bit\-map and activity\-log in a textual representation\&. .RE .PP outdate .RS 4 .\" drbdmeta: outdate Sets the outdated flag in the meta data\&. This is used by the peer node when it wants to become primary, but cannot communicate with the DRBD stack on this host\&. .RE .PP dstate .RS 4 .\" drbdmeta: dstate Prints the state of the data on the backing storage\&. The output is always followed by \'/DUnknown\' since drbdmeta only looks at the local meta data\&. .RE .PP check\-resize .RS 4 .\" drbdmeta: check-resize Examines the device size of a backing device, and it\'s last known device size, recorded in a file /var/lib/drbd/drbd\-minor\-??\&.lkbd\&. In case the size of the backing device changed, and the meta data can be found at the old position, it moves the meta data to the right position at the end of the block device\&. .RE .SH "EXPERT'S COMMANDS" .PP Drbdmeta allows you to modify the meta data as well\&. This is intentionally omitted for the command\'s usage output, since you should only use it if you really know what you are doing\&. By setting the generation identifiers to wrong values, you risk to overwrite your up\-to\-data data with an older version of your data\&. .PP set\-gi \fIgi\fR .RS 4 .\" drbdmeta: set-gi Set\-gi allows you to set the generation identifier\&. \fIGi\fR needs to be a generation counter for the 0\&.6 and 0\&.7 format, and a UUID set for 8\&.x\&. Specify it in the same way as get\-gi shows it\&. .RE .PP restore\-md \fIdump_file\fR .RS 4 .\" drbdmeta: restore-md Reads the \fIdump_file\fR and writes it to the meta data\&. .RE .SH "VERSION" .sp This document was revised for version 8\&.3\&.2 of the DRBD distribution\&. .SH "AUTHOR" .sp Written by Philipp Reisner philipp\&.reisner@linbit\&.com and Lars Ellenberg lars\&.ellenberg@linbit\&.com\&. .SH "REPORTING BUGS" .sp Report bugs to drbd\-user@lists\&.linbit\&.com\&. .SH "COPYRIGHT" .sp Copyright 2001\-2008 LINBIT Information Technologies, Philipp Reisner, Lars Ellenberg\&. This is free software; see the source for copying conditions\&. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE\&. .SH "SEE ALSO" .PP \fBdrbdadm\fR(8) drbd-utils-8.9.6/documentation/v84/drbdsetup.xml0000644000175000017500000024333112645466445021541 0ustar apoikosapoikos 6 May 2011 DRBD 8.4.0 drbdsetup 8 System Administration drbdsetup Setup tool for DRBD drbdsetup Description drbdsetup is used to associate DRBD devices with their backing block devices, to set up DRBD device pairs to mirror their backing block devices, and to inspect the configuration of running DRBD devices. Note drbdsetup is a low level tool of the DRBD program suite. It is used by the data disk and drbd scripts to communicate with the device driver. Commands Each drbdsetup sub-command might require arguments and bring its own set of options. All values have default units which might be overruled by K, M or G. These units are defined in the usual way (e.g. K = 2^10 = 1024). Common options All drbdsetup sub-commands accept these two options In case the specified DRBD device (minor number) does not exist yet, create it implicitly. new-resource Resources are the primary objects of any DRBD configuration. A resource must be created with the command before any volumes or minor devices can be created. Connections are referenced by name. new-minor A minor is used as a synonym for replicated block device. It is represented in the /dev/ directory by a block device. It is the application's interface to the DRBD-replicated block devices. These block devices get addressed by their minor numbers on the drbdsetup commandline. A pair of replicated block devices may have different minor numbers on the two machines. They are associated by a common volume-number. Volume numbers are local to each connection. Minor numbers are global on one node. del-resource Destroys a resource object. This is only possible if the resource has no volumes. del-minor Minors can only be destroyed if its disk is detached. attach, disk-options drbdsetup disk Attach associates device with lower_device to store its data blocks on. The (or ) should only be used if you wish not to use as much as possible from the backing block devices. If you do not use , the device is only ready for use as soon as it was connected to its peer once. (See the command.) With the disk-options command it is possible to change the options of a minor while it is attached. You can override DRBD's size determination method with this option. If you need to use the device before it was ever connected to its peer, use this option to pass the size of the DRBD device to the driver. Default unit is sectors (1s = 512 bytes). If you use the size parameter in drbd.conf, we strongly recommend to add an explicit unit postfix. drbdadm and drbdsetup used to have mismatching default units. If the driver of the lower_device reports an error to DRBD, DRBD will mark the disk as inconsistent, call a helper program, or detach the device from its backing storage and perform all further IO by requesting it from the peer. The valid err_handlers are: , and . Under we understand preventive measures to avoid situations where both nodes are primary and disconnected (AKA split brain). Valid fencing policies are: This is the default policy. No fencing actions are done. If a node becomes a disconnected primary, it tries to outdate the peer's disk. This is done by calling the fence-peer handler. The handler is supposed to reach the other node over alternative communication paths and call 'drbdadm outdate res' there. If a node becomes a disconnected primary, it freezes all its IO operations and calls its fence-peer handler. The fence-peer handler is supposed to reach the peer over alternative communication paths and call 'drbdadm outdate res' there. In case it cannot reach the peer, it should stonith the peer. IO is resumed as soon as the situation is resolved. In case your handler fails, you can resume IO with the command. DRBD has four implementations to express write-after-write dependencies to its backing storage device. DRBD will use the first method that is supported by the backing storage device and that is not disabled. By default the flush method is used. Since drbd-8.4.2 is disabled by default because since linux-2.6.36 (or 2.6.32 RHEL6) there is no reliable way to determine if queuing of IO-barriers works. Dangerous only enable if you are told so by one that knows for sure. When selecting the method you should not only base your decision on the measurable performance. In case your backing storage device has a volatile write cache (plain disks, RAID of plain disks) you should use one of the first two. In case your backing storage device has battery-backed write cache you may go with option 3. Option 4 (disable everything, use "none") is dangerous on most IO stacks, may result in write-reordering, and if so, can theoretically be the reason for data corruption, or disturb the DRBD protocol, causing spurious disconnect/reconnect cycles. Do not use . Unfortunately device mapper (LVM) might not support barriers. The letter after "wo:" in /proc/drbd indicates with method is currently in use for a device: b, f, d, n. The implementations: barrier The first requires that the driver of the backing storage device support barriers (called 'tagged command queuing' in SCSI and 'native command queuing' in SATA speak). The use of this method can be enabled by setting the options to . flush The second requires that the backing device support disk flushes (called 'force unit access' in the drive vendors speak). The use of this method can be disabled setting to . drain The third method is simply to let write requests drain before write requests of a new reordering domain are issued. That was the only implementation before 8.0.9. none The fourth method is to not express write-after-write dependencies to the backing store at all, by also specifying . This is dangerous on most IO stacks, may result in write-reordering, and if so, can theoretically be the reason for data corruption, or disturb the DRBD protocol, causing spurious disconnect/reconnect cycles. Do not use . Disables the use of disk flushes and barrier BIOs when accessing the meta data device. See the notes on . In some special circumstances the device mapper stack manages to pass BIOs to DRBD that violate the constraints that are set forth by DRBD's merge_bvec() function and which have more than one bvec. A known example is: phys-disk -> DRBD -> LVM -> Xen -> missaligned partition (63) -> DomU FS. Then you might see "bio would need to, but cannot, be split:" in the Dom0's kernel log. The best workaround is to proper align the partition within the VM (E.g. start it at sector 1024). That costs 480 KiB of storage. Unfortunately the default of most Linux partitioning tools is to start the first partition at an odd number (63). Therefore most distributions install helpers for virtual linux machines will end up with missaligned partitions. The second best workaround is to limit DRBD's max bvecs per BIO (i.e., the option) to 1, but that might cost performance. The default value of is 0, which means that there is no user imposed limitation. To ensure smooth operation of the application on top of DRBD, it is possible to limit the bandwidth that may be used by background synchronization. The default is 250 KiB/sec, the default unit is KiB/sec. Start resync on this device only if the device with minor is already in connected state. Otherwise this device waits in SyncPause state. DRBD automatically performs hot area detection. With this parameter you control how big the hot area (=active set) can get. Each extent marks 4M of the backing storage. In case a primary node leaves the cluster unexpectedly, the areas covered by the active set must be resynced upon rejoining of the failed node. The data structure is stored in the meta-data area, therefore each change of the active set is a write operation to the meta-data device. A higher number of extents gives longer resync times but less updates to the meta-data. The default number of extents is 1237. (Minimum: 7, Maximum: 65534) See also drbd.conf5 and drbdmeta8 for additional limitations and necessary preparation. DRBD's activity log transaction writing makes it possible, that after the crash of a primary node a partial (bit-map based) resync is sufficient to bring the node back to up-to-date. Setting to might increase normal operation performance but causes DRBD to do a full resync when a crashed primary gets reconnected. The default value is . The dynamic resync speed controller gets enabled with setting plan_time to a positive value. It aims to fill the buffers along the data path with either a constant amount of data fill_target, or aims to have a constant delay time of delay_target along the path. The controller has an upper bound of max_rate. By plan_time the agility of the controller is configured. Higher values yield for slower/lower responses of the controller to deviation from the target value. It should be at least 5 times RTT. For regular data paths a fill_target in the area of 4k to 100k is appropriate. For a setup that contains drbd-proxy it is advisable to use delay_target instead. Only when fill_target is set to 0 the controller will use delay_target. 5 times RTT is a reasonable starting value. Max_rate should be set to the bandwidth available between the DRBD-hosts and the machines hosting DRBD-proxy, or to the available disk-bandwidth. The default value of plan_time is 0, the default unit is 0.1 seconds. Fill_target has 0 and sectors as default unit. Delay_target has 1 (100ms) and 0.1 as default unit. Max_rate has 10240 (100MiB/s) and KiB/s as default unit. We track the disk IO rate caused by the resync, so we can detect non-resync IO on the lower level device. If the lower level device seems to be busy, and the current resync rate is above min_rate, we throttle the resync. The default value of min_rate is 4M, the default unit is k. If you want to not throttle at all, set it to zero, if you want to throttle always, set it to one. , If the lower-level device on which a DRBD device stores its data does not finish an I/O request within the defined , DRBD treats this as a failure. The lower-level device is detached, and the device's disk state advances to Diskless. If DRBD is connected to one or more peers, the failed request is passed on to one of them. This option is dangerous and may lead to kernel panic! "Aborting" requests, or force-detaching the disk, is intended for completely blocked/hung local backing devices which do no longer complete requests at all, not even do error completions. In this situation, usually a hard-reset and failover is the only way out. By "aborting", basically faking a local error-completion, we allow for a more graceful swichover by cleanly migrating services. Still the affected node has to be rebooted "soon". By completing these requests, we allow the upper layers to re-use the associated data pages. If later the local backing device "recovers", and now DMAs some data from disk into the original request pages, in the best case it will just put random data into unused pages; but typically it will corrupt meanwhile completely unrelated data, causing all sorts of damage. Which means delayed successful completion, especially for READ requests, is a reason to panic(). We assume that a delayed *error* completion is OK, though we still will complain noisily about it. The default value of is 0, which stands for an infinite timeout. Timeouts are specified in units of 0.1 seconds. This option is available since DRBD 8.3.12. Setting to will cause DRBD to always fall-back to zero-out on the receiving side, and to not even announce discard capabilities on the Primary, if the respective backend announces discard_zeroes_data=false. Setting to will allow DRBD to use discards, and to announce discard_zeroes=true, even on backends that announce discard_zeroes_data=false. We used to ignore the discard_zeroes_data setting completely. To not break established and expected behaviour, the default value is . This option is available since 8.4.7. See also drbd.conf5. The supported methods for load balancing of read requests are , , , and , , , , , and . The default value of is . This option is available since 8.4.1. When is set to a non zero, positive value then DRBD tries to do a resync operation in requests of this size. In case such a block contains only zero bytes on the sync source node, the sync target node will issue a discard/trim/unmap command for the area. The value is constrained by the discard granularity of the backing block device. In case is not a multiplier of the discard granularity of the backing block device DRBD rounds it up. The feature only gets active if the backing block device reads back zeroes after a discard command. The default value of is 0. This option is available since 8.4.7. connect, net-options drbdsetup net Connect sets up the device to listen on af:local_addr:port for incoming connections and to try to connect to af:remote_addr:port. If port is omitted, 7788 is used as default. If af is omitted gets used. Other supported address families are , for Dolphin Interconnect Solutions' "super sockets" and for Sockets Direct Protocol (Infiniband). The net-options command allows you to change options while the connection is established. On the TCP/IP link the specified protocol is used. Valid protocol specifiers are A, B, and C. Protocol A: write IO is reported as completed, if it has reached local disk and local TCP send buffer. Protocol B: write IO is reported as completed, if it has reached local disk and remote buffer cache. Protocol C: write IO is reported as completed, if it has reached both local and remote disk. In case it is not possible to connect to the remote DRBD device immediately, DRBD keeps on trying to connect. With this option you can set the time between two retries. The default value is 10. The unit is seconds. If the TCP/IP connection linking a DRBD device pair is idle for more than time seconds, DRBD will generate a keep-alive packet to check if its partner is still alive. The default value is 10. The unit is seconds. If the partner node fails to send an expected response packet within val tenths of a second, the partner node is considered dead and therefore the TCP/IP connection is abandoned. The default value is 60 (= 6 seconds). The socket send buffer is used to store packets sent to the secondary node, which are not yet acknowledged (from a network point of view) by the secondary node. When using protocol A, it might be necessary to increase the size of this data structure in order to increase asynchronicity between primary and secondary nodes. But keep in mind that more asynchronicity is synonymous with more data loss in the case of a primary node failure. Since 8.0.13 resp. 8.2.7 setting the size value to 0 means that the kernel should autotune this. The default size is 0, i.e. autotune. Packets received from the network are stored in the socket receive buffer first. From there they are consumed by DRBD. Before 8.3.2 the receive buffer's size was always set to the size of the socket send buffer. Since 8.3.2 they can be tuned independently. A value of 0 means that the kernel should autotune this. The default size is 0, i.e. autotune. In case the secondary node fails to complete a single write request for count times the timeout, it is expelled from the cluster, i.e. the primary node goes into StandAlone mode. To disable this feature, you should explicitly set it to 0; defaults may change between versions. With this option the maximal number of write requests between two barriers is limited. Typically set to the same as , or the allowed maximum. Values smaller than 10 can lead to degraded performance. The default value is 2048. With this option the maximal number of buffer pages allocated by DRBD's receiver thread is limited. Typically set to the same as . Small values could lead to degraded performance. The default value is 2048, the minimum 32. Increase this if you cannot saturate the IO backend of the receiving side during linear write or during resync while otherwise idle. See also drbd.conf5 This setting has no effect with recent kernels that use explicit on-stack plugging (upstream Linux kernel 2.6.39, distributions may have backported). When the number of pending write requests on the standby (secondary) node exceeds the unplug-watermark, we trigger the request processing of our backing storage device. Some storage controllers deliver better performance with small values, others deliver best performance when the value is set to the same value as max-buffers, yet others don't feel much effect at all. Minimum 16, default 128, maximum 131072. With this option set you may assign primary role to both nodes. You only should use this option if you use a shared storage file system on top of DRBD. At the time of writing the only ones are: OCFS2 and GFS. If you use this option with any other file system, you are going to crash your nodes and to corrupt your data! You need to specify the HMAC algorithm to enable peer authentication at all. You are strongly encouraged to use peer authentication. The HMAC algorithm will be used for the challenge response authentication of the peer. You may specify any digest algorithm that is named in /proc/crypto. The shared secret used in peer authentication. May be up to 64 characters. possible policies are: No automatic resynchronization, simply disconnect. Auto sync from the node that was primary before the split-brain situation occurred. Auto sync from the node that became primary as second during the split-brain situation. In case one node did not write anything since the split brain became evident, sync from the node that wrote something to the node that did not write anything. In case none wrote anything this policy uses a random decision to perform a "resync" of 0 blocks. In case both have written something this policy disconnects the nodes. Auto sync from the node that touched more blocks during the split brain situation. Auto sync to the named node. possible policies are: No automatic resynchronization, simply disconnect. Discard the version of the secondary if the outcome of the algorithm would also destroy the current secondary's data. Otherwise disconnect. Discard the secondary's version. Always honor the outcome of the algorithm. In case it decides the current secondary has the correct data, call the on the current primary. Always honor the outcome of the algorithm. In case it decides the current secondary has the correct data, accept a possible instantaneous change of the primary's data. possible policies are: No automatic resynchronization, simply disconnect. Always honor the outcome of the algorithm. In case it decides the current secondary has the right data, call the on the current primary. Always honor the outcome of the algorithm. In case it decides the current secondary has the right data, accept a possible instantaneous change of the primary's data. Normally the automatic after-split-brain policies are only used if current states of the UUIDs do not indicate the presence of a third node. With this option you request that the automatic after-split-brain policies are used as long as the data sets of the nodes are somehow related. This might cause a full sync, if the UUIDs indicate the presence of a third node. (Or double faults have led to strange UUID sets.) This option sets DRBD's behavior when DRBD deduces from its meta data that a resynchronization is needed, and the SyncTarget node is already primary. The possible settings are: , and . While speaks for itself, with the setting the handler is called which is expected to either change the role of the node to secondary, or remove the node from the cluster. The default is . With the setting you allow DRBD to force a primary node into SyncTarget state. This means that the data exposed by DRBD changes to the SyncSource's version of the data instantaneously. USE THIS OPTION ONLY IF YOU KNOW WHAT YOU ARE DOING. DRBD can ensure the data integrity of the user's data on the network by comparing hash values. Normally this is ensured by the 16 bit checksums in the headers of TCP/IP packets. This option can be set to any of the kernel's data digest algorithms. In a typical kernel configuration you should have at least one of , , and available. By default this is not enabled. See also the notes on data integrity on the drbd.conf manpage. DRBD usually uses the TCP socket option TCP_CORK to hint to the network stack when it can expect more data, and when it should flush out what it has in its send queue. There is at least one network stack that performs worse when one uses this hinting method. Therefore we introduced this option, which disable the setting and clearing of the TCP_CORK socket option by DRBD. The time the peer has to answer to a keep-alive packet. In case the peer's reply is not received within this time period, it is considered dead. The default unit is tenths of a second, the default value is 5 (for half a second). Use this option to manually recover from a split-brain situation. In case you do not have any automatic after-split-brain policies selected, the nodes refuse to connect. By passing this option you make this node a sync target immediately after successful connect. Causes DRBD to abort the connection process after the resync handshake, i.e. no resync gets performed. You can find out which resync DRBD would perform by looking at the kernel's log file. By default DRBD blocks when the available TCP send queue becomes full. That means it will slow down the application that generates the write requests that cause DRBD to send more data down that TCP connection. When DRBD is deployed with DRBD-proxy it might be more desirable that DRBD goes into AHEAD/BEHIND mode shortly before the send queue becomes full. In AHEAD/BEHIND mode DRBD does no longer replicate data, but still keeps the connection open. The advantage of the AHEAD/BEHIND mode is that the application is not slowed down, even if DRBD-proxy's buffer is not sufficient to buffer all write requests. The downside is that the peer node falls behind, and that a resync will be necessary to bring it back into sync. During that resync the peer node will have an inconsistent disk. Available congestion_policys are and . The default is . Fill_threshold might be in the range of 0 to 10GiBytes. The default is 0 which disables the check. Active_extents_threshold has the same limits as . The AHEAD/BEHIND mode and its settings are available since DRBD 8.3.10. During online verification (as initiated by the verify sub-command), rather than doing a bit-wise comparison, DRBD applies a hash function to the contents of every block being verified, and compares that hash with the peer. This option defines the hash algorithm being used for that purpose. It can be set to any of the kernel's data digest algorithms. In a typical kernel configuration you should have at least one of , , and available. By default this is not enabled; you must set this option explicitly in order to be able to use on-line device verification. See also the notes on data integrity on the drbd.conf manpage. A resync process sends all marked data blocks form the source to the destination node, as long as no is given. When one is specified the resync process exchanges hash values of all marked blocks first, and sends only those data blocks over, that have different hash values. This setting is useful for DRBD setups with low bandwidth links. During the restart of a crashed primary node, all blocks covered by the activity log are marked for resync. But a large part of those will actually be still in sync, therefore using will lower the required bandwidth in exchange for CPU cycles. During resync-handshake, the dirty-bitmaps of the nodes are exchanged and merged (using bit-or), so the nodes will have the same understanding of which blocks are dirty. On large devices, the fine grained dirty-bitmap can become large as well, and the bitmap exchange can take quite some time on low-bandwidth links. Because the bitmap typically contains compact areas where all bits are unset (clean) or set (dirty), a simple run-length encoding scheme can considerably reduce the network traffic necessary for the bitmap exchange. For backward compatibility reasons, and because on fast links this possibly does not improve transfer time but consumes cpu cycles, this defaults to off. Introduced in 8.3.2. In setups involving a DRBD-proxy and connections that experience a lot of buffer-bloat it might be necessary to set to an unusual high value. By default DRBD uses the same value to wait if a newly established TCP-connection is stable. Since the DRBD-proxy is usually located in the same data center such a long wait time may hinder DRBD's connect process. In such setups should be set to at least to the round trip time between DRBD and DRBD-proxy. I.e. in most cases to 1. The default unit is tenths of a second, the default value is 0 (which causes DRBD to use the value of instead). Introduced in 8.4.5. resource-options drbdsetup resource-options Changes the options of the resource at runtime. Sets the cpu-affinity-mask for DRBD's kernel threads of this device. The default value of cpu-mask is 0, which means that DRBD's kernel threads should be spread over all CPUs of the machine. This value must be given in hexadecimal notation. If it is too big it will be truncated. This setting controls what happens to IO requests on a degraded, disk less node (I.e. no data store is reachable). The available policies are and . If ond-policy is set to you can either resume IO by attaching/connecting the last lost data storage, or by the drbdadm resume-io res command. The latter will result in IO errors of course. The default is . This setting is available since DRBD 8.3.9. primary drbdsetup primary Sets the device into primary role. This means that applications (e.g. a file system) may open the device for read and write access. Data written to the device in primary role are mirrored to the device in secondary role. Normally it is not possible to set both devices of a connected DRBD device pair to primary role. By using the option, you override this behavior and instruct DRBD to allow two primaries. Alias for --force. Becoming primary fails if the local replica is not up-to-date. I.e. when it is inconsistent, outdated of consistent. By using this option you can force it into primary role anyway. USE THIS OPTION ONLY IF YOU KNOW WHAT YOU ARE DOING. secondary drbdsetup secondary Brings the device into secondary role. This operation fails as long as at least one application (or file system) has opened the device. It is possible that both devices of a connected DRBD device pair are secondary. verify drbdsetup verify This initiates on-line device verification. During on-line verification, the contents of every block on the local node are compared to those on the peer node. Device verification progress can be monitored via /proc/drbd. Any blocks whose content differs from that of the corresponding block on the peer node will be marked out-of-sync in DRBD's on-disk bitmap; they are not brought back in sync automatically. To do that, simply disconnect and reconnect the resource. If on-line verification is already in progress (and this node is "VerifyS"), this command silently "succeeds". In this case, any start-sector (see below) will be ignored, and any stop-sector (see below) will be honored. This can be used to stop a running verify, or to update/shorten/extend the coverage of the currently running verify. This command will fail if the device is not part of a connected device pair. See also the notes on data integrity on the drbd.conf manpage. Since version 8.3.2, on-line verification should resume from the last position after connection loss. It may also be started from an arbitrary position by setting this option. If you had reached some stop-sector before, and you do not specify an explicit start-sector, verify should resume from the previous stop-sector. Default unit is sectors. You may also specify a unit explicitly. The will be rounded down to a multiple of 8 sectors (4kB). , Since version 8.3.14, on-line verification can be stopped before it reaches end-of-device. Default unit is sectors. You may also specify a unit explicitly. The may be updated by issuing an additional drbdsetup verify command on the same node while the verify is running. This can be used to stop a running verify, or to update/shorten/extend the coverage of the currently running verify. invalidate drbdsetup invalidate This forces the local device of a pair of connected DRBD devices into SyncTarget state, which means that all data blocks of the device are copied over from the peer. This command will fail if the device is not either part of a connected device pair, or disconnected Secondary. invalidate-remote drbdsetup invalidate-remote This forces the local device of a pair of connected DRBD devices into SyncSource state, which means that all data blocks of the device are copied to the peer. On a disconnected Primary device, this will set all bits in the out of sync bitmap. As a side affect this suspends updates to the on disk activity log. Updates to the on disk activity log resume automatically when necessary. wait-connect drbdsetup wait-connect Returns as soon as the device can communicate with its partner device. This command will fail if the device cannot communicate with its partner for timeout seconds. If the peer was working before this node was rebooted, the wfc_timeout is used. If the peer was already down before this node was rebooted, the degr_wfc_timeout is used. If the peer was successfully outdated before this node was rebooted the outdated_wfc_timeout is used. The default value for all those timeout values is 0 which means to wait forever. The unit is seconds. In case the connection status goes down to StandAlone because the peer appeared but the devices had a split brain situation, the default for the command is to terminate. You can change this behavior with the option. wait-sync drbdsetup wait-sync Returns as soon as the device leaves any synchronization into connected state. The options are the same as with the wait-connect command. disconnect drbdsetup disconnect Removes the information set by the command from the device. This means that the device goes into unconnected state and will no longer listen for incoming connections. detach drbdsetup detach Removes the information set by the command from the device. This means that the device is detached from its backing storage device. , A regular detach returns after the disk state finally reached diskless. As a consequence detaching from a frozen backing block device never terminates. On the other hand A forced detach returns immediately. It allows you to detach DRBD from a frozen backing block device. Please note that the disk will be marked as failed until all pending IO requests where finished by the backing block device. down drbdsetup down Removes all configuration information from the device and forces it back to unconfigured state. role drbdsetup role Shows the current roles of the device and its peer, as local/peer. state drbdsetup state Deprecated alias for "role" cstate drbdsetup cstate Shows the current connection state of the device. dstate drbdsetup dstate Shows the current states of the backing storage devices, as local/peer. resize drbdsetup resize This causes DRBD to reexamine the size of the device's backing storage device. To actually do online growing you need to extend the backing storages on both devices and call the command on one of your nodes. The option can be used to online shrink the usable size of a drbd device. It's the users responsibility to make sure that a file system on the device is not truncated by that operation. The allows you to resize a device which is currently not connected to the peer. Use with care, since if you do not resize the peer's disk as well, further connect attempts of the two will fail. When the option is given DRBD will skip the resync of the new storage. Only do this if you know that the new storage was initialized to the same content by other means. The options and may be used to change the layout of the activity log online. In case of internal meta data this may invovle shrinking the user visible size at the same time (unsing the ) or increasing the avalable space on the backing devices. check-resize drbdsetup check-resize To enable DRBD to detect offline resizing of backing devices this command may be used to record the current size of backing devices. The size is stored in files in /var/lib/drbd/ named drbd-minor-??.lkbd This command is called by drbdadm resize res after drbdsetup device resize returned. pause-sync drbdsetup pause-sync Temporarily suspend an ongoing resynchronization by setting the local pause flag. Resync only progresses if neither the local nor the remote pause flag is set. It might be desirable to postpone DRBD's resynchronization after eventual resynchronization of the backing storage's RAID setup. resume-sync drbdsetup resume-sync Unset the local sync pause flag. outdate drbdsetup outdate Mark the data on the local backing storage as outdated. An outdated device refuses to become primary. This is used in conjunction with and by the peer's handler. show-gi drbdsetup show-gi Displays the device's data generation identifiers verbosely. get-gi drbdsetup get-gi Displays the device's data generation identifiers. show drbdsetup show Shows all available configuration information of a resource, or of all resources. Available options: Show all configuration parameters, even the ones with default values. Normally, parameters with default values are not shown. suspend-io drbdsetup suspend-io This command is of no apparent use and just provided for the sake of completeness. resume-io drbdsetup resume-io If the fence-peer handler fails to stonith the peer node, and your policy is set to resource-and-stonith, you can unfreeze IO operations with this command. status drbdsetup status Show the status of a resource, or of all resources. The output consists of one paragraph for each configured resource. Each paragraph contains one line for each resource, followed by one line for each device, and one line for each connection. The device and connection lines are indented. The connection lines are followed by one line for each peer device; these lines are indented against the connection line. Long lines are wrapped around at terminal width, and indented to indicate how the lines belongs together. Available options: Include more information in the output even when it is likely redundant or irrelevant. Include data transfer statistics in the output. Colorize the output. With , emits color codes only when standard output is connected to a terminal. For example, the non-verbose output for a resource with only one connection and only one volume could look like this: fs-backoffice role:Primary disk:UpToDate peer role:Secondary replication:Established peer-disk:UpToDate With the options, the same resource could be reported as: fs-data role:Primary suspended:no write-ordering:drain volume:0 minor:1 disk:UpToDate size:10616472 read:134465 written:144800 al-writes:18 bm-writes:0 upper-pending:0 lower-pending:0 al-suspended:no blocked:no peer connection:Connected role:Secondary congested:no volume:0 replication:Established peer-disk:UpToDate resync-suspended:no received:122596 sent:22204 out-of-sync:0 pending:0 unacked:0 events2 drbdsetup events2 Show the current state of all configured DRBD objects, followed by all changes to the state. The output format is meant to be human as well as machine readable. Each line starts with the event number, which is followed by an asterisk if the event continues in the next line. The second word in each line indicates the kind of event: for an existing object; , , and if an object is created, destroyed, or changed; or or if an event handler is called or it returns. The third word indicates the object the event applies to: , , , , , or a dash () to indicate that the current state has been dumped completely. The remaining words identify the object and describe the state that he object is in. Available options: Terminate after reporting the current state. The default is to continuously listen and report state changes. Include statistics in the output. events drbdsetup events Deprecated. If possible, change to the events2 subcommand instead. Displays every state change of DRBD and all calls to helper programs. This might be used to get notified of DRBD's state changes by piping the output to another program. Display the events of all DRBD minors. This is a debugging aid that displays the content of all received netlink messages. new-current-uuid drbdsetup new-current-uuid Generates a new current UUID and rotates all other UUID values. This has at least two use cases, namely to skip the initial sync, and to reduce network bandwidth when starting in a single node configuration and then later (re-)integrating a remote site. Available option: Clears the sync bitmap in addition to generating a new current UUID. This can be used to skip the initial sync, if you want to start from scratch. This use-case does only work on "Just Created" meta data. Necessary steps: On both nodes, initialize meta data and configure the device. drbdadm -- --force create-md res They need to do the initial handshake, so they know their sizes. drbdadm up res They are now Connected Secondary/Secondary Inconsistent/Inconsistent. Generate a new current-uuid and clear the dirty bitmap. drbdadm new-current-uuid --clear-bitmap res They are now Connected Secondary/Secondary UpToDate/UpToDate. Make one side primary and create a file system. drbdadm primary res mkfs -t fs-type $(drbdadm sh-dev res) One obvious side-effect is that the replica is full of old garbage (unless you made them identical using other means), so any online-verify is expected to find any number of out-of-sync blocks. You must not use this on pre-existing data! Even though it may appear to work at first glance, once you switch to the other node, your data is toast, as it never got replicated. So do not leave out the mkfs (or equivalent). This can also be used to shorten the initial resync of a cluster where the second node is added after the first node is gone into production, by means of disk shipping. This use-case works on disconnected devices only, the device may be in primary or secondary role. The necessary steps on the current active server are: drbdsetup new-current-uuid --clear-bitmap minor Take the copy of the current active server. E.g. by pulling a disk out of the RAID1 controller, or by copying with dd. You need to copy the actual data, and the meta data. drbdsetup new-current-uuid minor Now add the disk to the new secondary node, and join it to the cluster. You will get a resync of that parts that were changed since the first call to drbdsetup in step 1. Examples For examples, please have a look at the DRBD User's Guide. Version This document was revised for version 8.3.2 of the DRBD distribution. Author Written by Philipp Reisner philipp.reisner@linbit.com and Lars Ellenberg lars.ellenberg@linbit.com Reporting Bugs Report bugs to drbd-user@lists.linbit.com. Copyright Copyright 2001-2008 LINBIT Information Technologies, Philipp Reisner, Lars Ellenberg. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See Also drbd.conf 5 , drbd 8 , drbddisk 8 , drbdadm 8 , DRBD User's Guide, DRBD web site drbd-utils-8.9.6/documentation/v84/drbd.80000644000175000017500000000454012654452471020016 0ustar apoikosapoikos'\" t .\" Title: drbd .\" Author: [see the "Author" section] .\" Generator: DocBook XSL Stylesheets v1.75.2 .\" Date: 15 Oct 2008 .\" Manual: System Administration .\" Source: DRBD 8.3.2 .\" Language: English .\" .TH "DRBD" "8" "15 Oct 2008" "DRBD 8.3.2" "System Administration" .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" drbd \- The start and stop script for DRBD .SH "SYNOPSIS" .HP \w'\fB/etc/init\&.d/drbd\fR\ 'u \fB/etc/init\&.d/drbd\fR [\fIresource\fR] {{start}\ |\ {stop}\ |\ {status}\ |\ {reload}\ |\ {restart}\ |\ {force\-reload}} .SH "INTRODUCTION" .PP The \fB/etc/init\&.d/drbd\fR script is used to start and stop drbd on a system V style init system\&. .PP In order to use \fB/etc/init\&.d/drbd\fR you must define a resource, a host, and any other configuration options in the drbd configuration file\&. See \fB/etc/drbd\&.conf\fR for details\&. If \fIresource\fR is omitted, then all of the resources listed in the config file are configured\&. .PP This script might ask you \(lqDo you want to abort waiting for other server and make this one primary?\(rq .PP Only answer this question with \(lqyes\(rq if you are sure that it is impossible to repair the other node\&. .SH "VERSION" .sp This document was revised for version 8\&.3\&.2 of the DRBD distribution\&. .SH "AUTHOR" .sp Written by Philipp Reisner philipp\&.reisner@linbit\&.com and Lars Ellenberg lars\&.ellenberg@linbit\&.com\&. .SH "REPORTING BUGS" .sp Report bugs to drbd\-user@lists\&.linbit\&.com\&. .SH "COPYRIGHT" .sp Copyright 2001\-2008 LINBIT Information Technologies, Philipp Reisner, Lars Ellenberg\&. This is free software; see the source for copying conditions\&. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE\&. .SH "SEE ALSO" .PP \fBdrbd.conf\fR(5), \fBdrbddisk\fR(8), \fBdrbdsetup\fR(8)\fBdrbdadm\fR(8)\m[blue]\fBDRBD Homepage\fR\m[]\&\s-2\u[1]\d\s+2 .SH "NOTES" .IP " 1." 4 DRBD Homepage .RS 4 \%http://www.drbd.org/ .RE drbd-utils-8.9.6/documentation/v84/drbd.conf.xml0000644000175000017500000027274312654402323021376 0ustar apoikosapoikos 6 May 2011 DRBD 8.4.0 drbd.conf 5 Configuration Files drbd.conf Configuration file for DRBD's devices drbd.conf Introduction The file is read by . The file format was designed as to allow to have a verbatim copy of the file on both nodes of the cluster. It is highly recommended to do so in order to keep your configuration manageable. The file should be the same on both nodes of the cluster. Changes to do not apply immediately. By convention the main config contains two include statements. The first one includes the file , the second one all file with a suffix. A small example.res file resource r0 { net { protocol C; cram-hmac-alg sha1; shared-secret "FooFunFactory"; } disk { resync-rate 10M; } on alice { volume 0 { device minor 1; disk /dev/sda7; meta-disk internal; } address 10.1.1.31:7789; } on bob { volume 0 { device minor 1; disk /dev/sda7; meta-disk internal; } address 10.1.1.32:7789; } } In this example, there is a single DRBD resource (called r0) which uses protocol C for the connection between its devices. It contains a single volume which runs on host alice uses /dev/drbd1 as devices for its application, and /dev/sda7 as low-level storage for the data. The IP addresses are used to specify the networking interfaces to be used. An eventually running resync process should use about 10MByte/second of IO bandwidth. This sync-rate statement is valid for volume 0, but would also be valid for further volumes. In this example it assigns full 10MByte/second to each volume. There may be multiple resource sections in a single drbd.conf file. For more examples, please have a look at the DRBD User's Guide. File Format The file consists of sections and parameters. A section begins with a keyword, sometimes an additional name, and an opening brace ({). A section ends with a closing brace (}. The braces enclose the parameters. section [name] { parameter value; [...] } A parameter starts with the identifier of the parameter followed by whitespace. Every subsequent character is considered as part of the parameter's value. A special case are Boolean parameters which consist only of the identifier. Parameters are terminated by a semicolon (;). Some parameter values have default units which might be overruled by K, M or G. These units are defined in the usual way (K = 2^10 = 1024, M = 1024 K, G = 1024 M). Comments may be placed into the configuration file and must begin with a hash sign (#). Subsequent characters are ignored until the end of the line. Sections drbd.conf skip Comments out chunks of text, even spanning more than one line. Characters between the keyword and the opening brace ({) are ignored. Everything enclosed by the braces is skipped. This comes in handy, if you just want to comment out some '' section: just precede it with ''. drbd.conf global Configures some global parameters. Currently only , , and are allowed here. You may only have one global section, preferably as the first section. drbd.conf common All resources inherit the options set in this section. The common section might have a , a , a , a and a section. drbd.conf resource Configures a DRBD resource. Each resource section needs to have two (or more) sections and may have a , a , a , a and a section. It might contain s sections. drbd.conf on Carries the necessary configuration parameters for a DRBD device of the enclosing resource. host-name is mandatory and must match the Linux host name (uname -n) of one of the nodes. You may list more than one host name here, in case you want to use the same parameters on several hosts (you'd have to move the IP around usually). Or you may list more than two such sections. resource r1 { protocol C; device minor 1; meta-disk internal; on alice bob { address 10.2.2.100:7801; disk /dev/mapper/some-san; } on charlie { address 10.2.2.101:7801; disk /dev/mapper/other-san; } on daisy { address 10.2.2.103:7801; disk /dev/mapper/other-san-as-seen-from-daisy; } } See also the section keyword. Required statements in this section: and . Note for backward compatibility and convenience it is valid to embed the statements of a single volume directly into the host section. drbd.conf volume Defines a volume within a connection. The minor numbers of a replicated volume might be different on different hosts, the volume number (vnr) is what groups them together. Required parameters in this section: , , . drbd.conf stacked-on-top-of For a stacked DRBD setup (3 or 4 nodes), a is used instead of an section. Required parameters in this section: and . drbd.conf on Carries the necessary configuration parameters for a DRBD device of the enclosing resource. This section is very similar to the section. The difference to the section is that the matching of the host sections to machines is done by the IP-address instead of the node name. Required parameters in this section: , , , all of which may be inherited from the resource section, in which case you may shorten this section down to just the address identifier. resource r2 { protocol C; device minor 2; disk /dev/sda7; meta-disk internal; # short form, device, disk and meta-disk inherited floating 10.1.1.31:7802; # longer form, only device inherited floating 10.1.1.32:7802 { disk /dev/sdb; meta-disk /dev/sdc8; } } drbd.conf disk This section is used to fine tune DRBD's properties in respect to the low level storage. Please refer to drbdsetup 8 for detailed description of the parameters. Optional parameters: , , , , , , , , , , , , , , , , , , , , . drbd.conf net This section is used to fine tune DRBD's properties. Please refer to drbdsetup 8 for a detailed description of this section's parameters. Optional parameters: , , , , , , , , , , , , , , , , , , , , , , , , . drbd.conf startup This section is used to fine tune DRBD's properties. Please refer to drbdsetup 8 for a detailed description of this section's parameters. Optional parameters: , , , , and . drbd.conf options This section is used to fine tune the behaviour of the resource object. Please refer to drbdsetup 8 for a detailed description of this section's parameters. Optional parameters: , and . drbd.conf handlers In this section you can define handlers (executables) that are started by the DRBD system in response to certain events. Optional parameters: , , , (formerly oudate-peer), , , , , . The interface is done via environment variables: is the name of the resource is the minor number of the DRBD device, in decimal. is the path to the primary configuration file; if you split your configuration into multiple files (e.g. in ), this will not be helpful. , , are the address family (e.g. ), the peer's address and hostnames. is deprecated. Please note that not all of these might be set for all handlers, and that some values might not be useable for a definition. Parameters drbd.conf minor-count count may be a number from 1 to 1048575. Minor-count is a sizing hint for DRBD. It helps to right-size various memory pools. It should be set in the in the same order of magnitude than the actual number of minors you use. Per default the module loads with 11 more resources than you have currently in your config but at least 32. drbd.conf dialog-refresh time may be 0 or a positive number. The user dialog redraws the second count every time seconds (or does no redraws if time is 0). The default value is 1. drbd.conf disable-ip-verification Use disable-ip-verification if, for some obscure reasons, drbdadm can/might not use or to do a sanity check for the IP address. You can disable the IP verification with this option. drbd.conf usage-count Please participate in DRBD's online usage counter. The most convenient way to do so is to set this option to . Valid options are: , and . drbd.conf protocol On the TCP/IP link the specified protocol is used. Valid protocol specifiers are A, B, and C. Protocol A: write IO is reported as completed, if it has reached local disk and local TCP send buffer. Protocol B: write IO is reported as completed, if it has reached local disk and remote buffer cache. Protocol C: write IO is reported as completed, if it has reached both local and remote disk. drbd.conf device The name of the block device node of the resource being described. You must use this device with your application (file system) and you must not use the low level block device which is specified with the parameter. One can ether omit the name or and the minor number. If you omit the name a default of /dev/drbdminor will be used. Udev will create additional symlinks in /dev/drbd/by-res and /dev/drbd/by-disk. drbd.conf disk DRBD uses this block device to actually store and retrieve the data. Never access such a device while DRBD is running on top of it. This also holds true for dumpe2fs 8 and similar commands. drbd.conf address A resource needs one IP address per device, which is used to wait for incoming connections from the partner device respectively to reach the partner device. AF must be one of , , or (for compatibility reasons is an alias for ). It may be omited for IPv4 addresses. The actual IPv6 address that follows the keyword must be placed inside brackets: ipv6 [fd01:2345:6789:abcd::1]:7800. Each DRBD resource needs a TCP port which is used to connect to the node's partner device. Two different DRBD resources may not use the same addr:port combination on the same node. drbd.conf meta-disk Internal means that the last part of the backing device is used to store the meta-data. The size of the meta-data is computed based on the size of the device. When a device is specified, either with or without an index, DRBD stores the meta-data on this device. Without index, the size of the meta-data is determined by the size of the data device. This is usually used with LVM, which allows to have many variable sized block devices. The meta-data size is 36kB + Backing-Storage-size / 32k, rounded up to the next 4kb boundary. (Rule of the thumb: 32kByte per 1GByte of storage, rounded up to the next MB.) When an index is specified, each index number refers to a fixed slot of meta-data of 128 MB, which allows a maximum data size of 4 TiB. This way, multiple DBRD devices can share the same meta-data device. For example, if /dev/sde6[0] and /dev/sde6[1] are used, /dev/sde6 must be at least 256 MB big. Because of the hard size limit, use of meta-disk indexes is discouraged. drbd.conf on-io-error handler is taken, if the lower level device reports io-errors to the upper layers. handler may be , or : The node downgrades the disk status to inconsistent, marks the erroneous block as inconsistent in the bitmap and retries the IO on the remote node. : Call the handler script . : The node drops its low level device, and continues in diskless mode. drbd.conf fencing By we understand preventive measures to avoid situations where both nodes are primary and disconnected (AKA split brain). Valid fencing policies are: This is the default policy. No fencing actions are taken. If a node becomes a disconnected primary, it tries to fence the peer's disk. This is done by calling the handler. The handler is supposed to reach the other node over alternative communication paths and call '' there. If a node becomes a disconnected primary, it freezes all its IO operations and calls its fence-peer handler. The fence-peer handler is supposed to reach the peer over alternative communication paths and call 'drbdadm outdate res' there. In case it cannot reach the peer it should stonith the peer. IO is resumed as soon as the situation is resolved. In case your handler fails, you can resume IO with the command. drbd.conf disk-barrier drbd.conf disk-flushes drbd.conf disk-drain DRBD has four implementations to express write-after-write dependencies to its backing storage device. DRBD will use the first method that is supported by the backing storage device and that is not disabled. By default the flush method is used. Since drbd-8.4.2 is disabled by default because since linux-2.6.36 (or 2.6.32 RHEL6) there is no reliable way to determine if queuing of IO-barriers works. Dangerous only enable if you are told so by one that knows for sure. When selecting the method you should not only base your decision on the measurable performance. In case your backing storage device has a volatile write cache (plain disks, RAID of plain disks) you should use one of the first two. In case your backing storage device has battery-backed write cache you may go with option 3. Option 4 (disable everything, use "none") is dangerous on most IO stacks, may result in write-reordering, and if so, can theoretically be the reason for data corruption, or disturb the DRBD protocol, causing spurious disconnect/reconnect cycles. Do not use . Unfortunately device mapper (LVM) might not support barriers. The letter after "wo:" in /proc/drbd indicates with method is currently in use for a device: , , , . The implementations are: barrier The first requires that the driver of the backing storage device support barriers (called 'tagged command queuing' in SCSI and 'native command queuing' in SATA speak). The use of this method can be enabled by setting the options to . flush The second requires that the backing device support disk flushes (called 'force unit access' in the drive vendors speak). The use of this method can be disabled setting to . drain The third method is simply to let write requests drain before write requests of a new reordering domain are issued. This was the only implementation before 8.0.9. none The fourth method is to not express write-after-write dependencies to the backing store at all, by also specifying . This is dangerous on most IO stacks, may result in write-reordering, and if so, can theoretically be the reason for data corruption, or disturb the DRBD protocol, causing spurious disconnect/reconnect cycles. Do not use . drbd.conf md-flushes Disables the use of disk flushes and barrier BIOs when accessing the meta data device. See the notes on . drbd.conf max-bio-bvecs In some special circumstances the device mapper stack manages to pass BIOs to DRBD that violate the constraints that are set forth by DRBD's merge_bvec() function and which have more than one bvec. A known example is: phys-disk -> DRBD -> LVM -> Xen -> misaligned partition (63) -> DomU FS. Then you might see "bio would need to, but cannot, be split:" in the Dom0's kernel log. The best workaround is to proper align the partition within the VM (E.g. start it at sector 1024). This costs 480 KiB of storage. Unfortunately the default of most Linux partitioning tools is to start the first partition at an odd number (63). Therefore most distribution's install helpers for virtual linux machines will end up with misaligned partitions. The second best workaround is to limit DRBD's max bvecs per BIO (= ) to 1, but that might cost performance. The default value of is 0, which means that there is no user imposed limitation. drbd.conf disk-timeout If the lower-level device on which a DRBD device stores its data does not finish an I/O request within the defined , DRBD treats this as a failure. The lower-level device is detached, and the device's disk state advances to Diskless. If DRBD is connected to one or more peers, the failed request is passed on to one of them. This option is dangerous and may lead to kernel panic! "Aborting" requests, or force-detaching the disk, is intended for completely blocked/hung local backing devices which do no longer complete requests at all, not even do error completions. In this situation, usually a hard-reset and failover is the only way out. By "aborting", basically faking a local error-completion, we allow for a more graceful swichover by cleanly migrating services. Still the affected node has to be rebooted "soon". By completing these requests, we allow the upper layers to re-use the associated data pages. If later the local backing device "recovers", and now DMAs some data from disk into the original request pages, in the best case it will just put random data into unused pages; but typically it will corrupt meanwhile completely unrelated data, causing all sorts of damage. Which means delayed successful completion, especially for READ requests, is a reason to panic(). We assume that a delayed *error* completion is OK, though we still will complain noisily about it. The default value of is 0, which stands for an infinite timeout. Timeouts are specified in units of 0.1 seconds. This option is available since DRBD 8.3.12. drbd.conf discard-zeroes-if-aligned There are several aspects to discard/trim/unmap support on linux block devices. Even if discard is supported in general, it may fail silently, or may partially ignore discard requests. Devices also announce whether reading from unmapped blocks returns defined data (usually zeroes), or undefined data (possibly old data, possibly garbage). If on different nodes, DRBD is backed by devices with differing discard characteristics, discards may lead to data divergence (old data or garbage left over on one backend, zeroes due to unmapped areas on the other backend). Online verify would now potentially report tons of spurious differences. While probably harmless for most use cases (fstrim on a file system), DRBD cannot have that. To play safe, we have to disable discard support, if our local backend (on a Primary) does not support "discard_zeroes_data=true". We also have to translate discards to explicit zero-out on the receiving side, unless the receiving side (Secondary) supports "discard_zeroes_data=true", thereby allocating areas what were supposed to be unmapped. There are some devices (notably the LVM/DM thin provisioning) that are capable of discard, but announce discard_zeroes_data=false. In the case of DM-thin, discards aligned to the chunk size will be unmapped, and reading from unmapped sectors will return zeroes. However, unaligned partial head or tail areas of discard requests will be silently ignored. If we now add a helper to explicitly zero-out these unaligned partial areas, while passing on the discard of the aligned full chunks, we effectively achieve discard_zeroes_data=true on such devices. Setting to will allow DRBD to use discards, and to announce discard_zeroes_data=true, even on backends that announce discard_zeroes_data=false. Setting to will cause DRBD to always fall-back to zero-out on the receiving side, and to not even announce discard capabilities on the Primary, if the respective backend announces discard_zeroes_data=false. We used to ignore the discard_zeroes_data setting completely. To not break established and expected behaviour, and suddenly cause fstrim on thin-provisioned LVs to run out-of-space instead of freeing up space, the default value is . This option is available since 8.4.7. drbd.conf read-balancing The supported methods for load balancing of read requests are , , , , , , , , , and . The default value of is . This option is available since 8.4.1. drbd.conf rs-discard-granularity When is set to a non zero, positive value then DRBD tries to do a resync operation in requests of this size. In case such a block contains only zero bytes on the sync source node, the sync target node will issue a discard/trim/unmap command for the area. The value is constrained by the discard granularity of the backing block device. In case is not a multiplier of the discard granularity of the backing block device DRBD rounds it up. The feature only gets active if the backing block device reads back zeroes after a discard command. The default value of is 0. This option is available since 8.4.7. drbd.conf sndbuf-size size is the size of the TCP socket send buffer. The default value is 0, i.e. autotune. You can specify smaller or larger values. Larger values are appropriate for reasonable write throughput with protocol A over high latency networks. Values below 32K do not make sense. Since 8.0.13 resp. 8.2.7, setting the size value to 0 means that the kernel should autotune this. drbd.conf rcvbuf-size size is the size of the TCP socket receive buffer. The default value is 0, i.e. autotune. You can specify smaller or larger values. Usually this should be left at its default. Setting the size value to 0 means that the kernel should autotune this. drbd.conf timeout If the partner node fails to send an expected response packet within time tenths of a second, the partner node is considered dead and therefore the TCP/IP connection is abandoned. This must be lower than connect-int and ping-int. The default value is 60 = 6 seconds, the unit 0.1 seconds. drbd.conf connect-int In case it is not possible to connect to the remote DRBD device immediately, DRBD keeps on trying to connect. With this option you can set the time between two retries. The default value is 10 seconds, the unit is 1 second. drbd.conf ping-int If the TCP/IP connection linking a DRBD device pair is idle for more than time seconds, DRBD will generate a keep-alive packet to check if its partner is still alive. The default is 10 seconds, the unit is 1 second. drbd.conf ping-timeout The time the peer has time to answer to a keep-alive packet. In case the peer's reply is not received within this time period, it is considered as dead. The default value is 500ms, the default unit are tenths of a second. drbd.conf max-buffers Limits the memory usage per DRBD minor device on the receiving side, or for internal buffers during resync or online-verify. Unit is PAGE_SIZE, which is 4 KiB on most systems. The minimum possible setting is hard coded to 32 (=128 KiB). These buffers are used to hold data blocks while they are written to/read from disk. To avoid possible distributed deadlocks on congestion, this setting is used as a throttle threshold rather than a hard limit. Once more than max-buffers pages are in use, further allocation from this pool is throttled. You want to increase max-buffers if you cannot saturate the IO backend on the receiving side. drbd.conf ko-count In case the secondary node fails to complete a single write request for count times the timeout, it is expelled from the cluster. (I.e. the primary node will kill and restart the connection.) To disable this feature, you should explicitly set it to 0; defaults may change between versions. drbd.conf max-epoch-size The highest number of data blocks between two write barriers. If you set this smaller than 10, you might decrease your performance. drbd.conf allow-two-primaries With this option set you may assign the primary role to both nodes. You only should use this option if you use a shared storage file system on top of DRBD. At the time of writing the only ones are: OCFS2 and GFS. If you use this option with any other file system, you are going to crash your nodes and to corrupt your data! drbd.conf unplug-watermark This setting has no effect with recent kernels that use explicit on-stack plugging (upstream Linux kernel 2.6.39, distributions may have backported). When the number of pending write requests on the standby (secondary) node exceeds the , we trigger the request processing of our backing storage device. Some storage controllers deliver better performance with small values, others deliver best performance when the value is set to the same value as max-buffers, yet others don't feel much effect at all. Minimum 16, default 128, maximum 131072. drbd.conf cram-hmac-alg You need to specify the HMAC algorithm to enable peer authentication at all. You are strongly encouraged to use peer authentication. The HMAC algorithm will be used for the challenge response authentication of the peer. You may specify any digest algorithm that is named in . drbd.conf shared-secret The shared secret used in peer authentication. May be up to 64 characters. Note that peer authentication is disabled as long as no (see above) is specified. policy drbd.conf after-sb-0pri possible policies are: No automatic resynchronization, simply disconnect. Auto sync from the node that was primary before the split-brain situation happened. Auto sync from the node that became primary as second during the split-brain situation. In case one node did not write anything since the split brain became evident, sync from the node that wrote something to the node that did not write anything. In case none wrote anything this policy uses a random decision to perform a "resync" of 0 blocks. In case both have written something this policy disconnects the nodes. Auto sync from the node that touched more blocks during the split brain situation. Auto sync to the named node. policy drbd.conf after-sb-1pri possible policies are: No automatic resynchronization, simply disconnect. Discard the version of the secondary if the outcome of the algorithm would also destroy the current secondary's data. Otherwise disconnect. Always take the decision of the algorithm, even if that causes an erratic change of the primary's view of the data. This is only useful if you use a one-node FS (i.e. not OCFS2 or GFS) with the flag, AND if you really know what you are doing. This is DANGEROUS and MAY CRASH YOUR MACHINE if you have an FS mounted on the primary node. Discard the secondary's version. Always honor the outcome of the algorithm. In case it decides the current secondary has the right data, it calls the "pri-lost-after-sb" handler on the current primary. policy drbd.conf after-sb-2pri possible policies are: No automatic resynchronization, simply disconnect. Always take the decision of the algorithm, even if that causes an erratic change of the primary's view of the data. This is only useful if you use a one-node FS (i.e. not OCFS2 or GFS) with the flag, AND if you really know what you are doing. This is DANGEROUS and MAY CRASH YOUR MACHINE if you have an FS mounted on the primary node. Call the "pri-lost-after-sb" helper program on one of the machines. This program is expected to reboot the machine, i.e. make it secondary. Normally the automatic after-split-brain policies are only used if current states of the UUIDs do not indicate the presence of a third node. With this option you request that the automatic after-split-brain policies are used as long as the data sets of the nodes are somehow related. This might cause a full sync, if the UUIDs indicate the presence of a third node. (Or double faults led to strange UUID sets.) policy drbd.conf rr-conflict This option helps to solve the cases when the outcome of the resync decision is incompatible with the current role assignment in the cluster. No automatic resynchronization, simply disconnect. Sync to the primary node is allowed, violating the assumption that data on a block device are stable for one of the nodes. Dangerous, do not use. Call the helper program on one of the machines unless that machine can demote to secondary. The helper program is expected to reboot the machine, which brings the node into a secondary role. Which machine runs the helper program is determined by the strategy. alg drbd.conf data-integrity-alg DRBD can ensure the data integrity of the user's data on the network by comparing hash values. Normally this is ensured by the 16 bit checksums in the headers of TCP/IP packets. This option can be set to any of the kernel's data digest algorithms. In a typical kernel configuration you should have at least one of , , and available. By default this is not enabled. See also the notes on data integrity. drbd.conf tcp-cork DRBD usually uses the TCP socket option TCP_CORK to hint to the network stack when it can expect more data, and when it should flush out what it has in its send queue. It turned out that there is at least one network stack that performs worse when one uses this hinting method. Therefore we introducted this option. By setting to you can disable the setting and clearing of the TCP_CORK socket option by DRBD. By default DRBD blocks when the available TCP send queue becomes full. That means it will slow down the application that generates the write requests that cause DRBD to send more data down that TCP connection. When DRBD is deployed with DRBD-proxy it might be more desirable that DRBD goes into AHEAD/BEHIND mode shortly before the send queue becomes full. In AHEAD/BEHIND mode DRBD does no longer replicate data, but still keeps the connection open. The advantage of the AHEAD/BEHIND mode is that the application is not slowed down, even if DRBD-proxy's buffer is not sufficient to buffer all write requests. The downside is that the peer node falls behind, and that a resync will be necessary to bring it back into sync. During that resync the peer node will have an inconsistent disk. Available congestion_policys are and . The default is . Fill_threshold might be in the range of 0 to 10GiBytes. The default is 0 which disables the check. Active_extents_threshold has the same limits as . The AHEAD/BEHIND mode and its settings are available since DRBD 8.3.10. Wait for connection timeout. drbd.conf wfc-timeout The init script drbd 8 blocks the boot process until the DRBD resources are connected. When the cluster manager starts later, it does not see a resource with internal split-brain. In case you want to limit the wait time, do it here. Default is 0, which means unlimited. The unit is seconds. drbd.conf degr-wfc-timeout Wait for connection timeout, if this node was a degraded cluster. In case a degraded cluster (= cluster with only one node left) is rebooted, this timeout value is used instead of wfc-timeout, because the peer is less likely to show up in time, if it had been dead before. Value 0 means unlimited. drbd.conf outdated-wfc-timeout Wait for connection timeout, if the peer was outdated. In case a degraded cluster (= cluster with only one node left) with an outdated peer disk is rebooted, this timeout value is used instead of wfc-timeout, because the peer is not allowed to become primary in the meantime. Value 0 means unlimited. By setting this option you can make the init script to continue to wait even if the device pair had a split brain situation and therefore refuses to connect. Sets on which node the device should be promoted to primary role by the init script. The node-name might either be a host name or the keyword . When this option is not set the devices stay in secondary role on both nodes. Usually one delegates the role assignment to a cluster manager (e.g. heartbeat). Usually and are ignored for stacked devices, instead twice the amount of is used for the connection timeouts. With the keyword you disable this, and force DRBD to mind the and statements. Only do that if the peer of the stacked resource is usually not available or will usually not become primary. By using this option incorrectly, you run the risk of causing unexpected split brain. drbd.conf resync-rate To ensure a smooth operation of the application on top of DRBD, it is possible to limit the bandwidth which may be used by background synchronizations. The default is 250 KB/sec, the default unit is KB/sec. Optional suffixes K, M, G are allowed. drbd.conf use-rle During resync-handshake, the dirty-bitmaps of the nodes are exchanged and merged (using bit-or), so the nodes will have the same understanding of which blocks are dirty. On large devices, the fine grained dirty-bitmap can become large as well, and the bitmap exchange can take quite some time on low-bandwidth links. Because the bitmap typically contains compact areas where all bits are unset (clean) or set (dirty), a simple run-length encoding scheme can considerably reduce the network traffic necessary for the bitmap exchange. For backward compatibilty reasons, and because on fast links this possibly does not improve transfer time but consumes cpu cycles, this defaults to off. drbd.conf socket-check-timeout In setups involving a DRBD-proxy and connections that experience a lot of buffer-bloat it might be necessary to set to an unusual high value. By default DRBD uses the same value to wait if a newly established TCP-connection is stable. Since the DRBD-proxy is usually located in the same data center such a long wait time may hinder DRBD's connect process. In such setups should be set to at least to the round trip time between DRBD and DRBD-proxy. I.e. in most cases to 1. The default unit is tenths of a second, the default value is 0 (which causes DRBD to use the value of instead). Introduced in 8.4.5. drbd.conf resync-after By default, resynchronization of all devices would run in parallel. By defining a resync-after dependency, the resynchronization of this resource will start only if the resource res-name is already in connected state (i.e., has finished its resynchronization). drbd.conf al-extents DRBD automatically performs hot area detection. With this parameter you control how big the hot area (= active set) can get. Each extent marks 4M of the backing storage (= low-level device). In case a primary node leaves the cluster unexpectedly, the areas covered by the active set must be resynced upon rejoining of the failed node. The data structure is stored in the meta-data area, therefore each change of the active set is a write operation to the meta-data device. A higher number of extents gives longer resync times but less updates to the meta-data. The default number of extents is 1237. (Minimum: 7, Maximum: 65534) Note that the effective maximum may be smaller, depending on how you created the device meta data, see also drbdmeta8. The effective maximum is 919 * (available on-disk activity-log ring-buffer area/4kB -1), the default 32kB ring-buffer effects a maximum of 6433 (covers more than 25 GiB of data). We recommend to keep this well within the amount your backend storage and replication link are able to resync inside of about 5 minutes. drbd.conf al-updates DRBD's activity log transaction writing makes it possible, that after the crash of a primary node a partial (bit-map based) resync is sufficient to bring the node back to up-to-date. Setting to might increase normal operation performance but causes DRBD to do a full resync when a crashed primary gets reconnected. The default value is . During online verification (as initiated by the verify sub-command), rather than doing a bit-wise comparison, DRBD applies a hash function to the contents of every block being verified, and compares that hash with the peer. This option defines the hash algorithm being used for that purpose. It can be set to any of the kernel's data digest algorithms. In a typical kernel configuration you should have at least one of , , and available. By default this is not enabled; you must set this option explicitly in order to be able to use on-line device verification. See also the notes on data integrity. A resync process sends all marked data blocks from the source to the destination node, as long as no is given. When one is specified the resync process exchanges hash values of all marked blocks first, and sends only those data blocks that have different hash values. This setting is useful for DRBD setups with low bandwidth links. During the restart of a crashed primary node, all blocks covered by the activity log are marked for resync. But a large part of those will actually be still in sync, therefore using will lower the required bandwidth in exchange for CPU cycles. The dynamic resync speed controller gets enabled with setting plan_time to a positive value. It aims to fill the buffers along the data path with either a constant amount of data fill_target, or aims to have a constant delay time of delay_target along the path. The controller has an upper bound of max_rate. By plan_time the agility of the controller is configured. Higher values yield for slower/lower responses of the controller to deviation from the target value. It should be at least 5 times RTT. For regular data paths a fill_target in the area of 4k to 100k is appropriate. For a setup that contains drbd-proxy it is advisable to use delay_target instead. Only when fill_target is set to 0 the controller will use delay_target. 5 times RTT is a reasonable starting value. Max_rate should be set to the bandwidth available between the DRBD-hosts and the machines hosting DRBD-proxy, or to the available disk-bandwidth. The default value of plan_time is 0, the default unit is 0.1 seconds. Fill_target has 0 and sectors as default unit. Delay_target has 1 (100ms) and 0.1 as default unit. Max_rate has 10240 (100MiB/s) and KiB/s as default unit. The dynamic resync speed controller and its settings are available since DRBD 8.3.9. A node that is primary and sync-source has to schedule application IO requests and resync IO requests. The min_rate tells DRBD use only up to min_rate for resync IO and to dedicate all other available IO bandwidth to application requests. Note: The value 0 has a special meaning. It disables the limitation of resync IO completely, which might slow down application IO considerably. Set it to a value of 1, if you prefer that resync IO never slows down application IO. Note: Although the name might suggest that it is a lower bound for the dynamic resync speed controller, it is not. If the DRBD-proxy buffer is full, the dynamic resync speed controller is free to lower the resync speed down to 0, completely independent of the setting. Min_rate has 4096 (4MiB/s) and KiB/s as default unit. This setting controls what happens to IO requests on a degraded, disk less node (I.e. no data store is reachable). The available policies are and . If ond-policy is set to you can either resume IO by attaching/connecting the last lost data storage, or by the drbdadm resume-io res command. The latter will result in IO errors of course. The default is . This setting is available since DRBD 8.3.9. drbd.conf cpu-mask Sets the cpu-affinity-mask for DRBD's kernel threads of this device. The default value of cpu-mask is 0, which means that DRBD's kernel threads should be spread over all CPUs of the machine. This value must be given in hexadecimal notation. If it is too big it will be truncated. drbd.conf pri-on-incon-degr This handler is called if the node is primary, degraded and if the local copy of the data is inconsistent. drbd.conf pri-lost-after-sb The node is currently primary, but lost the after-split-brain auto recovery procedure. As as consequence, it should be abandoned. drbd.conf pri-lost The node is currently primary, but DRBD's algorithm thinks that it should become sync target. As a consequence it should give up its primary role. drbd.conf fence-peer The handler is part of the mechanism. This handler is called in case the node needs to fence the peer's disk. It should use other communication paths than DRBD's network link. drbd.conf local-io-error DRBD got an IO error from the local IO subsystem. drbd.conf initial-split-brain DRBD has connected and detected a split brain situation. This handler can alert someone in all cases of split brain, not just those that go unresolved. drbd.conf split-brain DRBD detected a split brain situation but remains unresolved. Manual recovery is necessary. This handler should alert someone on duty. drbd.conf before-resync-target DRBD calls this handler just before a resync begins on the node that becomes resync target. It might be used to take a snapshot of the backing block device. drbd.conf after-resync-target DRBD calls this handler just after a resync operation finished on the node whose disk just became consistent after being inconsistent for the duration of the resync. It might be used to remove a snapshot of the backing device that was created by the handler. Other Keywords drbd.conf include Include all files matching the wildcard pattern file-pattern. The statement is only allowed on the top level, i.e. it is not allowed inside any section. Notes on data integrity There are two independent methods in DRBD to ensure the integrity of the mirrored data. The online-verify mechanism and the of the section. Both mechanisms might deliver false positives if the user of DRBD modifies the data which gets written to disk while the transfer goes on. This may happen for swap, or for certain append while global sync, or truncate/rewrite workloads, and not necessarily poses a problem for the integrity of the data. Usually when the initiator of the data transfer does this, it already knows that that data block will not be part of an on disk data structure, or will be resubmitted with correct data soon enough. The causes the receiving side to log an error about "Digest integrity check FAILED: Ns +x\n", where N is the sector offset, and x is the size of the request in bytes. It will then disconnect, and reconnect, thus causing a quick resync. If the sending side at the same time detected a modification, it warns about "Digest mismatch, buffer modified by upper layers during write: Ns +x\n", which shows that this was a false positive. The sending side may detect these buffer modifications immediately after the unmodified data has been copied to the tcp buffers, in which case the receiving side won't notice it. The most recent (2007) example of systematic corruption was an issue with the TCP offloading engine and the driver of a certain type of GBit NIC. The actual corruption happened on the DMA transfer from core memory to the card. Since the TCP checksum gets calculated on the card, this type of corruption stays undetected as long as you do not use either the online or the . We suggest to use the only during a pre-production phase due to its CPU costs. Further we suggest to do online runs regularly e.g. once a month during a low load period. Version This document was revised for version 8.4.0 of the DRBD distribution. Author Written by Philipp Reisner philipp.reisner@linbit.com and Lars Ellenberg lars.ellenberg@linbit.com. Reporting Bugs Report bugs to drbd-user@lists.linbit.com. Copyright Copyright 2001-2008 LINBIT Information Technologies, Philipp Reisner, Lars Ellenberg. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See Also drbd8, drbddisk8, drbdsetup8, drbdmeta8, drbdadm8, DRBD User's Guide, DRBD web site drbd-utils-8.9.6/documentation/v84/drbddisk.xml0000644000175000017500000000615012466702073021316 0ustar apoikosapoikos drbddisk Script to mark devices as primary and mount file systems 15 Oct 2008 DRBD 8.3.2 drbddisk 8 System Administration /etc/ha.d/resource.d/drbddisk resource start stop status Introduction The script brings the local device of resource into primary role. It is designed to be used by Heartbeat. In order to use you must define a resource, a host, and any other configuration options in the DRBD configuration file. See for details. If resource is omitted, then all of the resources listed in the config file are affected. Version This document was revised for version 8.0.14 of the DRBD distribution. Author Written by Philipp Reisner philipp.reisner@linbit.com and Lars Ellenberg lars.ellenberg@linbit.com. Reporting Bugs Report bugs to drbd-user@lists.linbit.com. Copyright Copyright 2001-2008 LINBIT Information Technologies, Philipp Reisner, Lars Ellenberg. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See Also drbd.conf5, drbd8, drbdsetup8drbdadm8DRBD Homepage drbd-utils-8.9.6/documentation/v84/drbdsetup.80000644000175000017500000016221712654452470021104 0ustar apoikosapoikos'\" t .\" Title: drbdsetup .\" Author: [see the "Author" section] .\" Generator: DocBook XSL Stylesheets v1.75.2 .\" Date: 6 May 2011 .\" Manual: System Administration .\" Source: DRBD 8.4.0 .\" Language: English .\" .TH "DRBDSETUP" "8" "6 May 2011" "DRBD 8.4.0" "System Administration" .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" drbdsetup \- Setup tool for DRBD .\" drbdsetup .SH "SYNOPSIS" .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR new\-resource \fIresource\fR [\-\-cpu\-mask\ {\fIval\fR}] [\-\-on\-no\-data\-accessible\ {io\-error\ |\ suspend\-io}] .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR new\-minor \fIresource\fR \fIminor\fR \fIvolume\fR .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR del\-resource \fIresource\fR .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR del\-minor \fIminor\fR .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR attach \fIminor\fR \fIlower_dev\fR \fImeta_data_dev\fR \fImeta_data_index\fR [\-\-size\ {\fIval\fR}] [\-\-max\-bio\-bvecs\ {\fIval\fR}] [\-\-on\-io\-error\ {pass_on\ |\ call\-local\-io\-error\ |\ detach}] [\-\-fencing\ {dont\-care\ |\ resource\-only\ |\ resource\-and\-stonith}] [\-\-disk\-barrier] [\-\-disk\-flushes] [\-\-disk\-drain] [\-\-md\-flushes] [\-\-resync\-rate\ {\fIval\fR}] [\-\-resync\-after\ {\fIval\fR}] [\-\-al\-extents\ {\fIval\fR}] [\-\-al\-updates] [\-\-discard\-zeroes\-if\-aligned] [\-\-c\-plan\-ahead\ {\fIval\fR}] [\-\-c\-delay\-target\ {\fIval\fR}] [\-\-c\-fill\-target\ {\fIval\fR}] [\-\-c\-max\-rate\ {\fIval\fR}] [\-\-c\-min\-rate\ {\fIval\fR}] [\-\-disk\-timeout\ {\fIval\fR}] [\-\-read\-balancing\ {prefer\-local\ |\ prefer\-remote\ |\ round\-robin\ |\ least\-pending\ |\ when\-congested\-remote\ |\ 32K\-striping\ |\ 64K\-striping\ |\ 128K\-striping\ |\ 256K\-striping\ |\ 512K\-striping\ |\ 1M\-striping}] [\-\-rs\-discard\-granularity\ {\fIval\fR}] .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR connect \fIresource\fR \fIlocal_addr\fR \fIremote_addr\fR [\-\-tentative] [\-\-discard\-my\-data] [\-\-protocol\ {A\ |\ B\ |\ C}] [\-\-timeout\ {\fIval\fR}] [\-\-max\-epoch\-size\ {\fIval\fR}] [\-\-max\-buffers\ {\fIval\fR}] [\-\-unplug\-watermark\ {\fIval\fR}] [\-\-connect\-int\ {\fIval\fR}] [\-\-ping\-int\ {\fIval\fR}] [\-\-sndbuf\-size\ {\fIval\fR}] [\-\-rcvbuf\-size\ {\fIval\fR}] [\-\-ko\-count\ {\fIval\fR}] [\-\-allow\-two\-primaries] [\-\-cram\-hmac\-alg\ {\fIval\fR}] [\-\-shared\-secret\ {\fIval\fR}] [\-\-after\-sb\-0pri\ {disconnect\ |\ discard\-younger\-primary\ |\ discard\-older\-primary\ |\ discard\-zero\-changes\ |\ discard\-least\-changes\ |\ discard\-local\ |\ discard\-remote}] [\-\-after\-sb\-1pri\ {disconnect\ |\ consensus\ |\ discard\-secondary\ |\ call\-pri\-lost\-after\-sb\ |\ violently\-as0p}] [\-\-after\-sb\-2pri\ {disconnect\ |\ call\-pri\-lost\-after\-sb\ |\ violently\-as0p}] [\-\-always\-asbp] [\-\-rr\-conflict\ {disconnect\ |\ call\-pri\-lost\ |\ violently}] [\-\-ping\-timeout\ {\fIval\fR}] [\-\-data\-integrity\-alg\ {\fIval\fR}] [\-\-tcp\-cork] [\-\-on\-congestion\ {block\ |\ pull\-ahead\ |\ disconnect}] [\-\-congestion\-fill\ {\fIval\fR}] [\-\-congestion\-extents\ {\fIval\fR}] [\-\-csums\-alg\ {\fIval\fR}] [\-\-csums\-after\-crash\-only] [\-\-verify\-alg\ {\fIval\fR}] [\-\-use\-rle] [\-\-socket\-check\-timeout\ {\fIval\fR}] .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR disk\-options \fIminor\fR [\-\-on\-io\-error\ {pass_on\ |\ call\-local\-io\-error\ |\ detach}] [\-\-fencing\ {dont\-care\ |\ resource\-only\ |\ resource\-and\-stonith}] [\-\-disk\-barrier] [\-\-disk\-flushes] [\-\-disk\-drain] [\-\-md\-flushes] [\-\-resync\-rate\ {\fIval\fR}] [\-\-resync\-after\ {\fIval\fR}] [\-\-al\-extents\ {\fIval\fR}] [\-\-al\-updates] [\-\-discard\-zeroes\-if\-aligned] [\-\-c\-plan\-ahead\ {\fIval\fR}] [\-\-c\-delay\-target\ {\fIval\fR}] [\-\-c\-fill\-target\ {\fIval\fR}] [\-\-c\-max\-rate\ {\fIval\fR}] [\-\-c\-min\-rate\ {\fIval\fR}] [\-\-disk\-timeout\ {\fIval\fR}] [\-\-read\-balancing\ {prefer\-local\ |\ prefer\-remote\ |\ round\-robin\ |\ least\-pending\ |\ when\-congested\-remote\ |\ 32K\-striping\ |\ 64K\-striping\ |\ 128K\-striping\ |\ 256K\-striping\ |\ 512K\-striping\ |\ 1M\-striping}] [\-\-rs\-discard\-granularity\ {\fIval\fR}] .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR net\-options \fIlocal_addr\fR \fIremote_addr\fR [\-\-protocol\ {A\ |\ B\ |\ C}] [\-\-timeout\ {\fIval\fR}] [\-\-max\-epoch\-size\ {\fIval\fR}] [\-\-max\-buffers\ {\fIval\fR}] [\-\-unplug\-watermark\ {\fIval\fR}] [\-\-connect\-int\ {\fIval\fR}] [\-\-ping\-int\ {\fIval\fR}] [\-\-sndbuf\-size\ {\fIval\fR}] [\-\-rcvbuf\-size\ {\fIval\fR}] [\-\-ko\-count\ {\fIval\fR}] [\-\-allow\-two\-primaries] [\-\-cram\-hmac\-alg\ {\fIval\fR}] [\-\-shared\-secret\ {\fIval\fR}] [\-\-after\-sb\-0pri\ {disconnect\ |\ discard\-younger\-primary\ |\ discard\-older\-primary\ |\ discard\-zero\-changes\ |\ discard\-least\-changes\ |\ discard\-local\ |\ discard\-remote}] [\-\-after\-sb\-1pri\ {disconnect\ |\ consensus\ |\ discard\-secondary\ |\ call\-pri\-lost\-after\-sb\ |\ violently\-as0p}] [\-\-after\-sb\-2pri\ {disconnect\ |\ call\-pri\-lost\-after\-sb\ |\ violently\-as0p}] [\-\-always\-asbp] [\-\-rr\-conflict\ {disconnect\ |\ call\-pri\-lost\ |\ violently}] [\-\-ping\-timeout\ {\fIval\fR}] [\-\-data\-integrity\-alg\ {\fIval\fR}] [\-\-tcp\-cork] [\-\-on\-congestion\ {block\ |\ pull\-ahead\ |\ disconnect}] [\-\-congestion\-fill\ {\fIval\fR}] [\-\-congestion\-extents\ {\fIval\fR}] [\-\-csums\-alg\ {\fIval\fR}] [\-\-csums\-after\-crash\-only] [\-\-verify\-alg\ {\fIval\fR}] [\-\-use\-rle] [\-\-socket\-check\-timeout\ {\fIval\fR}] .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR resource\-options \fIresource\fR [\-\-cpu\-mask\ {\fIval\fR}] [\-\-on\-no\-data\-accessible\ {io\-error\ |\ suspend\-io}] .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR disconnect \fIlocal_addr\fR \fIremote_addr\fR [\-\-force] .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR detach \fIminor\fR [\-\-force] .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR primary \fIminor\fR [\-\-force] .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR secondary \fIminor\fR .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR down \fIresource\fR .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR verify \fIminor\fR [\-\-start\ {\fIval\fR}] [\-\-stop\ {\fIval\fR}] .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR invalidate \fIminor\fR .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR invalidate\-remote \fIminor\fR .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR wait\-connect \fIminor\fR [\-\-wfc\-timeout\ {\fIval\fR}] [\-\-degr\-wfc\-timeout\ {\fIval\fR}] [\-\-outdated\-wfc\-timeout\ {\fIval\fR}] [\-\-wait\-after\-sb\ {\fIval\fR}] .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR wait\-sync \fIminor\fR [\-\-wfc\-timeout\ {\fIval\fR}] [\-\-degr\-wfc\-timeout\ {\fIval\fR}] [\-\-outdated\-wfc\-timeout\ {\fIval\fR}] [\-\-wait\-after\-sb\ {\fIval\fR}] .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR role \fIminor\fR .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR cstate \fIminor\fR .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR dstate \fIminor\fR .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR resize \fIminor\fR [\-\-size\ {\fIval\fR}] [\-\-assume\-peer\-has\-space] [\-\-assume\-clean] [\-\-al\-stripes\ {\fIval\fR}] [\-\-al\-stripe\-size\-kB\ {\fIval\fR}] .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR check\-resize \fIminor\fR .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR pause\-sync \fIminor\fR .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR resume\-sync \fIminor\fR .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR outdate \fIminor\fR .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR show\-gi \fIminor\fR .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR get\-gi \fIminor\fR .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR show {\fIresource\fR | \fIminor\fR | \fIall\fR} .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR suspend\-io \fIminor\fR .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR resume\-io \fIminor\fR .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR status {\fIresource\fR | \fIall\fR} [\-\-color\ {\fIval\fR}] .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR events2 {\fIresource\fR | \fIall\fR} .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR events {\fIresource\fR | \fIminor\fR | \fIall\fR} .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR new\-current\-uuid \fIminor\fR [\-\-clear\-bitmap] .SH "DESCRIPTION" .PP drbdsetup is used to associate DRBD devices with their backing block devices, to set up DRBD device pairs to mirror their backing block devices, and to inspect the configuration of running DRBD devices\&. .SH "NOTE" .PP drbdsetup is a low level tool of the DRBD program suite\&. It is used by the data disk and drbd scripts to communicate with the device driver\&. .SH "COMMANDS" .PP Each drbdsetup sub\-command might require arguments and bring its own set of options\&. All values have default units which might be overruled by K, M or G\&. These units are defined in the usual way (e\&.g\&. K = 2^10 = 1024)\&. .SS "Common options" .PP All drbdsetup sub\-commands accept these two options .PP \fB\-\-create\-device\fR .RS 4 In case the specified DRBD device (minor number) does not exist yet, create it implicitly\&. .RE .SS "new\-resource" .PP Resources are the primary objects of any DRBD configuration\&. A resource must be created with the \fBnew\-resource\fR command before any volumes or minor devices can be created\&. Connections are referenced by name\&. .SS "new\-minor" .PP A \fIminor\fR is used as a synonym for replicated block device\&. It is represented in the /dev/ directory by a block device\&. It is the application\'s interface to the DRBD\-replicated block devices\&. These block devices get addressed by their minor numbers on the drbdsetup commandline\&. .PP A pair of replicated block devices may have different minor numbers on the two machines\&. They are associated by a common \fIvolume\-number\fR\&. Volume numbers are local to each connection\&. Minor numbers are global on one node\&. .SS "del\-resource" .PP Destroys a resource object\&. This is only possible if the resource has no volumes\&. .SS "del\-minor" .PP Minors can only be destroyed if its disk is detached\&. .SS "attach, disk\-options" .\" drbdsetup: disk .PP Attach associates \fIdevice\fR with \fIlower_device\fR to store its data blocks on\&. The \fB\-d\fR (or \fB\-\-disk\-size\fR) should only be used if you wish not to use as much as possible from the backing block devices\&. If you do not use \fB\-d\fR, the \fIdevice\fR is only ready for use as soon as it was connected to its peer once\&. (See the \fBnet\fR command\&.) .PP With the disk\-options command it is possible to change the options of a minor while it is attached\&. .PP \fB\-\-disk\-size \fR\fB\fIsize\fR\fR .RS 4 You can override DRBD\'s size determination method with this option\&. If you need to use the device before it was ever connected to its peer, use this option to pass the \fIsize\fR of the DRBD device to the driver\&. Default unit is sectors (1s = 512 bytes)\&. .sp If you use the \fIsize\fR parameter in drbd\&.conf, we strongly recommend to add an explicit unit postfix\&. drbdadm and drbdsetup used to have mismatching default units\&. .RE .PP \fB\-\-on\-io\-error \fR\fB\fIerr_handler\fR\fR .RS 4 If the driver of the \fIlower_device\fR reports an error to DRBD, DRBD will mark the disk as inconsistent, call a helper program, or detach the device from its backing storage and perform all further IO by requesting it from the peer\&. The valid \fIerr_handlers\fR are: \fBpass_on\fR, \fBcall\-local\-io\-error\fR and \fBdetach\fR\&. .RE .PP \fB\-\-fencing \fR\fB\fIfencing_policy\fR\fR .RS 4 Under \fBfencing\fR we understand preventive measures to avoid situations where both nodes are primary and disconnected (AKA split brain)\&. .sp Valid fencing policies are: .PP \fBdont\-care\fR .RS 4 This is the default policy\&. No fencing actions are done\&. .RE .PP \fBresource\-only\fR .RS 4 If a node becomes a disconnected primary, it tries to outdate the peer\'s disk\&. This is done by calling the fence\-peer handler\&. The handler is supposed to reach the other node over alternative communication paths and call \'drbdadm outdate res\' there\&. .RE .PP \fBresource\-and\-stonith\fR .RS 4 If a node becomes a disconnected primary, it freezes all its IO operations and calls its fence\-peer handler\&. The fence\-peer handler is supposed to reach the peer over alternative communication paths and call \'drbdadm outdate res\' there\&. In case it cannot reach the peer, it should stonith the peer\&. IO is resumed as soon as the situation is resolved\&. In case your handler fails, you can resume IO with the \fBresume\-io\fR command\&. .RE .RE .PP \fB\-\-disk\-barrier\fR, .br \fB\-\-disk\-flushes\fR, .br \fB\-\-disk\-drain\fR .RS 4 DRBD has four implementations to express write\-after\-write dependencies to its backing storage device\&. DRBD will use the first method that is supported by the backing storage device and that is not disabled\&. By default the \fIflush\fR method is used\&. .sp Since drbd\-8\&.4\&.2 \fBdisk\-barrier\fR is disabled by default because since linux\-2\&.6\&.36 (or 2\&.6\&.32 RHEL6) there is no reliable way to determine if queuing of IO\-barriers works\&. \fIDangerous\fR only enable if you are told so by one that knows for sure\&. .sp When selecting the method you should not only base your decision on the measurable performance\&. In case your backing storage device has a volatile write cache (plain disks, RAID of plain disks) you should use one of the first two\&. In case your backing storage device has battery\-backed write cache you may go with option 3\&. Option 4 (disable everything, use "none") \fIis dangerous\fR on most IO stacks, may result in write\-reordering, and if so, can theoretically be the reason for data corruption, or disturb the DRBD protocol, causing spurious disconnect/reconnect cycles\&. \fIDo not use\fR \fBno\-disk\-drain\fR\&. .sp Unfortunately device mapper (LVM) might not support barriers\&. .sp The letter after "wo:" in /proc/drbd indicates with method is currently in use for a device: b, f, d, n\&. The implementations: .PP barrier .RS 4 The first requires that the driver of the backing storage device support barriers (called \'tagged command queuing\' in SCSI and \'native command queuing\' in SATA speak)\&. The use of this method can be enabled by setting the \fBdisk\-barrier\fR options to \fByes\fR\&. .RE .PP flush .RS 4 The second requires that the backing device support disk flushes (called \'force unit access\' in the drive vendors speak)\&. The use of this method can be disabled setting \fBdisk\-flushes\fR to \fBno\fR\&. .RE .PP drain .RS 4 The third method is simply to let write requests drain before write requests of a new reordering domain are issued\&. That was the only implementation before 8\&.0\&.9\&. .RE .PP none .RS 4 The fourth method is to not express write\-after\-write dependencies to the backing store at all, by also specifying \fB\-\-no\-disk\-drain\fR\&. This \fIis dangerous\fR on most IO stacks, may result in write\-reordering, and if so, can theoretically be the reason for data corruption, or disturb the DRBD protocol, causing spurious disconnect/reconnect cycles\&. \fIDo not use\fR \fB\-\-no\-disk\-drain\fR\&. .RE .RE .PP \fB\-\-md\-flushes\fR .RS 4 Disables the use of disk flushes and barrier BIOs when accessing the meta data device\&. See the notes on \fB\-\-disk\-flushes\fR\&. .RE .PP \fB\-\-max\-bio\-bvecs\fR .RS 4 In some special circumstances the device mapper stack manages to pass BIOs to DRBD that violate the constraints that are set forth by DRBD\'s merge_bvec() function and which have more than one bvec\&. A known example is: phys\-disk \-> DRBD \-> LVM \-> Xen \-> missaligned partition (63) \-> DomU FS\&. Then you might see "bio would need to, but cannot, be split:" in the Dom0\'s kernel log\&. .sp The best workaround is to proper align the partition within the VM (E\&.g\&. start it at sector 1024)\&. That costs 480 KiB of storage\&. Unfortunately the default of most Linux partitioning tools is to start the first partition at an odd number (63)\&. Therefore most distributions install helpers for virtual linux machines will end up with missaligned partitions\&. The second best workaround is to limit DRBD\'s max bvecs per BIO (i\&.e\&., the \fBmax\-bio\-bvecs\fR option) to 1, but that might cost performance\&. .sp The default value of \fBmax\-bio\-bvecs\fR is 0, which means that there is no user imposed limitation\&. .RE .PP \fB\-\-resync\-rate \fR\fB\fIrate\fR\fR .RS 4 To ensure smooth operation of the application on top of DRBD, it is possible to limit the bandwidth that may be used by background synchronization\&. The default is 250 KiB/sec, the default unit is KiB/sec\&. .RE .PP \fB\-\-resync\-after \fR\fB\fIminor\fR\fR .RS 4 Start resync on this device only if the device with \fIminor\fR is already in connected state\&. Otherwise this device waits in SyncPause state\&. .RE .PP \fB\-\-al\-extents \fR\fB\fIextents\fR\fR .RS 4 DRBD automatically performs hot area detection\&. With this parameter you control how big the hot area (=active set) can get\&. Each extent marks 4M of the backing storage\&. In case a primary node leaves the cluster unexpectedly, the areas covered by the active set must be resynced upon rejoining of the failed node\&. The data structure is stored in the meta\-data area, therefore each change of the active set is a write operation to the meta\-data device\&. A higher number of extents gives longer resync times but less updates to the meta\-data\&. The default number of \fIextents\fR is 1237\&. (Minimum: 7, Maximum: 65534) .sp See also \fBdrbd.conf\fR(5) and \fBdrbdmeta\fR(8) for additional limitations and necessary preparation\&. .RE .PP \fB\-\-al\-updates \fR\fB{yes | no}\fR .RS 4 DRBD\'s activity log transaction writing makes it possible, that after the crash of a primary node a partial (bit\-map based) resync is sufficient to bring the node back to up\-to\-date\&. Setting \fBal\-updates\fR to \fBno\fR might increase normal operation performance but causes DRBD to do a full resync when a crashed primary gets reconnected\&. The default value is \fByes\fR\&. .RE .PP \fB\-\-c\-plan\-ahead \fR\fB\fIplan_time\fR\fR, .br \fB\-\-c\-fill\-target \fR\fB\fIfill_target\fR\fR, .br \fB\-\-c\-delay\-target \fR\fB\fIdelay_target\fR\fR, .br \fB\-\-c\-max\-rate \fR\fB\fImax_rate\fR\fR .RS 4 The dynamic resync speed controller gets enabled with setting \fIplan_time\fR to a positive value\&. It aims to fill the buffers along the data path with either a constant amount of data \fIfill_target\fR, or aims to have a constant delay time of \fIdelay_target\fR along the path\&. The controller has an upper bound of \fImax_rate\fR\&. .sp By \fIplan_time\fR the agility of the controller is configured\&. Higher values yield for slower/lower responses of the controller to deviation from the target value\&. It should be at least 5 times RTT\&. For regular data paths a \fIfill_target\fR in the area of 4k to 100k is appropriate\&. For a setup that contains drbd\-proxy it is advisable to use \fIdelay_target\fR instead\&. Only when \fIfill_target\fR is set to 0 the controller will use \fIdelay_target\fR\&. 5 times RTT is a reasonable starting value\&. \fIMax_rate\fR should be set to the bandwidth available between the DRBD\-hosts and the machines hosting DRBD\-proxy, or to the available disk\-bandwidth\&. .sp The default value of \fIplan_time\fR is 0, the default unit is 0\&.1 seconds\&. \fIFill_target\fR has 0 and sectors as default unit\&. \fIDelay_target\fR has 1 (100ms) and 0\&.1 as default unit\&. \fIMax_rate\fR has 10240 (100MiB/s) and KiB/s as default unit\&. .RE .PP \fB\-\-c\-min\-rate \fR\fB\fImin_rate\fR\fR .RS 4 We track the disk IO rate caused by the resync, so we can detect non\-resync IO on the lower level device\&. If the lower level device seems to be busy, and the current resync rate is above \fImin_rate\fR, we throttle the resync\&. .sp The default value of \fImin_rate\fR is 4M, the default unit is k\&. If you want to not throttle at all, set it to zero, if you want to throttle always, set it to one\&. .RE .PP \fB\-t\fR, \fB\-\-disk\-timeout \fR\fB\fIdisk_timeout\fR\fR .RS 4 If the lower\-level device on which a DRBD device stores its data does not finish an I/O request within the defined \fBdisk\-timeout\fR, DRBD treats this as a failure\&. The lower\-level device is detached, and the device\'s disk state advances to Diskless\&. If DRBD is connected to one or more peers, the failed request is passed on to one of them\&. .sp This option is \fIdangerous and may lead to kernel panic!\fR .sp "Aborting" requests, or force\-detaching the disk, is intended for completely blocked/hung local backing devices which do no longer complete requests at all, not even do error completions\&. In this situation, usually a hard\-reset and failover is the only way out\&. .sp By "aborting", basically faking a local error\-completion, we allow for a more graceful swichover by cleanly migrating services\&. Still the affected node has to be rebooted "soon"\&. .sp By completing these requests, we allow the upper layers to re\-use the associated data pages\&. .sp If later the local backing device "recovers", and now DMAs some data from disk into the original request pages, in the best case it will just put random data into unused pages; but typically it will corrupt meanwhile completely unrelated data, causing all sorts of damage\&. .sp Which means delayed successful completion, especially for READ requests, is a reason to panic()\&. We assume that a delayed *error* completion is OK, though we still will complain noisily about it\&. .sp The default value of \fBdisk\-timeout\fR is 0, which stands for an infinite timeout\&. Timeouts are specified in units of 0\&.1 seconds\&. This option is available since DRBD 8\&.3\&.12\&. .RE .PP \fB\-\-discard\-zeroes\-if\-aligned \fR\fB{yes | no}\fR .RS 4 Setting \fBdiscard\-zeroes\-if\-aligned\fR to \fBno\fR will cause DRBD to always fall\-back to zero\-out on the receiving side, and to not even announce discard capabilities on the Primary, if the respective backend announces discard_zeroes_data=false\&. .sp Setting \fBdiscards\-zeroes\-if\-aligned\fR to \fByes\fR will allow DRBD to use discards, and to announce discard_zeroes=true, even on backends that announce discard_zeroes_data=false\&. .sp We used to ignore the discard_zeroes_data setting completely\&. To not break established and expected behaviour, the default value is \fByes\fR\&. .sp This option is available since 8\&.4\&.7\&. See also \fBdrbd.conf\fR(5)\&. .RE .PP \fB\-\-read\-balancing \fR\fB\fImethod\fR\fR .RS 4 The supported \fImethods\fR for load balancing of read requests are \fBprefer\-local\fR, \fBprefer\-remote\fR, \fBround\-robin\fR, \fBleast\-pending\fR and \fBwhen\-congested\-remote\fR, \fB32K\-striping\fR, \fB64K\-striping\fR, \fB128K\-striping\fR, \fB256K\-striping\fR, \fB512K\-striping\fR and \fB1M\-striping\fR\&. .sp The default value of is \fBprefer\-local\fR\&. This option is available since 8\&.4\&.1\&. .RE .PP \fB\-\-rs\-discard\-granularity \fR\fB\fIbytes\fR\fR .RS 4 When \fBrs\-discard\-granularity\fR is set to a non zero, positive value then DRBD tries to do a resync operation in requests of this size\&. In case such a block contains only zero bytes on the sync source node, the sync target node will issue a discard/trim/unmap command for the area\&. .sp The value is constrained by the discard granularity of the backing block device\&. In case \fBrs\-discard\-granularity\fR is not a multiplier of the discard granularity of the backing block device DRBD rounds it up\&. The feature only gets active if the backing block device reads back zeroes after a discard command\&. .sp The default value of is 0\&. This option is available since 8\&.4\&.7\&. .RE .SS "connect, net\-options" .\" drbdsetup: net .PP Connect sets up the \fIdevice\fR to listen on \fIaf:local_addr:port\fR for incoming connections and to try to connect to \fIaf:remote_addr:port\fR\&. If \fIport\fR is omitted, 7788 is used as default\&. If \fIaf\fR is omitted \fBipv4\fR gets used\&. Other supported address families are \fBipv6\fR, \fBssocks\fR for Dolphin Interconnect Solutions\' "super sockets" and \fBsdp\fR for Sockets Direct Protocol (Infiniband)\&. .PP The net\-options command allows you to change options while the connection is established\&. .PP \fB\-\-protocol \fR\fB\fIprotocol\fR\fR .RS 4 On the TCP/IP link the specified \fIprotocol\fR is used\&. Valid protocol specifiers are A, B, and C\&. .sp Protocol A: write IO is reported as completed, if it has reached local disk and local TCP send buffer\&. .sp Protocol B: write IO is reported as completed, if it has reached local disk and remote buffer cache\&. .sp Protocol C: write IO is reported as completed, if it has reached both local and remote disk\&. .RE .PP \fB\-\-connect\-int \fR\fB\fItime\fR\fR .RS 4 In case it is not possible to connect to the remote DRBD device immediately, DRBD keeps on trying to connect\&. With this option you can set the time between two retries\&. The default value is 10\&. The unit is seconds\&. .RE .PP \fB\-\-ping\-int \fR\fB\fItime\fR\fR .RS 4 If the TCP/IP connection linking a DRBD device pair is idle for more than \fItime\fR seconds, DRBD will generate a keep\-alive packet to check if its partner is still alive\&. The default value is 10\&. The unit is seconds\&. .RE .PP \fB\-\-timeout \fR\fB\fIval\fR\fR .RS 4 If the partner node fails to send an expected response packet within \fIval\fR tenths of a second, the partner node is considered dead and therefore the TCP/IP connection is abandoned\&. The default value is 60 (= 6 seconds)\&. .RE .PP \fB\-\-sndbuf\-size \fR\fB\fIsize\fR\fR .RS 4 The socket send buffer is used to store packets sent to the secondary node, which are not yet acknowledged (from a network point of view) by the secondary node\&. When using protocol A, it might be necessary to increase the size of this data structure in order to increase asynchronicity between primary and secondary nodes\&. But keep in mind that more asynchronicity is synonymous with more data loss in the case of a primary node failure\&. Since 8\&.0\&.13 resp\&. 8\&.2\&.7 setting the \fIsize\fR value to 0 means that the kernel should autotune this\&. The default \fIsize\fR is 0, i\&.e\&. autotune\&. .RE .PP \fB\-\-rcvbuf\-size \fR\fB\fIsize\fR\fR .RS 4 Packets received from the network are stored in the socket receive buffer first\&. From there they are consumed by DRBD\&. Before 8\&.3\&.2 the receive buffer\'s size was always set to the size of the socket send buffer\&. Since 8\&.3\&.2 they can be tuned independently\&. A value of 0 means that the kernel should autotune this\&. The default \fIsize\fR is 0, i\&.e\&. autotune\&. .RE .PP \fB\-\-ko\-count \fR\fB\fIcount\fR\fR .RS 4 In case the secondary node fails to complete a single write request for \fIcount\fR times the \fItimeout\fR, it is expelled from the cluster, i\&.e\&. the primary node goes into StandAlone mode\&. To disable this feature, you should explicitly set it to 0; defaults may change between versions\&. .RE .PP \fB\-\-max\-epoch\-size \fR\fB\fIval\fR\fR .RS 4 With this option the maximal number of write requests between two barriers is limited\&. Typically set to the same as \fB\-\-max\-buffers\fR, or the allowed maximum\&. Values smaller than 10 can lead to degraded performance\&. The default value is 2048\&. .RE .PP \fB\-\-max\-buffers \fR\fB\fIval\fR\fR .RS 4 With this option the maximal number of buffer pages allocated by DRBD\'s receiver thread is limited\&. Typically set to the same as \fB\-\-max\-epoch\-size\fR\&. Small values could lead to degraded performance\&. The default value is 2048, the minimum 32\&. Increase this if you cannot saturate the IO backend of the receiving side during linear write or during resync while otherwise idle\&. .sp See also \fBdrbd.conf\fR(5) .RE .PP \fB\-\-unplug\-watermark \fR\fB\fIval\fR\fR .RS 4 This setting has no effect with recent kernels that use explicit on\-stack plugging (upstream Linux kernel 2\&.6\&.39, distributions may have backported)\&. .sp When the number of pending write requests on the standby (secondary) node exceeds the unplug\-watermark, we trigger the request processing of our backing storage device\&. Some storage controllers deliver better performance with small values, others deliver best performance when the value is set to the same value as max\-buffers, yet others don\'t feel much effect at all\&. Minimum 16, default 128, maximum 131072\&. .RE .PP \fB\-\-allow\-two\-primaries \fR .RS 4 With this option set you may assign primary role to both nodes\&. You only should use this option if you use a shared storage file system on top of DRBD\&. At the time of writing the only ones are: OCFS2 and GFS\&. If you use this option with any other file system, you are going to crash your nodes and to corrupt your data! .RE .PP \fB\-\-cram\-hmac\-alg \fR\fB\fIalg\fR\fR .RS 4 You need to specify the HMAC algorithm to enable peer authentication at all\&. You are strongly encouraged to use peer authentication\&. The HMAC algorithm will be used for the challenge response authentication of the peer\&. You may specify any digest algorithm that is named in /proc/crypto\&. .RE .PP \fB\-\-shared\-secret \fR\fB\fIsecret\fR\fR .RS 4 The shared secret used in peer authentication\&. May be up to 64 characters\&. .RE .PP \fB\-\-after\-sb\-0pri \fR\fB\fIasb\-0p\-policy\fR\fR .RS 4 possible policies are: .PP \fBdisconnect\fR .RS 4 No automatic resynchronization, simply disconnect\&. .RE .PP \fBdiscard\-younger\-primary\fR .RS 4 Auto sync from the node that was primary before the split\-brain situation occurred\&. .RE .PP \fBdiscard\-older\-primary\fR .RS 4 Auto sync from the node that became primary as second during the split\-brain situation\&. .RE .PP \fBdiscard\-zero\-changes\fR .RS 4 In case one node did not write anything since the split brain became evident, sync from the node that wrote something to the node that did not write anything\&. In case none wrote anything this policy uses a random decision to perform a "resync" of 0 blocks\&. In case both have written something this policy disconnects the nodes\&. .RE .PP \fBdiscard\-least\-changes\fR .RS 4 Auto sync from the node that touched more blocks during the split brain situation\&. .RE .PP \fBdiscard\-node\-NODENAME\fR .RS 4 Auto sync to the named node\&. .RE .RE .PP \fB\-\-after\-sb\-1pri \fR\fB\fIasb\-1p\-policy\fR\fR .RS 4 possible policies are: .PP \fBdisconnect\fR .RS 4 No automatic resynchronization, simply disconnect\&. .RE .PP \fBconsensus\fR .RS 4 Discard the version of the secondary if the outcome of the \fBafter\-sb\-0pri\fR algorithm would also destroy the current secondary\'s data\&. Otherwise disconnect\&. .RE .PP \fBdiscard\-secondary\fR .RS 4 Discard the secondary\'s version\&. .RE .PP \fBcall\-pri\-lost\-after\-sb\fR .RS 4 Always honor the outcome of the \fBafter\-sb\-0pri \fR algorithm\&. In case it decides the current secondary has the correct data, call the \fBpri\-lost\-after\-sb\fR on the current primary\&. .RE .PP \fBviolently\-as0p\fR .RS 4 Always honor the outcome of the \fBafter\-sb\-0pri \fR algorithm\&. In case it decides the current secondary has the correct data, accept a possible instantaneous change of the primary\'s data\&. .RE .RE .PP \fB\-\-after\-sb\-2pri \fR\fB\fIasb\-2p\-policy\fR\fR .RS 4 possible policies are: .PP \fBdisconnect\fR .RS 4 No automatic resynchronization, simply disconnect\&. .RE .PP \fBcall\-pri\-lost\-after\-sb\fR .RS 4 Always honor the outcome of the \fBafter\-sb\-0pri \fR algorithm\&. In case it decides the current secondary has the right data, call the \fBpri\-lost\-after\-sb\fR on the current primary\&. .RE .PP \fBviolently\-as0p\fR .RS 4 Always honor the outcome of the \fBafter\-sb\-0pri \fR algorithm\&. In case it decides the current secondary has the right data, accept a possible instantaneous change of the primary\'s data\&. .RE .RE .PP \fB\-\-always\-asbp\fR .RS 4 Normally the automatic after\-split\-brain policies are only used if current states of the UUIDs do not indicate the presence of a third node\&. .sp With this option you request that the automatic after\-split\-brain policies are used as long as the data sets of the nodes are somehow related\&. This might cause a full sync, if the UUIDs indicate the presence of a third node\&. (Or double faults have led to strange UUID sets\&.) .RE .PP \fB\-\-rr\-conflict \fR\fB\fIrole\-resync\-conflict\-policy\fR\fR .RS 4 This option sets DRBD\'s behavior when DRBD deduces from its meta data that a resynchronization is needed, and the SyncTarget node is already primary\&. The possible settings are: \fBdisconnect\fR, \fBcall\-pri\-lost\fR and \fBviolently\fR\&. While \fBdisconnect\fR speaks for itself, with the \fBcall\-pri\-lost\fR setting the \fBpri\-lost\fR handler is called which is expected to either change the role of the node to secondary, or remove the node from the cluster\&. The default is \fBdisconnect\fR\&. .sp With the \fBviolently\fR setting you allow DRBD to force a primary node into SyncTarget state\&. This means that the data exposed by DRBD changes to the SyncSource\'s version of the data instantaneously\&. USE THIS OPTION ONLY IF YOU KNOW WHAT YOU ARE DOING\&. .RE .PP \fB\-\-data\-integrity\-alg \fR\fB\fIhash_alg\fR\fR .RS 4 DRBD can ensure the data integrity of the user\'s data on the network by comparing hash values\&. Normally this is ensured by the 16 bit checksums in the headers of TCP/IP packets\&. This option can be set to any of the kernel\'s data digest algorithms\&. In a typical kernel configuration you should have at least one of \fBmd5\fR, \fBsha1\fR, and \fBcrc32c\fR available\&. By default this is not enabled\&. .sp See also the notes on data integrity on the drbd\&.conf manpage\&. .RE .PP \fB\-\-no\-tcp\-cork\fR .RS 4 DRBD usually uses the TCP socket option TCP_CORK to hint to the network stack when it can expect more data, and when it should flush out what it has in its send queue\&. There is at least one network stack that performs worse when one uses this hinting method\&. Therefore we introduced this option, which disable the setting and clearing of the TCP_CORK socket option by DRBD\&. .RE .PP \fB\-\-ping\-timeout \fR\fB\fIping_timeout\fR\fR .RS 4 The time the peer has to answer to a keep\-alive packet\&. In case the peer\'s reply is not received within this time period, it is considered dead\&. The default unit is tenths of a second, the default value is 5 (for half a second)\&. .RE .PP \fB\-\-discard\-my\-data\fR .RS 4 Use this option to manually recover from a split\-brain situation\&. In case you do not have any automatic after\-split\-brain policies selected, the nodes refuse to connect\&. By passing this option you make this node a sync target immediately after successful connect\&. .RE .PP \fB\-\-tentative\fR .RS 4 Causes DRBD to abort the connection process after the resync handshake, i\&.e\&. no resync gets performed\&. You can find out which resync DRBD would perform by looking at the kernel\'s log file\&. .RE .PP \fB\-\-on\-congestion \fR\fB\fIcongestion_policy\fR\fR, .br \fB\-\-congestion\-fill \fR\fB\fIfill_threshold\fR\fR, .br \fB\-\-congestion\-extents \fR\fB\fIactive_extents_threshold\fR\fR .RS 4 By default DRBD blocks when the available TCP send queue becomes full\&. That means it will slow down the application that generates the write requests that cause DRBD to send more data down that TCP connection\&. .sp When DRBD is deployed with DRBD\-proxy it might be more desirable that DRBD goes into AHEAD/BEHIND mode shortly before the send queue becomes full\&. In AHEAD/BEHIND mode DRBD does no longer replicate data, but still keeps the connection open\&. .sp The advantage of the AHEAD/BEHIND mode is that the application is not slowed down, even if DRBD\-proxy\'s buffer is not sufficient to buffer all write requests\&. The downside is that the peer node falls behind, and that a resync will be necessary to bring it back into sync\&. During that resync the peer node will have an inconsistent disk\&. .sp Available \fIcongestion_policy\fRs are \fBblock\fR and \fBpull\-ahead\fR\&. The default is \fBblock\fR\&. \fIFill_threshold\fR might be in the range of 0 to 10GiBytes\&. The default is 0 which disables the check\&. \fIActive_extents_threshold\fR has the same limits as \fBal\-extents\fR\&. .sp The AHEAD/BEHIND mode and its settings are available since DRBD 8\&.3\&.10\&. .RE .PP \fB\-\-verify\-alg \fR\fB\fIhash\-alg\fR\fR .RS 4 During online verification (as initiated by the \fBverify\fR sub\-command), rather than doing a bit\-wise comparison, DRBD applies a hash function to the contents of every block being verified, and compares that hash with the peer\&. This option defines the hash algorithm being used for that purpose\&. It can be set to any of the kernel\'s data digest algorithms\&. In a typical kernel configuration you should have at least one of \fBmd5\fR, \fBsha1\fR, and \fBcrc32c\fR available\&. By default this is not enabled; you must set this option explicitly in order to be able to use on\-line device verification\&. .sp See also the notes on data integrity on the drbd\&.conf manpage\&. .RE .PP \fB\-\-csums\-alg \fR\fB\fIhash\-alg\fR\fR .RS 4 A resync process sends all marked data blocks form the source to the destination node, as long as no \fBcsums\-alg\fR is given\&. When one is specified the resync process exchanges hash values of all marked blocks first, and sends only those data blocks over, that have different hash values\&. .sp This setting is useful for DRBD setups with low bandwidth links\&. During the restart of a crashed primary node, all blocks covered by the activity log are marked for resync\&. But a large part of those will actually be still in sync, therefore using \fBcsums\-alg\fR will lower the required bandwidth in exchange for CPU cycles\&. .RE .PP \fB\-\-use\-rle\fR .RS 4 During resync\-handshake, the dirty\-bitmaps of the nodes are exchanged and merged (using bit\-or), so the nodes will have the same understanding of which blocks are dirty\&. On large devices, the fine grained dirty\-bitmap can become large as well, and the bitmap exchange can take quite some time on low\-bandwidth links\&. .sp Because the bitmap typically contains compact areas where all bits are unset (clean) or set (dirty), a simple run\-length encoding scheme can considerably reduce the network traffic necessary for the bitmap exchange\&. .sp For backward compatibility reasons, and because on fast links this possibly does not improve transfer time but consumes cpu cycles, this defaults to off\&. .sp Introduced in 8\&.3\&.2\&. .RE .PP \fB\-\-socket\-check\-timeout\fR .RS 4 In setups involving a DRBD\-proxy and connections that experience a lot of buffer\-bloat it might be necessary to set \fBping\-timeout\fR to an unusual high value\&. By default DRBD uses the same value to wait if a newly established TCP\-connection is stable\&. Since the DRBD\-proxy is usually located in the same data center such a long wait time may hinder DRBD\'s connect process\&. .sp In such setups \fBsocket\-check\-timeout\fR should be set to at least to the round trip time between DRBD and DRBD\-proxy\&. I\&.e\&. in most cases to 1\&. .sp The default unit is tenths of a second, the default value is 0 (which causes DRBD to use the value of \fBping\-timeout\fR instead)\&. Introduced in 8\&.4\&.5\&. .RE .SS "resource\-options" .\" drbdsetup: resource-options .PP Changes the options of the resource at runtime\&. .PP \fB\-\-cpu\-mask \fR\fB\fIcpu\-mask\fR\fR .RS 4 Sets the cpu\-affinity\-mask for DRBD\'s kernel threads of this device\&. The default value of \fIcpu\-mask\fR is 0, which means that DRBD\'s kernel threads should be spread over all CPUs of the machine\&. This value must be given in hexadecimal notation\&. If it is too big it will be truncated\&. .RE .PP \fB\-\-on\-no\-data\-accessible \fR\fB\fIond\-policy\fR\fR .RS 4 This setting controls what happens to IO requests on a degraded, disk less node (I\&.e\&. no data store is reachable)\&. The available policies are \fBio\-error\fR and \fBsuspend\-io\fR\&. .sp If \fIond\-policy\fR is set to \fBsuspend\-io\fR you can either resume IO by attaching/connecting the last lost data storage, or by the \fBdrbdadm resume\-io \fR\fB\fIres\fR\fR command\&. The latter will result in IO errors of course\&. .sp The default is \fBio\-error\fR\&. This setting is available since DRBD 8\&.3\&.9\&. .RE .SS "primary" .\" drbdsetup: primary .PP Sets the \fIdevice\fR into primary role\&. This means that applications (e\&.g\&. a file system) may open the \fIdevice\fR for read and write access\&. Data written to the \fIdevice\fR in primary role are mirrored to the device in secondary role\&. .PP Normally it is not possible to set both devices of a connected DRBD device pair to primary role\&. By using the \fB\-\-allow\-two\-primaries\fR option, you override this behavior and instruct DRBD to allow two primaries\&. .PP \fB\-\-overwrite\-data\-of\-peer\fR .RS 4 Alias for \-\-force\&. .RE .PP \fB\-\-force\fR .RS 4 Becoming primary fails if the local replica is not up\-to\-date\&. I\&.e\&. when it is inconsistent, outdated of consistent\&. By using this option you can force it into primary role anyway\&. USE THIS OPTION ONLY IF YOU KNOW WHAT YOU ARE DOING\&. .RE .SS "secondary" .\" drbdsetup: secondary .PP Brings the \fIdevice\fR into secondary role\&. This operation fails as long as at least one application (or file system) has opened the device\&. .PP It is possible that both devices of a connected DRBD device pair are secondary\&. .SS "verify" .\" drbdsetup: verify .PP This initiates on\-line device verification\&. During on\-line verification, the contents of every block on the local node are compared to those on the peer node\&. Device verification progress can be monitored via /proc/drbd\&. Any blocks whose content differs from that of the corresponding block on the peer node will be marked out\-of\-sync in DRBD\'s on\-disk bitmap; they are \fInot\fR brought back in sync automatically\&. To do that, simply disconnect and reconnect the resource\&. .PP If on\-line verification is already in progress (and this node is "VerifyS"), this command silently "succeeds"\&. In this case, any start\-sector (see below) will be ignored, and any stop\-sector (see below) will be honored\&. This can be used to stop a running verify, or to update/shorten/extend the coverage of the currently running verify\&. .PP This command will fail if the \fIdevice\fR is not part of a connected device pair\&. .PP See also the notes on data integrity on the drbd\&.conf manpage\&. .PP \fB\-\-start \fR\fB\fIstart\-sector\fR\fR .RS 4 Since version 8\&.3\&.2, on\-line verification should resume from the last position after connection loss\&. It may also be started from an arbitrary position by setting this option\&. If you had reached some stop\-sector before, and you do not specify an explicit start\-sector, verify should resume from the previous stop\-sector\&. .sp Default unit is sectors\&. You may also specify a unit explicitly\&. The \fBstart\-sector\fR will be rounded down to a multiple of 8 sectors (4kB)\&. .RE .PP \fB\-S\fR, \fB\-\-stop \fR\fB\fIstop\-sector\fR\fR .RS 4 Since version 8\&.3\&.14, on\-line verification can be stopped before it reaches end\-of\-device\&. .sp Default unit is sectors\&. You may also specify a unit explicitly\&. The \fBstop\-sector\fR may be updated by issuing an additional drbdsetup verify command on the same node while the verify is running\&. This can be used to stop a running verify, or to update/shorten/extend the coverage of the currently running verify\&. .RE .SS "invalidate" .\" drbdsetup: invalidate .PP This forces the local device of a pair of connected DRBD devices into SyncTarget state, which means that all data blocks of the device are copied over from the peer\&. .PP This command will fail if the \fIdevice\fR is not either part of a connected device pair, or disconnected Secondary\&. .SS "invalidate\-remote" .\" drbdsetup: invalidate-remote .PP This forces the local device of a pair of connected DRBD devices into SyncSource state, which means that all data blocks of the device are copied to the peer\&. .PP On a disconnected Primary device, this will set all bits in the out of sync bitmap\&. As a side affect this suspends updates to the on disk activity log\&. Updates to the on disk activity log resume automatically when necessary\&. .SS "wait\-connect" .\" drbdsetup: wait-connect .PP Returns as soon as the \fIdevice\fR can communicate with its partner device\&. .PP \fB\-\-wfc\-timeout \fR\fB\fIwfc_timeout\fR\fR, .br \fB\-\-degr\-wfc\-timeout \fR\fB\fIdegr_wfc_timeout\fR\fR, .br \fB\-\-outdated\-wfc\-timeout \fR\fB\fIoutdated_wfc_timeout\fR\fR, .br \fB\-\-wait\-after\-sb\fR .RS 4 This command will fail if the \fIdevice\fR cannot communicate with its partner for \fItimeout\fR seconds\&. If the peer was working before this node was rebooted, the \fIwfc_timeout\fR is used\&. If the peer was already down before this node was rebooted, the \fIdegr_wfc_timeout\fR is used\&. If the peer was successfully outdated before this node was rebooted the \fIoutdated_wfc_timeout\fR is used\&. The default value for all those timeout values is 0 which means to wait forever\&. The unit is seconds\&. In case the connection status goes down to StandAlone because the peer appeared but the devices had a split brain situation, the default for the command is to terminate\&. You can change this behavior with the \fB\-\-wait\-after\-sb\fR option\&. .RE .SS "wait\-sync" .\" drbdsetup: wait-sync .PP Returns as soon as the \fIdevice\fR leaves any synchronization into connected state\&. The options are the same as with the \fIwait\-connect\fR command\&. .SS "disconnect" .\" drbdsetup: disconnect .PP Removes the information set by the \fBnet\fR command from the \fIdevice\fR\&. This means that the \fIdevice\fR goes into unconnected state and will no longer listen for incoming connections\&. .SS "detach" .\" drbdsetup: detach .PP Removes the information set by the \fBdisk\fR command from the \fIdevice\fR\&. This means that the \fIdevice\fR is detached from its backing storage device\&. .PP \fB\-f\fR, \fB\-\-force\fR .RS 4 A regular detach returns after the disk state finally reached diskless\&. As a consequence detaching from a frozen backing block device never terminates\&. .sp On the other hand A forced detach returns immediately\&. It allows you to detach DRBD from a frozen backing block device\&. Please note that the disk will be marked as failed until all pending IO requests where finished by the backing block device\&. .RE .SS "down" .\" drbdsetup: down .PP Removes all configuration information from the \fIdevice\fR and forces it back to unconfigured state\&. .SS "role" .\" drbdsetup: role .PP Shows the current roles of the \fIdevice\fR and its peer, as \fIlocal\fR/\fIpeer\fR\&. .SS "state" .\" drbdsetup: state .PP Deprecated alias for "role" .SS "cstate" .\" drbdsetup: cstate .PP Shows the current connection state of the \fIdevice\fR\&. .SS "dstate" .\" drbdsetup: dstate .PP Shows the current states of the backing storage devices, as \fIlocal\fR/\fIpeer\fR\&. .SS "resize" .\" drbdsetup: resize .PP This causes DRBD to reexamine the size of the \fIdevice\fR\'s backing storage device\&. To actually do online growing you need to extend the backing storages on both devices and call the \fBresize\fR command on one of your nodes\&. .PP The \fB\-\-size\fR option can be used to online shrink the usable size of a drbd device\&. It\'s the users responsibility to make sure that a file system on the device is not truncated by that operation\&. .PP The \fB\-\-assume\-peer\-has\-space\fR allows you to resize a device which is currently not connected to the peer\&. Use with care, since if you do not resize the peer\'s disk as well, further connect attempts of the two will fail\&. .PP When the \fB\-\-assume\-clean\fR option is given DRBD will skip the resync of the new storage\&. Only do this if you know that the new storage was initialized to the same content by other means\&. .PP The options \fB\-\-al\-stripes\fR and \fB\-\-al\-stripe\-size\-kB\fR may be used to change the layout of the activity log online\&. In case of internal meta data this may invovle shrinking the user visible size at the same time (unsing the \fB\-\-size\fR) or increasing the avalable space on the backing devices\&. .SS "check\-resize" .\" drbdsetup: check-resize .PP To enable DRBD to detect offline resizing of backing devices this command may be used to record the current size of backing devices\&. The size is stored in files in /var/lib/drbd/ named drbd\-minor\-??\&.lkbd .PP This command is called by \fBdrbdadm resize \fR\fB\fIres\fR\fR after \fBdrbdsetup \fR\fB\fIdevice\fR\fR\fB resize\fR returned\&. .SS "pause\-sync" .\" drbdsetup: pause-sync .PP Temporarily suspend an ongoing resynchronization by setting the local pause flag\&. Resync only progresses if neither the local nor the remote pause flag is set\&. It might be desirable to postpone DRBD\'s resynchronization after eventual resynchronization of the backing storage\'s RAID setup\&. .SS "resume\-sync" .\" drbdsetup: resume-sync .PP Unset the local sync pause flag\&. .SS "outdate" .\" drbdsetup: outdate .PP Mark the data on the local backing storage as outdated\&. An outdated device refuses to become primary\&. This is used in conjunction with \fBfencing\fR and by the peer\'s \fBfence\-peer\fR handler\&. .SS "show\-gi" .\" drbdsetup: show-gi .PP Displays the device\'s data generation identifiers verbosely\&. .SS "get\-gi" .\" drbdsetup: get-gi .PP Displays the device\'s data generation identifiers\&. .SS "show" .\" drbdsetup: show .PP Shows all available configuration information of a resource, or of all resources\&. Available options: .PP \fB\-\-show\-defaults\fR .RS 4 Show all configuration parameters, even the ones with default values\&. Normally, parameters with default values are not shown\&. .RE .SS "suspend\-io" .\" drbdsetup: suspend-io .PP This command is of no apparent use and just provided for the sake of completeness\&. .SS "resume\-io" .\" drbdsetup: resume-io .PP If the fence\-peer handler fails to stonith the peer node, and your \fBfencing\fR policy is set to resource\-and\-stonith, you can unfreeze IO operations with this command\&. .SS "status" .\" drbdsetup: status .PP Show the status of a resource, or of all resources\&. The output consists of one paragraph for each configured resource\&. Each paragraph contains one line for each resource, followed by one line for each device, and one line for each connection\&. The device and connection lines are indented\&. The connection lines are followed by one line for each peer device; these lines are indented against the connection line\&. .PP Long lines are wrapped around at terminal width, and indented to indicate how the lines belongs together\&. Available options: .PP \fB\-\-verbose\fR .RS 4 Include more information in the output even when it is likely redundant or irrelevant\&. .RE .PP \fB\-\-statistics\fR .RS 4 Include data transfer statistics in the output\&. .RE .PP \fB\-\-color=\fR\fB{always | auto | never}\fR\fB \fR .RS 4 Colorize the output\&. With \fB\-\-color=auto\fR, \fBdrbdsetup\fR emits color codes only when standard output is connected to a terminal\&. .RE .PP For example, the non\-verbose output for a resource with only one connection and only one volume could look like this: .sp .if n \{\ .RS 4 .\} .nf fs\-backoffice role:Primary disk:UpToDate peer role:Secondary replication:Established peer\-disk:UpToDate .fi .if n \{\ .RE .\} .PP With the \fB\-\-verbose\fR \fB\-\-statistics\fR options, the same resource could be reported as: .sp .if n \{\ .RS 4 .\} .nf fs\-data role:Primary suspended:no write\-ordering:drain volume:0 minor:1 disk:UpToDate size:10616472 read:134465 written:144800 al\-writes:18 bm\-writes:0 upper\-pending:0 lower\-pending:0 al\-suspended:no blocked:no peer connection:Connected role:Secondary congested:no volume:0 replication:Established peer\-disk:UpToDate resync\-suspended:no received:122596 sent:22204 out\-of\-sync:0 pending:0 unacked:0 .fi .if n \{\ .RE .\} .sp .SS "events2" .\" drbdsetup: events2 .PP Show the current state of all configured DRBD objects, followed by all changes to the state\&. .PP The output format is meant to be human as well as machine readable\&. Each line starts with the event number, which is followed by an asterisk if the event continues in the next line\&. The second word in each line indicates the kind of event: \fBexists\fR for an existing object; \fBcreate\fR, \fBdestroy\fR, and \fBchange\fR if an object is created, destroyed, or changed; or \fBcall\fR or \fBresponse\fR if an event handler is called or it returns\&. The third word indicates the object the event applies to: \fBresource\fR, \fBdevice\fR, \fBconnection\fR, \fBpeer\-device\fR, \fBhelper\fR, or a dash (\fB\-\fR) to indicate that the current state has been dumped completely\&. .PP The remaining words identify the object and describe the state that he object is in\&. Available options: .PP \fB\-\-now\fR .RS 4 Terminate after reporting the current state\&. The default is to continuously listen and report state changes\&. .RE .PP \fB\-\-statistics\fR .RS 4 Include statistics in the output\&. .RE .SS "events" .\" drbdsetup: events .PP Deprecated\&. If possible, change to the events2 subcommand instead\&. .PP Displays every state change of DRBD and all calls to helper programs\&. This might be used to get notified of DRBD\'s state changes by piping the output to another program\&. .PP \fB\-\-all\-devices\fR .RS 4 Display the events of all DRBD minors\&. .RE .PP \fB\-\-unfiltered\fR .RS 4 This is a debugging aid that displays the content of all received netlink messages\&. .RE .SS "new\-current\-uuid" .\" drbdsetup: new-current-uuid .PP Generates a new current UUID and rotates all other UUID values\&. This has at least two use cases, namely to skip the initial sync, and to reduce network bandwidth when starting in a single node configuration and then later (re\-)integrating a remote site\&. .PP Available option: .PP \fB\-\-clear\-bitmap\fR .RS 4 Clears the sync bitmap in addition to generating a new current UUID\&. .RE .PP This can be used to skip the initial sync, if you want to start from scratch\&. This use\-case does only work on "Just Created" meta data\&. Necessary steps: .sp .RS 4 .ie n \{\ \h'-04' 1.\h'+01'\c .\} .el \{\ .sp -1 .IP " 1." 4.2 .\} On \fIboth\fR nodes, initialize meta data and configure the device\&. .sp \fBdrbdadm \-\- \-\-force create\-md \fR\fB\fIres\fR\fR .RE .sp .RS 4 .ie n \{\ \h'-04' 2.\h'+01'\c .\} .el \{\ .sp -1 .IP " 2." 4.2 .\} They need to do the initial handshake, so they know their sizes\&. .sp \fBdrbdadm up \fR\fB\fIres\fR\fR .RE .sp .RS 4 .ie n \{\ \h'-04' 3.\h'+01'\c .\} .el \{\ .sp -1 .IP " 3." 4.2 .\} They are now Connected Secondary/Secondary Inconsistent/Inconsistent\&. Generate a new current\-uuid and clear the dirty bitmap\&. .sp \fBdrbdadm new\-current\-uuid \-\-clear\-bitmap \fR\fB\fIres\fR\fR .RE .sp .RS 4 .ie n \{\ \h'-04' 4.\h'+01'\c .\} .el \{\ .sp -1 .IP " 4." 4.2 .\} They are now Connected Secondary/Secondary UpToDate/UpToDate\&. Make one side primary and create a file system\&. .sp \fBdrbdadm primary \fR\fB\fIres\fR\fR .sp \fBmkfs \-t \fR\fB\fIfs\-type\fR\fR\fB $(drbdadm sh\-dev \fR\fB\fIres\fR\fR\fB)\fR .RE .PP One obvious side\-effect is that the replica is full of old garbage (unless you made them identical using other means), so any online\-verify is expected to find any number of out\-of\-sync blocks\&. .PP \fIYou must not use this on pre\-existing data!\fR Even though it may appear to work at first glance, once you switch to the other node, your data is toast, as it never got replicated\&. So \fIdo not leave out the mkfs\fR (or equivalent)\&. .PP This can also be used to shorten the initial resync of a cluster where the second node is added after the first node is gone into production, by means of disk shipping\&. This use\-case works on disconnected devices only, the device may be in primary or secondary role\&. .PP The necessary steps on the current active server are: .sp .RS 4 .ie n \{\ \h'-04' 1.\h'+01'\c .\} .el \{\ .sp -1 .IP " 1." 4.2 .\} \fBdrbdsetup new\-current\-uuid \-\-clear\-bitmap \fR\fB\fIminor\fR\fR\fB \fR .RE .sp .RS 4 .ie n \{\ \h'-04' 2.\h'+01'\c .\} .el \{\ .sp -1 .IP " 2." 4.2 .\} Take the copy of the current active server\&. E\&.g\&. by pulling a disk out of the RAID1 controller, or by copying with dd\&. You need to copy the actual data, and the meta data\&. .RE .sp .RS 4 .ie n \{\ \h'-04' 3.\h'+01'\c .\} .el \{\ .sp -1 .IP " 3." 4.2 .\} \fBdrbdsetup new\-current\-uuid \fR\fB\fIminor\fR\fR\fB \fR .RE .sp .RE Now add the disk to the new secondary node, and join it to the cluster\&. You will get a resync of that parts that were changed since the first call to \fBdrbdsetup\fR in step 1\&. .SH "EXAMPLES" .PP For examples, please have a look at the \m[blue]\fBDRBD User\'s Guide\fR\m[]\&\s-2\u[1]\d\s+2\&. .SH "VERSION" .sp This document was revised for version 8\&.3\&.2 of the DRBD distribution\&. .SH "AUTHOR" .sp Written by Philipp Reisner philipp\&.reisner@linbit\&.com and Lars Ellenberg lars\&.ellenberg@linbit\&.com .SH "REPORTING BUGS" .sp Report bugs to drbd\-user@lists\&.linbit\&.com\&. .SH "COPYRIGHT" .sp Copyright 2001\-2008 LINBIT Information Technologies, Philipp Reisner, Lars Ellenberg\&. This is free software; see the source for copying conditions\&. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE\&. .SH "SEE ALSO" .PP \fBdrbd.conf\fR(5), \fBdrbd\fR(8), \fBdrbddisk\fR(8), \fBdrbdadm\fR(8), \m[blue]\fBDRBD User\'s Guide\fR\m[]\&\s-2\u[1]\d\s+2, \m[blue]\fBDRBD web site\fR\m[]\&\s-2\u[2]\d\s+2 .SH "NOTES" .IP " 1." 4 DRBD User's Guide .RS 4 \%http://www.drbd.org/users-guide/ .RE .IP " 2." 4 DRBD web site .RS 4 \%http://www.drbd.org/ .RE drbd-utils-8.9.6/documentation/v84/drbdadm.xml0000644000175000017500000005472012466702073021133 0ustar apoikosapoikos 6 May 2011 DRBD 8.4.0 drbdadm 8 System Administration drbdadm Administration tool for DRBD drbdadm drbdadm -d -cfile -tfile -scmd -mcmd -S -hhost --backend-options command all resource/volume> Description is the high level tool of the DRBD program suite. is to and what / is to . reads its configuration file and performs the specified commands by calling the and/or the program. can operate on whole resources or on individual volumes in a resource. The sub commands: , , , , , , , , , , , , , , , , , , work on whole resources and on individual volumes. Resource level only commands are: , , , , and . Options , Just prints the calls of to stdout, but does not run the commands. , file Specifies the configuration file drbdadm will use. If this parameter is not specified, drbdadm will look for , , and . , file Specifies an additional configuration file drbdadm to check. This option is only allowed with the dump and the sh-nop commands. , file Specifies the full path to the program. If this option is omitted, drbdadm will look for it beneath itself first, and then in the PATH. , file Specifies the full path to the program. If this option is omitted, drbdadm will look for it beneath itself first, and then in the PATH. , Specifies that this command should be performed on a stacked resource. , Specifies to which peer node to connect. Only necessary if there are more than two host sections in the resource you are working on. backend-options All options following the doubly hyphen are considered backend-options. These are passed through to the backend command. I.e. to , or . Commands attach Attaches a local backing block device to the DRBD resource's device. detach drbdadm detach Removes the backing storage device from a DRBD resource's device. connect drbdadm connect Sets up the network configuration of the resource's device. If the peer device is already configured, the two DRBD devices will connect. If there are more than two host sections in the resource you need to use the option to select the peer you want to connect to. disconnect drbdadm disconnect Removes the network configuration from the resource. The device will then go into StandAlone state. syncer drbdadm syncer Loads the resynchronization parameters into the device. up drbdadm up Is a shortcut for attach and connect. down drbdadm down Is a shortcut for disconnect and detach. primary drbdadm primary Promote the resource's device into primary role. You need to do this before any access to the device, such as creating or mounting a file system. secondary drbdadm secondary Brings the device back into secondary role. This is needed since in a connected DRBD device pair, only one of the two peers may have primary role (except if is explicitly set in the configuration file). invalidate drbdadm invalidate Forces DRBD to consider the data on the local backing storage device as out-of-sync. Therefore DRBD will copy each and every block from its peer, to bring the local storage device back in sync. To avoid races, you need an established replication link, or be disconnected Secondary. invalidate-remote drbdadm invalidate-remote This command is similar to the invalidate command, however, the peer's backing storage is invalidated and hence rewritten with the data of the local node. To avoid races, you need an established replication link, or be disconnected Primary. resize drbdadm resize Causes DRBD to re-examine all sizing constraints, and resize the resource's device accordingly. For example, if you increased the size of your backing storage devices (on both nodes, of course), then DRBD will adopt the new size after you called this command on one of your nodes. Since new storage space must be synchronised this command only works if there is at least one primary node present. The option can be used to online shrink the usable size of a drbd device. It's the users responsibility to make sure that a file system on the device is not truncated by that operation. The allows you to resize a device which is currently not connected to the peer. Use with care, since if you do not resize the peer's disk as well, further connect attempts of the two will fail. The allows you to resize an existing device and avoid syncing the new space. This is useful when adding addtional blank storage to your device. Example: # drbdadm -- --assume-clean resize r0 The options and may be used to change the layout of the activity log online. In case of internal meta data this may invovle shrinking the user visible size at the same time (unsing the ) or increasing the avalable space on the backing devices. check-resize drbdadm check-resize Calls drbdmeta to eventually move internal meta data. If the backing device was resized, while DRBD was not running, meta data has to be moved to the end of the device, so that the next command can succeed. create-md drbdadm create-md Initializes the meta data storage. This needs to be done before a DRBD resource can be taken online for the first time. In case of issues with that command have a look at drbdmeta 8 get-gi drbdadm get-gi Shows a short textual representation of the data generation identifiers. show-gi drbdadm show-gi Prints a textual representation of the data generation identifiers including explanatory information. dump-md drbdadm dump-md Dumps the whole contents of the meta data storage, including the stored bit-map and activity-log, in a textual representation. outdate drbdadm outdate Sets the outdated flag in the meta data. adjust drbdadm adjust Synchronizes the configuration of the device with your configuration file. You should always examine the output of the dry-run mode before actually executing this command. wait-connect drbdadm wait-connect Waits until the device is connected to its peer device. role drbdadm role Shows the current roles of the devices (local/peer). E.g. Primary/Secondary state drbdadm state Deprecated alias for "role", see above. cstate drbdadm cstate Shows the current connection state of the devices. dump drbdadm dump Just parse the configuration file and dump it to stdout. May be used to check the configuration file for syntactic correctness. outdate drbdadm outdate Used to mark the node's data as outdated. Usually used by the peer's fence-peer handler. verify drbdadm verify Starts online verify. During online verify, data on both nodes is compared for equality. See /proc/drbd for online verify progress. If out-of-sync blocks are found, they are not resynchronized automatically. To do that, disconnect and connect the resource when verification has completed. See also the notes on data integrity on the drbd.conf manpage. pause-sync drbdadm pause-sync Temporarily suspend an ongoing resynchronization by setting the local pause flag. Resync only progresses if neither the local nor the remote pause flag is set. It might be desirable to postpone DRBD's resynchronization until after any resynchronization of the backing storage's RAID setup. resume-sync drbdadm resume-sync Unset the local sync pause flag. new-current-uuid drbdadm new-current-uuid Generates a new currend UUID and rotates all other UUID values. This can be used to shorten the initial resync of a cluster. See the manpage for a more details. dstate drbdadm dstate Show the current state of the backing storage devices. (local/peer) hidden-commands Shows all commands undocumented on purpose. Version This document was revised for version 8.4.0 of the DRBD distribution. Author Written by Philipp Reisner philipp.reisner@linbit.com and Lars Ellenberg lars.ellenberg@linbit.com Reporting Bugs Report bugs to drbd-user@lists.linbit.com. Copyright Copyright 2001-2011 LINBIT Information Technologies, Philipp Reisner, Lars Ellenberg. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See Also drbd.conf 5 , drbd 8 , drbddisk 8 , drbdsetup 8 , drbdmeta 8 and the DRBD project web site drbd-utils-8.9.6/documentation/v84/drbdmeta.xml0000644000175000017500000002416312466702073021316 0ustar apoikosapoikos 15 Oct 2008 DRBD 8.3.2 drbdmeta 8 System Administration drbdmeta DRBD's meta data management tool drbdmeta drbdmeta --force --ignore-sanity-checks device v06 minor v07 meta_dev index v08 meta_dev index command cmd args Description Drbdmeta is used to create, display and modify the contents of DRBD's meta data storage. Usually you do not want to use this command directly, but start it via the frontend drbdadm8. This command only works if the DRBD resource is currently down, or at least detached from its backing storage. The first parameter is the device node associated to the resource. With the second parameter you can select the version of the meta data. Currently all major DRBD releases (0.6, 0.7 and 8) are supported. Options --force drbdmeta--force All questions that get asked by drbdmeta are treated as if the user answered 'yes'. --ignore-sanity-checks drbdmeta--ignore-sanity-checks Some sanity checks cause drbdmeta to terminate. E.g. if a file system image would get destroyed by creating the meta data. By using that option you can force drbdmeta to ignore these checks. Commands create-md drbdmetacreate-md Create-md initializes the meta data storage. This needs to be done before a DRBD resource can be taken online for the first time. In case there is already a meta data signature of an older format in place, drbdmeta will ask you if it should convert the older format to the selected format. If you will use the resource before it is connected to its peer for the first time DRBD may perform better if you use the option. For DRBD versions of the peer use up to these values: <8.3.7 -> 4k, 8.3.8 -> 32k, 8.3.9 -> 128k, 8.4.0 -> 1M. If you want to use more than 6433 activity log extents, or live on top of a spriped RAID, you may specify the number of stripes (, default 1), and the stripe size (, default 32). To just use a larger linear on-disk ring-buffer, leave the number of stripes at 1, and increase the size only: drbdmeta 0 v08 /dev/vg23/lv42 internal create-md --al-stripe-size 1M To avoid a single "spindle" from becoming a bottleneck, increase the number of stripes, to achieve an interleaved layout of the on-disk activity-log transactions. What you give as "stripe-size" should be what is a.k.a. "chunk size" or "granularity" or "strip unit": the minimum skip to the next "spindle". drbdmeta 0 v08 /dev/vg23/lv42 internal create-md --al-stripes 7 --al-stripe-size 64k get-gi drbdmetaget-gi Get-gi shows a short textual representation of the data generation identifier. In version 0.6 and 0.7 these are generation counters, while in version 8 it is a set of UUIDs. show-gi drbdmetashow-gi Show-gi prints a textual representation of the data generation identifiers including explanatory information. dump-md drbdmetadump-md Dumps the whole contents of the meta data storage including the stored bit-map and activity-log in a textual representation. outdate drbdmetaoutdate Sets the outdated flag in the meta data. This is used by the peer node when it wants to become primary, but cannot communicate with the DRBD stack on this host. dstate drbdmetadstate Prints the state of the data on the backing storage. The output is always followed by '/DUnknown' since drbdmeta only looks at the local meta data. check-resize drbdmetacheck-resize Examines the device size of a backing device, and it's last known device size, recorded in a file /var/lib/drbd/drbd-minor-??.lkbd. In case the size of the backing device changed, and the meta data can be found at the old position, it moves the meta data to the right position at the end of the block device. Expert's commands Drbdmeta allows you to modify the meta data as well. This is intentionally omitted for the command's usage output, since you should only use it if you really know what you are doing. By setting the generation identifiers to wrong values, you risk to overwrite your up-to-data data with an older version of your data. set-gi gi drbdmetaset-gi Set-gi allows you to set the generation identifier. Gi needs to be a generation counter for the 0.6 and 0.7 format, and a UUID set for 8.x. Specify it in the same way as get-gi shows it. restore-md dump_file drbdmetarestore-md Reads the dump_file and writes it to the meta data. Version This document was revised for version 8.3.2 of the DRBD distribution. Author Written by Philipp Reisner philipp.reisner@linbit.com and Lars Ellenberg lars.ellenberg@linbit.com. Reporting Bugs Report bugs to drbd-user@lists.linbit.com. Copyright Copyright 2001-2008 LINBIT Information Technologies, Philipp Reisner, Lars Ellenberg. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See Also drbdadm 8 drbd-utils-8.9.6/documentation/v84/Makefile.in0000644000175000017500000001254212634271674021062 0ustar apoikosapoikos# Makefile in documentation directory # # This file is part of DRBD by Philipp Reisner and Lars Ellenberg. # # drbd is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # drbd is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with drbd; see the file COPYING. If not, write to # the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. # variables set by configure DISTRO = @DISTRO@ prefix = @prefix@ exec_prefix = @exec_prefix@ localstatedir = @localstatedir@ datarootdir = @datarootdir@ datadir = @datadir@ sbindir = @sbindir@ sysconfdir = @sysconfdir@ mandir = @mandir@ BASH_COMPLETION_SUFFIX = @BASH_COMPLETION_SUFFIX@ UDEV_RULE_SUFFIX = @UDEV_RULE_SUFFIX@ INITDIR = @INITDIR@ LIBDIR = @prefix@/lib/@PACKAGE_TARNAME@ CC = @CC@ CFLAGS = @CFLAGS@ XSLTPROC = @XSLTPROC@ # features enabled or disabled by configure WITH_83_SUPPORT = @WITH_83_SUPPORT@ WITH_84_SUPPORT = @WITH_84_SUPPORT@ WITH_UDEV = @WITH_UDEV@ WITH_XEN = @WITH_XEN@ WITH_PACEMAKER = @WITH_PACEMAKER@ WITH_HEARTBEAT = @WITH_HEARTBEAT@ WITH_RGMANAGER = @WITH_RGMANAGER@ WITH_BASHCOMPLETION = @WITH_BASHCOMPLETION@ # variables meant to be overridden from the make command line DESTDIR ?= / # Needed for pattern substitution SHELL=/bin/bash MANPAGES := drbdsetup.8 drbd.conf.5 drbd.8 drbdadm.8 drbdmeta.8 ifeq ($(WITH_HEARTBEAT),yes) MANPAGES += drbddisk.8 endif STYLESHEET_PREFIX ?= http://docbook.sourceforge.net/release/xsl/current MANPAGES_STYLESHEET ?= $(STYLESHEET_PREFIX)/manpages/docbook.xsl HTML_STYLESHEET ?= $(STYLESHEET_PREFIX)/xhtml/docbook.xsl FO_STYLESHEET ?= $(STYLESHEET_PREFIX)/fo/docbook.xsl XSLTPROC_OPTIONS ?= --xinclude XSLTPROC_OPTIONS += --stringparam variablelist.term.break.after 1 #XSLTPROC_OPTIONS += --stringparam variablelist.term.separator "" XSLTPROC_MANPAGES_OPTIONS ?= $(XSLTPROC_OPTIONS) XSLTPROC_HTML_OPTIONS ?= $(XSLTPROC_OPTIONS) XSLTPROC_FO_OPTIONS ?= $(XSLTPROC_OPTIONS) DRBDSETUP_CMDS = new-resource new-minor del-resource del-minor DRBDSETUP_CMDS += attach connect disk-options net-options resource-options DRBDSETUP_CMDS += disconnect detach primary secondary verify invalidate invalidate-remote DRBDSETUP_CMDS += down wait-connect wait-sync role cstate dstate DRBDSETUP_CMDS += resize check-resize pause-sync resume-sync DRBDSETUP_CMDS += outdate show-gi get-gi show events events2 DRBDSETUP_CMDS += status suspend-io resume-io new-current-uuid make_doc := $(shell $(XSLTPROC) \ $(XSLTPROC_MANPAGES_OPTIONS) \ $(MANPAGES_STYLESHEET) < /dev/null > /dev/null 2>&1 && echo doc ) ifeq ($(make_doc),doc) all: doc else all: @echo "To (re)make the documentation: make doc" endif clean: @echo "To clean the documentation: make doc-clean" .PHONY: all clean doc man doc-clean distclean .PHONY: install uninstall html pdf ps ifeq ($(WITH_84_SUPPORT),yes) doc: man else doc: endif doc-clean: distclean ####### Implicit rules .SUFFIXES: .sgml .5 .8 .html .pdf .ps %.5 %.8: %.xml $(XSLTPROC) \ $(XSLTPROC_MANPAGES_OPTIONS) \ $(MANPAGES_STYLESHEET) $< %.html: %.xml $(XSLTPROC) -o $@ \ $(XSLTPROC_HTML_OPTIONS) \ $(HTML_STYLESHEET) $< %.fo: %.xml $(XSLTPROC) -o $@ \ $(XSLTPROC_FO_OPTIONS) \ $(FO_STYLESHEET) $< ../../user/v84/drbdsetup.o: FORCE $(MAKE) -C $(@D) drbdsetup-84 .PHONY: FORCE FORCE: # Don't try to re-make files tracked in git FILES_IN_GIT := # $(shell git ls-files) FILES_IN_GIT += Makefile.in drbd.conf.xml drbd.xml drbdadm.xml drbddisk.xml FILES_IN_GIT += drbdmeta.xml drbdsetup.xml xml-usage-to-docbook.xsl $(FILES_IN_GIT): ; drbdsetup_X.xml := $(patsubst %,drbdsetup_%.xml,$(DRBDSETUP_CMDS)) drbdsetup_xml-help_X.xml := $(patsubst %,drbdsetup_xml-help_%.xml,$(DRBDSETUP_CMDS)) $(drbdsetup_xml-help_X.xml): ../../user/v84/drbdsetup.o $(drbdsetup_X.xml): xml-usage-to-docbook.xsl drbdsetup_xml-help_%.xml: ../../user/v84/drbdsetup-84 xml-help $* > $@ drbdsetup_%.xml: drbdsetup_xml-help_%.xml $(XSLTPROC) -o $@ xml-usage-to-docbook.xsl $< distclean: ifeq ($(make_doc),doc) rm -f *.[58] manpage.links manpage.refs *~ manpage.log endif rm -f *.ps.gz *.pdf *.ps *.html pod2htm* rm -f drbdsetup_*.xml ####### man: $(MANPAGES) install: ifeq ($(WITH_84_SUPPORT),yes) @ok=true; for f in $(MANPAGES) ; \ do [ -e $$f ] || { echo $$f missing ; ok=false; } ; \ done ; $$ok set -e; for f in $(MANPAGES) ; do \ s=$${f##*.}; \ b=$${f%.[0-9]}; \ install -v -D -m 644 $$f $(DESTDIR)$(mandir)/man$$s/$$b-8.4.$$s ; \ done endif uninstall: ifeq ($(WITH_84_SUPPORT),yes) @ set -e; for f in $(MANPAGES) ; do \ s=$${f##*.}; \ b=$${f%.[0-9]}; \ rm -vf $(DESTDIR)$(mandir)/man$$s/$$b-8.4.$$s ; \ done endif html: $(MANPAGES:.8=.html) pdf: $(MANPAGES:.8=.pdf) ps: $(MANPAGES:.8=.ps) drbdsetup.8: drbdsetup.xml $(drbdsetup_X.xml) .PHONY: install uninstall clean distclean ../../configure: @echo "please (re-)run ./autogen.sh with appropriate arguments"; exit 1 ../../config.status: ../../configure @echo "please (re-)run ./configure with appropriate arguments"; exit 1 Makefile: Makefile.in ../../config.status cd ../.. && ./config.status documentation/v84/Makefile drbd-utils-8.9.6/documentation/v84/drbd.xml0000644000175000017500000000670212466702073020446 0ustar apoikosapoikos drbd The start and stop script for DRBD DRBD 8.3.2 15 Oct 2008 drbd 8 System Administration /etc/init.d/drbd resource start stop status reload restart force-reload Introduction The script is used to start and stop drbd on a system V style init system. In order to use you must define a resource, a host, and any other configuration options in the drbd configuration file. See for details. If resource is omitted, then all of the resources listed in the config file are configured. This script might ask you Do you want to abort waiting for other server and make this one primary? Only answer this question with yes if you are sure that it is impossible to repair the other node. Version This document was revised for version 8.3.2 of the DRBD distribution. Author Written by Philipp Reisner philipp.reisner@linbit.com and Lars Ellenberg lars.ellenberg@linbit.com. Reporting Bugs Report bugs to drbd-user@lists.linbit.com. Copyright Copyright 2001-2008 LINBIT Information Technologies, Philipp Reisner, Lars Ellenberg. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See Also drbd.conf5, drbddisk8, drbdsetup8drbdadm8DRBD Homepage drbd-utils-8.9.6/documentation/v84/drbddisk.80000644000175000017500000000432112654452473020670 0ustar apoikosapoikos'\" t .\" Title: drbddisk .\" Author: [see the "Author" section] .\" Generator: DocBook XSL Stylesheets v1.75.2 .\" Date: 15 Oct 2008 .\" Manual: System Administration .\" Source: DRBD 8.3.2 .\" Language: English .\" .TH "DRBDDISK" "8" "15 Oct 2008" "DRBD 8.3.2" "System Administration" .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" drbddisk \- Script to mark devices as primary and mount file systems .SH "SYNOPSIS" .HP \w'\fB/etc/ha\&.d/resource\&.d/drbddisk\fR\ 'u \fB/etc/ha\&.d/resource\&.d/drbddisk\fR [\fIresource\fR] {{start}\ |\ {stop}\ |\ {status}} .SH "INTRODUCTION" .PP The \fB/etc/ha\&.d/resource\&.d/drbddisk\fR script brings the local device of \fIresource\fR into primary role\&. It is designed to be used by Heartbeat\&. .PP In order to use \fB/etc/ha\&.d/resource\&.d/drbddisk\fR you must define a resource, a host, and any other configuration options in the DRBD configuration file\&. See \fB/etc/drbd\&.conf\fR for details\&. If \fIresource\fR is omitted, then all of the resources listed in the config file are affected\&. .SH "VERSION" .sp This document was revised for version 8\&.0\&.14 of the DRBD distribution\&. .SH "AUTHOR" .sp Written by Philipp Reisner philipp\&.reisner@linbit\&.com and Lars Ellenberg lars\&.ellenberg@linbit\&.com\&. .SH "REPORTING BUGS" .sp Report bugs to drbd\-user@lists\&.linbit\&.com\&. .SH "COPYRIGHT" .sp Copyright 2001\-2008 LINBIT Information Technologies, Philipp Reisner, Lars Ellenberg\&. This is free software; see the source for copying conditions\&. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE\&. .SH "SEE ALSO" .PP \fBdrbd.conf\fR(5), \fBdrbd\fR(8), \fBdrbdsetup\fR(8)\fBdrbdadm\fR(8)\m[blue]\fBDRBD Homepage\fR\m[]\&\s-2\u[1]\d\s+2 .SH "NOTES" .IP " 1." 4 DRBD Homepage .RS 4 \%http://www.drbd.org/ .RE drbd-utils-8.9.6/documentation/v84/drbdadm.80000644000175000017500000002603212654452472020501 0ustar apoikosapoikos'\" t .\" Title: drbdadm .\" Author: [see the "Author" section] .\" Generator: DocBook XSL Stylesheets v1.75.2 .\" Date: 6 May 2011 .\" Manual: System Administration .\" Source: DRBD 8.4.0 .\" Language: English .\" .TH "DRBDADM" "8" "6 May 2011" "DRBD 8.4.0" "System Administration" .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" drbdadm \- Administration tool for DRBD .\" drbdadm .SH "SYNOPSIS" .HP \w'\fBdrbdadm\fR\ 'u \fBdrbdadm\fR [\-d] [\-c\ {\fIfile\fR}] [\-t\ {\fIfile\fR}] [\-s\ {\fIcmd\fR}] [\-m\ {\fIcmd\fR}] [\-S] [\-h\ {\fIhost\fR}] [\-\-\ {\fIbackend\-options\fR}] {\fIcommand\fR} [{all} | {\fIresource\fR\fI[/volume>]\fR...}] .SH "DESCRIPTION" .PP \fBDrbdadm\fR is the high level tool of the DRBD program suite\&. \fBDrbdadm\fR is to \fBdrbdsetup\fR and \fBdrbdmeta\fR what \fBifup\fR/\fBifdown\fR is to \fBifconfig\fR\&. \fBDrbdadm\fR reads its configuration file and performs the specified commands by calling the \fBdrbdsetup\fR and/or the \fBdrbdmeta\fR program\&. .PP \fBDrbdadm\fR can operate on whole resources or on individual volumes in a resource\&. The sub commands: \fBattach\fR, \fBdetach\fR, \fBprimary\fR, \fBsecondary\fR, \fBinvalidate\fR, \fBinvalidate\-remote\fR, \fBoutdate\fR, \fBresize\fR, \fBverify\fR, \fBpause\-sync\fR, \fBresume\-sync\fR, \fBrole\fR, \fBcsytate\fR, \fBdstate\fR, \fBcreate\-md\fR, \fBshow\-gi\fR, \fBget\-gi\fR, \fBdump\-md\fR, \fBwipe\-md\fR work on whole resources and on individual volumes\&. .PP Resource level only commands are: \fBconnect\fR, \fBdisconnect\fR, \fBup\fR, \fBdown\fR, \fBwait\-connect\fR and \fBdump\fR\&. .SH "OPTIONS" .PP \fB\-d\fR, \fB\-\-dry\-run\fR .RS 4 Just prints the calls of \fBdrbdsetup\fR to stdout, but does not run the commands\&. .RE .PP \fB\-c\fR, \fB\-\-config\-file\fR \fIfile\fR .RS 4 Specifies the configuration file drbdadm will use\&. If this parameter is not specified, drbdadm will look for \fB/etc/drbd\-84\&.conf\fR, \fB/etc/drbd\-83\&.conf\fR, \fB/etc/drbd\-08\&.conf\fR and \fB/etc/drbd\&.conf\fR\&. .RE .PP \fB\-t\fR, \fB\-\-config\-to\-test\fR \fIfile\fR .RS 4 Specifies an additional configuration file drbdadm to check\&. This option is only allowed with the dump and the sh\-nop commands\&. .RE .PP \fB\-s\fR, \fB\-\-drbdsetup\fR \fIfile\fR .RS 4 Specifies the full path to the \fBdrbdsetup\fR program\&. If this option is omitted, drbdadm will look for it beneath itself first, and then in the PATH\&. .RE .PP \fB\-m\fR, \fB\-\-drbdmeta\fR \fIfile\fR .RS 4 Specifies the full path to the \fBdrbdmeta\fR program\&. If this option is omitted, drbdadm will look for it beneath itself first, and then in the PATH\&. .RE .PP \fB\-S\fR, \fB\-\-stacked\fR .RS 4 Specifies that this command should be performed on a stacked resource\&. .RE .PP \fB\-P\fR, \fB\-\-peer\fR .RS 4 Specifies to which peer node to connect\&. Only necessary if there are more than two host sections in the resource you are working on\&. .RE .PP \fB\-\-\fR \fIbackend\-options\fR .RS 4 All options following the doubly hyphen are considered \fIbackend\-options\fR\&. These are passed through to the backend command\&. I\&.e\&. to \fBdrbdsetup\fR, \fBdrbdmeta\fR or \fBdrbd\-proxy\-ctl\fR\&. .RE .SH "COMMANDS" .PP attach .RS 4 Attaches a local backing block device to the DRBD resource\'s device\&. .RE .PP detach .RS 4 .\" drbdadm: detach Removes the backing storage device from a DRBD resource\'s device\&. .RE .PP connect .RS 4 .\" drbdadm: connect Sets up the network configuration of the resource\'s device\&. If the peer device is already configured, the two DRBD devices will connect\&. If there are more than two host sections in the resource you need to use the \fB\-\-peer\fR option to select the peer you want to connect to\&. .RE .PP disconnect .RS 4 .\" drbdadm: disconnect Removes the network configuration from the resource\&. The device will then go into StandAlone state\&. .RE .PP syncer .RS 4 .\" drbdadm: syncer Loads the resynchronization parameters into the device\&. .RE .PP up .RS 4 .\" drbdadm: up Is a shortcut for attach and connect\&. .RE .PP down .RS 4 .\" drbdadm: down Is a shortcut for disconnect and detach\&. .RE .PP primary .RS 4 .\" drbdadm: primary Promote the resource\'s device into primary role\&. You need to do this before any access to the device, such as creating or mounting a file system\&. .RE .PP secondary .RS 4 .\" drbdadm: secondary Brings the device back into secondary role\&. This is needed since in a connected DRBD device pair, only one of the two peers may have primary role (except if \fBallow\-two\-primaries\fR is explicitly set in the configuration file)\&. .RE .PP invalidate .RS 4 .\" drbdadm: invalidate Forces DRBD to consider the data on the \fIlocal\fR backing storage device as out\-of\-sync\&. Therefore DRBD will copy each and every block from its peer, to bring the local storage device back in sync\&. To avoid races, you need an established replication link, or be disconnected Secondary\&. .RE .PP invalidate\-remote .RS 4 .\" drbdadm: invalidate-remote This command is similar to the invalidate command, however, the \fIpeer\'s\fR backing storage is invalidated and hence rewritten with the data of the local node\&. To avoid races, you need an established replication link, or be disconnected Primary\&. .RE .PP resize .RS 4 .\" drbdadm: resize Causes DRBD to re\-examine all sizing constraints, and resize the resource\'s device accordingly\&. For example, if you increased the size of your backing storage devices (on both nodes, of course), then DRBD will adopt the new size after you called this command on one of your nodes\&. Since new storage space must be synchronised this command only works if there is at least one primary node present\&. .sp The \fB\-\-size\fR option can be used to online shrink the usable size of a drbd device\&. It\'s the users responsibility to make sure that a file system on the device is not truncated by that operation\&. .sp The \fB\-\-assume\-peer\-has\-space\fR allows you to resize a device which is currently not connected to the peer\&. Use with care, since if you do not resize the peer\'s disk as well, further connect attempts of the two will fail\&. .sp The \fB\-\-assume\-clean\fR allows you to resize an existing device and avoid syncing the new space\&. This is useful when adding addtional blank storage to your device\&. Example: .sp .if n \{\ .RS 4 .\} .nf # drbdadm \-\- \-\-assume\-clean resize r0 .fi .if n \{\ .RE .\} .sp The options \fB\-\-al\-stripes\fR and \fB\-\-al\-stripe\-size\-kB\fR may be used to change the layout of the activity log online\&. In case of internal meta data this may invovle shrinking the user visible size at the same time (unsing the \fB\-\-size\fR) or increasing the avalable space on the backing devices\&. .RE .PP check\-resize .RS 4 .\" drbdadm: check-resize Calls drbdmeta to eventually move internal meta data\&. If the backing device was resized, while DRBD was not running, meta data has to be moved to the end of the device, so that the next \fBattach\fR command can succeed\&. .RE .PP create\-md .RS 4 .\" drbdadm: create-md Initializes the meta data storage\&. This needs to be done before a DRBD resource can be taken online for the first time\&. In case of issues with that command have a look at \fBdrbdmeta\fR(8) .RE .PP get\-gi .RS 4 .\" drbdadm: get-gi Shows a short textual representation of the data generation identifiers\&. .RE .PP show\-gi .RS 4 .\" drbdadm: show-gi Prints a textual representation of the data generation identifiers including explanatory information\&. .RE .PP dump\-md .RS 4 .\" drbdadm: dump-md Dumps the whole contents of the meta data storage, including the stored bit\-map and activity\-log, in a textual representation\&. .RE .PP outdate .RS 4 .\" drbdadm: outdate Sets the outdated flag in the meta data\&. .RE .PP adjust .RS 4 .\" drbdadm: adjust Synchronizes the configuration of the device with your configuration file\&. You should always examine the output of the dry\-run mode before actually executing this command\&. .RE .PP wait\-connect .RS 4 .\" drbdadm: wait-connect Waits until the device is connected to its peer device\&. .RE .PP role .RS 4 .\" drbdadm: role Shows the current roles of the devices (local/peer)\&. E\&.g\&. Primary/Secondary .RE .PP state .RS 4 .\" drbdadm: state Deprecated alias for "role", see above\&. .RE .PP cstate .RS 4 .\" drbdadm: cstate Shows the current connection state of the devices\&. .RE .PP dump .RS 4 .\" drbdadm: dump Just parse the configuration file and dump it to stdout\&. May be used to check the configuration file for syntactic correctness\&. .RE .PP outdate .RS 4 .\" drbdadm: outdate Used to mark the node\'s data as outdated\&. Usually used by the peer\'s fence\-peer handler\&. .RE .PP verify .RS 4 .\" drbdadm: verify Starts online verify\&. During online verify, data on both nodes is compared for equality\&. See /proc/drbd for online verify progress\&. If out\-of\-sync blocks are found, they are \fInot\fR resynchronized automatically\&. To do that, \fBdisconnect\fR and \fBconnect\fR the resource when verification has completed\&. .sp See also the notes on data integrity on the drbd\&.conf manpage\&. .RE .PP pause\-sync .RS 4 .\" drbdadm: pause-sync Temporarily suspend an ongoing resynchronization by setting the local pause flag\&. Resync only progresses if neither the local nor the remote pause flag is set\&. It might be desirable to postpone DRBD\'s resynchronization until after any resynchronization of the backing storage\'s RAID setup\&. .RE .PP resume\-sync .RS 4 .\" drbdadm: resume-sync Unset the local sync pause flag\&. .RE .PP new\-current\-uuid .RS 4 .\" drbdadm: new-current-uuid Generates a new currend UUID and rotates all other UUID values\&. .sp This can be used to shorten the initial resync of a cluster\&. See the \fBdrbdsetup\fR manpage for a more details\&. .RE .PP dstate .RS 4 .\" drbdadm: dstate Show the current state of the backing storage devices\&. (local/peer) .RE .PP hidden\-commands .RS 4 Shows all commands undocumented on purpose\&. .RE .SH "VERSION" .sp This document was revised for version 8\&.4\&.0 of the DRBD distribution\&. .SH "AUTHOR" .sp Written by Philipp Reisner philipp\&.reisner@linbit\&.com and Lars Ellenberg lars\&.ellenberg@linbit\&.com .SH "REPORTING BUGS" .sp Report bugs to drbd\-user@lists\&.linbit\&.com\&. .SH "COPYRIGHT" .sp Copyright 2001\-2011 LINBIT Information Technologies, Philipp Reisner, Lars Ellenberg\&. This is free software; see the source for copying conditions\&. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE\&. .SH "SEE ALSO" .PP \fBdrbd.conf\fR(5), \fBdrbd\fR(8), \fBdrbddisk\fR(8), \fBdrbdsetup\fR(8), \fBdrbdmeta\fR(8) and the \m[blue]\fBDRBD project web site\fR\m[]\&\s-2\u[1]\d\s+2 .SH "NOTES" .IP " 1." 4 DRBD project web site .RS 4 \%http://www.drbd.org/ .RE drbd-utils-8.9.6/documentation/v84/drbd.conf.50000644000175000017500000015431512654452471020745 0ustar apoikosapoikos'\" t .\" Title: drbd.conf .\" Author: [see the "Author" section] .\" Generator: DocBook XSL Stylesheets v1.75.2 .\" Date: 6 May 2011 .\" Manual: Configuration Files .\" Source: DRBD 8.4.0 .\" Language: English .\" .TH "DRBD\&.CONF" "5" "6 May 2011" "DRBD 8.4.0" "Configuration Files" .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" drbd.conf \- Configuration file for DRBD\'s devices .\" drbd.conf .SH "INTRODUCTION" .PP The file \fB/etc/drbd\&.conf\fR is read by \fBdrbdadm\fR\&. .PP The file format was designed as to allow to have a verbatim copy of the file on both nodes of the cluster\&. It is highly recommended to do so in order to keep your configuration manageable\&. The file \fB/etc/drbd\&.conf\fR should be the same on both nodes of the cluster\&. Changes to \fB/etc/drbd\&.conf\fR do not apply immediately\&. .PP By convention the main config contains two include statements\&. The first one includes the file \fB/etc/drbd\&.d/global_common\&.conf\fR, the second one all file with a \fB\&.res\fR suffix\&. .PP .PP \fBExample\ \&1.\ \&A small example.res file\fR .sp .if n \{\ .RS 4 .\} .nf resource r0 { net { protocol C; cram\-hmac\-alg sha1; shared\-secret "FooFunFactory"; } disk { resync\-rate 10M; } on alice { volume 0 { device minor 1; disk /dev/sda7; meta\-disk internal; } address 10\&.1\&.1\&.31:7789; } on bob { volume 0 { device minor 1; disk /dev/sda7; meta\-disk internal; } address 10\&.1\&.1\&.32:7789; } } .fi .if n \{\ .RE .\}In this example, there is a single DRBD resource (called r0) which uses protocol C for the connection between its devices\&. It contains a single volume which runs on host \fIalice\fR uses \fI/dev/drbd1\fR as devices for its application, and \fI/dev/sda7\fR as low\-level storage for the data\&. The IP addresses are used to specify the networking interfaces to be used\&. An eventually running resync process should use about 10MByte/second of IO bandwidth\&. This sync\-rate statement is valid for volume 0, but would also be valid for further volumes\&. In this example it assigns full 10MByte/second to each volume\&. .PP There may be multiple resource sections in a single drbd\&.conf file\&. For more examples, please have a look at the \m[blue]\fBDRBD User\'s Guide\fR\m[]\&\s-2\u[1]\d\s+2\&. .SH "FILE FORMAT" .PP The file consists of sections and parameters\&. A section begins with a keyword, sometimes an additional name, and an opening brace (\(lq{\(rq)\&. A section ends with a closing brace (\(lq}\(rq\&. The braces enclose the parameters\&. .PP section [name] { parameter value; [\&.\&.\&.] } .PP A parameter starts with the identifier of the parameter followed by whitespace\&. Every subsequent character is considered as part of the parameter\'s value\&. A special case are Boolean parameters which consist only of the identifier\&. Parameters are terminated by a semicolon (\(lq;\(rq)\&. .PP Some parameter values have default units which might be overruled by K, M or G\&. These units are defined in the usual way (K = 2^10 = 1024, M = 1024 K, G = 1024 M)\&. .PP Comments may be placed into the configuration file and must begin with a hash sign (\(lq#\(rq)\&. Subsequent characters are ignored until the end of the line\&. .SS "Sections" .PP \fBskip\fR .RS 4 .\" drbd.conf: skip Comments out chunks of text, even spanning more than one line\&. Characters between the keyword \fBskip\fR and the opening brace (\(lq{\(rq) are ignored\&. Everything enclosed by the braces is skipped\&. This comes in handy, if you just want to comment out some \'\fBresource [name] {\&.\&.\&.}\fR\' section: just precede it with \'\fBskip\fR\'\&. .RE .PP \fBglobal\fR .RS 4 .\" drbd.conf: global Configures some global parameters\&. Currently only \fBminor\-count\fR, \fBdialog\-refresh\fR, \fBdisable\-ip\-verification\fR and \fBusage\-count\fR are allowed here\&. You may only have one global section, preferably as the first section\&. .RE .PP \fBcommon\fR .RS 4 .\" drbd.conf: common All resources inherit the options set in this section\&. The common section might have a \fBstartup\fR, a \fBoptions\fR, a \fBhandlers\fR, a \fBnet\fR and a \fBdisk\fR section\&. .RE .PP \fBresource \fR\fB\fIname\fR\fR .RS 4 .\" drbd.conf: resource Configures a DRBD resource\&. Each resource section needs to have two (or more) \fBon \fR\fB\fIhost\fR\fR sections and may have a \fBstartup\fR, a \fBoptions\fR, a \fBhandlers\fR, a \fBnet\fR and a \fBdisk\fR section\&. It might contain \fBvolume\fRs sections\&. .RE .PP \fBon \fR\fB\fIhost\-name\fR\fR .RS 4 .\" drbd.conf: on Carries the necessary configuration parameters for a DRBD device of the enclosing resource\&. \fIhost\-name\fR is mandatory and must match the Linux host name (uname \-n) of one of the nodes\&. You may list more than one host name here, in case you want to use the same parameters on several hosts (you\'d have to move the IP around usually)\&. Or you may list more than two such sections\&. .sp .if n \{\ .RS 4 .\} .nf resource r1 { protocol C; device minor 1; meta\-disk internal; on alice bob { address 10\&.2\&.2\&.100:7801; disk /dev/mapper/some\-san; } on charlie { address 10\&.2\&.2\&.101:7801; disk /dev/mapper/other\-san; } on daisy { address 10\&.2\&.2\&.103:7801; disk /dev/mapper/other\-san\-as\-seen\-from\-daisy; } } .fi .if n \{\ .RE .\} .sp See also the \fBfloating\fR section keyword\&. Required statements in this section: \fBaddress\fR and \fBvolume\fR\&. Note for backward compatibility and convenience it is valid to embed the statements of a single volume directly into the host section\&. .RE .PP \fBvolume \fR\fB\fIvnr\fR\fR .RS 4 .\" drbd.conf: volume Defines a volume within a connection\&. The minor numbers of a replicated volume might be different on different hosts, the volume number (\fIvnr\fR) is what groups them together\&. Required parameters in this section: \fBdevice\fR, \fBdisk\fR, \fBmeta\-disk\fR\&. .RE .PP \fBstacked\-on\-top\-of \fR\fB\fIresource\fR\fR .RS 4 .\" drbd.conf: stacked-on-top-of For a stacked DRBD setup (3 or 4 nodes), a \fBstacked\-on\-top\-of\fR is used instead of an \fBon\fR section\&. Required parameters in this section: \fBdevice\fR and \fBaddress\fR\&. .RE .PP \fBfloating \fR\fB\fIAF addr:port\fR\fR .RS 4 .\" drbd.conf: on Carries the necessary configuration parameters for a DRBD device of the enclosing resource\&. This section is very similar to the \fBon\fR section\&. The difference to the \fBon\fR section is that the matching of the host sections to machines is done by the IP\-address instead of the node name\&. Required parameters in this section: \fBdevice\fR, \fBdisk\fR, \fBmeta\-disk\fR, all of which \fImay\fR be inherited from the resource section, in which case you may shorten this section down to just the address identifier\&. .sp .if n \{\ .RS 4 .\} .nf resource r2 { protocol C; device minor 2; disk /dev/sda7; meta\-disk internal; # short form, device, disk and meta\-disk inherited floating 10\&.1\&.1\&.31:7802; # longer form, only device inherited floating 10\&.1\&.1\&.32:7802 { disk /dev/sdb; meta\-disk /dev/sdc8; } } .fi .if n \{\ .RE .\} .RE .PP \fBdisk\fR .RS 4 .\" drbd.conf: disk This section is used to fine tune DRBD\'s properties in respect to the low level storage\&. Please refer to \fBdrbdsetup\fR(8) for detailed description of the parameters\&. Optional parameters: \fBon\-io\-error\fR, \fBsize\fR, \fBfencing\fR, \fBdisk\-barrier\fR, \fBdisk\-flushes\fR, \fBdisk\-drain\fR, \fBmd\-flushes\fR, \fBmax\-bio\-bvecs\fR, \fBresync\-rate\fR, \fBresync\-after\fR, \fBal\-extents\fR, \fBal\-updates\fR, \fBc\-plan\-ahead\fR, \fBc\-fill\-target\fR, \fBc\-delay\-target\fR, \fBc\-max\-rate\fR, \fBc\-min\-rate\fR, \fBdisk\-timeout\fR, \fBdiscard\-zeroes\-if\-aligned\fR, \fBrs\-discard\-granularity\fR, \fBread\-balancing\fR\&. .RE .PP \fBnet\fR .RS 4 .\" drbd.conf: net This section is used to fine tune DRBD\'s properties\&. Please refer to \fBdrbdsetup\fR(8) for a detailed description of this section\'s parameters\&. Optional parameters: \fBprotocol\fR, \fBsndbuf\-size\fR, \fBrcvbuf\-size\fR, \fBtimeout\fR, \fBconnect\-int\fR, \fBping\-int\fR, \fBping\-timeout\fR, \fBmax\-buffers\fR, \fBmax\-epoch\-size\fR, \fBko\-count\fR, \fBallow\-two\-primaries\fR, \fBcram\-hmac\-alg\fR, \fBshared\-secret\fR, \fBafter\-sb\-0pri\fR, \fBafter\-sb\-1pri\fR, \fBafter\-sb\-2pri\fR, \fBdata\-integrity\-alg\fR, \fBno\-tcp\-cork\fR, \fBon\-congestion\fR, \fBcongestion\-fill\fR, \fBcongestion\-extents\fR, \fBverify\-alg\fR, \fBuse\-rle\fR, \fBcsums\-alg\fR, \fBsocket\-check\-timeout\fR\&. .RE .PP \fBstartup\fR .RS 4 .\" drbd.conf: startup This section is used to fine tune DRBD\'s properties\&. Please refer to \fBdrbdsetup\fR(8) for a detailed description of this section\'s parameters\&. Optional parameters: \fBwfc\-timeout\fR, \fBdegr\-wfc\-timeout\fR, \fBoutdated\-wfc\-timeout\fR, \fBwait\-after\-sb\fR, \fBstacked\-timeouts\fR and \fBbecome\-primary\-on\fR\&. .RE .PP \fBoptions\fR .RS 4 .\" drbd.conf: options This section is used to fine tune the behaviour of the resource object\&. Please refer to \fBdrbdsetup\fR(8) for a detailed description of this section\'s parameters\&. Optional parameters: \fBcpu\-mask\fR, and \fBon\-no\-data\-accessible\fR\&. .RE .PP \fBhandlers\fR .RS 4 .\" drbd.conf: handlers In this section you can define handlers (executables) that are started by the DRBD system in response to certain events\&. Optional parameters: \fBpri\-on\-incon\-degr\fR, \fBpri\-lost\-after\-sb\fR, \fBpri\-lost\fR, \fBfence\-peer\fR (formerly oudate\-peer), \fBlocal\-io\-error\fR, \fBinitial\-split\-brain\fR, \fBsplit\-brain\fR, \fBbefore\-resync\-target\fR, \fBafter\-resync\-target\fR\&. .sp The interface is done via environment variables: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBDRBD_RESOURCE\fR is the name of the resource .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBDRBD_MINOR\fR is the minor number of the DRBD device, in decimal\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBDRBD_CONF\fR is the path to the primary configuration file; if you split your configuration into multiple files (e\&.g\&. in \fB/etc/drbd\&.conf\&.d/\fR), this will not be helpful\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBDRBD_PEER_AF\fR , \fBDRBD_PEER_ADDRESS\fR , \fBDRBD_PEERS\fR are the address family (e\&.g\&. \fBipv6\fR), the peer\'s address and hostnames\&. .RE .RS 4 \fBDRBD_PEER\fR is deprecated\&. .sp Please note that not all of these might be set for all handlers, and that some values might not be useable for a \fBfloating\fR definition\&. .RE .SS "Parameters" .PP \fBminor\-count \fR\fB\fIcount\fR\fR .RS 4 .\" drbd.conf: minor-count\fIcount\fR may be a number from 1 to 1048575\&. .sp \fIMinor\-count\fR is a sizing hint for DRBD\&. It helps to right\-size various memory pools\&. It should be set in the in the same order of magnitude than the actual number of minors you use\&. Per default the module loads with 11 more resources than you have currently in your config but at least 32\&. .RE .PP \fBdialog\-refresh \fR\fB\fItime\fR\fR .RS 4 .\" drbd.conf: dialog-refresh\fItime\fR may be 0 or a positive number\&. .sp The user dialog redraws the second count every \fItime\fR seconds (or does no redraws if \fItime\fR is 0)\&. The default value is 1\&. .RE .PP \fBdisable\-ip\-verification\fR .RS 4 .\" drbd.conf: disable-ip-verification Use \fIdisable\-ip\-verification\fR if, for some obscure reasons, drbdadm can/might not use \fBip\fR or \fBifconfig\fR to do a sanity check for the IP address\&. You can disable the IP verification with this option\&. .RE .PP \fBusage\-count \fR\fB\fIval\fR\fR .RS 4 .\" drbd.conf: usage-count Please participate in \m[blue]\fBDRBD\'s online usage counter\fR\m[]\&\s-2\u[2]\d\s+2\&. The most convenient way to do so is to set this option to \fByes\fR\&. Valid options are: \fByes\fR, \fBno\fR and \fBask\fR\&. .RE .PP \fBprotocol \fR\fB\fIprot\-id\fR\fR .RS 4 .\" drbd.conf: protocol On the TCP/IP link the specified \fIprotocol\fR is used\&. Valid protocol specifiers are A, B, and C\&. .sp Protocol A: write IO is reported as completed, if it has reached local disk and local TCP send buffer\&. .sp Protocol B: write IO is reported as completed, if it has reached local disk and remote buffer cache\&. .sp Protocol C: write IO is reported as completed, if it has reached both local and remote disk\&. .RE .PP \fBdevice \fR\fB\fIname\fR\fR\fB minor \fR\fB\fInr\fR\fR .RS 4 .\" drbd.conf: device The name of the block device node of the resource being described\&. You must use this device with your application (file system) and you must not use the low level block device which is specified with the \fBdisk\fR parameter\&. .sp One can ether omit the \fIname\fR or \fBminor\fR and the \fIminor number\fR\&. If you omit the \fIname\fR a default of /dev/drbd\fIminor\fR will be used\&. .sp Udev will create additional symlinks in /dev/drbd/by\-res and /dev/drbd/by\-disk\&. .RE .PP \fBdisk \fR\fB\fIname\fR\fR .RS 4 .\" drbd.conf: disk DRBD uses this block device to actually store and retrieve the data\&. Never access such a device while DRBD is running on top of it\&. This also holds true for \fBdumpe2fs\fR(8) and similar commands\&. .RE .PP \fBaddress \fR\fB\fIAF addr:port\fR\fR .RS 4 .\" drbd.conf: address A resource needs one \fIIP\fR address per device, which is used to wait for incoming connections from the partner device respectively to reach the partner device\&. \fIAF\fR must be one of \fBipv4\fR, \fBipv6\fR, \fBssocks\fR or \fBsdp\fR (for compatibility reasons \fBsci\fR is an alias for \fBssocks\fR)\&. It may be omited for IPv4 addresses\&. The actual IPv6 address that follows the \fBipv6\fR keyword must be placed inside brackets: ipv6 [fd01:2345:6789:abcd::1]:7800\&. .sp Each DRBD resource needs a TCP \fIport\fR which is used to connect to the node\'s partner device\&. Two different DRBD resources may not use the same \fIaddr:port\fR combination on the same node\&. .RE .PP \fBmeta\-disk internal\fR, .br \fBmeta\-disk \fR\fB\fIdevice\fR\fR, .br \fBmeta\-disk \fR\fB\fIdevice\fR\fR\fB [\fR\fB\fIindex\fR\fR\fB]\fR .RS 4 .\" drbd.conf: meta-disk Internal means that the last part of the backing device is used to store the meta\-data\&. The size of the meta\-data is computed based on the size of the device\&. .sp When a \fIdevice\fR is specified, either with or without an \fIindex\fR, DRBD stores the meta\-data on this device\&. Without \fIindex\fR, the size of the meta\-data is determined by the size of the data device\&. This is usually used with LVM, which allows to have many variable sized block devices\&. The meta\-data size is 36kB + Backing\-Storage\-size / 32k, rounded up to the next 4kb boundary\&. (Rule of the thumb: 32kByte per 1GByte of storage, rounded up to the next MB\&.) .sp When an \fIindex\fR is specified, each index number refers to a fixed slot of meta\-data of 128 MB, which allows a maximum data size of 4 TiB\&. This way, multiple DBRD devices can share the same meta\-data device\&. For example, if /dev/sde6[0] and /dev/sde6[1] are used, /dev/sde6 must be at least 256 MB big\&. Because of the hard size limit, use of meta\-disk indexes is discouraged\&. .RE .PP \fBon\-io\-error \fR\fB\fIhandler\fR\fR .RS 4 .\" drbd.conf: on-io-error\fIhandler\fR is taken, if the lower level device reports io\-errors to the upper layers\&. .sp \fIhandler\fR may be \fBpass_on\fR, \fBcall\-local\-io\-error\fR or \fBdetach\&.\fR .sp \fBpass_on\fR: The node downgrades the disk status to inconsistent, marks the erroneous block as inconsistent in the bitmap and retries the IO on the remote node\&. .sp \fBcall\-local\-io\-error\fR: Call the handler script \fBlocal\-io\-error\fR\&. .sp \fBdetach\fR: The node drops its low level device, and continues in diskless mode\&. .RE .PP \fBfencing \fR\fB\fIfencing_policy\fR\fR .RS 4 .\" drbd.conf: fencing By \fBfencing\fR we understand preventive measures to avoid situations where both nodes are primary and disconnected (AKA split brain)\&. .sp Valid fencing policies are: .PP \fBdont\-care\fR .RS 4 This is the default policy\&. No fencing actions are taken\&. .RE .PP \fBresource\-only\fR .RS 4 If a node becomes a disconnected primary, it tries to fence the peer\'s disk\&. This is done by calling the \fBfence\-peer\fR handler\&. The handler is supposed to reach the other node over alternative communication paths and call \'\fBdrbdadm outdate res\fR\' there\&. .RE .PP \fBresource\-and\-stonith\fR .RS 4 If a node becomes a disconnected primary, it freezes all its IO operations and calls its fence\-peer handler\&. The fence\-peer handler is supposed to reach the peer over alternative communication paths and call \'drbdadm outdate res\' there\&. In case it cannot reach the peer it should stonith the peer\&. IO is resumed as soon as the situation is resolved\&. In case your handler fails, you can resume IO with the \fBresume\-io\fR command\&. .RE .RE .PP \fBdisk\-barrier\fR, .br \fBdisk\-flushes\fR, .br \fBdisk\-drain\fR .RS 4 .\" drbd.conf: disk-barrier .\" drbd.conf: disk-flushes .\" drbd.conf: disk-drain DRBD has four implementations to express write\-after\-write dependencies to its backing storage device\&. DRBD will use the first method that is supported by the backing storage device and that is not disabled\&. By default the \fIflush\fR method is used\&. .sp Since drbd\-8\&.4\&.2 \fBdisk\-barrier\fR is disabled by default because since linux\-2\&.6\&.36 (or 2\&.6\&.32 RHEL6) there is no reliable way to determine if queuing of IO\-barriers works\&. \fIDangerous\fR only enable if you are told so by one that knows for sure\&. .sp When selecting the method you should not only base your decision on the measurable performance\&. In case your backing storage device has a volatile write cache (plain disks, RAID of plain disks) you should use one of the first two\&. In case your backing storage device has battery\-backed write cache you may go with option 3\&. Option 4 (disable everything, use "none") \fIis dangerous\fR on most IO stacks, may result in write\-reordering, and if so, can theoretically be the reason for data corruption, or disturb the DRBD protocol, causing spurious disconnect/reconnect cycles\&. \fIDo not use\fR \fBno\-disk\-drain\fR\&. .sp Unfortunately device mapper (LVM) might not support barriers\&. .sp The letter after "wo:" in /proc/drbd indicates with method is currently in use for a device: \fBb\fR, \fBf\fR, \fBd\fR, \fBn\fR\&. The implementations are: .PP barrier .RS 4 The first requires that the driver of the backing storage device support barriers (called \'tagged command queuing\' in SCSI and \'native command queuing\' in SATA speak)\&. The use of this method can be enabled by setting the \fBdisk\-barrier\fR options to \fByes\fR\&. .RE .PP flush .RS 4 The second requires that the backing device support disk flushes (called \'force unit access\' in the drive vendors speak)\&. The use of this method can be disabled setting \fBdisk\-flushes\fR to \fBno\fR\&. .RE .PP drain .RS 4 The third method is simply to let write requests drain before write requests of a new reordering domain are issued\&. This was the only implementation before 8\&.0\&.9\&. .RE .PP none .RS 4 The fourth method is to not express write\-after\-write dependencies to the backing store at all, by also specifying \fBno\-disk\-drain\fR\&. This \fIis dangerous\fR on most IO stacks, may result in write\-reordering, and if so, can theoretically be the reason for data corruption, or disturb the DRBD protocol, causing spurious disconnect/reconnect cycles\&. \fIDo not use\fR \fBno\-disk\-drain\fR\&. .RE .RE .PP \fBmd\-flushes\fR .RS 4 .\" drbd.conf: md-flushes Disables the use of disk flushes and barrier BIOs when accessing the meta data device\&. See the notes on \fBdisk\-flushes\fR\&. .RE .PP \fBmax\-bio\-bvecs\fR .RS 4 .\" drbd.conf: max-bio-bvecs In some special circumstances the device mapper stack manages to pass BIOs to DRBD that violate the constraints that are set forth by DRBD\'s merge_bvec() function and which have more than one bvec\&. A known example is: phys\-disk \-> DRBD \-> LVM \-> Xen \-> misaligned partition (63) \-> DomU FS\&. Then you might see "bio would need to, but cannot, be split:" in the Dom0\'s kernel log\&. .sp The best workaround is to proper align the partition within the VM (E\&.g\&. start it at sector 1024)\&. This costs 480 KiB of storage\&. Unfortunately the default of most Linux partitioning tools is to start the first partition at an odd number (63)\&. Therefore most distribution\'s install helpers for virtual linux machines will end up with misaligned partitions\&. The second best workaround is to limit DRBD\'s max bvecs per BIO (= \fBmax\-bio\-bvecs\fR) to 1, but that might cost performance\&. .sp The default value of \fBmax\-bio\-bvecs\fR is 0, which means that there is no user imposed limitation\&. .RE .PP \fBdisk\-timeout\fR .RS 4 .\" drbd.conf: disk-timeout If the lower\-level device on which a DRBD device stores its data does not finish an I/O request within the defined \fBdisk\-timeout\fR, DRBD treats this as a failure\&. The lower\-level device is detached, and the device\'s disk state advances to Diskless\&. If DRBD is connected to one or more peers, the failed request is passed on to one of them\&. .sp This option is \fIdangerous and may lead to kernel panic!\fR .sp "Aborting" requests, or force\-detaching the disk, is intended for completely blocked/hung local backing devices which do no longer complete requests at all, not even do error completions\&. In this situation, usually a hard\-reset and failover is the only way out\&. .sp By "aborting", basically faking a local error\-completion, we allow for a more graceful swichover by cleanly migrating services\&. Still the affected node has to be rebooted "soon"\&. .sp By completing these requests, we allow the upper layers to re\-use the associated data pages\&. .sp If later the local backing device "recovers", and now DMAs some data from disk into the original request pages, in the best case it will just put random data into unused pages; but typically it will corrupt meanwhile completely unrelated data, causing all sorts of damage\&. .sp Which means delayed successful completion, especially for READ requests, is a reason to panic()\&. We assume that a delayed *error* completion is OK, though we still will complain noisily about it\&. .sp The default value of \fBdisk\-timeout\fR is 0, which stands for an infinite timeout\&. Timeouts are specified in units of 0\&.1 seconds\&. This option is available since DRBD 8\&.3\&.12\&. .RE .PP \fBdiscard\-zeroes\-if\-aligned \fR\fB{yes | no}\fR .RS 4 .\" drbd.conf: discard-zeroes-if-aligned There are several aspects to discard/trim/unmap support on linux block devices\&. Even if discard is supported in general, it may fail silently, or may partially ignore discard requests\&. Devices also announce whether reading from unmapped blocks returns defined data (usually zeroes), or undefined data (possibly old data, possibly garbage)\&. .sp If on different nodes, DRBD is backed by devices with differing discard characteristics, discards may lead to data divergence (old data or garbage left over on one backend, zeroes due to unmapped areas on the other backend)\&. Online verify would now potentially report tons of spurious differences\&. While probably harmless for most use cases (fstrim on a file system), DRBD cannot have that\&. .sp To play safe, we have to disable discard support, if our local backend (on a Primary) does not support "discard_zeroes_data=true"\&. We also have to translate discards to explicit zero\-out on the receiving side, unless the receiving side (Secondary) supports "discard_zeroes_data=true", thereby allocating areas what were supposed to be unmapped\&. .sp There are some devices (notably the LVM/DM thin provisioning) that are capable of discard, but announce discard_zeroes_data=false\&. In the case of DM\-thin, discards aligned to the chunk size will be unmapped, and reading from unmapped sectors will return zeroes\&. However, unaligned partial head or tail areas of discard requests will be silently ignored\&. .sp If we now add a helper to explicitly zero\-out these unaligned partial areas, while passing on the discard of the aligned full chunks, we effectively achieve discard_zeroes_data=true on such devices\&. .sp Setting \fBdiscard\-zeroes\-if\-aligned\fR to \fByes\fR will allow DRBD to use discards, and to announce discard_zeroes_data=true, even on backends that announce discard_zeroes_data=false\&. .sp Setting \fBdiscard\-zeroes\-if\-aligned\fR to \fBno\fR will cause DRBD to always fall\-back to zero\-out on the receiving side, and to not even announce discard capabilities on the Primary, if the respective backend announces discard_zeroes_data=false\&. .sp We used to ignore the discard_zeroes_data setting completely\&. To not break established and expected behaviour, and suddenly cause fstrim on thin\-provisioned LVs to run out\-of\-space instead of freeing up space, the default value is \fByes\fR\&. .sp This option is available since 8\&.4\&.7\&. .RE .PP \fBread\-balancing \fR\fB\fImethod\fR\fR .RS 4 .\" drbd.conf: read-balancing The supported \fImethods\fR for load balancing of read requests are \fBprefer\-local\fR, \fBprefer\-remote\fR, \fBround\-robin\fR, \fBleast\-pending\fR, \fBwhen\-congested\-remote\fR, \fB32K\-striping\fR, \fB64K\-striping\fR, \fB128K\-striping\fR, \fB256K\-striping\fR, \fB512K\-striping\fR and \fB1M\-striping\fR\&. .sp The default value of is \fBprefer\-local\fR\&. This option is available since 8\&.4\&.1\&. .RE .PP \fBrs\-discard\-granularity \fR\fB\fIbyte\fR\fR .RS 4 .\" drbd.conf: rs-discard-granularity When \fBrs\-discard\-granularity\fR is set to a non zero, positive value then DRBD tries to do a resync operation in requests of this size\&. In case such a block contains only zero bytes on the sync source node, the sync target node will issue a discard/trim/unmap command for the area\&. .sp The value is constrained by the discard granularity of the backing block device\&. In case \fBrs\-discard\-granularity\fR is not a multiplier of the discard granularity of the backing block device DRBD rounds it up\&. The feature only gets active if the backing block device reads back zeroes after a discard command\&. .sp The default value of is 0\&. This option is available since 8\&.4\&.7\&. .RE .PP \fBsndbuf\-size \fR\fB\fIsize\fR\fR .RS 4 .\" drbd.conf: sndbuf-size\fIsize\fR is the size of the TCP socket send buffer\&. The default value is 0, i\&.e\&. autotune\&. You can specify smaller or larger values\&. Larger values are appropriate for reasonable write throughput with protocol A over high latency networks\&. Values below 32K do not make sense\&. Since 8\&.0\&.13 resp\&. 8\&.2\&.7, setting the \fIsize\fR value to 0 means that the kernel should autotune this\&. .RE .PP \fBrcvbuf\-size \fR\fB\fIsize\fR\fR .RS 4 .\" drbd.conf: rcvbuf-size\fIsize\fR is the size of the TCP socket receive buffer\&. The default value is 0, i\&.e\&. autotune\&. You can specify smaller or larger values\&. Usually this should be left at its default\&. Setting the \fIsize\fR value to 0 means that the kernel should autotune this\&. .RE .PP \fBtimeout \fR\fB\fItime\fR\fR .RS 4 .\" drbd.conf: timeout If the partner node fails to send an expected response packet within \fItime\fR tenths of a second, the partner node is considered dead and therefore the TCP/IP connection is abandoned\&. This must be lower than \fIconnect\-int\fR and \fIping\-int\fR\&. The default value is 60 = 6 seconds, the unit 0\&.1 seconds\&. .RE .PP \fBconnect\-int \fR\fB\fItime\fR\fR .RS 4 .\" drbd.conf: connect-int In case it is not possible to connect to the remote DRBD device immediately, DRBD keeps on trying to connect\&. With this option you can set the time between two retries\&. The default value is 10 seconds, the unit is 1 second\&. .RE .PP \fBping\-int \fR\fB\fItime\fR\fR .RS 4 .\" drbd.conf: ping-int If the TCP/IP connection linking a DRBD device pair is idle for more than \fItime\fR seconds, DRBD will generate a keep\-alive packet to check if its partner is still alive\&. The default is 10 seconds, the unit is 1 second\&. .RE .PP \fBping\-timeout \fR\fB\fItime\fR\fR .RS 4 .\" drbd.conf: ping-timeout The time the peer has time to answer to a keep\-alive packet\&. In case the peer\'s reply is not received within this time period, it is considered as dead\&. The default value is 500ms, the default unit are tenths of a second\&. .RE .PP \fBmax\-buffers \fR\fB\fInumber\fR\fR .RS 4 .\" drbd.conf: max-buffers Limits the memory usage per DRBD minor device on the receiving side, or for internal buffers during resync or online\-verify\&. Unit is PAGE_SIZE, which is 4 KiB on most systems\&. The minimum possible setting is hard coded to 32 (=128 KiB)\&. These buffers are used to hold data blocks while they are written to/read from disk\&. To avoid possible distributed deadlocks on congestion, this setting is used as a throttle threshold rather than a hard limit\&. Once more than max\-buffers pages are in use, further allocation from this pool is throttled\&. You want to increase max\-buffers if you cannot saturate the IO backend on the receiving side\&. .RE .PP \fBko\-count \fR\fB\fInumber\fR\fR .RS 4 .\" drbd.conf: ko-count In case the secondary node fails to complete a single write request for \fIcount\fR times the \fItimeout\fR, it is expelled from the cluster\&. (I\&.e\&. the primary node will kill and restart the connection\&.) To disable this feature, you should explicitly set it to 0; defaults may change between versions\&. .RE .PP \fBmax\-epoch\-size \fR\fB\fInumber\fR\fR .RS 4 .\" drbd.conf: max-epoch-size The highest number of data blocks between two write barriers\&. If you set this smaller than 10, you might decrease your performance\&. .RE .PP \fBallow\-two\-primaries\fR .RS 4 .\" drbd.conf: allow-two-primaries With this option set you may assign the primary role to both nodes\&. You only should use this option if you use a shared storage file system on top of DRBD\&. At the time of writing the only ones are: OCFS2 and GFS\&. If you use this option with any other file system, you are going to crash your nodes and to corrupt your data! .RE .PP \fBunplug\-watermark \fR\fB\fInumber\fR\fR .RS 4 .\" drbd.conf: unplug-watermark This setting has no effect with recent kernels that use explicit on\-stack plugging (upstream Linux kernel 2\&.6\&.39, distributions may have backported)\&. .sp When the number of pending write requests on the standby (secondary) node exceeds the \fBunplug\-watermark\fR, we trigger the request processing of our backing storage device\&. Some storage controllers deliver better performance with small values, others deliver best performance when the value is set to the same value as max\-buffers, yet others don\'t feel much effect at all\&. Minimum 16, default 128, maximum 131072\&. .RE .PP \fBcram\-hmac\-alg\fR .RS 4 .\" drbd.conf: cram-hmac-alg You need to specify the HMAC algorithm to enable peer authentication at all\&. You are strongly encouraged to use peer authentication\&. The HMAC algorithm will be used for the challenge response authentication of the peer\&. You may specify any digest algorithm that is named in \fB/proc/crypto\fR\&. .RE .PP \fBshared\-secret\fR .RS 4 .\" drbd.conf: shared-secret The shared secret used in peer authentication\&. May be up to 64 characters\&. Note that peer authentication is disabled as long as no \fBcram\-hmac\-alg\fR (see above) is specified\&. .RE .PP \fBafter\-sb\-0pri \fR \fIpolicy\fR .RS 4 .\" drbd.conf: after-sb-0pri possible policies are: .PP \fBdisconnect\fR .RS 4 No automatic resynchronization, simply disconnect\&. .RE .PP \fBdiscard\-younger\-primary\fR .RS 4 Auto sync from the node that was primary before the split\-brain situation happened\&. .RE .PP \fBdiscard\-older\-primary\fR .RS 4 Auto sync from the node that became primary as second during the split\-brain situation\&. .RE .PP \fBdiscard\-zero\-changes\fR .RS 4 In case one node did not write anything since the split brain became evident, sync from the node that wrote something to the node that did not write anything\&. In case none wrote anything this policy uses a random decision to perform a "resync" of 0 blocks\&. In case both have written something this policy disconnects the nodes\&. .RE .PP \fBdiscard\-least\-changes\fR .RS 4 Auto sync from the node that touched more blocks during the split brain situation\&. .RE .PP \fBdiscard\-node\-NODENAME\fR .RS 4 Auto sync to the named node\&. .RE .RE .PP \fBafter\-sb\-1pri \fR \fIpolicy\fR .RS 4 .\" drbd.conf: after-sb-1pri possible policies are: .PP \fBdisconnect\fR .RS 4 No automatic resynchronization, simply disconnect\&. .RE .PP \fBconsensus\fR .RS 4 Discard the version of the secondary if the outcome of the \fBafter\-sb\-0pri\fR algorithm would also destroy the current secondary\'s data\&. Otherwise disconnect\&. .RE .PP \fBviolently\-as0p\fR .RS 4 Always take the decision of the \fBafter\-sb\-0pri\fR algorithm, even if that causes an erratic change of the primary\'s view of the data\&. This is only useful if you use a one\-node FS (i\&.e\&. not OCFS2 or GFS) with the \fBallow\-two\-primaries\fR flag, \fIAND\fR if you really know what you are doing\&. This is \fIDANGEROUS and MAY CRASH YOUR MACHINE\fR if you have an FS mounted on the primary node\&. .RE .PP \fBdiscard\-secondary\fR .RS 4 Discard the secondary\'s version\&. .RE .PP \fBcall\-pri\-lost\-after\-sb\fR .RS 4 Always honor the outcome of the \fBafter\-sb\-0pri \fR algorithm\&. In case it decides the current secondary has the right data, it calls the "pri\-lost\-after\-sb" handler on the current primary\&. .RE .RE .PP \fBafter\-sb\-2pri \fR \fIpolicy\fR .RS 4 .\" drbd.conf: after-sb-2pri possible policies are: .PP \fBdisconnect\fR .RS 4 No automatic resynchronization, simply disconnect\&. .RE .PP \fBviolently\-as0p\fR .RS 4 Always take the decision of the \fBafter\-sb\-0pri\fR algorithm, even if that causes an erratic change of the primary\'s view of the data\&. This is only useful if you use a one\-node FS (i\&.e\&. not OCFS2 or GFS) with the \fBallow\-two\-primaries\fR flag, \fIAND\fR if you really know what you are doing\&. This is \fIDANGEROUS and MAY CRASH YOUR MACHINE\fR if you have an FS mounted on the primary node\&. .RE .PP \fBcall\-pri\-lost\-after\-sb\fR .RS 4 Call the "pri\-lost\-after\-sb" helper program on one of the machines\&. This program is expected to reboot the machine, i\&.e\&. make it secondary\&. .RE .RE .PP \fBalways\-asbp\fR .RS 4 Normally the automatic after\-split\-brain policies are only used if current states of the UUIDs do not indicate the presence of a third node\&. .sp With this option you request that the automatic after\-split\-brain policies are used as long as the data sets of the nodes are somehow related\&. This might cause a full sync, if the UUIDs indicate the presence of a third node\&. (Or double faults led to strange UUID sets\&.) .RE .PP \fBrr\-conflict \fR \fIpolicy\fR .RS 4 .\" drbd.conf: rr-conflict This option helps to solve the cases when the outcome of the resync decision is incompatible with the current role assignment in the cluster\&. .PP \fBdisconnect\fR .RS 4 No automatic resynchronization, simply disconnect\&. .RE .PP \fBviolently\fR .RS 4 Sync to the primary node is allowed, violating the assumption that data on a block device are stable for one of the nodes\&. \fIDangerous, do not use\&.\fR .RE .PP \fBcall\-pri\-lost\fR .RS 4 Call the \fBpri\-lost\-after\-sb\fR helper program on one of the machines unless that machine can demote to secondary\&. The helper program is expected to reboot the machine, which brings the node into a secondary role\&. Which machine runs the helper program is determined by the \fBafter\-sb\-0pri\fR strategy\&. .RE .RE .PP \fBdata\-integrity\-alg \fR \fIalg\fR .RS 4 .\" drbd.conf: data-integrity-alg DRBD can ensure the data integrity of the user\'s data on the network by comparing hash values\&. Normally this is ensured by the 16 bit checksums in the headers of TCP/IP packets\&. .sp This option can be set to any of the kernel\'s data digest algorithms\&. In a typical kernel configuration you should have at least one of \fBmd5\fR, \fBsha1\fR, and \fBcrc32c\fR available\&. By default this is not enabled\&. .sp See also the notes on data integrity\&. .RE .PP \fBtcp\-cork\fR .RS 4 .\" drbd.conf: tcp-cork DRBD usually uses the TCP socket option TCP_CORK to hint to the network stack when it can expect more data, and when it should flush out what it has in its send queue\&. It turned out that there is at least one network stack that performs worse when one uses this hinting method\&. Therefore we introducted this option\&. By setting \fBtcp\-cork\fR to \fBno\fR you can disable the setting and clearing of the TCP_CORK socket option by DRBD\&. .RE .PP \fBon\-congestion \fR\fB\fIcongestion_policy\fR\fR, .br \fBcongestion\-fill \fR\fB\fIfill_threshold\fR\fR, .br \fBcongestion\-extents \fR\fB\fIactive_extents_threshold\fR\fR .RS 4 By default DRBD blocks when the available TCP send queue becomes full\&. That means it will slow down the application that generates the write requests that cause DRBD to send more data down that TCP connection\&. .sp When DRBD is deployed with DRBD\-proxy it might be more desirable that DRBD goes into AHEAD/BEHIND mode shortly before the send queue becomes full\&. In AHEAD/BEHIND mode DRBD does no longer replicate data, but still keeps the connection open\&. .sp The advantage of the AHEAD/BEHIND mode is that the application is not slowed down, even if DRBD\-proxy\'s buffer is not sufficient to buffer all write requests\&. The downside is that the peer node falls behind, and that a resync will be necessary to bring it back into sync\&. During that resync the peer node will have an inconsistent disk\&. .sp Available \fIcongestion_policy\fRs are \fBblock\fR and \fBpull\-ahead\fR\&. The default is \fBblock\fR\&. \fIFill_threshold\fR might be in the range of 0 to 10GiBytes\&. The default is 0 which disables the check\&. \fIActive_extents_threshold\fR has the same limits as \fBal\-extents\fR\&. .sp The AHEAD/BEHIND mode and its settings are available since DRBD 8\&.3\&.10\&. .RE .PP \fBwfc\-timeout \fR\fB\fItime\fR\fR .RS 4 Wait for connection timeout\&. .\" drbd.conf: wfc-timeout The init script \fBdrbd\fR(8) blocks the boot process until the DRBD resources are connected\&. When the cluster manager starts later, it does not see a resource with internal split\-brain\&. In case you want to limit the wait time, do it here\&. Default is 0, which means unlimited\&. The unit is seconds\&. .RE .PP \fBdegr\-wfc\-timeout \fR\fB\fItime\fR\fR .RS 4 .\" drbd.conf: degr-wfc-timeout Wait for connection timeout, if this node was a degraded cluster\&. In case a degraded cluster (= cluster with only one node left) is rebooted, this timeout value is used instead of wfc\-timeout, because the peer is less likely to show up in time, if it had been dead before\&. Value 0 means unlimited\&. .RE .PP \fBoutdated\-wfc\-timeout \fR\fB\fItime\fR\fR .RS 4 .\" drbd.conf: outdated-wfc-timeout Wait for connection timeout, if the peer was outdated\&. In case a degraded cluster (= cluster with only one node left) with an outdated peer disk is rebooted, this timeout value is used instead of wfc\-timeout, because the peer is not allowed to become primary in the meantime\&. Value 0 means unlimited\&. .RE .PP \fBwait\-after\-sb\fR .RS 4 By setting this option you can make the init script to continue to wait even if the device pair had a split brain situation and therefore refuses to connect\&. .RE .PP \fBbecome\-primary\-on \fR\fB\fInode\-name\fR\fR .RS 4 Sets on which node the device should be promoted to primary role by the init script\&. The \fInode\-name\fR might either be a host name or the keyword \fBboth\fR\&. When this option is not set the devices stay in secondary role on both nodes\&. Usually one delegates the role assignment to a cluster manager (e\&.g\&. heartbeat)\&. .RE .PP \fBstacked\-timeouts\fR .RS 4 Usually \fBwfc\-timeout\fR and \fBdegr\-wfc\-timeout\fR are ignored for stacked devices, instead twice the amount of \fBconnect\-int\fR is used for the connection timeouts\&. With the \fBstacked\-timeouts\fR keyword you disable this, and force DRBD to mind the \fBwfc\-timeout\fR and \fBdegr\-wfc\-timeout\fR statements\&. Only do that if the peer of the stacked resource is usually not available or will usually not become primary\&. By using this option incorrectly, you run the risk of causing unexpected split brain\&. .RE .PP \fBresync\-rate \fR\fB\fIrate\fR\fR .RS 4 .\" drbd.conf: resync-rate To ensure a smooth operation of the application on top of DRBD, it is possible to limit the bandwidth which may be used by background synchronizations\&. The default is 250 KB/sec, the default unit is KB/sec\&. Optional suffixes K, M, G are allowed\&. .RE .PP \fBuse\-rle\fR .RS 4 .\" drbd.conf: use-rle During resync\-handshake, the dirty\-bitmaps of the nodes are exchanged and merged (using bit\-or), so the nodes will have the same understanding of which blocks are dirty\&. On large devices, the fine grained dirty\-bitmap can become large as well, and the bitmap exchange can take quite some time on low\-bandwidth links\&. .sp Because the bitmap typically contains compact areas where all bits are unset (clean) or set (dirty), a simple run\-length encoding scheme can considerably reduce the network traffic necessary for the bitmap exchange\&. .sp For backward compatibilty reasons, and because on fast links this possibly does not improve transfer time but consumes cpu cycles, this defaults to off\&. .RE .PP \fBsocket\-check\-timeout \fR\fB\fIvalue\fR\fR .RS 4 .\" drbd.conf: socket-check-timeout In setups involving a DRBD\-proxy and connections that experience a lot of buffer\-bloat it might be necessary to set \fBping\-timeout\fR to an unusual high value\&. By default DRBD uses the same value to wait if a newly established TCP\-connection is stable\&. Since the DRBD\-proxy is usually located in the same data center such a long wait time may hinder DRBD\'s connect process\&. .sp In such setups \fBsocket\-check\-timeout\fR should be set to at least to the round trip time between DRBD and DRBD\-proxy\&. I\&.e\&. in most cases to 1\&. .sp The default unit is tenths of a second, the default value is 0 (which causes DRBD to use the value of \fBping\-timeout\fR instead)\&. Introduced in 8\&.4\&.5\&. .RE .PP \fBresync\-after \fR\fB\fIres\-name\fR\fR .RS 4 .\" drbd.conf: resync-after By default, resynchronization of all devices would run in parallel\&. By defining a resync\-after dependency, the resynchronization of this resource will start only if the resource \fIres\-name\fR is already in connected state (i\&.e\&., has finished its resynchronization)\&. .RE .PP \fBal\-extents \fR\fB\fIextents\fR\fR .RS 4 .\" drbd.conf: al-extents DRBD automatically performs hot area detection\&. With this parameter you control how big the hot area (= active set) can get\&. Each extent marks 4M of the backing storage (= low\-level device)\&. In case a primary node leaves the cluster unexpectedly, the areas covered by the active set must be resynced upon rejoining of the failed node\&. The data structure is stored in the meta\-data area, therefore each change of the active set is a write operation to the meta\-data device\&. A higher number of extents gives longer resync times but less updates to the meta\-data\&. The default number of \fIextents\fR is 1237\&. (Minimum: 7, Maximum: 65534) .sp Note that the effective maximum may be smaller, depending on how you created the device meta data, see also \fBdrbdmeta\fR(8)\&. The effective maximum is 919 * (available on\-disk activity\-log ring\-buffer area/4kB \-1), the default 32kB ring\-buffer effects a maximum of 6433 (covers more than 25 GiB of data)\&. We recommend to keep this well within the amount your backend storage and replication link are able to resync inside of about 5 minutes\&. .RE .PP \fBal\-updates \fR\fB{yes | no}\fR .RS 4 .\" drbd.conf: al-updates DRBD\'s activity log transaction writing makes it possible, that after the crash of a primary node a partial (bit\-map based) resync is sufficient to bring the node back to up\-to\-date\&. Setting \fBal\-updates\fR to \fBno\fR might increase normal operation performance but causes DRBD to do a full resync when a crashed primary gets reconnected\&. The default value is \fByes\fR\&. .RE .PP \fBverify\-alg \fR\fB\fIhash\-alg\fR\fR .RS 4 During online verification (as initiated by the \fBverify\fR sub\-command), rather than doing a bit\-wise comparison, DRBD applies a hash function to the contents of every block being verified, and compares that hash with the peer\&. This option defines the hash algorithm being used for that purpose\&. It can be set to any of the kernel\'s data digest algorithms\&. In a typical kernel configuration you should have at least one of \fBmd5\fR, \fBsha1\fR, and \fBcrc32c\fR available\&. By default this is not enabled; you must set this option explicitly in order to be able to use on\-line device verification\&. .sp See also the notes on data integrity\&. .RE .PP \fBcsums\-alg \fR\fB\fIhash\-alg\fR\fR .RS 4 A resync process sends all marked data blocks from the source to the destination node, as long as no \fBcsums\-alg\fR is given\&. When one is specified the resync process exchanges hash values of all marked blocks first, and sends only those data blocks that have different hash values\&. .sp This setting is useful for DRBD setups with low bandwidth links\&. During the restart of a crashed primary node, all blocks covered by the activity log are marked for resync\&. But a large part of those will actually be still in sync, therefore using \fBcsums\-alg\fR will lower the required bandwidth in exchange for CPU cycles\&. .RE .PP \fBc\-plan\-ahead \fR\fB\fIplan_time\fR\fR, .br \fBc\-fill\-target \fR\fB\fIfill_target\fR\fR, .br \fBc\-delay\-target \fR\fB\fIdelay_target\fR\fR, .br \fBc\-max\-rate \fR\fB\fImax_rate\fR\fR .RS 4 The dynamic resync speed controller gets enabled with setting \fIplan_time\fR to a positive value\&. It aims to fill the buffers along the data path with either a constant amount of data \fIfill_target\fR, or aims to have a constant delay time of \fIdelay_target\fR along the path\&. The controller has an upper bound of \fImax_rate\fR\&. .sp By \fIplan_time\fR the agility of the controller is configured\&. Higher values yield for slower/lower responses of the controller to deviation from the target value\&. It should be at least 5 times RTT\&. For regular data paths a \fIfill_target\fR in the area of 4k to 100k is appropriate\&. For a setup that contains drbd\-proxy it is advisable to use \fIdelay_target\fR instead\&. Only when \fIfill_target\fR is set to 0 the controller will use \fIdelay_target\fR\&. 5 times RTT is a reasonable starting value\&. \fIMax_rate\fR should be set to the bandwidth available between the DRBD\-hosts and the machines hosting DRBD\-proxy, or to the available disk\-bandwidth\&. .sp The default value of \fIplan_time\fR is 0, the default unit is 0\&.1 seconds\&. \fIFill_target\fR has 0 and sectors as default unit\&. \fIDelay_target\fR has 1 (100ms) and 0\&.1 as default unit\&. \fIMax_rate\fR has 10240 (100MiB/s) and KiB/s as default unit\&. .sp The dynamic resync speed controller and its settings are available since DRBD 8\&.3\&.9\&. .RE .PP \fBc\-min\-rate \fR\fB\fImin_rate\fR\fR .RS 4 A node that is primary and sync\-source has to schedule application IO requests and resync IO requests\&. The \fImin_rate\fR tells DRBD use only up to min_rate for resync IO and to dedicate all other available IO bandwidth to application requests\&. .sp Note: The value 0 has a special meaning\&. It disables the limitation of resync IO completely, which might slow down application IO considerably\&. Set it to a value of 1, if you prefer that resync IO never slows down application IO\&. .sp Note: Although the name might suggest that it is a lower bound for the dynamic resync speed controller, it is not\&. If the DRBD\-proxy buffer is full, the dynamic resync speed controller is free to lower the resync speed down to 0, completely independent of the \fBc\-min\-rate\fR setting\&. .sp \fIMin_rate\fR has 4096 (4MiB/s) and KiB/s as default unit\&. .RE .PP \fBon\-no\-data\-accessible \fR\fB\fIond\-policy\fR\fR .RS 4 This setting controls what happens to IO requests on a degraded, disk less node (I\&.e\&. no data store is reachable)\&. The available policies are \fBio\-error\fR and \fBsuspend\-io\fR\&. .sp If \fIond\-policy\fR is set to \fBsuspend\-io\fR you can either resume IO by attaching/connecting the last lost data storage, or by the \fBdrbdadm resume\-io \fR\fB\fIres\fR\fR command\&. The latter will result in IO errors of course\&. .sp The default is \fBio\-error\fR\&. This setting is available since DRBD 8\&.3\&.9\&. .RE .PP \fBcpu\-mask \fR\fB\fIcpu\-mask\fR\fR .RS 4 .\" drbd.conf: cpu-mask Sets the cpu\-affinity\-mask for DRBD\'s kernel threads of this device\&. The default value of \fIcpu\-mask\fR is 0, which means that DRBD\'s kernel threads should be spread over all CPUs of the machine\&. This value must be given in hexadecimal notation\&. If it is too big it will be truncated\&. .RE .PP \fBpri\-on\-incon\-degr \fR\fB\fIcmd\fR\fR .RS 4 .\" drbd.conf: pri-on-incon-degr This handler is called if the node is primary, degraded and if the local copy of the data is inconsistent\&. .RE .PP \fBpri\-lost\-after\-sb \fR\fB\fIcmd\fR\fR .RS 4 .\" drbd.conf: pri-lost-after-sb The node is currently primary, but lost the after\-split\-brain auto recovery procedure\&. As as consequence, it should be abandoned\&. .RE .PP \fBpri\-lost \fR\fB\fIcmd\fR\fR .RS 4 .\" drbd.conf: pri-lost The node is currently primary, but DRBD\'s algorithm thinks that it should become sync target\&. As a consequence it should give up its primary role\&. .RE .PP \fBfence\-peer \fR\fB\fIcmd\fR\fR .RS 4 .\" drbd.conf: fence-peer The handler is part of the \fBfencing\fR mechanism\&. This handler is called in case the node needs to fence the peer\'s disk\&. It should use other communication paths than DRBD\'s network link\&. .RE .PP \fBlocal\-io\-error \fR\fB\fIcmd\fR\fR .RS 4 .\" drbd.conf: local-io-error DRBD got an IO error from the local IO subsystem\&. .RE .PP \fBinitial\-split\-brain \fR\fB\fIcmd\fR\fR .RS 4 .\" drbd.conf: initial-split-brain DRBD has connected and detected a split brain situation\&. This handler can alert someone in all cases of split brain, not just those that go unresolved\&. .RE .PP \fBsplit\-brain \fR\fB\fIcmd\fR\fR .RS 4 .\" drbd.conf: split-brain DRBD detected a split brain situation but remains unresolved\&. Manual recovery is necessary\&. This handler should alert someone on duty\&. .RE .PP \fBbefore\-resync\-target \fR\fB\fIcmd\fR\fR .RS 4 .\" drbd.conf: before-resync-target DRBD calls this handler just before a resync begins on the node that becomes resync target\&. It might be used to take a snapshot of the backing block device\&. .RE .PP \fBafter\-resync\-target \fR\fB\fIcmd\fR\fR .RS 4 .\" drbd.conf: after-resync-target DRBD calls this handler just after a resync operation finished on the node whose disk just became consistent after being inconsistent for the duration of the resync\&. It might be used to remove a snapshot of the backing device that was created by the \fBbefore\-resync\-target\fR handler\&. .RE .SS "Other Keywords" .PP \fBinclude \fR\fB\fIfile\-pattern\fR\fR .RS 4 .\" drbd.conf: include Include all files matching the wildcard pattern \fIfile\-pattern\fR\&. The \fBinclude\fR statement is only allowed on the top level, i\&.e\&. it is not allowed inside any section\&. .RE .SH "NOTES ON DATA INTEGRITY" .PP There are two independent methods in DRBD to ensure the integrity of the mirrored data\&. The online\-verify mechanism and the \fBdata\-integrity\-alg\fR of the \fBnetwork\fR section\&. .PP Both mechanisms might deliver false positives if the user of DRBD modifies the data which gets written to disk while the transfer goes on\&. This may happen for swap, or for certain append while global sync, or truncate/rewrite workloads, and not necessarily poses a problem for the integrity of the data\&. Usually when the initiator of the data transfer does this, it already knows that that data block will not be part of an on disk data structure, or will be resubmitted with correct data soon enough\&. .PP The \fBdata\-integrity\-alg\fR causes the receiving side to log an error about "Digest integrity check FAILED: Ns +x\en", where N is the sector offset, and x is the size of the request in bytes\&. It will then disconnect, and reconnect, thus causing a quick resync\&. If the sending side at the same time detected a modification, it warns about "Digest mismatch, buffer modified by upper layers during write: Ns +x\en", which shows that this was a false positive\&. The sending side may detect these buffer modifications immediately after the unmodified data has been copied to the tcp buffers, in which case the receiving side won\'t notice it\&. .PP The most recent (2007) example of systematic corruption was an issue with the TCP offloading engine and the driver of a certain type of GBit NIC\&. The actual corruption happened on the DMA transfer from core memory to the card\&. Since the TCP checksum gets calculated on the card, this type of corruption stays undetected as long as you do not use either the online \fBverify\fR or the \fBdata\-integrity\-alg\fR\&. .PP We suggest to use the \fBdata\-integrity\-alg\fR only during a pre\-production phase due to its CPU costs\&. Further we suggest to do online \fBverify\fR runs regularly e\&.g\&. once a month during a low load period\&. .SH "VERSION" .sp This document was revised for version 8\&.4\&.0 of the DRBD distribution\&. .SH "AUTHOR" .sp Written by Philipp Reisner philipp\&.reisner@linbit\&.com and Lars Ellenberg lars\&.ellenberg@linbit\&.com\&. .SH "REPORTING BUGS" .sp Report bugs to drbd\-user@lists\&.linbit\&.com\&. .SH "COPYRIGHT" .sp Copyright 2001\-2008 LINBIT Information Technologies, Philipp Reisner, Lars Ellenberg\&. This is free software; see the source for copying conditions\&. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE\&. .SH "SEE ALSO" .PP \fBdrbd\fR(8), \fBdrbddisk\fR(8), \fBdrbdsetup\fR(8), \fBdrbdmeta\fR(8), \fBdrbdadm\fR(8), \m[blue]\fBDRBD User\'s Guide\fR\m[]\&\s-2\u[1]\d\s+2, \m[blue]\fBDRBD web site\fR\m[]\&\s-2\u[3]\d\s+2 .SH "NOTES" .IP " 1." 4 DRBD User's Guide .RS 4 \%http://www.drbd.org/users-guide/ .RE .IP " 2." 4 DRBD's online usage counter .RS 4 \%http://usage.drbd.org .RE .IP " 3." 4 DRBD web site .RS 4 \%http://www.drbd.org/ .RE drbd-utils-8.9.6/documentation/v84/xml-usage-to-docbook.xsl0000644000175000017500000000323412466702073023476 0ustar apoikosapoikos drbdsetup -- val -- -- drbd-utils-8.9.6/documentation/v83/0000755000175000017500000000000012654475367017017 5ustar apoikosapoikosdrbd-utils-8.9.6/documentation/v83/drbdmeta.80000644000175000017500000001245212654452465020670 0ustar apoikosapoikos'\" t .\" Title: drbdmeta .\" Author: [see the "Author" section] .\" Generator: DocBook XSL Stylesheets v1.75.2 .\" Date: 15 Oct 2008 .\" Manual: System Administration .\" Source: DRBD 8.3.2 .\" Language: English .\" .TH "DRBDMETA" "8" "15 Oct 2008" "DRBD 8.3.2" "System Administration" .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" drbdmeta \- DRBD\'s meta data management tool .\" drbdmeta .SH "SYNOPSIS" .HP \w'\fBdrbdmeta\fR\ 'u \fBdrbdmeta\fR [\-\-force] [\-\-ignore\-sanity\-checks] {\fIdevice\fR} {v06\ \fIminor\fR | v07\ \fImeta_dev\ index\fR | v08\ \fImeta_dev\ index\fR} {\fIcommand\fR} [\fIcmd\ args\fR...] .SH "DESCRIPTION" .PP Drbdmeta is used to create, display and modify the contents of DRBD\'s meta data storage\&. Usually you do not want to use this command directly, but start it via the frontend \fBdrbdadm\fR(8)\&. .PP This command only works if the DRBD resource is currently down, or at least detached from its backing storage\&. The first parameter is the device node associated to the resource\&. With the second parameter you can select the version of the meta data\&. Currently all major DRBD releases (0\&.6, 0\&.7 and 8) are supported\&. .SH "OPTIONS" .PP \-\-force .RS 4 .\" drbdmeta: --force All questions that get asked by drbdmeta are treated as if the user answered \'yes\'\&. .RE .PP \-\-ignore\-sanity\-checks .RS 4 .\" drbdmeta: --ignore-sanity-checks Some sanity checks cause drbdmeta to terminate\&. E\&.g\&. if a file system image would get destroyed by creating the meta data\&. By using that option you can force drbdmeta to ignore these checks\&. .RE .SH "COMMANDS" .PP create\-md \fB\-\-peer\-max\-bio\-size \fR\fB\fIval\fR\fR .RS 4 .\" drbdmeta: create-md Create\-md initializes the meta data storage\&. This needs to be done before a DRBD resource can be taken online for the first time\&. In case there is already a meta data signature of an older format in place, drbdmeta will ask you if it should convert the older format to the selected format\&. .sp If you will use the resource before it is connected to its peer for the first time DRBD may perform better if you use the \fB\-\-peer\-max\-bio\-size\fR option\&. For DRBD versions of the peer use up to these values: <8\&.3\&.7 \-> 4k, 8\&.3\&.8 \-> 32k, 8\&.3\&.9 \-> 128k, 8\&.4\&.0 \-> 1M\&. .RE .PP get\-gi .RS 4 .\" drbdmeta: get-gi Get\-gi shows a short textual representation of the data generation identifier\&. In version 0\&.6 and 0\&.7 these are generation counters, while in version 8 it is a set of UUIDs\&. .RE .PP show\-gi .RS 4 .\" drbdmeta: show-gi Show\-gi prints a textual representation of the data generation identifiers including explanatory information\&. .RE .PP dump\-md .RS 4 .\" drbdmeta: dump-md Dumps the whole contents of the meta data storage including the stored bit\-map and activity\-log in a textual representation\&. .RE .PP outdate .RS 4 .\" drbdmeta: outdate Sets the outdated flag in the meta data\&. This is used by the peer node when it wants to become primary, but cannot communicate with the DRBD stack on this host\&. .RE .PP dstate .RS 4 .\" drbdmeta: dstate Prints the state of the data on the backing storage\&. The output is always followed by \'/DUnknown\' since drbdmeta only looks at the local meta data\&. .RE .PP check\-resize .RS 4 .\" drbdmeta: check-resize Examines the device size of a backing device, and it\'s last known device size, recorded in a file /var/lib/drbd/drbd\-minor\-??\&.lkbd\&. In case the size of the backing device changed, and the meta data can be found at the old position, it moves the meta data to the right position at the end of the block device\&. .RE .SH "EXPERT'S COMMANDS" .PP Drbdmeta allows you to modify the meta data as well\&. This is intentionally omitted for the command\'s usage output, since you should only use it if you really know what you are doing\&. By setting the generation identifiers to wrong values, you risk to overwrite your up\-to\-data data with an older version of your data\&. .PP set\-gi \fIgi\fR .RS 4 .\" drbdmeta: set-gi Set\-gi allows you to set the generation identifier\&. \fIGi\fR needs to be a generation counter for the 0\&.6 and 0\&.7 format, and a UUID set for 8\&.x\&. Specify it in the same way as get\-gi shows it\&. .RE .PP restore\-md \fIdump_file\fR .RS 4 .\" drbdmeta: restore-md Reads the \fIdump_file\fR and writes it to the meta data\&. .RE .SH "VERSION" .sp This document was revised for version 8\&.3\&.2 of the DRBD distribution\&. .SH "AUTHOR" .sp Written by Philipp Reisner philipp\&.reisner@linbit\&.com and Lars Ellenberg lars\&.ellenberg@linbit\&.com\&. .SH "REPORTING BUGS" .sp Report bugs to drbd\-user@lists\&.linbit\&.com\&. .SH "COPYRIGHT" .sp Copyright 2001\-2008 LINBIT Information Technologies, Philipp Reisner, Lars Ellenberg\&. This is free software; see the source for copying conditions\&. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE\&. .SH "SEE ALSO" .PP \fBdrbdadm\fR(8) drbd-utils-8.9.6/documentation/v83/drbdsetup.xml0000644000175000017500000024364712504755522021541 0ustar apoikosapoikos 5 Dec 2008 DRBD 8.3.2 drbdsetup 8 System Administration drbdsetup Setup tool for DRBD drbdsetup drbdsetup device disk lower_dev meta_data_dev meta_data_index -dsize -eerr_handler -ffencing_policy -b -tdisk_timeout drbdsetup device net af: local_addr :port af: remote_addr :port protocol -ctime -itime -tval -Ssize -rsize -kcount -emax_epoch_size -bmax_buffers -m -ahash_alg -xshared_secret -Aasb-0p-policy -Basb-1p-policy -Casb-2p-policy -D -Rrole-resync-conflict-policy -pping_timeout -uval -dhash_alg -o -n -gcongestion_policy -fval -hval drbdsetup device syncer -adev_minor -rrate -eextents -vverify-hash-alg -ccpu-mask -Ccsums-hash-alg -R -pplan_time -sfill_target -ddelay_target -mmax_rate -nond-policy drbdsetup device disconnect drbdsetup device detach -f drbdsetup device down drbdsetup device primary -f -o drbdsetup device secondary drbdsetup device verify -sstart-position -Sstop-position drbdsetup device invalidate drbdsetup device invalidate-remote drbdsetup device wait-connect -twfc_timeout -ddegr_wfc_timeout -ooutdated_wfc_timeout -w drbdsetup device wait-sync -twfc_timeout -ddegr_wfc_timeout -ooutdated_wfc_timeout -w drbdsetup device role drbdsetup device cstate drbdsetup device dstate drbdsetup device status drbdsetup device resize -dsize -fassume-peer-has-space -cassume-clean drbdsetup device check-resize drbdsetup device pause-sync drbdsetup device resume-sync drbdsetup device outdate drbdsetup device show-gi drbdsetup device get-gi drbdsetup device show drbdsetup device suspend-io drbdsetup device resume-io drbdsetup device events -u -a drbdsetup device new-current-uuid -c Description drbdsetup is used to associate DRBD devices with their backing block devices, to set up DRBD device pairs to mirror their backing block devices, and to inspect the configuration of running DRBD devices. Note drbdsetup is a low level tool of the DRBD program suite. It is used by the data disk and drbd scripts to communicate with the device driver. Commands Each drbdsetup sub-command might require arguments and bring its own set of options. All values have default units which might be overruled by K, M or G. These units are defined in the usual way (e.g. K = 2^10 = 1024). Common options All drbdsetup sub-commands accept these two options In case the specified DRBD device (minor number) does not exist yet, create it implicitly. When is given on the command line, all options of the invoked sub-command that are not explicitly set are reset to their default values. disk drbdsetup disk Associates device with lower_device to store its data blocks on. The (or ) should only be used if you wish not to use as much as possible from the backing block devices. If you do not use , the device is only ready for use as soon as it was connected to its peer once. (See the command.) , You can override DRBD's size determination method with this option. If you need to use the device before it was ever connected to its peer, use this option to pass the size of the DRBD device to the driver. Default unit is sectors (1s = 512 bytes). If you use the size parameter in drbd.conf, we strongly recommend to add an explicit unit postfix. drbdadm and drbdsetup used to have mismatching default units. , If the driver of the lower_device reports an error to DRBD, DRBD will mark the disk as inconsistent, call a helper program, or detach the device from its backing storage and perform all further IO by requesting it from the peer. The valid err_handlers are: , and . , Under we understand preventive measures to avoid situations where both nodes are primary and disconnected (AKA split brain). Valid fencing policies are: This is the default policy. No fencing actions are done. If a node becomes a disconnected primary, it tries to outdate the peer's disk. This is done by calling the fence-peer handler. The handler is supposed to reach the other node over alternative communication paths and call 'drbdadm outdate res' there. If a node becomes a disconnected primary, it freezes all its IO operations and calls its fence-peer handler. The fence-peer handler is supposed to reach the peer over alternative communication paths and call 'drbdadm outdate res' there. In case it cannot reach the peer, it should stonith the peer. IO is resumed as soon as the situation is resolved. In case your handler fails, you can resume IO with the command. , In case the backing storage's driver has a merge_bvec_fn() function, DRBD has to pretend that it can only process IO requests in units not larger than 4 KiB. (At time of writing the only known drivers which have such a function are: md (software raid driver), dm (device mapper - LVM) and DRBD itself) To get best performance out of DRBD on top of software raid (or any other driver with a merge_bvec_fn() function) you might enable this option, if you know for sure that the merge_bvec_fn() function will deliver the same results on all nodes of your cluster. I.e. the physical disks of the software raid are exactly of the same type. USE THIS OPTION ONLY IF YOU KNOW WHAT YOU ARE DOING. , , , DRBD has four implementations to express write-after-write dependencies to its backing storage device. DRBD will use the first method that is supported by the backing storage device and that is not disabled by the user. When selecting the method you should not only base your decision on the measurable performance. In case your backing storage device has a volatile write cache (plain disks, RAID of plain disks) you should use one of the first two. In case your backing storage device has battery-backed write cache you may go with option 3. Option 4 (disable everything, use "none") is dangerous on most IO stacks, may result in write-reordering, and if so, can theoretically be the reason for data corruption, or disturb the DRBD protocol, causing spurious disconnect/reconnect cycles. Do not use . Unfortunately device mapper (LVM) might not support barriers. The letter after "wo:" in /proc/drbd indicates with method is currently in use for a device: b, f, d, n. The implementations: barrier The first requires that the driver of the backing storage device support barriers (called 'tagged command queuing' in SCSI and 'native command queuing' in SATA speak). The use of this method can be disabled by the option. Note: Since Linux-2.6.36 (or RHEL's 2.6.32) this method is disabled. flush The second requires that the backing device support disk flushes (called 'force unit access' in the drive vendors speak). The use of this method can be disabled using the option. drain The third method is simply to let write requests drain before write requests of a new reordering domain are issued. That was the only implementation before 8.0.9. none The fourth method is to not express write-after-write dependencies to the backing store at all, by also specifying . This is dangerous on most IO stacks, may result in write-reordering, and if so, can theoretically be the reason for data corruption, or disturb the DRBD protocol, causing spurious disconnect/reconnect cycles. Do not use . , Disables the use of disk flushes and barrier BIOs when accessing the meta data device. See the notes on . , In some special circumstances the device mapper stack manages to pass BIOs to DRBD that violate the constraints that are set forth by DRBD's merge_bvec() function and which have more than one bvec. A known example is: phys-disk -> DRBD -> LVM -> Xen -> missaligned partition (63) -> DomU FS. Then you might see "bio would need to, but cannot, be split:" in the Dom0's kernel log. The best workaround is to proper align the partition within the VM (E.g. start it at sector 1024). That costs 480 KiB of storage. Unfortunately the default of most Linux partitioning tools is to start the first partition at an odd number (63). Therefore most distributions install helpers for virtual linux machines will end up with missaligned partitions. The second best workaround is to limit DRBD's max bvecs per BIO (i.e., the option) to 1, but that might cost performance. The default value of is 0, which means that there is no user imposed limitation. , If the driver of the lower_device does not finish an IO request within disk_timeout, DRBD considers the disk as failed. If DRBD is connected to a remote host, it will reissue local pending IO requests to the peer, and ship all new IO requests to the peer only. The disk state advances to diskless, as soon as the backing block device has finished all IO requests. The default value of is 0, which means that no timeout is enforced. The default unit is 100ms. This option is available since 8.3.12. net drbdsetup net Sets up the device to listen on af:local_addr:port for incoming connections and to try to connect to af:remote_addr:port. If port is omitted, 7788 is used as default. If af is omitted gets used. Other supported address families are , for Dolphin Interconnect Solutions' "super sockets" and for Sockets Direct Protocol (Infiniband). On the TCP/IP link the specified protocol is used. Valid protocol specifiers are A, B, and C. Protocol A: write IO is reported as completed, if it has reached local disk and local TCP send buffer. Protocol B: write IO is reported as completed, if it has reached local disk and remote buffer cache. Protocol C: write IO is reported as completed, if it has reached both local and remote disk. , In case it is not possible to connect to the remote DRBD device immediately, DRBD keeps on trying to connect. With this option you can set the time between two retries. The default value is 10 seconds, the unit is 1 second. , If the TCP/IP connection linking a DRBD device pair is idle for more than time seconds, DRBD will generate a keep-alive packet to check if its partner is still alive. The default value is 10 seconds, the unit is 1 second. , If the partner node fails to send an expected response packet within val tenths of a second, the partner node is considered dead and therefore the TCP/IP connection is abandoned. The default value is 60 (= 6 seconds). , The socket send buffer is used to store packets sent to the secondary node, which are not yet acknowledged (from a network point of view) by the secondary node. When using protocol A, it might be necessary to increase the size of this data structure in order to increase asynchronicity between primary and secondary nodes. But keep in mind that more asynchronicity is synonymous with more data loss in the case of a primary node failure. Since 8.0.13 resp. 8.2.7 setting the size value to 0 means that the kernel should autotune this. The default size is 0, i.e. autotune. , Packets received from the network are stored in the socket receive buffer first. From there they are consumed by DRBD. Before 8.3.2 the receive buffer's size was always set to the size of the socket send buffer. Since 8.3.2 they can be tuned independently. A value of 0 means that the kernel should autotune this. The default size is 0, i.e. autotune. , In case the secondary node fails to complete a single write request for count times the timeout, it is expelled from the cluster, i.e. the primary node goes into StandAlone mode. To disable this feature, you should explicitly set it to 0; defaults may change between versions. , With this option the maximal number of write requests between two barriers is limited. Typically set to the same as , or the allowed maximum. Values smaller than 10 can lead to degraded performance. The default value is 2048. , With this option the maximal number of buffer pages allocated by DRBD's receiver thread is limited. Typically set to the same as . Small values could lead to degraded performance. The default value is 2048, the minimum 32. Increase this if you cannot saturate the IO backend of the receiving side during linear write or during resync while otherwise idle. See also drbd.conf5 , This setting has no effect with recent kernels that use explicit on-stack plugging (upstream Linux kernel 2.6.39, distributions may have backported). When the number of pending write requests on the standby (secondary) node exceeds the unplug-watermark, we trigger the request processing of our backing storage device. Some storage controllers deliver better performance with small values, others deliver best performance when the value is set to the same value as max-buffers, yet others don't feel much effect at all. Minimum 16, default 128, maximum 131072. , With this option set you may assign primary role to both nodes. You only should use this option if you use a shared storage file system on top of DRBD. At the time of writing the only ones are: OCFS2 and GFS. If you use this option with any other file system, you are going to crash your nodes and to corrupt your data! , alg You need to specify the HMAC algorithm to enable peer authentication at all. You are strongly encouraged to use peer authentication. The HMAC algorithm will be used for the challenge response authentication of the peer. You may specify any digest algorithm that is named in /proc/crypto. , secret The shared secret used in peer authentication. May be up to 64 characters. , asb-0p-policy possible policies are: No automatic resynchronization, simply disconnect. Auto sync from the node that was primary before the split-brain situation occurred. Auto sync from the node that became primary as second during the split-brain situation. In case one node did not write anything since the split brain became evident, sync from the node that wrote something to the node that did not write anything. In case none wrote anything this policy uses a random decision to perform a "resync" of 0 blocks. In case both have written something this policy disconnects the nodes. Auto sync from the node that touched more blocks during the split brain situation. Auto sync to the named node. , asb-1p-policy possible policies are: No automatic resynchronization, simply disconnect. Discard the version of the secondary if the outcome of the algorithm would also destroy the current secondary's data. Otherwise disconnect. Discard the secondary's version. Always honor the outcome of the algorithm. In case it decides the current secondary has the correct data, call the on the current primary. Always honor the outcome of the algorithm. In case it decides the current secondary has the correct data, accept a possible instantaneous change of the primary's data. , asb-2p-policy possible policies are: No automatic resynchronization, simply disconnect. Always honor the outcome of the algorithm. In case it decides the current secondary has the right data, call the on the current primary. Always honor the outcome of the algorithm. In case it decides the current secondary has the right data, accept a possible instantaneous change of the primary's data. , Normally the automatic after-split-brain policies are only used if current states of the UUIDs do not indicate the presence of a third node. With this option you request that the automatic after-split-brain policies are used as long as the data sets of the nodes are somehow related. This might cause a full sync, if the UUIDs indicate the presence of a third node. (Or double faults have led to strange UUID sets.) , role-resync-conflict-policy This option sets DRBD's behavior when DRBD deduces from its meta data that a resynchronization is needed, and the SyncTarget node is already primary. The possible settings are: , and . While speaks for itself, with the setting the handler is called which is expected to either change the role of the node to secondary, or remove the node from the cluster. The default is . With the setting you allow DRBD to force a primary node into SyncTarget state. This means that the data exposed by DRBD changes to the SyncSource's version of the data instantaneously. USE THIS OPTION ONLY IF YOU KNOW WHAT YOU ARE DOING. , hash_alg DRBD can ensure the data integrity of the user's data on the network by comparing hash values. Normally this is ensured by the 16 bit checksums in the headers of TCP/IP packets. This option can be set to any of the kernel's data digest algorithms. In a typical kernel configuration you should have at least one of , , and available. By default this is not enabled. See also the notes on data integrity on the drbd.conf manpage. , DRBD usually uses the TCP socket option TCP_CORK to hint to the network stack when it can expect more data, and when it should flush out what it has in its send queue. There is at least one network stack that performs worse when one uses this hinting method. Therefore we introduced this option, which disable the setting and clearing of the TCP_CORK socket option by DRBD. , ping_timeout The time the peer has to answer to a keep-alive packet. In case the peer's reply is not received within this time period, it is considered dead. The default unit is tenths of a second, the default value is 5 (for half a second). , Use this option to manually recover from a split-brain situation. In case you do not have any automatic after-split-brain policies selected, the nodes refuse to connect. By passing this option you make this node a sync target immediately after successful connect. , Causes DRBD to abort the connection process after the resync handshake, i.e. no resync gets performed. You can find out which resync DRBD would perform by looking at the kernel's log file. , congestion_policy , fill_threshold , active_extents_threshold By default DRBD blocks when the available TCP send queue becomes full. That means it will slow down the application that generates the write requests that cause DRBD to send more data down that TCP connection. When DRBD is deployed with DRBD-proxy it might be more desirable that DRBD goes into AHEAD/BEHIND mode shortly before the send queue becomes full. In AHEAD/BEHIND mode DRBD does no longer replicate data, but still keeps the connection open. The advantage of the AHEAD/BEHIND mode is that the application is not slowed down, even if DRBD-proxy's buffer is not sufficient to buffer all write requests. The downside is that the peer node falls behind, and that a resync will be necessary to bring it back into sync. During that resync the peer node will have an inconsistent disk. Available congestion_policys are and . The default is . Fill_threshold might be in the range of 0 to 10GiBytes. The default is 0 which disables the check. Active_extents_threshold has the same limits as . The AHEAD/BEHIND mode and its settings are available since DRBD 8.3.10. syncer drbdsetup syncer Changes the synchronization daemon parameters of device at runtime. , To ensure smooth operation of the application on top of DRBD, it is possible to limit the bandwidth that may be used by background synchronization. The default is 250 KiB/sec, the default unit is KiB/sec. , Start resync on this device only if the device with minor is already in connected state. Otherwise this device waits in SyncPause state. , DRBD automatically performs hot area detection. With this parameter you control how big the hot area (=active set) can get. Each extent marks 4M of the backing storage. In case a primary node leaves the cluster unexpectedly, the areas covered by the active set must be resynced upon rejoining of the failed node. The data structure is stored in the meta-data area, therefore each change of the active set is a write operation to the meta-data device. A higher number of extents gives longer resync times but less updates to the meta-data. The default number of extents is 127. (Minimum: 7, Maximum: 3843) , During online verification (as initiated by the verify sub-command), rather than doing a bit-wise comparison, DRBD applies a hash function to the contents of every block being verified, and compares that hash with the peer. This option defines the hash algorithm being used for that purpose. It can be set to any of the kernel's data digest algorithms. In a typical kernel configuration you should have at least one of , , and available. By default this is not enabled; you must set this option explicitly in order to be able to use on-line device verification. See also the notes on data integrity on the drbd.conf manpage. , Sets the cpu-affinity-mask for DRBD's kernel threads of this device. The default value of cpu-mask is 0, which means that DRBD's kernel threads should be spread over all CPUs of the machine. This value must be given in hexadecimal notation. If it is too big it will be truncated. , A resync process sends all marked data blocks form the source to the destination node, as long as no is given. When one is specified the resync process exchanges hash values of all marked blocks first, and sends only those data blocks over, that have different hash values. This setting is useful for DRBD setups with low bandwidth links. During the restart of a crashed primary node, all blocks covered by the activity log are marked for resync. But a large part of those will actually be still in sync, therefore using will lower the required bandwidth in exchange for CPU cycles. , During resync-handshake, the dirty-bitmaps of the nodes are exchanged and merged (using bit-or), so the nodes will have the same understanding of which blocks are dirty. On large devices, the fine grained dirty-bitmap can become large as well, and the bitmap exchange can take quite some time on low-bandwidth links. Because the bitmap typically contains compact areas where all bits are unset (clean) or set (dirty), a simple run-length encoding scheme can considerably reduce the network traffic necessary for the bitmap exchange. For backward compatibilty reasons, and because on fast links this possibly does not improve transfer time but consumes cpu cycles, this defaults to off. Introduced in 8.3.2. , , , , The dynamic resync speed controller gets enabled with setting plan_time to a positive value. It aims to fill the buffers along the data path with either a constant amount of data fill_target, or aims to have a constant delay time of delay_target along the path. The controller has an upper bound of max_rate. By plan_time the agility of the controller is configured. Higher values yield for slower/lower responses of the controller to deviation from the target value. It should be at least 5 times RTT. For regular data paths a fill_target in the area of 4k to 100k is appropriate. For a setup that contains drbd-proxy it is advisable to use delay_target instead. Only when fill_target is set to 0 the controller will use delay_target. 5 times RTT is a reasonable starting value. Max_rate should be set to the bandwidth available between the DRBD-hosts and the machines hosting DRBD-proxy, or to the available disk-bandwidth. The default value of plan_time is 0, the default unit is 0.1 seconds. Fill_target has 0 and sectors as default unit. Delay_target has 1 (100ms) and 0.1 as default unit. Max_rate has 10240 (100MiB/s) and KiB/s as default unit. , We track the disk IO rate caused by the resync, so we can detect non-resync IO on the lower level device. If the lower level device seems to be busy, and the current resync rate is above min_rate, we throttle the resync. The default value of min_rate is 4M, the default unit is k. If you want to not throttle at all, set it to zero, if you want to throttle always, set it to one. , This setting controls what happens to IO requests on a degraded, disk less node (I.e. no data store is reachable). The available policies are and . If ond-policy is set to you can either resume IO by attaching/connecting the last lost data storage, or by the drbdadm resume-io res command. The latter will result in IO errors of course. The default is . This setting is available since DRBD 8.3.9. primary drbdsetup primary Sets the device into primary role. This means that applications (e.g. a file system) may open the device for read and write access. Data written to the device in primary role are mirrored to the device in secondary role. Normally it is not possible to set both devices of a connected DRBD device pair to primary role. By using the option, you override this behavior and instruct DRBD to allow two primaries. , Alias for --force. , Becoming primary fails if the local replica is not up-to-date. I.e. when it is inconsistent, outdated of consistent. By using this option you can force it into primary role anyway. USE THIS OPTION ONLY IF YOU KNOW WHAT YOU ARE DOING. secondary drbdsetup secondary Brings the device into secondary role. This operation fails as long as at least one application (or file system) has opened the device. It is possible that both devices of a connected DRBD device pair are secondary. verify drbdsetup verify This initiates on-line device verification. During on-line verification, the contents of every block on the local node are compared to those on the peer node. Device verification progress can be monitored via /proc/drbd. Any blocks whose content differs from that of the corresponding block on the peer node will be marked out-of-sync in DRBD's on-disk bitmap; they are not brought back in sync automatically. To do that, simply disconnect and reconnect the resource. If on-line verification is already in progress (and this node is "VerifyS"), this command silently "succeeds". In this case, any start-sector (see below) will be ignored, and any stop-sector (see below) will be honored. This can be used to stop a running verify, or to update/shorten/extend the coverage of the currently running verify. This command will fail if the device is not part of a connected device pair. See also the notes on data integrity on the drbd.conf manpage. , Since version 8.3.2, on-line verification should resume from the last position after connection loss. It may also be started from an arbitrary position by setting this option. If you had reached some stop-sector before, and you do not specify an explicit start-sector, verify should resume from the previous stop-sector. Default unit is sectors. You may also specify a unit explicitly. The will be rounded down to a multiple of 8 sectors (4kB). , Since version 8.3.14, on-line verification can be stopped before it reaches end-of-device. This can be Default unit is sectors. You may also specify a unit explicitly. The may be updated by issuing an additional drbdsetup verify command on the same node while the verify is running. invalidate drbdsetup invalidate This forces the local device of a pair of connected DRBD devices into SyncTarget state, which means that all data blocks of the device are copied over from the peer. This command will fail if the device is not either part of a connected device pair, or disconnected Secondary. invalidate-remote drbdsetup invalidate-remote This forces the local device of a pair of connected DRBD devices into SyncSource state, which means that all data blocks of the device are copied to the peer. On a disconnected Primary device, this will set all bits in the out of sync bitmap. As a side affect this suspends updates to the on disk activity log. Updates to the on disk activity log resume automatically when necessary. wait-connect drbdsetup wait-connect Returns as soon as the device can communicate with its partner device. , , , , This command will fail if the device cannot communicate with its partner for timeout seconds. If the peer was working before this node was rebooted, the wfc_timeout is used. If the peer was already down before this node was rebooted, the degr_wfc_timeout is used. If the peer was sucessfully outdated before this node was rebooted the outdated_wfc_timeout is used. The default value for all those timeout values is 0 which means to wait forever. In case the connection status goes down to StandAlone because the peer appeared but the devices had a split brain situation, the default for the command is to terminate. You can change this behavior with the option. wait-sync drbdsetup wait-sync Returns as soon as the device leaves any synchronization into connected state. The options are the same as with the wait-connect command. disconnect drbdsetup disconnect Removes the information set by the command from the device. This means that the device goes into unconnected state and will no longer listen for incoming connections. detach drbdsetup detach Removes the information set by the command from the device. This means that the device is detached from its backing storage device. , A regular detach returns after the disk state finally reached diskless. As a consequence detaching from a frozen backing block device never terminates. On the other hand A forced detach returns immediately. It allows you to detach DRBD from a frozen backing block device. Please note that the disk will be marked as failed until all pending IO requests where finished by the backing block device. down drbdsetup down Removes all configuration information from the device and forces it back to unconfigured state. role drbdsetup role Shows the current roles of the device and its peer, as local/peer. state drbdsetup state Deprecated alias for "role" cstate drbdsetup cstate Shows the current connection state of the device. dstate drbdsetup dstate Shows the current states of the backing storage devices, as local/peer. status drbdsetup status Shows the current status of the device in XML-like format. Example output: <resource minor="0" name="s0" cs="SyncTarget" st1="Secondary" st2="Secondary" ds1="Inconsistent" ds2="UpToDate" resynced_precent="5.9" /> resize drbdsetup resize This causes DRBD to reexamine the size of the device's backing storage device. To actually do online growing you need to extend the backing storages on both devices and call the command on one of your nodes. The allows you to resize a device which is currently not connected to the peer. Use with care, since if you do not resize the peer's disk as well, further connect attempts of the two will fail. When the option is given DRBD will skip the resync of the new storage. Only do this if you know that the new storage was initialized to the same content by other means. check-resize drbdsetup check-resize To enable DRBD to detect offline resizing of backing devices this command may be used to record the current size of backing devices. The size is stored in files in /var/lib/drbd/ named drbd-minor-??.lkbd This command is called by drbdadm resize res after drbdsetup device resize returned. pause-sync drbdsetup pause-sync Temporarily suspend an ongoing resynchronization by setting the local pause flag. Resync only progresses if neither the local nor the remote pause flag is set. It might be desirable to postpone DRBD's resynchronization after eventual resynchronization of the backing storage's RAID setup. resume-sync drbdsetup resume-sync Unset the local sync pause flag. outdate drbdsetup outdate Mark the data on the local backing storage as outdated. An outdated device refuses to become primary. This is used in conjunction with and by the peer's handler. show-gi drbdsetup show-gi Displays the device's data generation identifiers verbosely. get-gi drbdsetup get-gi Displays the device's data generation identifiers. show drbdsetup show Shows all available configuration information of the device. suspend-io drbdsetup suspend-io This command is of no apparent use and just provided for the sake of completeness. resume-io drbdsetup resume-io If the fence-peer handler fails to stonith the peer node, and your policy is set to resource-and-stonith, you can unfreeze IO operations with this command. events drbdsetup events Displays every state change of DRBD and all calls to helper programs. This might be used to get notified of DRBD's state changes by piping the output to another program. , Display the events of all DRBD minors. , This is a debugging aid that displays the content of all received netlink messages. new-current-uuid drbdsetup new-current-uuid Generates a new current UUID and rotates all other UUID values. This has at least two use cases, namely to skip the initial sync, and to reduce network bandwidth when starting in a single node configuration and then later (re-)integrating a remote site. Available option: , Clears the sync bitmap in addition to generating a new current UUID. This can be used to skip the initial sync, if you want to start from scratch. This use-case does only work on "Just Created" meta data. Necessary steps: On both nodes, initialize meta data and configure the device. drbdadm -- --force create-md res They need to do the initial handshake, so they know their sizes. drbdadm up res They are now Connected Secondary/Secondary Inconsistent/Inconsistent. Generate a new current-uuid and clear the dirty bitmap. drbdadm -- --clear-bitmap new-current-uuid res They are now Connected Secondary/Secondary UpToDate/UpToDate. Make one side primary and create a file system. drbdadm primary resmkfs -t fs-type $(drbdadm sh-dev res) One obvious side-effect is that the replica is full of old garbage (unless you made them identical using other means), so any online-verify is expected to find any number of out-of-sync blocks. You must not use this on pre-existing data! Even though it may appear to work at first glance, once you switch to the other node, your data is toast, as it never got replicated. So do not leave out the mkfs (or equivalent). This can also be used to shorten the initial resync of a cluster where the second node is added after the first node is gone into production, by means of disk shipping. This use-case works on disconnected devices only, the device may be in primary or secondary role. The necessary steps on the current active server are: drbdsetup device new-current-uuid --clear-bitmap Take the copy of the current active server. E.g. by pulling a disk out of the RAID1 controller, or by copying with dd. You need to copy the actual data, and the meta data. drbdsetup device new-current-uuid Now add the disk to the new secondary node, and join it to the cluster. You will get a resync of that parts that were changed since the first call to drbdsetup in step 1. Examples For examples, please have a look at the DRBD User's Guide. Version This document was revised for version 8.3.2 of the DRBD distribution. Author Written by Philipp Reisner philipp.reisner@linbit.com and Lars Ellenberg lars.ellenberg@linbit.com Reporting Bugs Report bugs to drbd-user@lists.linbit.com. Copyright Copyright 2001-2008 LINBIT Information Technologies, Philipp Reisner, Lars Ellenberg. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See Also drbd.conf5, drbd8, drbddisk8, drbdadm8, DRBD User's Guide, DRBD web site drbd-utils-8.9.6/documentation/v83/drbd.80000644000175000017500000000454012654452464020017 0ustar apoikosapoikos'\" t .\" Title: drbd .\" Author: [see the "Author" section] .\" Generator: DocBook XSL Stylesheets v1.75.2 .\" Date: 15 Oct 2008 .\" Manual: System Administration .\" Source: DRBD 8.3.2 .\" Language: English .\" .TH "DRBD" "8" "15 Oct 2008" "DRBD 8.3.2" "System Administration" .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" drbd \- The start and stop script for DRBD .SH "SYNOPSIS" .HP \w'\fB/etc/init\&.d/drbd\fR\ 'u \fB/etc/init\&.d/drbd\fR [\fIresource\fR] {{start}\ |\ {stop}\ |\ {status}\ |\ {reload}\ |\ {restart}\ |\ {force\-reload}} .SH "INTRODUCTION" .PP The \fB/etc/init\&.d/drbd\fR script is used to start and stop drbd on a system V style init system\&. .PP In order to use \fB/etc/init\&.d/drbd\fR you must define a resource, a host, and any other configuration options in the drbd configuration file\&. See \fB/etc/drbd\&.conf\fR for details\&. If \fIresource\fR is omitted, then all of the resources listed in the config file are configured\&. .PP This script might ask you \(lqDo you want to abort waiting for other server and make this one primary?\(rq .PP Only answer this question with \(lqyes\(rq if you are sure that it is impossible to repair the other node\&. .SH "VERSION" .sp This document was revised for version 8\&.3\&.2 of the DRBD distribution\&. .SH "AUTHOR" .sp Written by Philipp Reisner philipp\&.reisner@linbit\&.com and Lars Ellenberg lars\&.ellenberg@linbit\&.com\&. .SH "REPORTING BUGS" .sp Report bugs to drbd\-user@lists\&.linbit\&.com\&. .SH "COPYRIGHT" .sp Copyright 2001\-2008 LINBIT Information Technologies, Philipp Reisner, Lars Ellenberg\&. This is free software; see the source for copying conditions\&. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE\&. .SH "SEE ALSO" .PP \fBdrbd.conf\fR(5), \fBdrbddisk\fR(8), \fBdrbdsetup\fR(8)\fBdrbdadm\fR(8)\m[blue]\fBDRBD Homepage\fR\m[]\&\s-2\u[1]\d\s+2 .SH "NOTES" .IP " 1." 4 DRBD Homepage .RS 4 \%http://www.drbd.org/ .RE drbd-utils-8.9.6/documentation/v83/drbd.conf.xml0000644000175000017500000023722612504755522021400 0ustar apoikosapoikos 5 Dec 2008 DRBD 8.3.2 drbd.conf 5 Configuration Files drbd.conf Configuration file for DRBD's devices drbd.conf Introduction The file is read by . The file format was designed as to allow to have a verbatim copy of the file on both nodes of the cluster. It is highly recommended to do so in order to keep your configuration manageable. The file should be the same on both nodes of the cluster. Changes to do not apply immediately. A small drbd.conf fileglobal { usage-count yes; } common { syncer { rate 10M; } } resource r0 { protocol C; net { cram-hmac-alg sha1; shared-secret "FooFunFactory"; } on alice { device minor 1; disk /dev/sda7; address 10.1.1.31:7789; meta-disk internal; } on bob { device minor 1; disk /dev/sda7; address 10.1.1.32:7789; meta-disk internal; } } In this example, there is a single DRBD resource (called r0) which uses protocol C for the connection between its devices. The device which runs on host alice uses /dev/drbd1 as devices for its application, and /dev/sda7 as low-level storage for the data. The IP addresses are used to specify the networking interfaces to be used. An eventually running resync process should use about 10MByte/second of IO bandwidth. There may be multiple resource sections in a single drbd.conf file. For more examples, please have a look at the DRBD User's Guide. File Format The file consists of sections and parameters. A section begins with a keyword, sometimes an additional name, and an opening brace ({). A section ends with a closing brace (}. The braces enclose the parameters. section [name] { parameter value; [...] } A parameter starts with the identifier of the parameter followed by whitespace. Every subsequent character is considered as part of the parameter's value. A special case are Boolean parameters which consist only of the identifier. Parameters are terminated by a semicolon (;). Some parameter values have default units which might be overruled by K, M or G. These units are defined in the usual way (K = 2^10 = 1024, M = 1024 K, G = 1024 M). Comments may be placed into the configuration file and must begin with a hash sign (#). Subsequent characters are ignored until the end of the line. Sections drbd.confskip Comments out chunks of text, even spanning more than one line. Characters between the keyword and the opening brace ({) are ignored. Everything enclosed by the braces is skipped. This comes in handy, if you just want to comment out some '' section: just precede it with 'skip'. drbd.confglobal Configures some global parameters. Currently only , , and are allowed here. You may only have one global section, preferably as the first section. drbd.confcommon All resources inherit the options set in this section. The common section might have a , a , a , a and a section. drbd.confresource Configures a DRBD resource. Each resource section needs to have two (or more) sections and may have a , a , a , a and a section. Required parameter in this section: . drbd.confon Carries the necessary configuration parameters for a DRBD device of the enclosing resource. host-name is mandatory and must match the Linux host name (uname -n) of one of the nodes. You may list more than one host name here, in case you want to use the same parameters on several hosts (you'd have to move the IP around usually). Or you may list more than two such sections. resource r1 { protocol C; device minor 1; meta-disk internal; on alice bob { address 10.2.2.100:7801; disk /dev/mapper/some-san; } on charlie { address 10.2.2.101:7801; disk /dev/mapper/other-san; } on daisy { address 10.2.2.103:7801; disk /dev/mapper/other-san-as-seen-from-daisy; } } See also the section keyword. Required parameters in this section: , , , , . drbd.confstacked-on-top-of For a stacked DRBD setup (3 or 4 nodes), a is used instead of an section. Required parameters in this section: and . drbd.confon Carries the necessary configuration parameters for a DRBD device of the enclosing resource. This section is very similar to the section. The difference to the section is that the matching of the host sections to machines is done by the IP-address instead of the node name. Required parameters in this section: , , , , all of which may be inherited from the resource section, in which case you may shorten this section down to just the address identifier. resource r2 { protocol C; device minor 2; disk /dev/sda7; meta-disk internal; # short form, device, disk and meta-disk inherited floating 10.1.1.31:7802; # longer form, only device inherited floating 10.1.1.32:7802 { disk /dev/sdb; meta-disk /dev/sdc8; } } drbd.confdisk This section is used to fine tune DRBD's properties in respect to the low level storage. Please refer to drbdsetup8 for detailed description of the parameters. Optional parameters: , , , , , , , , , . drbd.confnet This section is used to fine tune DRBD's properties. Please refer to drbdsetup8 for a detailed description of this section's parameters. Optional parameters: , , , , , , , , , , , , , , , , , , , drbd.confstartup This section is used to fine tune DRBD's properties. Please refer to drbdsetup8 for a detailed description of this section's parameters. Optional parameters: , , , , and . drbd.confsyncer This section is used to fine tune the synchronization daemon for the device. Please refer to drbdsetup8 for a detailed description of this section's parameters. Optional parameters: , , , , , , , , , , , and . drbd.confhandlers In this section you can define handlers (executables) that are started by the DRBD system in response to certain events. Optional parameters: , , , (formerly oudate-peer), , , , , . The interface is done via environment variables: is the name of the resource is the minor number of the DRBD device, in decimal. is the path to the primary configuration file; if you split your configuration into multiple files (e.g. in ), this will not be helpful. , , are the address family (e.g. ), the peer's address and hostnames. (note the singular form) is deprecated, and superseeded by DRBD_PEERS. Please note that not all of these might be set for all handlers, and that some values might not be useable for a definition. Parameters drbd.confminor-count count may be a number from 1 to 255. Use minor-count if you want to define massively more resources later without reloading the DRBD kernel module. Per default the module loads with 11 more resources than you have currently in your config but at least 32. drbd.confdialog-refresh time may be 0 or a positive number. The user dialog redraws the second count every time seconds (or does no redraws if time is 0). The default value is 1. drbd.conf disable-ip-verification Use disable-ip-verification if, for some obscure reasons, drbdadm can/might not use or to do a sanity check for the IP address. You can disable the IP verification with this option. drbd.conf usage-count Please participate in DRBD's online usage counter. The most convenient way to do so is to set this option to . Valid options are: , and . drbd.conf protocol On the TCP/IP link the specified protocol is used. Valid protocol specifiers are A, B, and C. Protocol A: write IO is reported as completed, if it has reached local disk and local TCP send buffer. Protocol B: write IO is reported as completed, if it has reached local disk and remote buffer cache. Protocol C: write IO is reported as completed, if it has reached both local and remote disk. drbd.confdevice The name of the block device node of the resource being described. You must use this device with your application (file system) and you must not use the low level block device which is specified with the parameter. One can ether omit the name or and the minor number. If you omit the name a default of /dev/drbdminor will be used. Udev will create additional symlinks in /dev/drbd/by-res and /dev/drbd/by-disk. drbd.confdisk DRBD uses this block device to actually store and retrieve the data. Never access such a device while DRBD is running on top of it. This also holds true for dumpe2fs8 and similar commands. drbd.confaddress A resource needs one IP address per device, which is used to wait for incoming connections from the partner device respectively to reach the partner device. AF must be one of , , or (for compatibility reasons is an alias for ). It may be omited for IPv4 addresses. The actual IPv6 address that follows the keyword must be placed inside brackets: ipv6 [fd01:2345:6789:abcd::1]:7800. Each DRBD resource needs a TCP port which is used to connect to the node's partner device. Two different DRBD resources may not use the same addr:port combination on the same node. drbd.confmeta-diskdrbd.confflexible-meta-disk Internal means that the last part of the backing device is used to store the meta-data. You must not use [index] with internal. Note: Regardless of whether you use the or the keyword, it will always be of the size needed for the remaining storage size. You can use a single block device to store meta-data of multiple DRBD devices. E.g. use meta-disk /dev/sde6[0]; and meta-disk /dev/sde6[1]; for two different resources. In this case the meta-disk would need to be at least 256 MB in size. With the keyword you specify a block device as meta-data storage. You usually use this with LVM, which allows you to have many variable sized block devices. The required size of the meta-disk block device is 36kB + Backing-Storage-size / 32k. Round this number to the next 4kb boundary up and you have the exact size. Rule of the thumb: 32kByte per 1GByte of storage, round up to the next MB. drbd.confon-io-errorhandler is taken, if the lower level device reports io-errors to the upper layers. handler may be , or : The node downgrades the disk status to inconsistent, marks the erroneous block as inconsistent in the bitmap and retries the IO on the remote node. : Call the handler script . : The node drops its low level device, and continues in diskless mode. drbd.conffencing By we understand preventive measures to avoid situations where both nodes are primary and disconnected (AKA split brain). Valid fencing policies are: This is the default policy. No fencing actions are taken. If a node becomes a disconnected primary, it tries to fence the peer's disk. This is done by calling the handler. The handler is supposed to reach the other node over alternative communication paths and call '' there. If a node becomes a disconnected primary, it freezes all its IO operations and calls its fence-peer handler. The fence-peer handler is supposed to reach the peer over alternative communication paths and call 'drbdadm outdate res' there. In case it cannot reach the peer it should stonith the peer. IO is resumed as soon as the situation is resolved. In case your handler fails, you can resume IO with the command. drbd.conf use-bmbv In case the backing storage's driver has a merge_bvec_fn() function, DRBD has to pretend that it can only process IO requests in units not larger than 4KiB. (At the time of writing the only known drivers which have such a function are: md (software raid driver), dm (device mapper - LVM) and DRBD itself). To get the best performance out of DRBD on top of software RAID (or any other driver with a merge_bvec_fn() function) you might enable this function, if you know for sure that the merge_bvec_fn() function will deliver the same results on all nodes of your cluster. I.e. the physical disks of the software RAID are of exactly the same type. Use this option only if you know what you are doing. drbd.conf no-disk-barrier drbd.conf no-disk-flushes drbd.conf no-disk-drain DRBD has four implementations to express write-after-write dependencies to its backing storage device. DRBD will use the first method that is supported by the backing storage device and that is not disabled by the user. When selecting the method you should not only base your decision on the measurable performance. In case your backing storage device has a volatile write cache (plain disks, RAID of plain disks) you should use one of the first two. In case your backing storage device has battery-backed write cache you may go with option 3. Option 4 (disable everything, use "none") is dangerous on most IO stacks, may result in write-reordering, and if so, can theoretically be the reason for data corruption, or disturb the DRBD protocol, causing spurious disconnect/reconnect cycles. Do not use . Unfortunately device mapper (LVM) might not support barriers. The letter after "wo:" in /proc/drbd indicates with method is currently in use for a device: , , , . The implementations are: barrier The first requires that the driver of the backing storage device support barriers (called 'tagged command queuing' in SCSI and 'native command queuing' in SATA speak). The use of this method can be disabled by the option. Note: Since Linux-2.6.36 (or RHEL's 2.6.32) this method is disabled. flush The second requires that the backing device support disk flushes (called 'force unit access' in the drive vendors speak). The use of this method can be disabled using the option. drain The third method is simply to let write requests drain before write requests of a new reordering domain are issued. This was the only implementation before 8.0.9. none The fourth method is to not express write-after-write dependencies to the backing store at all, by also specifying . This is dangerous on most IO stacks, may result in write-reordering, and if so, can theoretically be the reason for data corruption, or disturb the DRBD protocol, causing spurious disconnect/reconnect cycles. Do not use . drbd.conf no-md-flushes Disables the use of disk flushes and barrier BIOs when accessing the meta data device. See the notes on . drbd.conf max-bio-bvecs In some special circumstances the device mapper stack manages to pass BIOs to DRBD that violate the constraints that are set forth by DRBD's merge_bvec() function and which have more than one bvec. A known example is: phys-disk -> DRBD -> LVM -> Xen -> misaligned partition (63) -> DomU FS. Then you might see "bio would need to, but cannot, be split:" in the Dom0's kernel log. The best workaround is to proper align the partition within the VM (E.g. start it at sector 1024). This costs 480 KiB of storage. Unfortunately the default of most Linux partitioning tools is to start the first partition at an odd number (63). Therefore most distribution's install helpers for virtual linux machines will end up with misaligned partitions. The second best workaround is to limit DRBD's max bvecs per BIO (= ) to 1, but that might cost performance. The default value of is 0, which means that there is no user imposed limitation. drbd.conf disk-timeout If the driver of the lower_device does not finish an IO request within disk_timeout, DRBD considers the disk as failed. If DRBD is connected to a remote host, it will reissue local pending IO requests to the peer, and ship all new IO requests to the peer only. The disk state advances to diskless, as soon as the backing block device has finished all IO requests. The default value of is 0, which means that no timeout is enforced. The default unit is 100ms. This option is available since 8.3.12. drbd.confsndbuf-size size is the size of the TCP socket send buffer. The default value is 0, i.e. autotune. You can specify smaller or larger values. Larger values are appropriate for reasonable write throughput with protocol A over high latency networks. Values below 32K do not make sense. Since 8.0.13 resp. 8.2.7, setting the size value to 0 means that the kernel should autotune this. drbd.confrcvbuf-size size is the size of the TCP socket receive buffer. The default value is 0, i.e. autotune. You can specify smaller or larger values. Usually this should be left at its default. Setting the size value to 0 means that the kernel should autotune this. drbd.conftimeout If the partner node fails to send an expected response packet within time tenths of a second, the partner node is considered dead and therefore the TCP/IP connection is abandoned. This must be lower than connect-int and ping-int. The default value is 60 = 6 seconds, the unit 0.1 seconds. drbd.confconnect-int In case it is not possible to connect to the remote DRBD device immediately, DRBD keeps on trying to connect. With this option you can set the time between two retries. The default value is 10 seconds, the unit is 1 second. drbd.confping-int If the TCP/IP connection linking a DRBD device pair is idle for more than time seconds, DRBD will generate a keep-alive packet to check if its partner is still alive. The default is 10 seconds, the unit is 1 second. drbd.confping-timeout The time the peer has time to answer to a keep-alive packet. In case the peer's reply is not received within this time period, it is considered as dead. The default value is 500ms, the default unit are tenths of a second. drbd.confmax-buffers Limits the memory usage per DRBD minor device on the receiving side, or for internal buffers during resync or online-verify. Unit is PAGE_SIZE, which is 4 KiB on most systems. The minimum possible setting is hard coded to 32 (=128 KiB). These buffers are used to hold data blocks while they are written to/read from disk. To avoid possible distributed deadlocks on congestion, this setting is used as a throttle threshold rather than a hard limit. Once more than max-buffers pages are in use, further allocation from this pool is throttled. You want to increase max-buffers if you cannot saturate the IO backend on the receiving side. drbd.confko-count In case the secondary node fails to complete a single write request for count times the timeout, it is expelled from the cluster. (I.e. the primary node goes into mode.) To disable this feature, you should explicitly set it to 0; defaults may change between versions. drbd.confmax-epoch-size The highest number of data blocks between two write barriers. If you set this smaller than 10, you might decrease your performance. drbd.confallow-two-primaries With this option set you may assign the primary role to both nodes. You only should use this option if you use a shared storage file system on top of DRBD. At the time of writing the only ones are: OCFS2 and GFS. If you use this option with any other file system, you are going to crash your nodes and to corrupt your data! drbd.conf unplug-watermark This setting has no effect with recent kernels that use explicit on-stack plugging (upstream Linux kernel 2.6.39, distributions may have backported). When the number of pending write requests on the standby (secondary) node exceeds the , we trigger the request processing of our backing storage device. Some storage controllers deliver better performance with small values, others deliver best performance when the value is set to the same value as max-buffers, yet others don't feel much effect at all. Minimum 16, default 128, maximum 131072. drbd.confcram-hmac-alg You need to specify the HMAC algorithm to enable peer authentication at all. You are strongly encouraged to use peer authentication. The HMAC algorithm will be used for the challenge response authentication of the peer. You may specify any digest algorithm that is named in . drbd.confshared-secret The shared secret used in peer authentication. May be up to 64 characters. Note that peer authentication is disabled as long as no (see above) is specified. policy drbd.conf after-sb-0pri possible policies are: No automatic resynchronization, simply disconnect. Auto sync from the node that was primary before the split-brain situation happened. Auto sync from the node that became primary as second during the split-brain situation. In case one node did not write anything since the split brain became evident, sync from the node that wrote something to the node that did not write anything. In case none wrote anything this policy uses a random decision to perform a "resync" of 0 blocks. In case both have written something this policy disconnects the nodes. Auto sync from the node that touched more blocks during the split brain situation. Auto sync to the named node. policy drbd.conf after-sb-1pri possible policies are: No automatic resynchronization, simply disconnect. Discard the version of the secondary if the outcome of the algorithm would also destroy the current secondary's data. Otherwise disconnect. Always take the decision of the algorithm, even if that causes an erratic change of the primary's view of the data. This is only useful if you use a one-node FS (i.e. not OCFS2 or GFS) with the flag, AND if you really know what you are doing. This is DANGEROUS and MAY CRASH YOUR MACHINE if you have an FS mounted on the primary node. Discard the secondary's version. Always honor the outcome of the algorithm. In case it decides the current secondary has the right data, it calls the "pri-lost-after-sb" handler on the current primary. policy drbd.conf after-sb-2pri possible policies are: No automatic resynchronization, simply disconnect. Always take the decision of the algorithm, even if that causes an erratic change of the primary's view of the data. This is only useful if you use a one-node FS (i.e. not OCFS2 or GFS) with the flag, AND if you really know what you are doing. This is DANGEROUS and MAY CRASH YOUR MACHINE if you have an FS mounted on the primary node. Call the "pri-lost-after-sb" helper program on one of the machines. This program is expected to reboot the machine, i.e. make it secondary. Normally the automatic after-split-brain policies are only used if current states of the UUIDs do not indicate the presence of a third node. With this option you request that the automatic after-split-brain policies are used as long as the data sets of the nodes are somehow related. This might cause a full sync, if the UUIDs indicate the presence of a third node. (Or double faults led to strange UUID sets.) policy drbd.conf rr-conflict This option helps to solve the cases when the outcome of the resync decision is incompatible with the current role assignment in the cluster. No automatic resynchronization, simply disconnect. Sync to the primary node is allowed, violating the assumption that data on a block device are stable for one of the nodes. Dangerous, do not use. Call the "pri-lost" helper program on one of the machines. This program is expected to reboot the machine, i.e. make it secondary. alg drbd.conf data-integrity-alg DRBD can ensure the data integrity of the user's data on the network by comparing hash values. Normally this is ensured by the 16 bit checksums in the headers of TCP/IP packets. This option can be set to any of the kernel's data digest algorithms. In a typical kernel configuration you should have at least one of , , and available. By default this is not enabled. See also the notes on data integrity. drbd.conf no-tcp-cork DRBD usually uses the TCP socket option TCP_CORK to hint to the network stack when it can expect more data, and when it should flush out what it has in its send queue. It turned out that there is at least one network stack that performs worse when one uses this hinting method. Therefore we introducted this option, which disables the setting and clearing of the TCP_CORK socket option by DRBD. By default DRBD blocks when the available TCP send queue becomes full. That means it will slow down the application that generates the write requests that cause DRBD to send more data down that TCP connection. When DRBD is deployed with DRBD-proxy it might be more desirable that DRBD goes into AHEAD/BEHIND mode shortly before the send queue becomes full. In AHEAD/BEHIND mode DRBD does no longer replicate data, but still keeps the connection open. The advantage of the AHEAD/BEHIND mode is that the application is not slowed down, even if DRBD-proxy's buffer is not sufficient to buffer all write requests. The downside is that the peer node falls behind, and that a resync will be necessary to bring it back into sync. During that resync the peer node will have an inconsistent disk. Available congestion_policys are and . The default is . Fill_threshold might be in the range of 0 to 10GiBytes. The default is 0 which disables the check. Active_extents_threshold has the same limits as . The AHEAD/BEHIND mode and its settings are available since DRBD 8.3.10. Wait for connection timeout. drbd.confwfc-timeout The init script drbd8 blocks the boot process until the DRBD resources are connected. When the cluster manager starts later, it does not see a resource with internal split-brain. In case you want to limit the wait time, do it here. Default is 0, which means unlimited. The unit is seconds. drbd.confdegr-wfc-timeout Wait for connection timeout, if this node was a degraded cluster. In case a degraded cluster (= cluster with only one node left) is rebooted, this timeout value is used instead of wfc-timeout, because the peer is less likely to show up in time, if it had been dead before. Value 0 means unlimited. drbd.confoutdated-wfc-timeout Wait for connection timeout, if the peer was outdated. In case a degraded cluster (= cluster with only one node left) with an outdated peer disk is rebooted, this timeout value is used instead of wfc-timeout, because the peer is not allowed to become primary in the meantime. Value 0 means unlimited. By setting this option you can make the init script to continue to wait even if the device pair had a split brain situation and therefore refuses to connect. Sets on which node the device should be promoted to primary role by the init script. The node-name might either be a host name or the keyword . When this option is not set the devices stay in secondary role on both nodes. Usually one delegates the role assignment to a cluster manager (e.g. heartbeat). Usually and are ignored for stacked devices, instead twice the amount of is used for the connection timeouts. With the keyword you disable this, and force DRBD to mind the and statements. Only do that if the peer of the stacked resource is usually not available or will usually not become primary. By using this option incorrectly, you run the risk of causing unexpected split brain. drbd.confrate To ensure a smooth operation of the application on top of DRBD, it is possible to limit the bandwidth which may be used by background synchronizations. The default is 250 KB/sec, the default unit is KB/sec. Optional suffixes K, M, G are allowed. drbd.confuse-rle During resync-handshake, the dirty-bitmaps of the nodes are exchanged and merged (using bit-or), so the nodes will have the same understanding of which blocks are dirty. On large devices, the fine grained dirty-bitmap can become large as well, and the bitmap exchange can take quite some time on low-bandwidth links. Because the bitmap typically contains compact areas where all bits are unset (clean) or set (dirty), a simple run-length encoding scheme can considerably reduce the network traffic necessary for the bitmap exchange. For backward compatibilty reasons, and because on fast links this possibly does not improve transfer time but consumes cpu cycles, this defaults to off. drbd.confafter By default, resynchronization of all devices would run in parallel. By defining a sync-after dependency, the resynchronization of this resource will start only if the resource res-name is already in connected state (i.e., has finished its resynchronization). drbd.confal-extents DRBD automatically performs hot area detection. With this parameter you control how big the hot area (= active set) can get. Each extent marks 4M of the backing storage (= low-level device). In case a primary node leaves the cluster unexpectedly, the areas covered by the active set must be resynced upon rejoining of the failed node. The data structure is stored in the meta-data area, therefore each change of the active set is a write operation to the meta-data device. A higher number of extents gives longer resync times but less updates to the meta-data. The default number of extents is 127. (Minimum: 7, Maximum: 3843) During online verification (as initiated by the verify sub-command), rather than doing a bit-wise comparison, DRBD applies a hash function to the contents of every block being verified, and compares that hash with the peer. This option defines the hash algorithm being used for that purpose. It can be set to any of the kernel's data digest algorithms. In a typical kernel configuration you should have at least one of , , and available. By default this is not enabled; you must set this option explicitly in order to be able to use on-line device verification. See also the notes on data integrity. A resync process sends all marked data blocks from the source to the destination node, as long as no is given. When one is specified the resync process exchanges hash values of all marked blocks first, and sends only those data blocks that have different hash values. This setting is useful for DRBD setups with low bandwidth links. During the restart of a crashed primary node, all blocks covered by the activity log are marked for resync. But a large part of those will actually be still in sync, therefore using will lower the required bandwidth in exchange for CPU cycles. The dynamic resync speed controller gets enabled with setting plan_time to a positive value. It aims to fill the buffers along the data path with either a constant amount of data fill_target, or aims to have a constant delay time of delay_target along the path. The controller has an upper bound of max_rate. By plan_time the agility of the controller is configured. Higher values yield for slower/lower responses of the controller to deviation from the target value. It should be at least 5 times RTT. For regular data paths a fill_target in the area of 4k to 100k is appropriate. For a setup that contains drbd-proxy it is advisable to use delay_target instead. Only when fill_target is set to 0 the controller will use delay_target. 5 times RTT is a reasonable starting value. Max_rate should be set to the bandwidth available between the DRBD-hosts and the machines hosting DRBD-proxy, or to the available disk-bandwidth. The default value of plan_time is 0, the default unit is 0.1 seconds. Fill_target has 0 and sectors as default unit. Delay_target has 1 (100ms) and 0.1 as default unit. Max_rate has 10240 (100MiB/s) and KiB/s as default unit. The dynamic resync speed controller and its settings are available since DRBD 8.3.9. A node that is primary and sync-source has to schedule application IO requests and resync IO requests. The min_rate tells DRBD use only up to min_rate for resync IO and to dedicate all other available IO bandwidth to application requests. Note: The value 0 has a special meaning. It disables the limitation of resync IO completely, which might slow down application IO considerably. Set it to a value of 1, if you prefer that resync IO never slows down application IO. Note: Although the name might suggest that it is a lower bound for the dynamic resync speed controller, it is not. If the DRBD-proxy buffer is full, the dynamic resync speed controller is free to lower the resync speed down to 0, completely independent of the setting. Min_rate has 4096 (4MiB/s) and KiB/s as default unit. This setting controls what happens to IO requests on a degraded, disk less node (I.e. no data store is reachable). The available policies are and . If ond-policy is set to you can either resume IO by attaching/connecting the last lost data storage, or by the drbdadm resume-io res command. The latter will result in IO errors of course. The default is . This setting is available since DRBD 8.3.9. drbd.confcpu-mask Sets the cpu-affinity-mask for DRBD's kernel threads of this device. The default value of cpu-mask is 0, which means that DRBD's kernel threads should be spread over all CPUs of the machine. This value must be given in hexadecimal notation. If it is too big it will be truncated. drbd.confpri-on-incon-degr This handler is called if the node is primary, degraded and if the local copy of the data is inconsistent. drbd.confpri-lost-after-sb The node is currently primary, but lost the after-split-brain auto recovery procedure. As as consequence, it should be abandoned. drbd.confpri-lost The node is currently primary, but DRBD's algorithm thinks that it should become sync target. As a consequence it should give up its primary role. drbd.conffence-peer The handler is part of the mechanism. This handler is called in case the node needs to fence the peer's disk. It should use other communication paths than DRBD's network link. drbd.conflocal-io-error DRBD got an IO error from the local IO subsystem. drbd.confinitial-split-brain DRBD has connected and detected a split brain situation. This handler can alert someone in all cases of split brain, not just those that go unresolved. drbd.confsplit-brain DRBD detected a split brain situation but remains unresolved. Manual recovery is necessary. This handler should alert someone on duty. drbd.confbefore-resync-target DRBD calls this handler just before a resync begins on the node that becomes resync target. It might be used to take a snapshot of the backing block device. drbd.confafter-resync-target DRBD calls this handler just after a resync operation finished on the node whose disk just became consistent after being inconsistent for the duration of the resync. It might be used to remove a snapshot of the backing device that was created by the handler. Other Keywords drbd.confinclude Include all files matching the wildcard pattern file-pattern. The statement is only allowed on the top level, i.e. it is not allowed inside any section. Notes on data integrity There are two independent methods in DRBD to ensure the integrity of the mirrored data. The online-verify mechanism and the of the section. Both mechanisms might deliver false positives if the user of DRBD modifies the data which gets written to disk while the transfer goes on. This may happen for swap, or for certain append while global sync, or truncate/rewrite workloads, and not necessarily poses a problem for the integrity of the data. Usually when the initiator of the data transfer does this, it already knows that that data block will not be part of an on disk data structure, or will be resubmitted with correct data soon enough. The causes the receiving side to log an error about "Digest integrity check FAILED: Ns +x\n", where N is the sector offset, and x is the size of the requst in bytes. It will then disconnect, and reconnect, thus causing a quick resync. If the sending side at the same time detected a modification, it warns about "Digest mismatch, buffer modified by upper layers during write: Ns +x\n", which shows that this was a false positive. The sending side may detect these buffer modifications immediately after the unmodified data has been copied to the tcp buffers, in which case the receiving side won't notice it. The most recent (2007) example of systematic corruption was an issue with the TCP offloading engine and the driver of a certain type of GBit NIC. The actual corruption happened on the DMA transfer from core memory to the card. Since the TCP checksum gets calculated on the card, this type of corruption stays undetected as long as you do not use either the online or the . We suggest to use the only during a pre-production phase due to its CPU costs. Further we suggest to do online runs regularly e.g. once a month during a low load period. Version This document was revised for version 8.3.2 of the DRBD distribution. Author Written by Philipp Reisner philipp.reisner@linbit.com and Lars Ellenberg lars.ellenberg@linbit.com. Reporting Bugs Report bugs to drbd-user@lists.linbit.com. Copyright Copyright 2001-2008 LINBIT Information Technologies, Philipp Reisner, Lars Ellenberg. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See Also drbd8, drbddisk8, drbdsetup8, drbdadm8, DRBD User's Guide, DRBD web site drbd-utils-8.9.6/documentation/v83/drbddisk.xml0000644000175000017500000000615012466702073021315 0ustar apoikosapoikos drbddisk Script to mark devices as primary and mount file systems 15 Oct 2008 DRBD 8.3.2 drbddisk 8 System Administration /etc/ha.d/resource.d/drbddisk resource start stop status Introduction The script brings the local device of resource into primary role. It is designed to be used by Heartbeat. In order to use you must define a resource, a host, and any other configuration options in the DRBD configuration file. See for details. If resource is omitted, then all of the resources listed in the config file are affected. Version This document was revised for version 8.0.14 of the DRBD distribution. Author Written by Philipp Reisner philipp.reisner@linbit.com and Lars Ellenberg lars.ellenberg@linbit.com. Reporting Bugs Report bugs to drbd-user@lists.linbit.com. Copyright Copyright 2001-2008 LINBIT Information Technologies, Philipp Reisner, Lars Ellenberg. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See Also drbd.conf5, drbd8, drbdsetup8drbdadm8DRBD Homepage drbd-utils-8.9.6/documentation/v83/drbdsetup.80000644000175000017500000013207712654452463021106 0ustar apoikosapoikos'\" t .\" Title: drbdsetup .\" Author: [see the "Author" section] .\" Generator: DocBook XSL Stylesheets v1.75.2 .\" Date: 5 Dec 2008 .\" Manual: System Administration .\" Source: DRBD 8.3.2 .\" Language: English .\" .TH "DRBDSETUP" "8" "5 Dec 2008" "DRBD 8.3.2" "System Administration" .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" drbdsetup \- Setup tool for DRBD .\" drbdsetup .SH "SYNOPSIS" .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR {\fIdevice\fR} disk {\fIlower_dev\fR} {\fImeta_data_dev\fR} {\fImeta_data_index\fR} [\-d\ {\fIsize\fR}] [\-e\ {\fIerr_handler\fR}] [\-f\ {\fIfencing_policy\fR}] [\-b] [\-t\ {\fIdisk_timeout\fR}] .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR {\fIdevice\fR} net [\fIaf:\fR] {\fIlocal_addr\fR} [\fI:port\fR] [\fIaf:\fR] {\fIremote_addr\fR} [\fI:port\fR] {\fIprotocol\fR} [\-c\ {\fItime\fR}] [\-i\ {\fItime\fR}] [\-t\ {\fIval\fR}] [\-S\ {\fIsize\fR}] [\-r\ {\fIsize\fR}] [\-k\ {\fIcount\fR}] [\-e\ {\fImax_epoch_size\fR}] [\-b\ {\fImax_buffers\fR}] [\-m] [\-a\ {\fIhash_alg\fR}] [\-x\ {\fIshared_secret\fR}] [\-A\ {\fIasb\-0p\-policy\fR}] [\-B\ {\fIasb\-1p\-policy\fR}] [\-C\ {\fIasb\-2p\-policy\fR}] [\-D] [\-R\ {\fIrole\-resync\-conflict\-policy\fR}] [\-p\ {\fIping_timeout\fR}] [\-u\ {\fIval\fR}] [\-d\ {\fIhash_alg\fR}] [\-o] [\-n] [\-g\ {\fIcongestion_policy\fR}] [\-f\ {\fIval\fR}] [\-h\ {\fIval\fR}] .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR {\fIdevice\fR} syncer [\-a\ {\fIdev_minor\fR}] [\-r\ {\fIrate\fR}] [\-e\ {\fIextents\fR}] [\-v\ {\fIverify\-hash\-alg\fR}] [\-c\ {\fIcpu\-mask\fR}] [\-C\ {\fIcsums\-hash\-alg\fR}] [\-R] [\-p\ {\fIplan_time\fR}] [\-s\ {\fIfill_target\fR}] [\-d\ {\fIdelay_target\fR}] [\-m\ {\fImax_rate\fR}] [\-n\ {\fIond\-policy\fR}] .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR {\fIdevice\fR} disconnect .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR {\fIdevice\fR} detach [\-f] .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR {\fIdevice\fR} down .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR {\fIdevice\fR} primary [\-f] [\-o] .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR {\fIdevice\fR} secondary .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR {\fIdevice\fR} verify [\-s\ {\fIstart\-position\fR}] [\-S\ {\fIstop\-position\fR}] .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR {\fIdevice\fR} invalidate .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR {\fIdevice\fR} invalidate\-remote .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR {\fIdevice\fR} wait\-connect [\-t\ {\fIwfc_timeout\fR}] [\-d\ {\fIdegr_wfc_timeout\fR}] [\-o\ {\fIoutdated_wfc_timeout\fR}] [\-w] .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR {\fIdevice\fR} wait\-sync [\-t\ {\fIwfc_timeout\fR}] [\-d\ {\fIdegr_wfc_timeout\fR}] [\-o\ {\fIoutdated_wfc_timeout\fR}] [\-w] .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR {\fIdevice\fR} role .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR {\fIdevice\fR} cstate .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR {\fIdevice\fR} dstate .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR {\fIdevice\fR} status .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR {\fIdevice\fR} resize [\-d\ {\fIsize\fR}] [\-f\ {\fIassume\-peer\-has\-space\fR}] [\-c\ {\fIassume\-clean\fR}] .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR {\fIdevice\fR} check\-resize .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR {\fIdevice\fR} pause\-sync .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR {\fIdevice\fR} resume\-sync .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR {\fIdevice\fR} outdate .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR {\fIdevice\fR} show\-gi .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR {\fIdevice\fR} get\-gi .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR {\fIdevice\fR} show .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR {\fIdevice\fR} suspend\-io .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR {\fIdevice\fR} resume\-io .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR {\fIdevice\fR} events [\-u] [\-a] .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR {\fIdevice\fR} new\-current\-uuid [\-c] .SH "DESCRIPTION" .PP drbdsetup is used to associate DRBD devices with their backing block devices, to set up DRBD device pairs to mirror their backing block devices, and to inspect the configuration of running DRBD devices\&. .SH "NOTE" .PP drbdsetup is a low level tool of the DRBD program suite\&. It is used by the data disk and drbd scripts to communicate with the device driver\&. .SH "COMMANDS" .PP Each drbdsetup sub\-command might require arguments and bring its own set of options\&. All values have default units which might be overruled by K, M or G\&. These units are defined in the usual way (e\&.g\&. K = 2^10 = 1024)\&. .SS "Common options" .PP All drbdsetup sub\-commands accept these two options .PP \fB\-\-create\-device\fR .RS 4 In case the specified DRBD device (minor number) does not exist yet, create it implicitly\&. .RE .PP \fB\-\-set\-defaults\fR .RS 4 When \fB\-\-set\-defaults\fR is given on the command line, all options of the invoked sub\-command that are not explicitly set are reset to their default values\&. .RE .SS "disk" .\" drbdsetup: disk .PP Associates \fIdevice\fR with \fIlower_device\fR to store its data blocks on\&. The \fB\-d\fR (or \fB\-\-disk\-size\fR) should only be used if you wish not to use as much as possible from the backing block devices\&. If you do not use \fB\-d\fR, the \fIdevice\fR is only ready for use as soon as it was connected to its peer once\&. (See the \fBnet\fR command\&.) .PP \fB\-d\fR, \fB\-\-disk\-size \fR\fB\fIsize\fR\fR .RS 4 You can override DRBD\'s size determination method with this option\&. If you need to use the device before it was ever connected to its peer, use this option to pass the \fIsize\fR of the DRBD device to the driver\&. Default unit is sectors (1s = 512 bytes)\&. .sp If you use the \fIsize\fR parameter in drbd\&.conf, we strongly recommend to add an explicit unit postfix\&. drbdadm and drbdsetup used to have mismatching default units\&. .RE .PP \fB\-e\fR, \fB\-\-on\-io\-error \fR\fB\fIerr_handler\fR\fR .RS 4 If the driver of the \fIlower_device\fR reports an error to DRBD, DRBD will mark the disk as inconsistent, call a helper program, or detach the device from its backing storage and perform all further IO by requesting it from the peer\&. The valid \fIerr_handlers\fR are: \fBpass_on\fR, \fBcall\-local\-io\-error\fR and \fBdetach\fR\&. .RE .PP \fB\-f\fR, \fB\-\-fencing \fR\fB\fIfencing_policy\fR\fR .RS 4 Under \fBfencing\fR we understand preventive measures to avoid situations where both nodes are primary and disconnected (AKA split brain)\&. .sp Valid fencing policies are: .PP \fBdont\-care\fR .RS 4 This is the default policy\&. No fencing actions are done\&. .RE .PP \fBresource\-only\fR .RS 4 If a node becomes a disconnected primary, it tries to outdate the peer\'s disk\&. This is done by calling the fence\-peer handler\&. The handler is supposed to reach the other node over alternative communication paths and call \'drbdadm outdate res\' there\&. .RE .PP \fBresource\-and\-stonith\fR .RS 4 If a node becomes a disconnected primary, it freezes all its IO operations and calls its fence\-peer handler\&. The fence\-peer handler is supposed to reach the peer over alternative communication paths and call \'drbdadm outdate res\' there\&. In case it cannot reach the peer, it should stonith the peer\&. IO is resumed as soon as the situation is resolved\&. In case your handler fails, you can resume IO with the \fBresume\-io\fR command\&. .RE .RE .PP \fB\-b\fR, \fB\-\-use\-bmbv\fR .RS 4 In case the backing storage\'s driver has a merge_bvec_fn() function, DRBD has to pretend that it can only process IO requests in units not larger than 4 KiB\&. (At time of writing the only known drivers which have such a function are: md (software raid driver), dm (device mapper \- LVM) and DRBD itself) .sp To get best performance out of DRBD on top of software raid (or any other driver with a merge_bvec_fn() function) you might enable this option, if you know for sure that the merge_bvec_fn() function will deliver the same results on all nodes of your cluster\&. I\&.e\&. the physical disks of the software raid are exactly of the same type\&. USE THIS OPTION ONLY IF YOU KNOW WHAT YOU ARE DOING\&. .RE .PP \fB\-a\fR, \fB\-\-no\-disk\-barrier\fR, \fB\-i\fR, \fB\-\-no\-disk\-flushes\fR, \fB\-D\fR, \fB\-\-no\-disk\-drain\fR .RS 4 DRBD has four implementations to express write\-after\-write dependencies to its backing storage device\&. DRBD will use the first method that is supported by the backing storage device and that is not disabled by the user\&. .sp When selecting the method you should not only base your decision on the measurable performance\&. In case your backing storage device has a volatile write cache (plain disks, RAID of plain disks) you should use one of the first two\&. In case your backing storage device has battery\-backed write cache you may go with option 3\&. Option 4 (disable everything, use "none") \fIis dangerous\fR on most IO stacks, may result in write\-reordering, and if so, can theoretically be the reason for data corruption, or disturb the DRBD protocol, causing spurious disconnect/reconnect cycles\&. \fIDo not use\fR \fBno\-disk\-drain\fR\&. .sp Unfortunately device mapper (LVM) might not support barriers\&. .sp The letter after "wo:" in /proc/drbd indicates with method is currently in use for a device: b, f, d, n\&. The implementations: .PP barrier .RS 4 The first requires that the driver of the backing storage device support barriers (called \'tagged command queuing\' in SCSI and \'native command queuing\' in SATA speak)\&. The use of this method can be disabled by the \fB\-\-no\-disk\-barrier\fR option\&. Note: Since Linux\-2\&.6\&.36 (or RHEL\'s 2\&.6\&.32) this method is disabled\&. .RE .PP flush .RS 4 The second requires that the backing device support disk flushes (called \'force unit access\' in the drive vendors speak)\&. The use of this method can be disabled using the \fB\-\-no\-disk\-flushes\fR option\&. .RE .PP drain .RS 4 The third method is simply to let write requests drain before write requests of a new reordering domain are issued\&. That was the only implementation before 8\&.0\&.9\&. .RE .PP none .RS 4 The fourth method is to not express write\-after\-write dependencies to the backing store at all, by also specifying \fB\-\-no\-disk\-drain\fR\&. This \fIis dangerous\fR on most IO stacks, may result in write\-reordering, and if so, can theoretically be the reason for data corruption, or disturb the DRBD protocol, causing spurious disconnect/reconnect cycles\&. \fIDo not use\fR \fB\-\-no\-disk\-drain\fR\&. .RE .RE .PP \fB\-m\fR, \fB\-\-no\-md\-flushes\fR .RS 4 Disables the use of disk flushes and barrier BIOs when accessing the meta data device\&. See the notes on \fB\-\-no\-disk\-flushes\fR\&. .RE .PP \fB\-s\fR, \fB\-\-max\-bio\-bvecs\fR .RS 4 In some special circumstances the device mapper stack manages to pass BIOs to DRBD that violate the constraints that are set forth by DRBD\'s merge_bvec() function and which have more than one bvec\&. A known example is: phys\-disk \-> DRBD \-> LVM \-> Xen \-> missaligned partition (63) \-> DomU FS\&. Then you might see "bio would need to, but cannot, be split:" in the Dom0\'s kernel log\&. .sp The best workaround is to proper align the partition within the VM (E\&.g\&. start it at sector 1024)\&. That costs 480 KiB of storage\&. Unfortunately the default of most Linux partitioning tools is to start the first partition at an odd number (63)\&. Therefore most distributions install helpers for virtual linux machines will end up with missaligned partitions\&. The second best workaround is to limit DRBD\'s max bvecs per BIO (i\&.e\&., the \fBmax\-bio\-bvecs\fR option) to 1, but that might cost performance\&. .sp The default value of \fBmax\-bio\-bvecs\fR is 0, which means that there is no user imposed limitation\&. .RE .PP \fB\-t\fR, \fB\-\-disk\-timeout \fR\fB\fIdisk_timeout\fR\fR .RS 4 If the driver of the \fIlower_device\fR does not finish an IO request within \fIdisk_timeout\fR, DRBD considers the disk as failed\&. If DRBD is connected to a remote host, it will reissue local pending IO requests to the peer, and ship all new IO requests to the peer only\&. The disk state advances to diskless, as soon as the backing block device has finished all IO requests\&. .sp The default value of is 0, which means that no timeout is enforced\&. The default unit is 100ms\&. This option is available since 8\&.3\&.12\&. .RE .SS "net" .\" drbdsetup: net .PP Sets up the \fIdevice\fR to listen on \fIaf:local_addr:port\fR for incoming connections and to try to connect to \fIaf:remote_addr:port\fR\&. If \fIport\fR is omitted, 7788 is used as default\&. If \fIaf\fR is omitted \fBipv4\fR gets used\&. Other supported address families are \fBipv6\fR, \fBssocks\fR for Dolphin Interconnect Solutions\' "super sockets" and \fBsdp\fR for Sockets Direct Protocol (Infiniband)\&. .PP On the TCP/IP link the specified \fIprotocol\fR is used\&. Valid protocol specifiers are A, B, and C\&. .PP Protocol A: write IO is reported as completed, if it has reached local disk and local TCP send buffer\&. .PP Protocol B: write IO is reported as completed, if it has reached local disk and remote buffer cache\&. .PP Protocol C: write IO is reported as completed, if it has reached both local and remote disk\&. .PP \fB\-c\fR, \fB\-\-connect\-int \fR\fB\fItime\fR\fR .RS 4 In case it is not possible to connect to the remote DRBD device immediately, DRBD keeps on trying to connect\&. With this option you can set the time between two retries\&. The default value is 10 seconds, the unit is 1 second\&. .RE .PP \fB\-i\fR, \fB\-\-ping\-int \fR\fB\fItime\fR\fR .RS 4 If the TCP/IP connection linking a DRBD device pair is idle for more than \fItime\fR seconds, DRBD will generate a keep\-alive packet to check if its partner is still alive\&. The default value is 10 seconds, the unit is 1 second\&. .RE .PP \fB\-t\fR, \fB\-\-timeout \fR\fB\fIval\fR\fR .RS 4 If the partner node fails to send an expected response packet within \fIval\fR tenths of a second, the partner node is considered dead and therefore the TCP/IP connection is abandoned\&. The default value is 60 (= 6 seconds)\&. .RE .PP \fB\-S\fR, \fB\-\-sndbuf\-size \fR\fB\fIsize\fR\fR .RS 4 The socket send buffer is used to store packets sent to the secondary node, which are not yet acknowledged (from a network point of view) by the secondary node\&. When using protocol A, it might be necessary to increase the size of this data structure in order to increase asynchronicity between primary and secondary nodes\&. But keep in mind that more asynchronicity is synonymous with more data loss in the case of a primary node failure\&. Since 8\&.0\&.13 resp\&. 8\&.2\&.7 setting the \fIsize\fR value to 0 means that the kernel should autotune this\&. The default \fIsize\fR is 0, i\&.e\&. autotune\&. .RE .PP \fB\-r\fR, \fB\-\-rcvbuf\-size \fR\fB\fIsize\fR\fR .RS 4 Packets received from the network are stored in the socket receive buffer first\&. From there they are consumed by DRBD\&. Before 8\&.3\&.2 the receive buffer\'s size was always set to the size of the socket send buffer\&. Since 8\&.3\&.2 they can be tuned independently\&. A value of 0 means that the kernel should autotune this\&. The default \fIsize\fR is 0, i\&.e\&. autotune\&. .RE .PP \fB\-k\fR, \fB\-\-ko\-count \fR\fB\fIcount\fR\fR .RS 4 In case the secondary node fails to complete a single write request for \fIcount\fR times the \fItimeout\fR, it is expelled from the cluster, i\&.e\&. the primary node goes into StandAlone mode\&. To disable this feature, you should explicitly set it to 0; defaults may change between versions\&. .RE .PP \fB\-e\fR, \fB\-\-max\-epoch\-size \fR\fB\fIval\fR\fR .RS 4 With this option the maximal number of write requests between two barriers is limited\&. Typically set to the same as \fB\-\-max\-buffers\fR, or the allowed maximum\&. Values smaller than 10 can lead to degraded performance\&. The default value is 2048\&. .RE .PP \fB\-b\fR, \fB\-\-max\-buffers \fR\fB\fIval\fR\fR .RS 4 With this option the maximal number of buffer pages allocated by DRBD\'s receiver thread is limited\&. Typically set to the same as \fB\-\-max\-epoch\-size\fR\&. Small values could lead to degraded performance\&. The default value is 2048, the minimum 32\&. Increase this if you cannot saturate the IO backend of the receiving side during linear write or during resync while otherwise idle\&. .sp See also \fBdrbd.conf\fR(5) .RE .PP \fB\-u\fR, \fB\-\-unplug\-watermark \fR\fB\fIval\fR\fR .RS 4 This setting has no effect with recent kernels that use explicit on\-stack plugging (upstream Linux kernel 2\&.6\&.39, distributions may have backported)\&. .sp When the number of pending write requests on the standby (secondary) node exceeds the unplug\-watermark, we trigger the request processing of our backing storage device\&. Some storage controllers deliver better performance with small values, others deliver best performance when the value is set to the same value as max\-buffers, yet others don\'t feel much effect at all\&. Minimum 16, default 128, maximum 131072\&. .RE .PP \fB\-m\fR, \fB\-\-allow\-two\-primaries \fR .RS 4 With this option set you may assign primary role to both nodes\&. You only should use this option if you use a shared storage file system on top of DRBD\&. At the time of writing the only ones are: OCFS2 and GFS\&. If you use this option with any other file system, you are going to crash your nodes and to corrupt your data! .RE .PP \fB\-a\fR, \fB\-\-cram\-hmac\-alg \fR\fIalg\fR .RS 4 You need to specify the HMAC algorithm to enable peer authentication at all\&. You are strongly encouraged to use peer authentication\&. The HMAC algorithm will be used for the challenge response authentication of the peer\&. You may specify any digest algorithm that is named in /proc/crypto\&. .RE .PP \fB\-x\fR, \fB\-\-shared\-secret \fR\fIsecret\fR .RS 4 The shared secret used in peer authentication\&. May be up to 64 characters\&. .RE .PP \fB\-A\fR, \fB\-\-after\-sb\-0pri \fR\fIasb\-0p\-policy\fR .RS 4 possible policies are: .PP \fBdisconnect\fR .RS 4 No automatic resynchronization, simply disconnect\&. .RE .PP \fBdiscard\-younger\-primary\fR .RS 4 Auto sync from the node that was primary before the split\-brain situation occurred\&. .RE .PP \fBdiscard\-older\-primary\fR .RS 4 Auto sync from the node that became primary as second during the split\-brain situation\&. .RE .PP \fBdiscard\-zero\-changes\fR .RS 4 In case one node did not write anything since the split brain became evident, sync from the node that wrote something to the node that did not write anything\&. In case none wrote anything this policy uses a random decision to perform a "resync" of 0 blocks\&. In case both have written something this policy disconnects the nodes\&. .RE .PP \fBdiscard\-least\-changes\fR .RS 4 Auto sync from the node that touched more blocks during the split brain situation\&. .RE .PP \fBdiscard\-node\-NODENAME\fR .RS 4 Auto sync to the named node\&. .RE .RE .PP \fB\-B\fR, \fB\-\-after\-sb\-1pri \fR\fIasb\-1p\-policy\fR .RS 4 possible policies are: .PP \fBdisconnect\fR .RS 4 No automatic resynchronization, simply disconnect\&. .RE .PP \fBconsensus\fR .RS 4 Discard the version of the secondary if the outcome of the \fBafter\-sb\-0pri\fR algorithm would also destroy the current secondary\'s data\&. Otherwise disconnect\&. .RE .PP \fBdiscard\-secondary\fR .RS 4 Discard the secondary\'s version\&. .RE .PP \fBcall\-pri\-lost\-after\-sb\fR .RS 4 Always honor the outcome of the \fBafter\-sb\-0pri \fR algorithm\&. In case it decides the current secondary has the correct data, call the \fBpri\-lost\-after\-sb\fR on the current primary\&. .RE .PP \fBviolently\-as0p\fR .RS 4 Always honor the outcome of the \fBafter\-sb\-0pri \fR algorithm\&. In case it decides the current secondary has the correct data, accept a possible instantaneous change of the primary\'s data\&. .RE .RE .PP \fB\-C\fR, \fB\-\-after\-sb\-2pri \fR\fIasb\-2p\-policy\fR .RS 4 possible policies are: .PP \fBdisconnect\fR .RS 4 No automatic resynchronization, simply disconnect\&. .RE .PP \fBcall\-pri\-lost\-after\-sb\fR .RS 4 Always honor the outcome of the \fBafter\-sb\-0pri \fR algorithm\&. In case it decides the current secondary has the right data, call the \fBpri\-lost\-after\-sb\fR on the current primary\&. .RE .PP \fBviolently\-as0p\fR .RS 4 Always honor the outcome of the \fBafter\-sb\-0pri \fR algorithm\&. In case it decides the current secondary has the right data, accept a possible instantaneous change of the primary\'s data\&. .RE .RE .PP \fB\-P\fR, \fB\-\-always\-asbp\fR .RS 4 Normally the automatic after\-split\-brain policies are only used if current states of the UUIDs do not indicate the presence of a third node\&. .sp With this option you request that the automatic after\-split\-brain policies are used as long as the data sets of the nodes are somehow related\&. This might cause a full sync, if the UUIDs indicate the presence of a third node\&. (Or double faults have led to strange UUID sets\&.) .RE .PP \fB\-R\fR, \fB\-\-rr\-conflict \fR\fIrole\-resync\-conflict\-policy\fR .RS 4 This option sets DRBD\'s behavior when DRBD deduces from its meta data that a resynchronization is needed, and the SyncTarget node is already primary\&. The possible settings are: \fBdisconnect\fR, \fBcall\-pri\-lost\fR and \fBviolently\fR\&. While \fBdisconnect\fR speaks for itself, with the \fBcall\-pri\-lost\fR setting the \fBpri\-lost\fR handler is called which is expected to either change the role of the node to secondary, or remove the node from the cluster\&. The default is \fBdisconnect\fR\&. .sp With the \fBviolently\fR setting you allow DRBD to force a primary node into SyncTarget state\&. This means that the data exposed by DRBD changes to the SyncSource\'s version of the data instantaneously\&. USE THIS OPTION ONLY IF YOU KNOW WHAT YOU ARE DOING\&. .RE .PP \fB\-d\fR, \fB\-\-data\-integrity\-alg \fR\fIhash_alg\fR .RS 4 DRBD can ensure the data integrity of the user\'s data on the network by comparing hash values\&. Normally this is ensured by the 16 bit checksums in the headers of TCP/IP packets\&. This option can be set to any of the kernel\'s data digest algorithms\&. In a typical kernel configuration you should have at least one of \fBmd5\fR, \fBsha1\fR, and \fBcrc32c\fR available\&. By default this is not enabled\&. .sp See also the notes on data integrity on the drbd\&.conf manpage\&. .RE .PP \fB\-o\fR, \fB\-\-no\-tcp\-cork \fR .RS 4 DRBD usually uses the TCP socket option TCP_CORK to hint to the network stack when it can expect more data, and when it should flush out what it has in its send queue\&. There is at least one network stack that performs worse when one uses this hinting method\&. Therefore we introduced this option, which disable the setting and clearing of the TCP_CORK socket option by DRBD\&. .RE .PP \fB\-p\fR, \fB\-\-ping\-timeout \fR\fIping_timeout\fR .RS 4 The time the peer has to answer to a keep\-alive packet\&. In case the peer\'s reply is not received within this time period, it is considered dead\&. The default unit is tenths of a second, the default value is 5 (for half a second)\&. .RE .PP \fB\-D\fR, \fB\-\-discard\-my\-data \fR .RS 4 Use this option to manually recover from a split\-brain situation\&. In case you do not have any automatic after\-split\-brain policies selected, the nodes refuse to connect\&. By passing this option you make this node a sync target immediately after successful connect\&. .RE .PP \fB\-n\fR, \fB\-\-dry\-run \fR .RS 4 Causes DRBD to abort the connection process after the resync handshake, i\&.e\&. no resync gets performed\&. You can find out which resync DRBD would perform by looking at the kernel\'s log file\&. .RE .PP \fB\-g\fR, \fB\-\-on\-congestion \fR\fIcongestion_policy\fR, \fB\-f\fR, \fB\-\-congestion\-fill \fR\fIfill_threshold\fR, \fB\-h\fR, \fB\-\-congestion\-extents \fR\fIactive_extents_threshold\fR .RS 4 By default DRBD blocks when the available TCP send queue becomes full\&. That means it will slow down the application that generates the write requests that cause DRBD to send more data down that TCP connection\&. .sp When DRBD is deployed with DRBD\-proxy it might be more desirable that DRBD goes into AHEAD/BEHIND mode shortly before the send queue becomes full\&. In AHEAD/BEHIND mode DRBD does no longer replicate data, but still keeps the connection open\&. .sp The advantage of the AHEAD/BEHIND mode is that the application is not slowed down, even if DRBD\-proxy\'s buffer is not sufficient to buffer all write requests\&. The downside is that the peer node falls behind, and that a resync will be necessary to bring it back into sync\&. During that resync the peer node will have an inconsistent disk\&. .sp Available \fIcongestion_policy\fRs are \fBblock\fR and \fBpull\-ahead\fR\&. The default is \fBblock\fR\&. \fIFill_threshold\fR might be in the range of 0 to 10GiBytes\&. The default is 0 which disables the check\&. \fIActive_extents_threshold\fR has the same limits as \fBal\-extents\fR\&. .sp The AHEAD/BEHIND mode and its settings are available since DRBD 8\&.3\&.10\&. .RE .SS "syncer" .\" drbdsetup: syncer .PP Changes the synchronization daemon parameters of \fIdevice\fR at runtime\&. .PP \fB\-r\fR, \fB\-\-rate \fR\fB\fIrate\fR\fR .RS 4 To ensure smooth operation of the application on top of DRBD, it is possible to limit the bandwidth that may be used by background synchronization\&. The default is 250 KiB/sec, the default unit is KiB/sec\&. .RE .PP \fB\-a\fR, \fB\-\-after \fR\fB\fIminor\fR\fR .RS 4 Start resync on this device only if the device with \fIminor\fR is already in connected state\&. Otherwise this device waits in SyncPause state\&. .RE .PP \fB\-e\fR, \fB\-\-al\-extents \fR\fB\fIextents\fR\fR .RS 4 DRBD automatically performs hot area detection\&. With this parameter you control how big the hot area (=active set) can get\&. Each extent marks 4M of the backing storage\&. In case a primary node leaves the cluster unexpectedly, the areas covered by the active set must be resynced upon rejoining of the failed node\&. The data structure is stored in the meta\-data area, therefore each change of the active set is a write operation to the meta\-data device\&. A higher number of extents gives longer resync times but less updates to the meta\-data\&. The default number of \fIextents\fR is 127\&. (Minimum: 7, Maximum: 3843) .RE .PP \fB\-v\fR, \fB\-\-verify\-alg \fR\fB\fIhash\-alg\fR\fR .RS 4 During online verification (as initiated by the \fBverify\fR sub\-command), rather than doing a bit\-wise comparison, DRBD applies a hash function to the contents of every block being verified, and compares that hash with the peer\&. This option defines the hash algorithm being used for that purpose\&. It can be set to any of the kernel\'s data digest algorithms\&. In a typical kernel configuration you should have at least one of \fBmd5\fR, \fBsha1\fR, and \fBcrc32c\fR available\&. By default this is not enabled; you must set this option explicitly in order to be able to use on\-line device verification\&. .sp See also the notes on data integrity on the drbd\&.conf manpage\&. .RE .PP \fB\-c\fR, \fB\-\-cpu\-mask \fR\fB\fIcpu\-mask\fR\fR .RS 4 Sets the cpu\-affinity\-mask for DRBD\'s kernel threads of this device\&. The default value of \fIcpu\-mask\fR is 0, which means that DRBD\'s kernel threads should be spread over all CPUs of the machine\&. This value must be given in hexadecimal notation\&. If it is too big it will be truncated\&. .RE .PP \fB\-C\fR, \fB\-\-csums\-alg \fR\fB\fIhash\-alg\fR\fR .RS 4 A resync process sends all marked data blocks form the source to the destination node, as long as no \fBcsums\-alg\fR is given\&. When one is specified the resync process exchanges hash values of all marked blocks first, and sends only those data blocks over, that have different hash values\&. .sp This setting is useful for DRBD setups with low bandwidth links\&. During the restart of a crashed primary node, all blocks covered by the activity log are marked for resync\&. But a large part of those will actually be still in sync, therefore using \fBcsums\-alg\fR will lower the required bandwidth in exchange for CPU cycles\&. .RE .PP \fB\-R\fR, \fB\-\-use\-rle\fR .RS 4 During resync\-handshake, the dirty\-bitmaps of the nodes are exchanged and merged (using bit\-or), so the nodes will have the same understanding of which blocks are dirty\&. On large devices, the fine grained dirty\-bitmap can become large as well, and the bitmap exchange can take quite some time on low\-bandwidth links\&. .sp Because the bitmap typically contains compact areas where all bits are unset (clean) or set (dirty), a simple run\-length encoding scheme can considerably reduce the network traffic necessary for the bitmap exchange\&. .sp For backward compatibilty reasons, and because on fast links this possibly does not improve transfer time but consumes cpu cycles, this defaults to off\&. .sp Introduced in 8\&.3\&.2\&. .RE .PP \fB\-p\fR, \fB\-\-c\-plan\-ahead \fR\fB\fIplan_time\fR\fR, \fB\-s\fR, \fB\-\-c\-fill\-target \fR\fB\fIfill_target\fR\fR, \fB\-d\fR, \fB\-\-c\-delay\-target \fR\fB\fIdelay_target\fR\fR, \fB\-M\fR, \fB\-\-c\-max\-rate \fR\fB\fImax_rate\fR\fR .RS 4 The dynamic resync speed controller gets enabled with setting \fIplan_time\fR to a positive value\&. It aims to fill the buffers along the data path with either a constant amount of data \fIfill_target\fR, or aims to have a constant delay time of \fIdelay_target\fR along the path\&. The controller has an upper bound of \fImax_rate\fR\&. .sp By \fIplan_time\fR the agility of the controller is configured\&. Higher values yield for slower/lower responses of the controller to deviation from the target value\&. It should be at least 5 times RTT\&. For regular data paths a \fIfill_target\fR in the area of 4k to 100k is appropriate\&. For a setup that contains drbd\-proxy it is advisable to use \fIdelay_target\fR instead\&. Only when \fIfill_target\fR is set to 0 the controller will use \fIdelay_target\fR\&. 5 times RTT is a reasonable starting value\&. \fIMax_rate\fR should be set to the bandwidth available between the DRBD\-hosts and the machines hosting DRBD\-proxy, or to the available disk\-bandwidth\&. .sp The default value of \fIplan_time\fR is 0, the default unit is 0\&.1 seconds\&. \fIFill_target\fR has 0 and sectors as default unit\&. \fIDelay_target\fR has 1 (100ms) and 0\&.1 as default unit\&. \fIMax_rate\fR has 10240 (100MiB/s) and KiB/s as default unit\&. .RE .PP \fB\-m\fR, \fB\-\-c\-min\-rate \fR\fB\fImin_rate\fR\fR .RS 4 We track the disk IO rate caused by the resync, so we can detect non\-resync IO on the lower level device\&. If the lower level device seems to be busy, and the current resync rate is above \fImin_rate\fR, we throttle the resync\&. .sp The default value of \fImin_rate\fR is 4M, the default unit is k\&. If you want to not throttle at all, set it to zero, if you want to throttle always, set it to one\&. .RE .PP \fB\-n\fR, \fB\-\-on\-no\-data\-accessible \fR\fB\fIond\-policy\fR\fR .RS 4 This setting controls what happens to IO requests on a degraded, disk less node (I\&.e\&. no data store is reachable)\&. The available policies are \fBio\-error\fR and \fBsuspend\-io\fR\&. .sp If \fIond\-policy\fR is set to \fBsuspend\-io\fR you can either resume IO by attaching/connecting the last lost data storage, or by the \fBdrbdadm resume\-io \fR\fB\fIres\fR\fR command\&. The latter will result in IO errors of course\&. .sp The default is \fBio\-error\fR\&. This setting is available since DRBD 8\&.3\&.9\&. .RE .SS "primary" .\" drbdsetup: primary .PP Sets the \fIdevice\fR into primary role\&. This means that applications (e\&.g\&. a file system) may open the \fIdevice\fR for read and write access\&. Data written to the \fIdevice\fR in primary role are mirrored to the device in secondary role\&. .PP Normally it is not possible to set both devices of a connected DRBD device pair to primary role\&. By using the \fB\-\-allow\-two\-primaries\fR option, you override this behavior and instruct DRBD to allow two primaries\&. .PP \fB\-o\fR, \fB\-\-overwrite\-data\-of\-peer\fR .RS 4 Alias for \-\-force\&. .RE .PP \fB\-f\fR, \fB\-\-force\fR .RS 4 Becoming primary fails if the local replica is not up\-to\-date\&. I\&.e\&. when it is inconsistent, outdated of consistent\&. By using this option you can force it into primary role anyway\&. USE THIS OPTION ONLY IF YOU KNOW WHAT YOU ARE DOING\&. .RE .SS "secondary" .\" drbdsetup: secondary .PP Brings the \fIdevice\fR into secondary role\&. This operation fails as long as at least one application (or file system) has opened the device\&. .PP It is possible that both devices of a connected DRBD device pair are secondary\&. .SS "verify" .\" drbdsetup: verify .PP This initiates on\-line device verification\&. During on\-line verification, the contents of every block on the local node are compared to those on the peer node\&. Device verification progress can be monitored via /proc/drbd\&. Any blocks whose content differs from that of the corresponding block on the peer node will be marked out\-of\-sync in DRBD\'s on\-disk bitmap; they are \fInot\fR brought back in sync automatically\&. To do that, simply disconnect and reconnect the resource\&. .PP If on\-line verification is already in progress (and this node is "VerifyS"), this command silently "succeeds"\&. In this case, any start\-sector (see below) will be ignored, and any stop\-sector (see below) will be honored\&. This can be used to stop a running verify, or to update/shorten/extend the coverage of the currently running verify\&. .PP This command will fail if the \fIdevice\fR is not part of a connected device pair\&. .PP See also the notes on data integrity on the drbd\&.conf manpage\&. .PP \fB\-s\fR, \fB\-\-start \fR\fB\fIstart\-sector\fR\fR .RS 4 Since version 8\&.3\&.2, on\-line verification should resume from the last position after connection loss\&. It may also be started from an arbitrary position by setting this option\&. If you had reached some stop\-sector before, and you do not specify an explicit start\-sector, verify should resume from the previous stop\-sector\&. .sp Default unit is sectors\&. You may also specify a unit explicitly\&. The \fBstart\-sector\fR will be rounded down to a multiple of 8 sectors (4kB)\&. .RE .PP \fB\-S\fR, \fB\-\-stop \fR\fB\fIstop\-sector\fR\fR .RS 4 Since version 8\&.3\&.14, on\-line verification can be stopped before it reaches end\-of\-device\&. This can be .sp Default unit is sectors\&. You may also specify a unit explicitly\&. The \fBstop\-sector\fR may be updated by issuing an additional drbdsetup verify command on the same node while the verify is running\&. .RE .SS "invalidate" .\" drbdsetup: invalidate .PP This forces the local device of a pair of connected DRBD devices into SyncTarget state, which means that all data blocks of the device are copied over from the peer\&. .PP This command will fail if the \fIdevice\fR is not either part of a connected device pair, or disconnected Secondary\&. .SS "invalidate\-remote" .\" drbdsetup: invalidate-remote .PP This forces the local device of a pair of connected DRBD devices into SyncSource state, which means that all data blocks of the device are copied to the peer\&. .PP On a disconnected Primary device, this will set all bits in the out of sync bitmap\&. As a side affect this suspends updates to the on disk activity log\&. Updates to the on disk activity log resume automatically when necessary\&. .SS "wait\-connect" .\" drbdsetup: wait-connect .PP Returns as soon as the \fIdevice\fR can communicate with its partner device\&. .PP \fB\-t\fR, \fB\-\-wfc\-timeout \fR\fB\fIwfc_timeout\fR\fR, \fB\-d\fR, \fB\-\-degr\-wfc\-timeout \fR\fB\fIdegr_wfc_timeout\fR\fR, \fB\-o\fR, \fB\-\-outdated\-wfc\-timeout \fR\fB\fIoutdated_wfc_timeout\fR\fR, \fB\-w\fR, \fB\-\-wait\-after\-sb\fR .RS 4 This command will fail if the \fIdevice\fR cannot communicate with its partner for \fItimeout\fR seconds\&. If the peer was working before this node was rebooted, the \fIwfc_timeout\fR is used\&. If the peer was already down before this node was rebooted, the \fIdegr_wfc_timeout\fR is used\&. If the peer was sucessfully outdated before this node was rebooted the \fIoutdated_wfc_timeout\fR is used\&. The default value for all those timeout values is 0 which means to wait forever\&. In case the connection status goes down to StandAlone because the peer appeared but the devices had a split brain situation, the default for the command is to terminate\&. You can change this behavior with the \fB\-\-wait\-after\-sb\fR option\&. .RE .SS "wait\-sync" .\" drbdsetup: wait-sync .PP Returns as soon as the \fIdevice\fR leaves any synchronization into connected state\&. The options are the same as with the \fIwait\-connect\fR command\&. .SS "disconnect" .\" drbdsetup: disconnect .PP Removes the information set by the \fBnet\fR command from the \fIdevice\fR\&. This means that the \fIdevice\fR goes into unconnected state and will no longer listen for incoming connections\&. .SS "detach" .\" drbdsetup: detach .PP Removes the information set by the \fBdisk\fR command from the \fIdevice\fR\&. This means that the \fIdevice\fR is detached from its backing storage device\&. .PP \fB\-f\fR, \fB\-\-force\fR .RS 4 A regular detach returns after the disk state finally reached diskless\&. As a consequence detaching from a frozen backing block device never terminates\&. .sp On the other hand A forced detach returns immediately\&. It allows you to detach DRBD from a frozen backing block device\&. Please note that the disk will be marked as failed until all pending IO requests where finished by the backing block device\&. .RE .SS "down" .\" drbdsetup: down .PP Removes all configuration information from the \fIdevice\fR and forces it back to unconfigured state\&. .SS "role" .\" drbdsetup: role .PP Shows the current roles of the \fIdevice\fR and its peer, as \fIlocal\fR/\fIpeer\fR\&. .SS "state" .\" drbdsetup: state .PP Deprecated alias for "role" .SS "cstate" .\" drbdsetup: cstate .PP Shows the current connection state of the \fIdevice\fR\&. .SS "dstate" .\" drbdsetup: dstate .PP Shows the current states of the backing storage devices, as \fIlocal\fR/\fIpeer\fR\&. .SS "status" .\" drbdsetup: status .PP Shows the current status of the device in XML\-like format\&. Example output: .sp .if n \{\ .RS 4 .\} .nf .fi .if n \{\ .RE .\} .sp .SS "resize" .\" drbdsetup: resize .PP This causes DRBD to reexamine the size of the \fIdevice\fR\'s backing storage device\&. To actually do online growing you need to extend the backing storages on both devices and call the \fBresize\fR command on one of your nodes\&. .PP The \fB\-\-assume\-peer\-has\-space\fR allows you to resize a device which is currently not connected to the peer\&. Use with care, since if you do not resize the peer\'s disk as well, further connect attempts of the two will fail\&. .PP When the \fB\-\-assume\-clean\fR option is given DRBD will skip the resync of the new storage\&. Only do this if you know that the new storage was initialized to the same content by other means\&. .SS "check\-resize" .\" drbdsetup: check-resize .PP To enable DRBD to detect offline resizing of backing devices this command may be used to record the current size of backing devices\&. The size is stored in files in /var/lib/drbd/ named drbd\-minor\-??\&.lkbd .PP This command is called by \fBdrbdadm resize \fR\fB\fIres\fR\fR after \fBdrbdsetup \fR\fB\fIdevice\fR\fR\fB resize\fR returned\&. .SS "pause\-sync" .\" drbdsetup: pause-sync .PP Temporarily suspend an ongoing resynchronization by setting the local pause flag\&. Resync only progresses if neither the local nor the remote pause flag is set\&. It might be desirable to postpone DRBD\'s resynchronization after eventual resynchronization of the backing storage\'s RAID setup\&. .SS "resume\-sync" .\" drbdsetup: resume-sync .PP Unset the local sync pause flag\&. .SS "outdate" .\" drbdsetup: outdate .PP Mark the data on the local backing storage as outdated\&. An outdated device refuses to become primary\&. This is used in conjunction with \fBfencing\fR and by the peer\'s \fBfence\-peer\fR handler\&. .SS "show\-gi" .\" drbdsetup: show-gi .PP Displays the device\'s data generation identifiers verbosely\&. .SS "get\-gi" .\" drbdsetup: get-gi .PP Displays the device\'s data generation identifiers\&. .SS "show" .\" drbdsetup: show .PP Shows all available configuration information of the \fIdevice\fR\&. .SS "suspend\-io" .\" drbdsetup: suspend-io .PP This command is of no apparent use and just provided for the sake of completeness\&. .SS "resume\-io" .\" drbdsetup: resume-io .PP If the fence\-peer handler fails to stonith the peer node, and your \fBfencing\fR policy is set to resource\-and\-stonith, you can unfreeze IO operations with this command\&. .SS "events" .\" drbdsetup: events .PP Displays every state change of DRBD and all calls to helper programs\&. This might be used to get notified of DRBD\'s state changes by piping the output to another program\&. .PP \fB\-a\fR, \fB\-\-all\-devices\fR .RS 4 Display the events of all DRBD minors\&. .RE .PP \fB\-u\fR, \fB\-\-unfiltered\fR .RS 4 This is a debugging aid that displays the content of all received netlink messages\&. .RE .SS "new\-current\-uuid" .\" drbdsetup: new-current-uuid .PP Generates a new current UUID and rotates all other UUID values\&. This has at least two use cases, namely to skip the initial sync, and to reduce network bandwidth when starting in a single node configuration and then later (re\-)integrating a remote site\&. .PP Available option: .PP \fB\-c\fR, \fB\-\-clear\-bitmap\fR .RS 4 Clears the sync bitmap in addition to generating a new current UUID\&. .RE .PP This can be used to skip the initial sync, if you want to start from scratch\&. This use\-case does only work on "Just Created" meta data\&. Necessary steps: .sp .RS 4 .ie n \{\ \h'-04' 1.\h'+01'\c .\} .el \{\ .sp -1 .IP " 1." 4.2 .\} On \fIboth\fR nodes, initialize meta data and configure the device\&. .sp \fBdrbdadm \-\- \-\-force create\-md \fR\fB\fIres\fR\fR .RE .sp .RS 4 .ie n \{\ \h'-04' 2.\h'+01'\c .\} .el \{\ .sp -1 .IP " 2." 4.2 .\} They need to do the initial handshake, so they know their sizes\&. .sp \fBdrbdadm up \fR\fB\fIres\fR\fR .RE .sp .RS 4 .ie n \{\ \h'-04' 3.\h'+01'\c .\} .el \{\ .sp -1 .IP " 3." 4.2 .\} They are now Connected Secondary/Secondary Inconsistent/Inconsistent\&. Generate a new current\-uuid and clear the dirty bitmap\&. .sp \fBdrbdadm \-\- \-\-clear\-bitmap new\-current\-uuid \fR\fB\fIres\fR\fR .RE .sp .RS 4 .ie n \{\ \h'-04' 4.\h'+01'\c .\} .el \{\ .sp -1 .IP " 4." 4.2 .\} They are now Connected Secondary/Secondary UpToDate/UpToDate\&. Make one side primary and create a file system\&. .sp \fBdrbdadm primary \fR\fB\fIres\fR\fR .sp \fBmkfs \-t \fR\fB\fIfs\-type\fR\fR\fB $(drbdadm sh\-dev \fR\fB\fIres\fR\fR\fB)\fR .RE .sp .RE .PP One obvious side\-effect is that the replica is full of old garbage (unless you made them identical using other means), so any online\-verify is expected to find any number of out\-of\-sync blocks\&. .PP \fIYou must not use this on pre\-existing data!\fR Even though it may appear to work at first glance, once you switch to the other node, your data is toast, as it never got replicated\&. So \fIdo not leave out the mkfs\fR (or equivalent)\&. .PP This can also be used to shorten the initial resync of a cluster where the second node is added after the first node is gone into production, by means of disk shipping\&. This use\-case works on disconnected devices only, the device may be in primary or secondary role\&. .PP The necessary steps on the current active server are: .sp .RS 4 .ie n \{\ \h'-04' 1.\h'+01'\c .\} .el \{\ .sp -1 .IP " 1." 4.2 .\} \fBdrbdsetup \fR\fB\fIdevice\fR\fR\fB new\-current\-uuid \-\-clear\-bitmap\fR .RE .sp .RS 4 .ie n \{\ \h'-04' 2.\h'+01'\c .\} .el \{\ .sp -1 .IP " 2." 4.2 .\} Take the copy of the current active server\&. E\&.g\&. by pulling a disk out of the RAID1 controller, or by copying with dd\&. You need to copy the actual data, and the meta data\&. .RE .sp .RS 4 .ie n \{\ \h'-04' 3.\h'+01'\c .\} .el \{\ .sp -1 .IP " 3." 4.2 .\} \fBdrbdsetup \fR\fB\fIdevice\fR\fR\fB new\-current\-uuid\fR .RE .sp .RE Now add the disk to the new secondary node, and join it to the cluster\&. You will get a resync of that parts that were changed since the first call to \fBdrbdsetup\fR in step 1\&. .SH "EXAMPLES" .PP For examples, please have a look at the \m[blue]\fBDRBD User\'s Guide\fR\m[]\&\s-2\u[1]\d\s+2\&. .SH "VERSION" .sp This document was revised for version 8\&.3\&.2 of the DRBD distribution\&. .SH "AUTHOR" .sp Written by Philipp Reisner philipp\&.reisner@linbit\&.com and Lars Ellenberg lars\&.ellenberg@linbit\&.com .SH "REPORTING BUGS" .sp Report bugs to drbd\-user@lists\&.linbit\&.com\&. .SH "COPYRIGHT" .sp Copyright 2001\-2008 LINBIT Information Technologies, Philipp Reisner, Lars Ellenberg\&. This is free software; see the source for copying conditions\&. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE\&. .SH "SEE ALSO" .PP \fBdrbd.conf\fR(5), \fBdrbd\fR(8), \fBdrbddisk\fR(8), \fBdrbdadm\fR(8), \m[blue]\fBDRBD User\'s Guide\fR\m[]\&\s-2\u[1]\d\s+2, \m[blue]\fBDRBD web site\fR\m[]\&\s-2\u[2]\d\s+2 .SH "NOTES" .IP " 1." 4 DRBD User's Guide .RS 4 \%http://www.drbd.org/users-guide/ .RE .IP " 2." 4 DRBD web site .RS 4 \%http://www.drbd.org/ .RE drbd-utils-8.9.6/documentation/v83/drbdadm.xml0000644000175000017500000005132612466702073021131 0ustar apoikosapoikos 5 Dec 2008 DRBD 8.3.2 drbdadm 8 System Administration drbdadm Administration tool for DRBD drbdadm drbdadm -d -cfile -tfile -scmd -mcmd -S -hhost --backend-options command all resource Description is the high level tool of the DRBD program suite. is to and what / is to . reads its configuration file and performs the specified commands by calling the and/or the program. Options , Just prints the calls of to stdout, but does not run the commands. , file Specifies the configuration file drbdadm will use. If this parameter is not specified, drbdadm will look for , and . , file Specifies an additional configuration file drbdadm to check. This option is only allowed with the dump and the sh-nop commands. , file Specifies the full path to the program. If this option is omitted, drbdadm will look for and . , file Specifies the full path to the program. If this option is omitted, drbdadm will look for and . , Specifies that this command should be performed on a stacked resource. , Specifies to which peer node to connect. Only necessary if there are more than two host sections in the resource you are working on. backend-options All options following the doubly hyphen are considered backend-options. These are passed through to the backend command. I.e. to , or . Commands attach Attaches a local backing block device to the DRBD resource's device. detach drbdadmdetach Removes the backing storage device from a DRBD resource's device. connect drbdadmconnect Sets up the network configuration of the resource's device. If the peer device is already configured, the two DRBD devices will connect. If there are more than two host sections in the resource you need to use the option to select the peer you want to connect to. disconnect drbdadmdisconnect Removes the network configuration from the resource. The device will then go into StandAlone state. syncer drbdadmsyncer Loads the resynchronization parameters into the device. up drbdadmup Is a shortcut for attach and connect. down drbdadmdown Is a shortcut for disconnect and detach. primary drbdadmprimary Promote the resource's device into primary role. You need to do this before any access to the device, such as creating or mounting a file system. secondary drbdadmsecondary Brings the device back into secondary role. This is needed since in a connected DRBD device pair, only one of the two peers may have primary role (except if is explicitly set in the configuration file). invalidate drbdadminvalidate Forces DRBD to consider the data on the local backing storage device as out-of-sync. Therefore DRBD will copy each and every block from its peer, to bring the local storage device back in sync. To avoid races, you need an established replication link, or be disconnected Secondary. invalidate-remote drbdadminvalidate-remote This command is similar to the invalidate command, however, the peer's backing storage is invalidated and hence rewritten with the data of the local node. To avoid races, you need an established replication link, or be disconnected Primary. resize drbdadmresize Causes DRBD to re-examine all sizing constraints, and resize the resource's device accordingly. For example, if you increased the size of your backing storage devices (on both nodes, of course), then DRBD will adopt the new size after you called this command on one of your nodes. Since new storage space must be synchronised this command only works if there is at least one primary node present. The allows you to resize a device which is currently not connected to the peer. Use with care, since if you do not resize the peer's disk as well, further connect attempts of the two will fail. The allows you to resize an existing device and avoid syncing the new space. This is useful when adding addtional blank storage to your device. Example: # drbdadm -- --assume-clean resize r0 check-resize drbdadmcheck-resize Calls drbdmeta to eventually move internal meta data. If the backing device was resized, while DRBD was not running, meta data has to be moved to the end of the device, so that the next command can succeed. create-md drbdadmcreate-md Initializes the meta data storage. This needs to be done before a DRBD resource can be taken online for the first time. In case of issues with that command have a look at drbdmeta8 get-gi drbdadmget-gi Shows a short textual representation of the data generation identifiers. show-gi drbdadmshow-gi Prints a textual representation of the data generation identifiers including explanatory information. dump-md drbdadmdump-md Dumps the whole contents of the meta data storage, including the stored bit-map and activity-log, in a textual representation. outdate drbdadmoutdate Sets the outdated flag in the meta data. adjust drbdadmadjust Synchronizes the configuration of the device with your configuration file. You should always examine the output of the dry-run mode before actually executing this command. wait-connect drbdadmwait-connect Waits until the device is connected to its peer device. role drbdadmrole Shows the current roles of the devices (local/peer). E.g. Primary/Secondary state drbdadmstate Deprecated alias for "role", see above. cstate drbdadmcstate Shows the current connection state of the devices. status drbdadmstatus Shows the current status of all devices defined in the current config file, in XML-like format. Example output: <drbd-status version="8.3.2" api="88"> <resources config_file="/etc/drbd.conf"> <resource minor="0" name="s0" cs="SyncTarget" st1="Secondary" st2="Secondary" ds1="Inconsistent" ds2="UpToDate" resynced_precent="5.9" /> <resource minor="1" name="s1" cs="WFConnection" st1="Secondary" st2="Unknown" ds1="Inconsistent" ds2="Outdated" /> <resource minor="3" name="dummy" cs="Unconfigured" /> <!-- resource minor="4" name="scratch" not available or not yet created --> </resources> </drbd-status> dump drbdadmdump Just parse the configuration file and dump it to stdout. May be used to check the configuration file for syntactic correctness. outdate drbdadmoutdate Used to mark the node's data as outdated. Usually used by the peer's fence-peer handler. verify drbdadmverify Starts online verify. During online verify, data on both nodes is compared for equality. See /proc/drbd for online verify progress. If out-of-sync blocks are found, they are not resynchronized automatically. To do that, disconnect and connect the resource when verification has completed. See also the notes on data integrity on the drbd.conf manpage. pause-sync drbdadmpause-sync Temporarily suspend an ongoing resynchronization by setting the local pause flag. Resync only progresses if neither the local nor the remote pause flag is set. It might be desirable to postpone DRBD's resynchronization until after any resynchronization of the backing storage's RAID setup. resume-sync drbdadmresume-sync Unset the local sync pause flag. new-current-uuid drbdadmnew-current-uuid Generates a new currend UUID and rotates all other UUID values. This can be used to shorten the initial resync of a cluster. See the manpage for a more details. dstate drbdadmdstate Show the current state of the backing storage devices. (local/peer) hidden-commands Shows all commands undocumented on purpose. Version This document was revised for version 8.3.2 of the DRBD distribution. Author Written by Philipp Reisner philipp.reisner@linbit.com and Lars Ellenberg lars.ellenberg@linbit.com Reporting Bugs Report bugs to drbd-user@lists.linbit.com. Copyright Copyright 2001-2008 LINBIT Information Technologies, Philipp Reisner, Lars Ellenberg. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See Also drbd.conf5, drbd8, drbddisk8, drbdsetup8, drbdmeta8 and the DRBD project web site drbd-utils-8.9.6/documentation/v83/drbdmeta.xml0000644000175000017500000002205312466702073021311 0ustar apoikosapoikos 15 Oct 2008 DRBD 8.3.2 drbdmeta 8 System Administration drbdmeta DRBD's meta data management tool drbdmeta drbdmeta --force --ignore-sanity-checks device v06 minor v07 meta_dev index v08 meta_dev index command cmd args Description Drbdmeta is used to create, display and modify the contents of DRBD's meta data storage. Usually you do not want to use this command directly, but start it via the frontend drbdadm8. This command only works if the DRBD resource is currently down, or at least detached from its backing storage. The first parameter is the device node associated to the resource. With the second parameter you can select the version of the meta data. Currently all major DRBD releases (0.6, 0.7 and 8) are supported. Options --force drbdmeta--force All questions that get asked by drbdmeta are treated as if the user answered 'yes'. --ignore-sanity-checks drbdmeta--ignore-sanity-checks Some sanity checks cause drbdmeta to terminate. E.g. if a file system image would get destroyed by creating the meta data. By using that option you can force drbdmeta to ignore these checks. Commands create-md drbdmetacreate-md Create-md initializes the meta data storage. This needs to be done before a DRBD resource can be taken online for the first time. In case there is already a meta data signature of an older format in place, drbdmeta will ask you if it should convert the older format to the selected format. If you will use the resource before it is connected to its peer for the first time DRBD may perform better if you use the option. For DRBD versions of the peer use up to these values: <8.3.7 -> 4k, 8.3.8 -> 32k, 8.3.9 -> 128k, 8.4.0 -> 1M. get-gi drbdmetaget-gi Get-gi shows a short textual representation of the data generation identifier. In version 0.6 and 0.7 these are generation counters, while in version 8 it is a set of UUIDs. show-gi drbdmetashow-gi Show-gi prints a textual representation of the data generation identifiers including explanatory information. dump-md drbdmetadump-md Dumps the whole contents of the meta data storage including the stored bit-map and activity-log in a textual representation. outdate drbdmetaoutdate Sets the outdated flag in the meta data. This is used by the peer node when it wants to become primary, but cannot communicate with the DRBD stack on this host. dstate drbdmetadstate Prints the state of the data on the backing storage. The output is always followed by '/DUnknown' since drbdmeta only looks at the local meta data. check-resize drbdmetacheck-resize Examines the device size of a backing device, and it's last known device size, recorded in a file /var/lib/drbd/drbd-minor-??.lkbd. In case the size of the backing device changed, and the meta data can be found at the old position, it moves the meta data to the right position at the end of the block device. Expert's commands Drbdmeta allows you to modify the meta data as well. This is intentionally omitted for the command's usage output, since you should only use it if you really know what you are doing. By setting the generation identifiers to wrong values, you risk to overwrite your up-to-data data with an older version of your data. set-gi gi drbdmetaset-gi Set-gi allows you to set the generation identifier. Gi needs to be a generation counter for the 0.6 and 0.7 format, and a UUID set for 8.x. Specify it in the same way as get-gi shows it. restore-md dump_file drbdmetarestore-md Reads the dump_file and writes it to the meta data. Version This document was revised for version 8.3.2 of the DRBD distribution. Author Written by Philipp Reisner philipp.reisner@linbit.com and Lars Ellenberg lars.ellenberg@linbit.com. Reporting Bugs Report bugs to drbd-user@lists.linbit.com. Copyright Copyright 2001-2008 LINBIT Information Technologies, Philipp Reisner, Lars Ellenberg. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See Also drbdadm 8 drbd-utils-8.9.6/documentation/v83/Makefile.in0000644000175000017500000000747612634271674021073 0ustar apoikosapoikos# Makefile in documentation directory # # This file is part of DRBD by Philipp Reisner and Lars Ellenberg. # # drbd is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # drbd is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with drbd; see the file COPYING. If not, write to # the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. # variables set by configure DISTRO = @DISTRO@ prefix = @prefix@ exec_prefix = @exec_prefix@ localstatedir = @localstatedir@ datarootdir = @datarootdir@ datadir = @datadir@ sbindir = @sbindir@ sysconfdir = @sysconfdir@ mandir = @mandir@ BASH_COMPLETION_SUFFIX = @BASH_COMPLETION_SUFFIX@ UDEV_RULE_SUFFIX = @UDEV_RULE_SUFFIX@ INITDIR = @INITDIR@ LIBDIR = @prefix@/lib/@PACKAGE_TARNAME@ CC = @CC@ CFLAGS = @CFLAGS@ XSLTPROC = @XSLTPROC@ # features enabled or disabled by configure WITH_83_SUPPORT = @WITH_83_SUPPORT@ WITH_UDEV = @WITH_UDEV@ WITH_XEN = @WITH_XEN@ WITH_PACEMAKER = @WITH_PACEMAKER@ WITH_HEARTBEAT = @WITH_HEARTBEAT@ WITH_RGMANAGER = @WITH_RGMANAGER@ WITH_BASHCOMPLETION = @WITH_BASHCOMPLETION@ # variables meant to be overridden from the make command line DESTDIR ?= / # Needed for pattern substitution SHELL=/bin/bash MANPAGES := drbdsetup.8 drbd.conf.5 drbd.8 drbdadm.8 drbdmeta.8 ifeq ($(WITH_HEARTBEAT),yes) MANPAGES += drbddisk.8 endif SOURCES := $(wildcard *.xml) STYLESHEET_PREFIX ?= http://docbook.sourceforge.net/release/xsl/current MANPAGES_STYLESHEET ?= $(STYLESHEET_PREFIX)/manpages/docbook.xsl HTML_STYLESHEET ?= $(STYLESHEET_PREFIX)/xhtml/docbook.xsl FO_STYLESHEET ?= $(STYLESHEET_PREFIX)/fo/docbook.xsl XSLTPROC_OPTIONS ?= --xinclude XSLTPROC_MANPAGES_OPTIONS ?= $(XSLTPROC_OPTIONS) XSLTPROC_HTML_OPTIONS ?= $(XSLTPROC_OPTIONS) XSLTPROC_FO_OPTIONS ?= $(XSLTPROC_OPTIONS) make_doc := $(shell $(XSLTPROC) \ $(XSLTPROC_MANPAGES_OPTIONS) \ $(MANPAGES_STYLESHEET) < /dev/null > /dev/null 2>&1 && echo doc ) ifeq ($(make_doc),doc) all: doc else all: @echo "To (re)make the documentation: make doc" endif clean: @echo "To clean the documentation: make doc-clean" ifeq ($(WITH_83_SUPPORT),yes) doc: man else doc: endif doc-clean: distclean ####### Implicit rules .SUFFIXES: .sgml .5 .8 .html .pdf .ps %.5 %.8: %.xml $(XSLTPROC) \ $(XSLTPROC_MANPAGES_OPTIONS) \ $(MANPAGES_STYLESHEET) $< %.html: %.xml $(XSLTPROC) -o $@ \ $(XSLTPROC_HTML_OPTIONS) \ $(HTML_STYLESHEET) $< %.fo: %.xml $(XSLTPROC) -o $@ \ $(XSLTPROC_FO_OPTIONS) \ $(FO_STYLESHEET) $< distclean: rm -f *.[58] manpage.links manpage.refs *~ manpage.log rm -f *.ps.gz *.pdf *.ps *.html pod2htm* ####### man: $(MANPAGES) install: ifeq ($(WITH_83_SUPPORT),yes) @ok=true; for f in $(MANPAGES) ; \ do [ -e $$f ] || { echo $$f missing ; ok=false; } ; \ done ; $$ok set -e; for f in $(MANPAGES) ; do \ s=$${f##*.}; \ b=$${f%.[0-9]}; \ install -v -D -m 644 $$f $(DESTDIR)$(mandir)/man$$s/$$b-8.3.$$s ; \ done endif uninstall: ifeq ($(WITH_83_SUPPORT),yes) @ set -e; for f in $(MANPAGES) ; do \ s=$${f##*.}; \ b=$${f%.[0-9]}; \ rm -v $(DESTDIR)$(mandir)/man$$s/$$b-8.3.$$s ; \ done endif html: $(SOURCES:.xml=.html) pdf: $(SOURCES:.xml=.pdf) ps: $(SOURCES:.xml=.ps) ../../configure: @echo "please (re-)run ./autogen.sh with appropriate arguments"; exit 1 ../../config.status: ../../configure @echo "please (re-)run ./configure with appropriate arguments"; exit 1 Makefile.in: ; Makefile: Makefile.in ../../config.status cd ../.. && ./config.status documentation/v83/Makefile drbd-utils-8.9.6/documentation/v83/drbd.xml0000644000175000017500000000670212466702073020445 0ustar apoikosapoikos drbd The start and stop script for DRBD DRBD 8.3.2 15 Oct 2008 drbd 8 System Administration /etc/init.d/drbd resource start stop status reload restart force-reload Introduction The script is used to start and stop drbd on a system V style init system. In order to use you must define a resource, a host, and any other configuration options in the drbd configuration file. See for details. If resource is omitted, then all of the resources listed in the config file are configured. This script might ask you Do you want to abort waiting for other server and make this one primary? Only answer this question with yes if you are sure that it is impossible to repair the other node. Version This document was revised for version 8.3.2 of the DRBD distribution. Author Written by Philipp Reisner philipp.reisner@linbit.com and Lars Ellenberg lars.ellenberg@linbit.com. Reporting Bugs Report bugs to drbd-user@lists.linbit.com. Copyright Copyright 2001-2008 LINBIT Information Technologies, Philipp Reisner, Lars Ellenberg. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See Also drbd.conf5, drbddisk8, drbdsetup8drbdadm8DRBD Homepage drbd-utils-8.9.6/documentation/v83/drbddisk.80000644000175000017500000000432112654452465020670 0ustar apoikosapoikos'\" t .\" Title: drbddisk .\" Author: [see the "Author" section] .\" Generator: DocBook XSL Stylesheets v1.75.2 .\" Date: 15 Oct 2008 .\" Manual: System Administration .\" Source: DRBD 8.3.2 .\" Language: English .\" .TH "DRBDDISK" "8" "15 Oct 2008" "DRBD 8.3.2" "System Administration" .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" drbddisk \- Script to mark devices as primary and mount file systems .SH "SYNOPSIS" .HP \w'\fB/etc/ha\&.d/resource\&.d/drbddisk\fR\ 'u \fB/etc/ha\&.d/resource\&.d/drbddisk\fR [\fIresource\fR] {{start}\ |\ {stop}\ |\ {status}} .SH "INTRODUCTION" .PP The \fB/etc/ha\&.d/resource\&.d/drbddisk\fR script brings the local device of \fIresource\fR into primary role\&. It is designed to be used by Heartbeat\&. .PP In order to use \fB/etc/ha\&.d/resource\&.d/drbddisk\fR you must define a resource, a host, and any other configuration options in the DRBD configuration file\&. See \fB/etc/drbd\&.conf\fR for details\&. If \fIresource\fR is omitted, then all of the resources listed in the config file are affected\&. .SH "VERSION" .sp This document was revised for version 8\&.0\&.14 of the DRBD distribution\&. .SH "AUTHOR" .sp Written by Philipp Reisner philipp\&.reisner@linbit\&.com and Lars Ellenberg lars\&.ellenberg@linbit\&.com\&. .SH "REPORTING BUGS" .sp Report bugs to drbd\-user@lists\&.linbit\&.com\&. .SH "COPYRIGHT" .sp Copyright 2001\-2008 LINBIT Information Technologies, Philipp Reisner, Lars Ellenberg\&. This is free software; see the source for copying conditions\&. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE\&. .SH "SEE ALSO" .PP \fBdrbd.conf\fR(5), \fBdrbd\fR(8), \fBdrbdsetup\fR(8)\fBdrbdadm\fR(8)\m[blue]\fBDRBD Homepage\fR\m[]\&\s-2\u[1]\d\s+2 .SH "NOTES" .IP " 1." 4 DRBD Homepage .RS 4 \%http://www.drbd.org/ .RE drbd-utils-8.9.6/documentation/v83/drbdadm.80000644000175000017500000002514312654452464020503 0ustar apoikosapoikos'\" t .\" Title: drbdadm .\" Author: [see the "Author" section] .\" Generator: DocBook XSL Stylesheets v1.75.2 .\" Date: 5 Dec 2008 .\" Manual: System Administration .\" Source: DRBD 8.3.2 .\" Language: English .\" .TH "DRBDADM" "8" "5 Dec 2008" "DRBD 8.3.2" "System Administration" .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" drbdadm \- Administration tool for DRBD .\" drbdadm .SH "SYNOPSIS" .HP \w'\fBdrbdadm\fR\ 'u \fBdrbdadm\fR [\-d] [\-c\ {\fIfile\fR}] [\-t\ {\fIfile\fR}] [\-s\ {\fIcmd\fR}] [\-m\ {\fIcmd\fR}] [\-S] [\-h\ {\fIhost\fR}] [\-\-\ {\fIbackend\-options\fR}] {\fIcommand\fR} [all | \fIresource\fR...] .SH "DESCRIPTION" .PP \fBDrbdadm\fR is the high level tool of the DRBD program suite\&. \fBDrbdadm\fR is to \fBdrbdsetup\fR and \fBdrbdmeta\fR what \fBifup\fR/\fBifdown\fR is to \fBifconfig\fR\&. \fBDrbdadm\fR reads its configuration file and performs the specified commands by calling the \fBdrbdsetup\fR and/or the \fBdrbdmeta\fR program\&. .SH "OPTIONS" .PP \fB\-d\fR, \fB\-\-dry\-run\fR .RS 4 Just prints the calls of \fBdrbdsetup\fR to stdout, but does not run the commands\&. .RE .PP \fB\-c\fR, \fB\-\-config\-file\fR \fIfile\fR .RS 4 Specifies the configuration file drbdadm will use\&. If this parameter is not specified, drbdadm will look for \fB/etc/drbd\-83\&.conf\fR, \fB/etc/drbd\-08\&.conf\fR and \fB/etc/drbd\&.conf\fR\&. .RE .PP \fB\-t\fR, \fB\-\-config\-to\-test\fR \fIfile\fR .RS 4 Specifies an additional configuration file drbdadm to check\&. This option is only allowed with the dump and the sh\-nop commands\&. .RE .PP \fB\-s\fR, \fB\-\-drbdsetup\fR \fIfile\fR .RS 4 Specifies the full path to the \fBdrbdsetup\fR program\&. If this option is omitted, drbdadm will look for \fB/sbin/drbdsetup\fR and \fB\&./drbdsetup\fR\&. .RE .PP \fB\-m\fR, \fB\-\-drbdmeta\fR \fIfile\fR .RS 4 Specifies the full path to the \fBdrbdmeta\fR program\&. If this option is omitted, drbdadm will look for \fB/sbin/drbdmeta\fR and \fB\&./drbdmeta\fR\&. .RE .PP \fB\-S\fR, \fB\-\-stacked\fR .RS 4 Specifies that this command should be performed on a stacked resource\&. .RE .PP \fB\-P\fR, \fB\-\-peer\fR .RS 4 Specifies to which peer node to connect\&. Only necessary if there are more than two host sections in the resource you are working on\&. .RE .PP \fB\-\-\fR \fIbackend\-options\fR .RS 4 All options following the doubly hyphen are considered \fIbackend\-options\fR\&. These are passed through to the backend command\&. I\&.e\&. to \fBdrbdsetup\fR, \fBdrbdmeta\fR or \fBdrbd\-proxy\-ctl\fR\&. .RE .SH "COMMANDS" .PP attach .RS 4 Attaches a local backing block device to the DRBD resource\'s device\&. .RE .PP detach .RS 4 .\" drbdadm: detach Removes the backing storage device from a DRBD resource\'s device\&. .RE .PP connect .RS 4 .\" drbdadm: connect Sets up the network configuration of the resource\'s device\&. If the peer device is already configured, the two DRBD devices will connect\&. If there are more than two host sections in the resource you need to use the \fB\-\-peer\fR option to select the peer you want to connect to\&. .RE .PP disconnect .RS 4 .\" drbdadm: disconnect Removes the network configuration from the resource\&. The device will then go into StandAlone state\&. .RE .PP syncer .RS 4 .\" drbdadm: syncer Loads the resynchronization parameters into the device\&. .RE .PP up .RS 4 .\" drbdadm: up Is a shortcut for attach and connect\&. .RE .PP down .RS 4 .\" drbdadm: down Is a shortcut for disconnect and detach\&. .RE .PP primary .RS 4 .\" drbdadm: primary Promote the resource\'s device into primary role\&. You need to do this before any access to the device, such as creating or mounting a file system\&. .RE .PP secondary .RS 4 .\" drbdadm: secondary Brings the device back into secondary role\&. This is needed since in a connected DRBD device pair, only one of the two peers may have primary role (except if \fBallow\-two\-primaries\fR is explicitly set in the configuration file)\&. .RE .PP invalidate .RS 4 .\" drbdadm: invalidate Forces DRBD to consider the data on the \fIlocal\fR backing storage device as out\-of\-sync\&. Therefore DRBD will copy each and every block from its peer, to bring the local storage device back in sync\&. To avoid races, you need an established replication link, or be disconnected Secondary\&. .RE .PP invalidate\-remote .RS 4 .\" drbdadm: invalidate-remote This command is similar to the invalidate command, however, the \fIpeer\'s\fR backing storage is invalidated and hence rewritten with the data of the local node\&. To avoid races, you need an established replication link, or be disconnected Primary\&. .RE .PP resize .RS 4 .\" drbdadm: resize Causes DRBD to re\-examine all sizing constraints, and resize the resource\'s device accordingly\&. For example, if you increased the size of your backing storage devices (on both nodes, of course), then DRBD will adopt the new size after you called this command on one of your nodes\&. Since new storage space must be synchronised this command only works if there is at least one primary node present\&. .sp The \fB\-\-assume\-peer\-has\-space\fR allows you to resize a device which is currently not connected to the peer\&. Use with care, since if you do not resize the peer\'s disk as well, further connect attempts of the two will fail\&. .sp The \fB\-\-assume\-clean\fR allows you to resize an existing device and avoid syncing the new space\&. This is useful when adding addtional blank storage to your device\&. Example: .sp .if n \{\ .RS 4 .\} .nf # drbdadm \-\- \-\-assume\-clean resize r0 .fi .if n \{\ .RE .\} .sp .RE .PP check\-resize .RS 4 .\" drbdadm: check-resize Calls drbdmeta to eventually move internal meta data\&. If the backing device was resized, while DRBD was not running, meta data has to be moved to the end of the device, so that the next \fBattach\fR command can succeed\&. .RE .PP create\-md .RS 4 .\" drbdadm: create-md Initializes the meta data storage\&. This needs to be done before a DRBD resource can be taken online for the first time\&. In case of issues with that command have a look at \fBdrbdmeta\fR(8) .RE .PP get\-gi .RS 4 .\" drbdadm: get-gi Shows a short textual representation of the data generation identifiers\&. .RE .PP show\-gi .RS 4 .\" drbdadm: show-gi Prints a textual representation of the data generation identifiers including explanatory information\&. .RE .PP dump\-md .RS 4 .\" drbdadm: dump-md Dumps the whole contents of the meta data storage, including the stored bit\-map and activity\-log, in a textual representation\&. .RE .PP outdate .RS 4 .\" drbdadm: outdate Sets the outdated flag in the meta data\&. .RE .PP adjust .RS 4 .\" drbdadm: adjust Synchronizes the configuration of the device with your configuration file\&. You should always examine the output of the dry\-run mode before actually executing this command\&. .RE .PP wait\-connect .RS 4 .\" drbdadm: wait-connect Waits until the device is connected to its peer device\&. .RE .PP role .RS 4 .\" drbdadm: role Shows the current roles of the devices (local/peer)\&. E\&.g\&. Primary/Secondary .RE .PP state .RS 4 .\" drbdadm: state Deprecated alias for "role", see above\&. .RE .PP cstate .RS 4 .\" drbdadm: cstate Shows the current connection state of the devices\&. .RE .PP status .RS 4 .\" drbdadm: status Shows the current status of all devices defined in the current config file, in XML\-like format\&. Example output: .sp .if n \{\ .RS 4 .\} .nf .fi .if n \{\ .RE .\} .sp .RE .PP dump .RS 4 .\" drbdadm: dump Just parse the configuration file and dump it to stdout\&. May be used to check the configuration file for syntactic correctness\&. .RE .PP outdate .RS 4 .\" drbdadm: outdate Used to mark the node\'s data as outdated\&. Usually used by the peer\'s fence\-peer handler\&. .RE .PP verify .RS 4 .\" drbdadm: verify Starts online verify\&. During online verify, data on both nodes is compared for equality\&. See /proc/drbd for online verify progress\&. If out\-of\-sync blocks are found, they are \fInot\fR resynchronized automatically\&. To do that, \fBdisconnect\fR and \fBconnect\fR the resource when verification has completed\&. .sp See also the notes on data integrity on the drbd\&.conf manpage\&. .RE .PP pause\-sync .RS 4 .\" drbdadm: pause-sync Temporarily suspend an ongoing resynchronization by setting the local pause flag\&. Resync only progresses if neither the local nor the remote pause flag is set\&. It might be desirable to postpone DRBD\'s resynchronization until after any resynchronization of the backing storage\'s RAID setup\&. .RE .PP resume\-sync .RS 4 .\" drbdadm: resume-sync Unset the local sync pause flag\&. .RE .PP new\-current\-uuid .RS 4 .\" drbdadm: new-current-uuid Generates a new currend UUID and rotates all other UUID values\&. .sp This can be used to shorten the initial resync of a cluster\&. See the \fBdrbdsetup\fR manpage for a more details\&. .RE .PP dstate .RS 4 .\" drbdadm: dstate Show the current state of the backing storage devices\&. (local/peer) .RE .PP hidden\-commands .RS 4 Shows all commands undocumented on purpose\&. .RE .SH "VERSION" .sp This document was revised for version 8\&.3\&.2 of the DRBD distribution\&. .SH "AUTHOR" .sp Written by Philipp Reisner philipp\&.reisner@linbit\&.com and Lars Ellenberg lars\&.ellenberg@linbit\&.com .SH "REPORTING BUGS" .sp Report bugs to drbd\-user@lists\&.linbit\&.com\&. .SH "COPYRIGHT" .sp Copyright 2001\-2008 LINBIT Information Technologies, Philipp Reisner, Lars Ellenberg\&. This is free software; see the source for copying conditions\&. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE\&. .SH "SEE ALSO" .PP \fBdrbd.conf\fR(5), \fBdrbd\fR(8), \fBdrbddisk\fR(8), \fBdrbdsetup\fR(8), \fBdrbdmeta\fR(8) and the \m[blue]\fBDRBD project web site\fR\m[]\&\s-2\u[1]\d\s+2 .SH "NOTES" .IP " 1." 4 DRBD project web site .RS 4 \%http://www.drbd.org/ .RE drbd-utils-8.9.6/documentation/v83/drbd.conf.50000644000175000017500000013552112654452463020743 0ustar apoikosapoikos'\" t .\" Title: drbd.conf .\" Author: [see the "Author" section] .\" Generator: DocBook XSL Stylesheets v1.75.2 .\" Date: 5 Dec 2008 .\" Manual: Configuration Files .\" Source: DRBD 8.3.2 .\" Language: English .\" .TH "DRBD\&.CONF" "5" "5 Dec 2008" "DRBD 8.3.2" "Configuration Files" .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" drbd.conf \- Configuration file for DRBD\'s devices .\" drbd.conf .SH "INTRODUCTION" .PP The file \fB/etc/drbd\&.conf\fR is read by \fBdrbdadm\fR\&. .PP The file format was designed as to allow to have a verbatim copy of the file on both nodes of the cluster\&. It is highly recommended to do so in order to keep your configuration manageable\&. The file \fB/etc/drbd\&.conf\fR should be the same on both nodes of the cluster\&. Changes to \fB/etc/drbd\&.conf\fR do not apply immediately\&. .PP \fBExample\ \&1.\ \&A small drbd.conf file\fR .sp .if n \{\ .RS 4 .\} .nf global { usage\-count yes; } common { syncer { rate 10M; } } resource r0 { protocol C; net { cram\-hmac\-alg sha1; shared\-secret "FooFunFactory"; } on alice { device minor 1; disk /dev/sda7; address 10\&.1\&.1\&.31:7789; meta\-disk internal; } on bob { device minor 1; disk /dev/sda7; address 10\&.1\&.1\&.32:7789; meta\-disk internal; } } .fi .if n \{\ .RE .\} In this example, there is a single DRBD resource (called r0) which uses protocol C for the connection between its devices\&. The device which runs on host \fIalice\fR uses \fI/dev/drbd1\fR as devices for its application, and \fI/dev/sda7\fR as low\-level storage for the data\&. The IP addresses are used to specify the networking interfaces to be used\&. An eventually running resync process should use about 10MByte/second of IO bandwidth\&. .PP There may be multiple resource sections in a single drbd\&.conf file\&. For more examples, please have a look at the \m[blue]\fBDRBD User\'s Guide\fR\m[]\&\s-2\u[1]\d\s+2\&. .SH "FILE FORMAT" .PP The file consists of sections and parameters\&. A section begins with a keyword, sometimes an additional name, and an opening brace (\(lq{\(rq)\&. A section ends with a closing brace (\(lq}\(rq\&. The braces enclose the parameters\&. .PP section [name] { parameter value; [\&.\&.\&.] } .PP A parameter starts with the identifier of the parameter followed by whitespace\&. Every subsequent character is considered as part of the parameter\'s value\&. A special case are Boolean parameters which consist only of the identifier\&. Parameters are terminated by a semicolon (\(lq;\(rq)\&. .PP Some parameter values have default units which might be overruled by K, M or G\&. These units are defined in the usual way (K = 2^10 = 1024, M = 1024 K, G = 1024 M)\&. .PP Comments may be placed into the configuration file and must begin with a hash sign (\(lq#\(rq)\&. Subsequent characters are ignored until the end of the line\&. .SS "Sections" .PP \fBskip\fR .RS 4 .\" drbd.conf: skip Comments out chunks of text, even spanning more than one line\&. Characters between the keyword \fBskip\fR and the opening brace (\(lq{\(rq) are ignored\&. Everything enclosed by the braces is skipped\&. This comes in handy, if you just want to comment out some \'\fBresource [name] {\&.\&.\&.}\fR\' section: just precede it with \'\(lqskip\(rq\'\&. .RE .PP \fBglobal\fR .RS 4 .\" drbd.conf: global Configures some global parameters\&. Currently only \fBminor\-count\fR, \fBdialog\-refresh\fR, \fBdisable\-ip\-verification\fR and \fBusage\-count\fR are allowed here\&. You may only have one global section, preferably as the first section\&. .RE .PP \fBcommon\fR .RS 4 .\" drbd.conf: common All resources inherit the options set in this section\&. The common section might have a \fBstartup\fR, a \fBsyncer\fR, a \fBhandlers\fR, a \fBnet\fR and a \fBdisk\fR section\&. .RE .PP \fBresource \fR\fB\fIname\fR\fR .RS 4 .\" drbd.conf: resource Configures a DRBD resource\&. Each resource section needs to have two (or more) \fBon \fR\fB\fIhost\fR\fR sections and may have a \fBstartup\fR, a \fBsyncer\fR, a \fBhandlers\fR, a \fBnet\fR and a \fBdisk\fR section\&. Required parameter in this section: \fBprotocol\fR\&. .RE .PP \fBon \fR\fB\fIhost\-name\fR\fR .RS 4 .\" drbd.conf: on Carries the necessary configuration parameters for a DRBD device of the enclosing resource\&. \fIhost\-name\fR is mandatory and must match the Linux host name (uname \-n) of one of the nodes\&. You may list more than one host name here, in case you want to use the same parameters on several hosts (you\'d have to move the IP around usually)\&. Or you may list more than two such sections\&. .sp .if n \{\ .RS 4 .\} .nf resource r1 { protocol C; device minor 1; meta\-disk internal; on alice bob { address 10\&.2\&.2\&.100:7801; disk /dev/mapper/some\-san; } on charlie { address 10\&.2\&.2\&.101:7801; disk /dev/mapper/other\-san; } on daisy { address 10\&.2\&.2\&.103:7801; disk /dev/mapper/other\-san\-as\-seen\-from\-daisy; } } .fi .if n \{\ .RE .\} .sp See also the \fBfloating\fR section keyword\&. Required parameters in this section: \fBdevice\fR, \fBdisk\fR, \fBaddress\fR, \fBmeta\-disk\fR, \fBflexible\-meta\-disk\fR\&. .RE .PP \fBstacked\-on\-top\-of \fR\fB\fIresource\fR\fR .RS 4 .\" drbd.conf: stacked-on-top-of For a stacked DRBD setup (3 or 4 nodes), a \fBstacked\-on\-top\-of\fR is used instead of an \fBon\fR section\&. Required parameters in this section: \fBdevice\fR and \fBaddress\fR\&. .RE .PP \fBfloating \fR\fB\fIAF addr:port\fR\fR .RS 4 .\" drbd.conf: on Carries the necessary configuration parameters for a DRBD device of the enclosing resource\&. This section is very similar to the \fBon\fR section\&. The difference to the \fBon\fR section is that the matching of the host sections to machines is done by the IP\-address instead of the node name\&. Required parameters in this section: \fBdevice\fR, \fBdisk\fR, \fBmeta\-disk\fR, \fBflexible\-meta\-disk\fR, all of which \fImay\fR be inherited from the resource section, in which case you may shorten this section down to just the address identifier\&. .sp .if n \{\ .RS 4 .\} .nf resource r2 { protocol C; device minor 2; disk /dev/sda7; meta\-disk internal; # short form, device, disk and meta\-disk inherited floating 10\&.1\&.1\&.31:7802; # longer form, only device inherited floating 10\&.1\&.1\&.32:7802 { disk /dev/sdb; meta\-disk /dev/sdc8; } } .fi .if n \{\ .RE .\} .sp .RE .PP \fBdisk\fR .RS 4 .\" drbd.conf: disk This section is used to fine tune DRBD\'s properties in respect to the low level storage\&. Please refer to \fBdrbdsetup\fR(8) for detailed description of the parameters\&. Optional parameters: \fBon\-io\-error\fR, \fBsize\fR, \fBfencing\fR, \fBuse\-bmbv\fR, \fBno\-disk\-barrier\fR, \fBno\-disk\-flushes\fR, \fBno\-disk\-drain\fR, \fBno\-md\-flushes\fR, \fBmax\-bio\-bvecs\fR, \fBdisk\-timeout\fR\&. .RE .PP \fBnet\fR .RS 4 .\" drbd.conf: net This section is used to fine tune DRBD\'s properties\&. Please refer to \fBdrbdsetup\fR(8) for a detailed description of this section\'s parameters\&. Optional parameters: \fBsndbuf\-size\fR, \fBrcvbuf\-size\fR, \fBtimeout\fR, \fBconnect\-int\fR, \fBping\-int\fR, \fBping\-timeout\fR, \fBmax\-buffers\fR, \fBmax\-epoch\-size\fR, \fBko\-count\fR, \fBallow\-two\-primaries\fR, \fBcram\-hmac\-alg\fR, \fBshared\-secret\fR, \fBafter\-sb\-0pri\fR, \fBafter\-sb\-1pri\fR, \fBafter\-sb\-2pri\fR, \fBdata\-integrity\-alg\fR, \fBno\-tcp\-cork\fR, \fBon\-congestion\fR, \fBcongestion\-fill\fR, \fBcongestion\-extents\fR .RE .PP \fBstartup\fR .RS 4 .\" drbd.conf: startup This section is used to fine tune DRBD\'s properties\&. Please refer to \fBdrbdsetup\fR(8) for a detailed description of this section\'s parameters\&. Optional parameters: \fBwfc\-timeout\fR, \fBdegr\-wfc\-timeout\fR, \fBoutdated\-wfc\-timeout\fR, \fBwait\-after\-sb\fR, \fBstacked\-timeouts\fR and \fBbecome\-primary\-on\fR\&. .RE .PP \fBsyncer\fR .RS 4 .\" drbd.conf: syncer This section is used to fine tune the synchronization daemon for the device\&. Please refer to \fBdrbdsetup\fR(8) for a detailed description of this section\'s parameters\&. Optional parameters: \fBrate\fR, \fBafter\fR, \fBal\-extents\fR, \fBuse\-rle\fR, \fBcpu\-mask\fR, \fBverify\-alg\fR, \fBcsums\-alg\fR, \fBc\-plan\-ahead\fR, \fBc\-fill\-target\fR, \fBc\-delay\-target\fR, \fBc\-max\-rate\fR, \fBc\-min\-rate\fR and \fBon\-no\-data\-accessible\fR\&. .RE .PP \fBhandlers\fR .RS 4 .\" drbd.conf: handlers In this section you can define handlers (executables) that are started by the DRBD system in response to certain events\&. Optional parameters: \fBpri\-on\-incon\-degr\fR, \fBpri\-lost\-after\-sb\fR, \fBpri\-lost\fR, \fBfence\-peer\fR (formerly oudate\-peer), \fBlocal\-io\-error\fR, \fBinitial\-split\-brain\fR, \fBsplit\-brain\fR, \fBbefore\-resync\-target\fR, \fBafter\-resync\-target\fR\&. .sp The interface is done via environment variables: .PP \fBDRBD_RESOURCE\fR .RS 4 is the name of the resource .RE .PP \fBDRBD_MINOR\fR .RS 4 is the minor number of the DRBD device, in decimal\&. .RE .PP \fBDRBD_CONF\fR .RS 4 is the path to the primary configuration file; if you split your configuration into multiple files (e\&.g\&. in \fB/etc/drbd\&.conf\&.d/\fR), this will not be helpful\&. .RE .PP \fBDRBD_PEER_AF\fR, \fBDRBD_PEER_ADDRESS\fR, \fBDRBD_PEERS\fR .RS 4 are the address family (e\&.g\&. \fBipv6\fR), the peer\'s address and hostnames\&. .RE .sp \fBDRBD_PEER\fR (note the singular form) is deprecated, and superseeded by DRBD_PEERS\&. .sp Please note that not all of these might be set for all handlers, and that some values might not be useable for a \fBfloating\fR definition\&. .RE .SS "Parameters" .PP \fBminor\-count \fR\fB\fIcount\fR\fR .RS 4 .\" drbd.conf: minor-count\fIcount\fR may be a number from 1 to 255\&. .sp Use \fIminor\-count\fR if you want to define massively more resources later without reloading the DRBD kernel module\&. Per default the module loads with 11 more resources than you have currently in your config but at least 32\&. .RE .PP \fBdialog\-refresh \fR\fB\fItime\fR\fR .RS 4 .\" drbd.conf: dialog-refresh\fItime\fR may be 0 or a positive number\&. .sp The user dialog redraws the second count every \fItime\fR seconds (or does no redraws if \fItime\fR is 0)\&. The default value is 1\&. .RE .PP \fBdisable\-ip\-verification\fR .RS 4 .\" drbd.conf: disable-ip-verification Use \fIdisable\-ip\-verification\fR if, for some obscure reasons, drbdadm can/might not use \fBip\fR or \fBifconfig\fR to do a sanity check for the IP address\&. You can disable the IP verification with this option\&. .RE .PP \fBusage\-count \fR\fB\fIval\fR\fR .RS 4 .\" drbd.conf: usage-count Please participate in \m[blue]\fBDRBD\'s online usage counter\fR\m[]\&\s-2\u[2]\d\s+2\&. The most convenient way to do so is to set this option to \fByes\fR\&. Valid options are: \fByes\fR, \fBno\fR and \fBask\fR\&. .RE .PP \fBprotocol \fR\fB\fIprot\-id\fR\fR .RS 4 .\" drbd.conf: protocol On the TCP/IP link the specified \fIprotocol\fR is used\&. Valid protocol specifiers are A, B, and C\&. .sp Protocol A: write IO is reported as completed, if it has reached local disk and local TCP send buffer\&. .sp Protocol B: write IO is reported as completed, if it has reached local disk and remote buffer cache\&. .sp Protocol C: write IO is reported as completed, if it has reached both local and remote disk\&. .RE .PP \fBdevice \fR\fB\fIname\fR\fR\fB minor \fR\fB\fInr\fR\fR .RS 4 .\" drbd.conf: device The name of the block device node of the resource being described\&. You must use this device with your application (file system) and you must not use the low level block device which is specified with the \fBdisk\fR parameter\&. .sp One can ether omit the \fIname\fR or \fBminor\fR and the \fIminor number\fR\&. If you omit the \fIname\fR a default of /dev/drbd\fIminor\fR will be used\&. .sp Udev will create additional symlinks in /dev/drbd/by\-res and /dev/drbd/by\-disk\&. .RE .PP \fBdisk \fR\fB\fIname\fR\fR .RS 4 .\" drbd.conf: disk DRBD uses this block device to actually store and retrieve the data\&. Never access such a device while DRBD is running on top of it\&. This also holds true for \fBdumpe2fs\fR(8) and similar commands\&. .RE .PP \fBaddress \fR\fB\fIAF addr:port\fR\fR .RS 4 .\" drbd.conf: address A resource needs one \fIIP\fR address per device, which is used to wait for incoming connections from the partner device respectively to reach the partner device\&. \fIAF\fR must be one of \fBipv4\fR, \fBipv6\fR, \fBssocks\fR or \fBsdp\fR (for compatibility reasons \fBsci\fR is an alias for \fBssocks\fR)\&. It may be omited for IPv4 addresses\&. The actual IPv6 address that follows the \fBipv6\fR keyword must be placed inside brackets: ipv6 [fd01:2345:6789:abcd::1]:7800\&. .sp Each DRBD resource needs a TCP \fIport\fR which is used to connect to the node\'s partner device\&. Two different DRBD resources may not use the same \fIaddr:port\fR combination on the same node\&. .RE .PP \fBmeta\-disk \fR\fB\fIinternal\fR\fR, \fBflexible\-meta\-disk \fR\fB\fIinternal\fR\fR, \fBmeta\-disk \fR\fB\fIdevice [index]\fR\fR, \fBflexible\-meta\-disk \fR\fB\fIdevice \fR\fR .RS 4 .\" drbd.conf: meta-disk.\" drbd.conf: flexible-meta-disk Internal means that the last part of the backing device is used to store the meta\-data\&. You must not use \fI[index]\fR with internal\&. Note: Regardless of whether you use the \fBmeta\-disk\fR or the \fBflexible\-meta\-disk\fR keyword, it will always be of the size needed for the remaining storage size\&. .sp You can use a single block \fIdevice\fR to store meta\-data of multiple DRBD devices\&. E\&.g\&. use meta\-disk /dev/sde6[0]; and meta\-disk /dev/sde6[1]; for two different resources\&. In this case the meta\-disk would need to be at least 256 MB in size\&. .sp With the \fBflexible\-meta\-disk\fR keyword you specify a block device as meta\-data storage\&. You usually use this with LVM, which allows you to have many variable sized block devices\&. The required size of the meta\-disk block device is 36kB + Backing\-Storage\-size / 32k\&. Round this number to the next 4kb boundary up and you have the exact size\&. Rule of the thumb: 32kByte per 1GByte of storage, round up to the next MB\&. .RE .PP \fBon\-io\-error \fR\fB\fIhandler\fR\fR .RS 4 .\" drbd.conf: on-io-error\fIhandler\fR is taken, if the lower level device reports io\-errors to the upper layers\&. .sp \fIhandler\fR may be \fBpass_on\fR, \fBcall\-local\-io\-error\fR or \fBdetach\&.\fR .sp \fBpass_on\fR: The node downgrades the disk status to inconsistent, marks the erroneous block as inconsistent in the bitmap and retries the IO on the remote node\&. .sp \fBcall\-local\-io\-error\fR: Call the handler script \fBlocal\-io\-error\fR\&. .sp \fBdetach\fR: The node drops its low level device, and continues in diskless mode\&. .RE .PP \fBfencing \fR\fB\fIfencing_policy\fR\fR .RS 4 .\" drbd.conf: fencing By \fBfencing\fR we understand preventive measures to avoid situations where both nodes are primary and disconnected (AKA split brain)\&. .sp Valid fencing policies are: .PP \fBdont\-care\fR .RS 4 This is the default policy\&. No fencing actions are taken\&. .RE .PP \fBresource\-only\fR .RS 4 If a node becomes a disconnected primary, it tries to fence the peer\'s disk\&. This is done by calling the \fBfence\-peer\fR handler\&. The handler is supposed to reach the other node over alternative communication paths and call \'\fBdrbdadm outdate res\fR\' there\&. .RE .PP \fBresource\-and\-stonith\fR .RS 4 If a node becomes a disconnected primary, it freezes all its IO operations and calls its fence\-peer handler\&. The fence\-peer handler is supposed to reach the peer over alternative communication paths and call \'drbdadm outdate res\' there\&. In case it cannot reach the peer it should stonith the peer\&. IO is resumed as soon as the situation is resolved\&. In case your handler fails, you can resume IO with the \fBresume\-io\fR command\&. .RE .RE .PP \fBuse\-bmbv\fR .RS 4 .\" drbd.conf: use-bmbv In case the backing storage\'s driver has a merge_bvec_fn() function, DRBD has to pretend that it can only process IO requests in units not larger than 4KiB\&. (At the time of writing the only known drivers which have such a function are: md (software raid driver), dm (device mapper \- LVM) and DRBD itself)\&. .sp To get the best performance out of DRBD on top of software RAID (or any other driver with a merge_bvec_fn() function) you might enable this function, if you know for sure that the merge_bvec_fn() function will deliver the same results on all nodes of your cluster\&. I\&.e\&. the physical disks of the software RAID are of exactly the same type\&. \fIUse this option only if you know what you are doing\&.\fR .RE .PP \fBno\-disk\-barrier\fR, \fBno\-disk\-flushes\fR, \fBno\-disk\-drain\fR .RS 4 .\" drbd.conf: no-disk-barrier .\" drbd.conf: no-disk-flushes .\" drbd.conf: no-disk-drain DRBD has four implementations to express write\-after\-write dependencies to its backing storage device\&. DRBD will use the first method that is supported by the backing storage device and that is not disabled by the user\&. .sp When selecting the method you should not only base your decision on the measurable performance\&. In case your backing storage device has a volatile write cache (plain disks, RAID of plain disks) you should use one of the first two\&. In case your backing storage device has battery\-backed write cache you may go with option 3\&. Option 4 (disable everything, use "none") \fIis dangerous\fR on most IO stacks, may result in write\-reordering, and if so, can theoretically be the reason for data corruption, or disturb the DRBD protocol, causing spurious disconnect/reconnect cycles\&. \fIDo not use\fR \fBno\-disk\-drain\fR\&. .sp Unfortunately device mapper (LVM) might not support barriers\&. .sp The letter after "wo:" in /proc/drbd indicates with method is currently in use for a device: \fBb\fR, \fBf\fR, \fBd\fR, \fBn\fR\&. The implementations are: .PP barrier .RS 4 The first requires that the driver of the backing storage device support barriers (called \'tagged command queuing\' in SCSI and \'native command queuing\' in SATA speak)\&. The use of this method can be disabled by the \fBno\-disk\-barrier\fR option\&. Note: Since Linux\-2\&.6\&.36 (or RHEL\'s 2\&.6\&.32) this method is disabled\&. .RE .PP flush .RS 4 The second requires that the backing device support disk flushes (called \'force unit access\' in the drive vendors speak)\&. The use of this method can be disabled using the \fBno\-disk\-flushes\fR option\&. .RE .PP drain .RS 4 The third method is simply to let write requests drain before write requests of a new reordering domain are issued\&. This was the only implementation before 8\&.0\&.9\&. .RE .PP none .RS 4 The fourth method is to not express write\-after\-write dependencies to the backing store at all, by also specifying \fBno\-disk\-drain\fR\&. This \fIis dangerous\fR on most IO stacks, may result in write\-reordering, and if so, can theoretically be the reason for data corruption, or disturb the DRBD protocol, causing spurious disconnect/reconnect cycles\&. \fIDo not use\fR \fBno\-disk\-drain\fR\&. .RE .RE .PP \fBno\-md\-flushes\fR .RS 4 .\" drbd.conf: no-md-flushes Disables the use of disk flushes and barrier BIOs when accessing the meta data device\&. See the notes on \fBno\-disk\-flushes\fR\&. .RE .PP \fBmax\-bio\-bvecs\fR .RS 4 .\" drbd.conf: max-bio-bvecs In some special circumstances the device mapper stack manages to pass BIOs to DRBD that violate the constraints that are set forth by DRBD\'s merge_bvec() function and which have more than one bvec\&. A known example is: phys\-disk \-> DRBD \-> LVM \-> Xen \-> misaligned partition (63) \-> DomU FS\&. Then you might see "bio would need to, but cannot, be split:" in the Dom0\'s kernel log\&. .sp The best workaround is to proper align the partition within the VM (E\&.g\&. start it at sector 1024)\&. This costs 480 KiB of storage\&. Unfortunately the default of most Linux partitioning tools is to start the first partition at an odd number (63)\&. Therefore most distribution\'s install helpers for virtual linux machines will end up with misaligned partitions\&. The second best workaround is to limit DRBD\'s max bvecs per BIO (= \fBmax\-bio\-bvecs\fR) to 1, but that might cost performance\&. .sp The default value of \fBmax\-bio\-bvecs\fR is 0, which means that there is no user imposed limitation\&. .RE .PP \fBdisk\-timeout\fR .RS 4 .\" drbd.conf: disk-timeout If the driver of the \fIlower_device\fR does not finish an IO request within \fIdisk_timeout\fR, DRBD considers the disk as failed\&. If DRBD is connected to a remote host, it will reissue local pending IO requests to the peer, and ship all new IO requests to the peer only\&. The disk state advances to diskless, as soon as the backing block device has finished all IO requests\&. .sp The default value of is 0, which means that no timeout is enforced\&. The default unit is 100ms\&. This option is available since 8\&.3\&.12\&. .RE .PP \fBsndbuf\-size \fR\fB\fIsize\fR\fR .RS 4 .\" drbd.conf: sndbuf-size\fIsize\fR is the size of the TCP socket send buffer\&. The default value is 0, i\&.e\&. autotune\&. You can specify smaller or larger values\&. Larger values are appropriate for reasonable write throughput with protocol A over high latency networks\&. Values below 32K do not make sense\&. Since 8\&.0\&.13 resp\&. 8\&.2\&.7, setting the \fIsize\fR value to 0 means that the kernel should autotune this\&. .RE .PP \fBrcvbuf\-size \fR\fB\fIsize\fR\fR .RS 4 .\" drbd.conf: rcvbuf-size\fIsize\fR is the size of the TCP socket receive buffer\&. The default value is 0, i\&.e\&. autotune\&. You can specify smaller or larger values\&. Usually this should be left at its default\&. Setting the \fIsize\fR value to 0 means that the kernel should autotune this\&. .RE .PP \fBtimeout \fR\fB\fItime\fR\fR .RS 4 .\" drbd.conf: timeout If the partner node fails to send an expected response packet within \fItime\fR tenths of a second, the partner node is considered dead and therefore the TCP/IP connection is abandoned\&. This must be lower than \fIconnect\-int\fR and \fIping\-int\fR\&. The default value is 60 = 6 seconds, the unit 0\&.1 seconds\&. .RE .PP \fBconnect\-int \fR\fB\fItime\fR\fR .RS 4 .\" drbd.conf: connect-int In case it is not possible to connect to the remote DRBD device immediately, DRBD keeps on trying to connect\&. With this option you can set the time between two retries\&. The default value is 10 seconds, the unit is 1 second\&. .RE .PP \fBping\-int \fR\fB\fItime\fR\fR .RS 4 .\" drbd.conf: ping-int If the TCP/IP connection linking a DRBD device pair is idle for more than \fItime\fR seconds, DRBD will generate a keep\-alive packet to check if its partner is still alive\&. The default is 10 seconds, the unit is 1 second\&. .RE .PP \fBping\-timeout \fR\fB\fItime\fR\fR .RS 4 .\" drbd.conf: ping-timeout The time the peer has time to answer to a keep\-alive packet\&. In case the peer\'s reply is not received within this time period, it is considered as dead\&. The default value is 500ms, the default unit are tenths of a second\&. .RE .PP \fBmax\-buffers \fR\fB\fInumber\fR\fR .RS 4 .\" drbd.conf: max-buffers Limits the memory usage per DRBD minor device on the receiving side, or for internal buffers during resync or online\-verify\&. Unit is PAGE_SIZE, which is 4 KiB on most systems\&. The minimum possible setting is hard coded to 32 (=128 KiB)\&. These buffers are used to hold data blocks while they are written to/read from disk\&. To avoid possible distributed deadlocks on congestion, this setting is used as a throttle threshold rather than a hard limit\&. Once more than max\-buffers pages are in use, further allocation from this pool is throttled\&. You want to increase max\-buffers if you cannot saturate the IO backend on the receiving side\&. .RE .PP \fBko\-count \fR\fB\fInumber\fR\fR .RS 4 .\" drbd.conf: ko-count In case the secondary node fails to complete a single write request for \fIcount\fR times the \fItimeout\fR, it is expelled from the cluster\&. (I\&.e\&. the primary node goes into \fBStandAlone\fR mode\&.) To disable this feature, you should explicitly set it to 0; defaults may change between versions\&. .RE .PP \fBmax\-epoch\-size \fR\fB\fInumber\fR\fR .RS 4 .\" drbd.conf: max-epoch-size The highest number of data blocks between two write barriers\&. If you set this smaller than 10, you might decrease your performance\&. .RE .PP \fBallow\-two\-primaries\fR .RS 4 .\" drbd.conf: allow-two-primaries With this option set you may assign the primary role to both nodes\&. You only should use this option if you use a shared storage file system on top of DRBD\&. At the time of writing the only ones are: OCFS2 and GFS\&. If you use this option with any other file system, you are going to crash your nodes and to corrupt your data! .RE .PP \fBunplug\-watermark \fR\fB\fInumber\fR\fR .RS 4 .\" drbd.conf: unplug-watermark This setting has no effect with recent kernels that use explicit on\-stack plugging (upstream Linux kernel 2\&.6\&.39, distributions may have backported)\&. .sp When the number of pending write requests on the standby (secondary) node exceeds the \fBunplug\-watermark\fR, we trigger the request processing of our backing storage device\&. Some storage controllers deliver better performance with small values, others deliver best performance when the value is set to the same value as max\-buffers, yet others don\'t feel much effect at all\&. Minimum 16, default 128, maximum 131072\&. .RE .PP \fBcram\-hmac\-alg\fR .RS 4 .\" drbd.conf: cram-hmac-alg You need to specify the HMAC algorithm to enable peer authentication at all\&. You are strongly encouraged to use peer authentication\&. The HMAC algorithm will be used for the challenge response authentication of the peer\&. You may specify any digest algorithm that is named in \fB/proc/crypto\fR\&. .RE .PP \fBshared\-secret\fR .RS 4 .\" drbd.conf: shared-secret The shared secret used in peer authentication\&. May be up to 64 characters\&. Note that peer authentication is disabled as long as no \fBcram\-hmac\-alg\fR (see above) is specified\&. .RE .PP \fBafter\-sb\-0pri \fR \fIpolicy\fR .RS 4 .\" drbd.conf: after-sb-0pri possible policies are: .PP \fBdisconnect\fR .RS 4 No automatic resynchronization, simply disconnect\&. .RE .PP \fBdiscard\-younger\-primary\fR .RS 4 Auto sync from the node that was primary before the split\-brain situation happened\&. .RE .PP \fBdiscard\-older\-primary\fR .RS 4 Auto sync from the node that became primary as second during the split\-brain situation\&. .RE .PP \fBdiscard\-zero\-changes\fR .RS 4 In case one node did not write anything since the split brain became evident, sync from the node that wrote something to the node that did not write anything\&. In case none wrote anything this policy uses a random decision to perform a "resync" of 0 blocks\&. In case both have written something this policy disconnects the nodes\&. .RE .PP \fBdiscard\-least\-changes\fR .RS 4 Auto sync from the node that touched more blocks during the split brain situation\&. .RE .PP \fBdiscard\-node\-NODENAME\fR .RS 4 Auto sync to the named node\&. .RE .RE .PP \fBafter\-sb\-1pri \fR \fIpolicy\fR .RS 4 .\" drbd.conf: after-sb-1pri possible policies are: .PP \fBdisconnect\fR .RS 4 No automatic resynchronization, simply disconnect\&. .RE .PP \fBconsensus\fR .RS 4 Discard the version of the secondary if the outcome of the \fBafter\-sb\-0pri\fR algorithm would also destroy the current secondary\'s data\&. Otherwise disconnect\&. .RE .PP \fBviolently\-as0p\fR .RS 4 Always take the decision of the \fBafter\-sb\-0pri\fR algorithm, even if that causes an erratic change of the primary\'s view of the data\&. This is only useful if you use a one\-node FS (i\&.e\&. not OCFS2 or GFS) with the \fBallow\-two\-primaries\fR flag, \fIAND\fR if you really know what you are doing\&. This is \fIDANGEROUS and MAY CRASH YOUR MACHINE\fR if you have an FS mounted on the primary node\&. .RE .PP \fBdiscard\-secondary\fR .RS 4 Discard the secondary\'s version\&. .RE .PP \fBcall\-pri\-lost\-after\-sb\fR .RS 4 Always honor the outcome of the \fBafter\-sb\-0pri \fR algorithm\&. In case it decides the current secondary has the right data, it calls the "pri\-lost\-after\-sb" handler on the current primary\&. .RE .RE .PP \fBafter\-sb\-2pri \fR \fIpolicy\fR .RS 4 .\" drbd.conf: after-sb-2pri possible policies are: .PP \fBdisconnect\fR .RS 4 No automatic resynchronization, simply disconnect\&. .RE .PP \fBviolently\-as0p\fR .RS 4 Always take the decision of the \fBafter\-sb\-0pri\fR algorithm, even if that causes an erratic change of the primary\'s view of the data\&. This is only useful if you use a one\-node FS (i\&.e\&. not OCFS2 or GFS) with the \fBallow\-two\-primaries\fR flag, \fIAND\fR if you really know what you are doing\&. This is \fIDANGEROUS and MAY CRASH YOUR MACHINE\fR if you have an FS mounted on the primary node\&. .RE .PP \fBcall\-pri\-lost\-after\-sb\fR .RS 4 Call the "pri\-lost\-after\-sb" helper program on one of the machines\&. This program is expected to reboot the machine, i\&.e\&. make it secondary\&. .RE .RE .PP \fBalways\-asbp\fR .RS 4 Normally the automatic after\-split\-brain policies are only used if current states of the UUIDs do not indicate the presence of a third node\&. .sp With this option you request that the automatic after\-split\-brain policies are used as long as the data sets of the nodes are somehow related\&. This might cause a full sync, if the UUIDs indicate the presence of a third node\&. (Or double faults led to strange UUID sets\&.) .RE .PP \fBrr\-conflict \fR \fIpolicy\fR .RS 4 .\" drbd.conf: rr-conflict This option helps to solve the cases when the outcome of the resync decision is incompatible with the current role assignment in the cluster\&. .PP \fBdisconnect\fR .RS 4 No automatic resynchronization, simply disconnect\&. .RE .PP \fBviolently\fR .RS 4 Sync to the primary node is allowed, violating the assumption that data on a block device are stable for one of the nodes\&. \fIDangerous, do not use\&.\fR .RE .PP \fBcall\-pri\-lost\fR .RS 4 Call the "pri\-lost" helper program on one of the machines\&. This program is expected to reboot the machine, i\&.e\&. make it secondary\&. .RE .RE .PP \fBdata\-integrity\-alg \fR \fIalg\fR .RS 4 .\" drbd.conf: data-integrity-alg DRBD can ensure the data integrity of the user\'s data on the network by comparing hash values\&. Normally this is ensured by the 16 bit checksums in the headers of TCP/IP packets\&. .sp This option can be set to any of the kernel\'s data digest algorithms\&. In a typical kernel configuration you should have at least one of \fBmd5\fR, \fBsha1\fR, and \fBcrc32c\fR available\&. By default this is not enabled\&. .sp See also the notes on data integrity\&. .RE .PP \fBno\-tcp\-cork\fR .RS 4 .\" drbd.conf: no-tcp-cork DRBD usually uses the TCP socket option TCP_CORK to hint to the network stack when it can expect more data, and when it should flush out what it has in its send queue\&. It turned out that there is at least one network stack that performs worse when one uses this hinting method\&. Therefore we introducted this option, which disables the setting and clearing of the TCP_CORK socket option by DRBD\&. .RE .PP \fBon\-congestion \fR\fB\fIcongestion_policy\fR\fR, \fBcongestion\-fill \fR\fB\fIfill_threshold\fR\fR, \fBcongestion\-extents \fR\fB\fIactive_extents_threshold\fR\fR .RS 4 By default DRBD blocks when the available TCP send queue becomes full\&. That means it will slow down the application that generates the write requests that cause DRBD to send more data down that TCP connection\&. .sp When DRBD is deployed with DRBD\-proxy it might be more desirable that DRBD goes into AHEAD/BEHIND mode shortly before the send queue becomes full\&. In AHEAD/BEHIND mode DRBD does no longer replicate data, but still keeps the connection open\&. .sp The advantage of the AHEAD/BEHIND mode is that the application is not slowed down, even if DRBD\-proxy\'s buffer is not sufficient to buffer all write requests\&. The downside is that the peer node falls behind, and that a resync will be necessary to bring it back into sync\&. During that resync the peer node will have an inconsistent disk\&. .sp Available \fIcongestion_policy\fRs are \fBblock\fR and \fBpull\-ahead\fR\&. The default is \fBblock\fR\&. \fIFill_threshold\fR might be in the range of 0 to 10GiBytes\&. The default is 0 which disables the check\&. \fIActive_extents_threshold\fR has the same limits as \fBal\-extents\fR\&. .sp The AHEAD/BEHIND mode and its settings are available since DRBD 8\&.3\&.10\&. .RE .PP \fBwfc\-timeout \fR\fB\fItime\fR\fR .RS 4 Wait for connection timeout\&. .\" drbd.conf: wfc-timeout The init script \fBdrbd\fR(8) blocks the boot process until the DRBD resources are connected\&. When the cluster manager starts later, it does not see a resource with internal split\-brain\&. In case you want to limit the wait time, do it here\&. Default is 0, which means unlimited\&. The unit is seconds\&. .RE .PP \fBdegr\-wfc\-timeout \fR\fB\fItime\fR\fR .RS 4 .\" drbd.conf: degr-wfc-timeout Wait for connection timeout, if this node was a degraded cluster\&. In case a degraded cluster (= cluster with only one node left) is rebooted, this timeout value is used instead of wfc\-timeout, because the peer is less likely to show up in time, if it had been dead before\&. Value 0 means unlimited\&. .RE .PP \fBoutdated\-wfc\-timeout \fR\fB\fItime\fR\fR .RS 4 .\" drbd.conf: outdated-wfc-timeout Wait for connection timeout, if the peer was outdated\&. In case a degraded cluster (= cluster with only one node left) with an outdated peer disk is rebooted, this timeout value is used instead of wfc\-timeout, because the peer is not allowed to become primary in the meantime\&. Value 0 means unlimited\&. .RE .PP \fBwait\-after\-sb\fR .RS 4 By setting this option you can make the init script to continue to wait even if the device pair had a split brain situation and therefore refuses to connect\&. .RE .PP \fBbecome\-primary\-on \fR\fB\fInode\-name\fR\fR .RS 4 Sets on which node the device should be promoted to primary role by the init script\&. The \fInode\-name\fR might either be a host name or the keyword \fBboth\fR\&. When this option is not set the devices stay in secondary role on both nodes\&. Usually one delegates the role assignment to a cluster manager (e\&.g\&. heartbeat)\&. .RE .PP \fBstacked\-timeouts\fR .RS 4 Usually \fBwfc\-timeout\fR and \fBdegr\-wfc\-timeout\fR are ignored for stacked devices, instead twice the amount of \fBconnect\-int\fR is used for the connection timeouts\&. With the \fBstacked\-timeouts\fR keyword you disable this, and force DRBD to mind the \fBwfc\-timeout\fR and \fBdegr\-wfc\-timeout\fR statements\&. Only do that if the peer of the stacked resource is usually not available or will usually not become primary\&. By using this option incorrectly, you run the risk of causing unexpected split brain\&. .RE .PP \fBrate \fR\fB\fIrate\fR\fR .RS 4 .\" drbd.conf: rate To ensure a smooth operation of the application on top of DRBD, it is possible to limit the bandwidth which may be used by background synchronizations\&. The default is 250 KB/sec, the default unit is KB/sec\&. Optional suffixes K, M, G are allowed\&. .RE .PP \fBuse\-rle\fR .RS 4 .\" drbd.conf: use-rle During resync\-handshake, the dirty\-bitmaps of the nodes are exchanged and merged (using bit\-or), so the nodes will have the same understanding of which blocks are dirty\&. On large devices, the fine grained dirty\-bitmap can become large as well, and the bitmap exchange can take quite some time on low\-bandwidth links\&. .sp Because the bitmap typically contains compact areas where all bits are unset (clean) or set (dirty), a simple run\-length encoding scheme can considerably reduce the network traffic necessary for the bitmap exchange\&. .sp For backward compatibilty reasons, and because on fast links this possibly does not improve transfer time but consumes cpu cycles, this defaults to off\&. .RE .PP \fBafter \fR\fB\fIres\-name\fR\fR .RS 4 .\" drbd.conf: after By default, resynchronization of all devices would run in parallel\&. By defining a sync\-after dependency, the resynchronization of this resource will start only if the resource \fIres\-name\fR is already in connected state (i\&.e\&., has finished its resynchronization)\&. .RE .PP \fBal\-extents \fR\fB\fIextents\fR\fR .RS 4 .\" drbd.conf: al-extents DRBD automatically performs hot area detection\&. With this parameter you control how big the hot area (= active set) can get\&. Each extent marks 4M of the backing storage (= low\-level device)\&. In case a primary node leaves the cluster unexpectedly, the areas covered by the active set must be resynced upon rejoining of the failed node\&. The data structure is stored in the meta\-data area, therefore each change of the active set is a write operation to the meta\-data device\&. A higher number of extents gives longer resync times but less updates to the meta\-data\&. The default number of \fIextents\fR is 127\&. (Minimum: 7, Maximum: 3843) .RE .PP \fBverify\-alg \fR\fB\fIhash\-alg\fR\fR .RS 4 During online verification (as initiated by the \fBverify\fR sub\-command), rather than doing a bit\-wise comparison, DRBD applies a hash function to the contents of every block being verified, and compares that hash with the peer\&. This option defines the hash algorithm being used for that purpose\&. It can be set to any of the kernel\'s data digest algorithms\&. In a typical kernel configuration you should have at least one of \fBmd5\fR, \fBsha1\fR, and \fBcrc32c\fR available\&. By default this is not enabled; you must set this option explicitly in order to be able to use on\-line device verification\&. .sp See also the notes on data integrity\&. .RE .PP \fBcsums\-alg \fR\fB\fIhash\-alg\fR\fR .RS 4 A resync process sends all marked data blocks from the source to the destination node, as long as no \fBcsums\-alg\fR is given\&. When one is specified the resync process exchanges hash values of all marked blocks first, and sends only those data blocks that have different hash values\&. .sp This setting is useful for DRBD setups with low bandwidth links\&. During the restart of a crashed primary node, all blocks covered by the activity log are marked for resync\&. But a large part of those will actually be still in sync, therefore using \fBcsums\-alg\fR will lower the required bandwidth in exchange for CPU cycles\&. .RE .PP \fBc\-plan\-ahead \fR\fB\fIplan_time\fR\fR, \fBc\-fill\-target \fR\fB\fIfill_target\fR\fR, \fBc\-delay\-target \fR\fB\fIdelay_target\fR\fR, \fBc\-max\-rate \fR\fB\fImax_rate\fR\fR .RS 4 The dynamic resync speed controller gets enabled with setting \fIplan_time\fR to a positive value\&. It aims to fill the buffers along the data path with either a constant amount of data \fIfill_target\fR, or aims to have a constant delay time of \fIdelay_target\fR along the path\&. The controller has an upper bound of \fImax_rate\fR\&. .sp By \fIplan_time\fR the agility of the controller is configured\&. Higher values yield for slower/lower responses of the controller to deviation from the target value\&. It should be at least 5 times RTT\&. For regular data paths a \fIfill_target\fR in the area of 4k to 100k is appropriate\&. For a setup that contains drbd\-proxy it is advisable to use \fIdelay_target\fR instead\&. Only when \fIfill_target\fR is set to 0 the controller will use \fIdelay_target\fR\&. 5 times RTT is a reasonable starting value\&. \fIMax_rate\fR should be set to the bandwidth available between the DRBD\-hosts and the machines hosting DRBD\-proxy, or to the available disk\-bandwidth\&. .sp The default value of \fIplan_time\fR is 0, the default unit is 0\&.1 seconds\&. \fIFill_target\fR has 0 and sectors as default unit\&. \fIDelay_target\fR has 1 (100ms) and 0\&.1 as default unit\&. \fIMax_rate\fR has 10240 (100MiB/s) and KiB/s as default unit\&. .sp The dynamic resync speed controller and its settings are available since DRBD 8\&.3\&.9\&. .RE .PP \fBc\-min\-rate \fR\fB\fImin_rate\fR\fR .RS 4 A node that is primary and sync\-source has to schedule application IO requests and resync IO requests\&. The \fImin_rate\fR tells DRBD use only up to min_rate for resync IO and to dedicate all other available IO bandwidth to application requests\&. .sp Note: The value 0 has a special meaning\&. It disables the limitation of resync IO completely, which might slow down application IO considerably\&. Set it to a value of 1, if you prefer that resync IO never slows down application IO\&. .sp Note: Although the name might suggest that it is a lower bound for the dynamic resync speed controller, it is not\&. If the DRBD\-proxy buffer is full, the dynamic resync speed controller is free to lower the resync speed down to 0, completely independent of the \fBc\-min\-rate\fR setting\&. .sp \fIMin_rate\fR has 4096 (4MiB/s) and KiB/s as default unit\&. .RE .PP \fBon\-no\-data\-accessible \fR\fB\fIond\-policy\fR\fR .RS 4 This setting controls what happens to IO requests on a degraded, disk less node (I\&.e\&. no data store is reachable)\&. The available policies are \fBio\-error\fR and \fBsuspend\-io\fR\&. .sp If \fIond\-policy\fR is set to \fBsuspend\-io\fR you can either resume IO by attaching/connecting the last lost data storage, or by the \fBdrbdadm resume\-io \fR\fB\fIres\fR\fR command\&. The latter will result in IO errors of course\&. .sp The default is \fBio\-error\fR\&. This setting is available since DRBD 8\&.3\&.9\&. .RE .PP \fBcpu\-mask \fR\fB\fIcpu\-mask\fR\fR .RS 4 .\" drbd.conf: cpu-mask Sets the cpu\-affinity\-mask for DRBD\'s kernel threads of this device\&. The default value of \fIcpu\-mask\fR is 0, which means that DRBD\'s kernel threads should be spread over all CPUs of the machine\&. This value must be given in hexadecimal notation\&. If it is too big it will be truncated\&. .RE .PP \fBpri\-on\-incon\-degr \fR\fB\fIcmd\fR\fR .RS 4 .\" drbd.conf: pri-on-incon-degr This handler is called if the node is primary, degraded and if the local copy of the data is inconsistent\&. .RE .PP \fBpri\-lost\-after\-sb \fR\fB\fIcmd\fR\fR .RS 4 .\" drbd.conf: pri-lost-after-sb The node is currently primary, but lost the after\-split\-brain auto recovery procedure\&. As as consequence, it should be abandoned\&. .RE .PP \fBpri\-lost \fR\fB\fIcmd\fR\fR .RS 4 .\" drbd.conf: pri-lost The node is currently primary, but DRBD\'s algorithm thinks that it should become sync target\&. As a consequence it should give up its primary role\&. .RE .PP \fBfence\-peer \fR\fB\fIcmd\fR\fR .RS 4 .\" drbd.conf: fence-peer The handler is part of the \fBfencing\fR mechanism\&. This handler is called in case the node needs to fence the peer\'s disk\&. It should use other communication paths than DRBD\'s network link\&. .RE .PP \fBlocal\-io\-error \fR\fB\fIcmd\fR\fR .RS 4 .\" drbd.conf: local-io-error DRBD got an IO error from the local IO subsystem\&. .RE .PP \fBinitial\-split\-brain \fR\fB\fIcmd\fR\fR .RS 4 .\" drbd.conf: initial-split-brain DRBD has connected and detected a split brain situation\&. This handler can alert someone in all cases of split brain, not just those that go unresolved\&. .RE .PP \fBsplit\-brain \fR\fB\fIcmd\fR\fR .RS 4 .\" drbd.conf: split-brain DRBD detected a split brain situation but remains unresolved\&. Manual recovery is necessary\&. This handler should alert someone on duty\&. .RE .PP \fBbefore\-resync\-target \fR\fB\fIcmd\fR\fR .RS 4 .\" drbd.conf: before-resync-target DRBD calls this handler just before a resync begins on the node that becomes resync target\&. It might be used to take a snapshot of the backing block device\&. .RE .PP \fBafter\-resync\-target \fR\fB\fIcmd\fR\fR .RS 4 .\" drbd.conf: after-resync-target DRBD calls this handler just after a resync operation finished on the node whose disk just became consistent after being inconsistent for the duration of the resync\&. It might be used to remove a snapshot of the backing device that was created by the \fBbefore\-resync\-target\fR handler\&. .RE .SS "Other Keywords" .PP \fBinclude \fR\fB\fIfile\-pattern\fR\fR .RS 4 .\" drbd.conf: include Include all files matching the wildcard pattern \fIfile\-pattern\fR\&. The \fBinclude\fR statement is only allowed on the top level, i\&.e\&. it is not allowed inside any section\&. .RE .SH "NOTES ON DATA INTEGRITY" .PP There are two independent methods in DRBD to ensure the integrity of the mirrored data\&. The online\-verify mechanism and the \fBdata\-integrity\-alg\fR of the \fBnetwork\fR section\&. .PP Both mechanisms might deliver false positives if the user of DRBD modifies the data which gets written to disk while the transfer goes on\&. This may happen for swap, or for certain append while global sync, or truncate/rewrite workloads, and not necessarily poses a problem for the integrity of the data\&. Usually when the initiator of the data transfer does this, it already knows that that data block will not be part of an on disk data structure, or will be resubmitted with correct data soon enough\&. .PP The \fBdata\-integrity\-alg\fR causes the receiving side to log an error about "Digest integrity check FAILED: Ns +x\en", where N is the sector offset, and x is the size of the requst in bytes\&. It will then disconnect, and reconnect, thus causing a quick resync\&. If the sending side at the same time detected a modification, it warns about "Digest mismatch, buffer modified by upper layers during write: Ns +x\en", which shows that this was a false positive\&. The sending side may detect these buffer modifications immediately after the unmodified data has been copied to the tcp buffers, in which case the receiving side won\'t notice it\&. .PP The most recent (2007) example of systematic corruption was an issue with the TCP offloading engine and the driver of a certain type of GBit NIC\&. The actual corruption happened on the DMA transfer from core memory to the card\&. Since the TCP checksum gets calculated on the card, this type of corruption stays undetected as long as you do not use either the online \fBverify\fR or the \fBdata\-integrity\-alg\fR\&. .PP We suggest to use the \fBdata\-integrity\-alg\fR only during a pre\-production phase due to its CPU costs\&. Further we suggest to do online \fBverify\fR runs regularly e\&.g\&. once a month during a low load period\&. .SH "VERSION" .sp This document was revised for version 8\&.3\&.2 of the DRBD distribution\&. .SH "AUTHOR" .sp Written by Philipp Reisner philipp\&.reisner@linbit\&.com and Lars Ellenberg lars\&.ellenberg@linbit\&.com\&. .SH "REPORTING BUGS" .sp Report bugs to drbd\-user@lists\&.linbit\&.com\&. .SH "COPYRIGHT" .sp Copyright 2001\-2008 LINBIT Information Technologies, Philipp Reisner, Lars Ellenberg\&. This is free software; see the source for copying conditions\&. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE\&. .SH "SEE ALSO" .PP \fBdrbd\fR(8), \fBdrbddisk\fR(8), \fBdrbdsetup\fR(8), \fBdrbdadm\fR(8), \m[blue]\fBDRBD User\'s Guide\fR\m[]\&\s-2\u[1]\d\s+2, \m[blue]\fBDRBD web site\fR\m[]\&\s-2\u[3]\d\s+2 .SH "NOTES" .IP " 1." 4 DRBD User's Guide .RS 4 \%http://www.drbd.org/users-guide/ .RE .IP " 2." 4 DRBD's online usage counter .RS 4 \%http://usage.drbd.org .RE .IP " 3." 4 DRBD web site .RS 4 \%http://www.drbd.org/ .RE drbd-utils-8.9.6/documentation/v9/0000755000175000017500000000000012654475367016735 5ustar apoikosapoikosdrbd-utils-8.9.6/documentation/v9/drbdsetup.xsl0000644000175000017500000000233012466702073021443 0ustar apoikosapoikos drbd-utils-8.9.6/documentation/v9/drbdmeta.80000644000175000017500000001763312654452461020610 0ustar apoikosapoikos'\" t .\" Title: drbdmeta .\" Author: [see the "Author" section] .\" Generator: DocBook XSL Stylesheets v1.75.2 .\" Date: 6 December 2012 .\" Manual: System Administration .\" Source: DRBD 9.0.0 .\" Language: English .\" .TH "DRBDMETA" "8" "6 December 2012" "DRBD 9.0.0" "System Administration" .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" drbdmeta \- Manipulate the DRBD on\-disk metadata.\" drbdmeta .SH "SYNOPSIS" .HP \w'\fBdrbdmeta\fR\ 'u \fBdrbdmeta\fR [\-\-force] [\-\-ignore\-sanity\-checks] {\fIdevice\fR} {v06\ \fIminor\fR | v07\ \fImeta_dev\ index\fR | v08\ \fImeta_dev\ index\fR | v09\ \fImeta_dev\ index\fR} {\fIcommand\fR} [\fIcmd\ args\fR...] .SH "DESCRIPTION" .PP The \fBdrbdmeta\fR utility is used for creating, displaying, and modifying DRBD\'s on\-disk metadata\&. Users usually interact with the \fBdrbdadm\fR utility, which provides a more high\-level interface to DRBD than \fBdrbdmeta\fR\&. (See \fBdrbdadm\fR\'s \fB\-\-dry\-run\fR option to see how \fBdrbdadm\fR uses \fBdrbdmeta\fR\&.) .PP This utility can only be used on devices which are not currently in use by the kernel\&. .PP The first argument (\fIdevice\fR) specifies the drbd device associated with a volume, or \(lq\-\(rq if no device is associated with that volume\&. If the drbd device is specified, the \fBdrbdmeta\fR utility makes sure that the drbd device does not currently have a volume attached to prevent meta\-data of an active volume from being destroyed\&. .PP The second argument specifies the metadata version to use (v06, v07, v08, v09)\&. In most metadata versions, the third argument (\fImeta_dev\fR) specifies the device which contains the metadata; this argument can be the same as \fIdevice\fR\&. The fourth argument (\fIindex\fR) can be one of the keywords \fBinternal\fR (for internal metadata), \fBflex\-internal\fR (in v07 for variable\-sized metadata; v07 otherwise defaults to fixed\-size internal metadata), \fBflex\-external\fR (for variable\-sized external metadata), or a numeric matadata index (for fixed\-size external metadata)\&. See the \fBmeta\-disk\fR parameter in \fBdrbd.conf\fR(5)\&. .SH "OPTIONS" .PP \-\-force .RS 4 .\" drbdmeta: --force Assume yes as the answer to all questions drbdmeta would ask\&. .RE .PP \-\-ignore\-sanity\-checks .RS 4 .\" drbdmeta: --ignore-sanity-checks Normally, \fBdrbdmeta\fR performs some sanity checks before writing to the metadata device: for example, if the device appears to contain a file system, it refuses to destroy the file system by writing into it\&. Use this option to ignore these checks\&. .RE .SH "COMMANDS" .PP \fBcreate\-md\fR [\fB\-\-peer\-max\-bio\-size=\fR\fIval\fR] (metadata versions v06, v07, and v08), .br \fBcreate\-md\fR {number\-of\-bitmap\-slots} [\fB\-\-peer\-max\-bio\-size=\fR\fIval\fR] [\fB\-\-al\-stripes=\fR\fIval\fR] [\fB\-\-al\-stripe\-size\-kB=\fR\fIval\fR] (metadata version v09) .RS 4 .\" drbdmeta: create-md Initialize the metadata\&. This is necessary before a DRBD resource can be attached\&. If \fBdrbdmeta\fR finds an older version of DRBD metadata on the device, it asks if the format should be converted\&. .sp When \fBdrbdadm\fR calls \fBdrbdmeta\fR\'s \fBcreate\-md\fR command for a device, it sets the \fInumber\-of\-bitmap\-slots\fR argument to the number of peers in the resource\&. To reserve additional bitmap slots (which allows to add more peers in the future), call \fBdrbdmeta\fR directly instead\&. .sp When a device is used before being connected to its peers the first time, DRBD assumes that peers can only handle 4 KiB requests by default\&. The \fB\-\-peer\-max\-bio\-size\fR option allows to set more optimistic values; use this if the versions of DRBD that this device will connect to are known\&. DRBD supports a maximum bio size of 32 KiB since version 8\&.3\&.8, of 128 KiB since version 8\&.3\&.9, and of 1 MiB since version 8\&.4\&.0\&. .sp If you want to use more than 6433 activity log extents, or live on top of a spriped RAID, you may specify the number of stripes (\fB\-\-al\-stripes\fR, default 1), and the stripe size (\fB\-\-al\-stripe\-size\-kB\fR, default 32)\&. To just use a larger linear on\-disk ring\-buffer, leave the number of stripes at 1, and increase the size only: \fBdrbdmeta 0 v08 /dev/vg23/lv42 internal create\-md \-\-al\-stripe\-size 1M\fR .sp To avoid a single "spindle" from becoming a bottleneck, increase the number of stripes, to achieve an interleaved layout of the on\-disk activity\-log transactions\&. What you give as "stripe\-size" should be what is a\&.k\&.a\&. "chunk size" or "granularity" or "strip unit": the minimum skip to the next "spindle"\&. \fBdrbdmeta 0 v08 /dev/vg23/lv42 internal create\-md \-\-al\-stripes 7 \-\-al\-stripe\-size 64\fR .RE .PP \fBget\-gi\fR [\fB\-\-node\-id=\fR\fIid\fR] .RS 4 .\" drbdmeta: get-gi Show the data generation identifiers for a device on a particular connection\&. DRBD version 9\&.0\&.0 and beyond support multiple peers; use the \fInode\-id\fR option to define which peer\'s data generation identifiers to show\&. .RE .PP \fBshow\-gi\fR [\fB\-\-node\-id=\fR\fIid\fR] .RS 4 .\" drbdmeta: show-gi Similar to \fBget\-gi\fR, but with explanatory information\&. .RE .PP \fBdump\-md\fR .RS 4 .\" drbdmeta: dump-md Dump the metadata of a device in text form, including the bitmap and activity log\&. .RE .PP \fBoutdate\fR .RS 4 Mark the data on a lower\-level device as outdated\&. See \fBdrbdsetup\fR(8) for details\&. .RE .PP \fBdstate\fR .RS 4 Show the current disk state of a lower\-level device\&. .RE .PP \fBcheck\-resize\fR .RS 4 .\" drbdmeta: check-resize Examine the device size of a lower\-level device and its last known device size (saved in \fB/var/lib/drbd/drbd\-minor\-\fR\fB\fIminor\fR\fR\fB\&.lkbd\fR by \fBdrbdsetup check\-resize\fR)\&. For internal metadata, if the size of the lower\-level device has changed and the metadata can be found at the previous position, move the metadata to the new position at the end of the block device\&. .RE .PP \fBapply\-al\fR .RS 4 .\" drbdmeta: apply-al Apply the activity log of the specified device\&. This is necessary before the device can be attached by the kernel again\&. .RE .SH "EXPERT COMMANDS" .PP The \fBdrbdmeta\fR utility can be used to fine tune metdata\&. Please note that this can lead to destroyed metadata or even silent data corruption; use with great care only\&. .PP \fBset\-gi\fR \fIgi\fR [\fB\-\-node\-id=\fR\fIid\fR] .RS 4 .\" drbdmeta: set-gi Set the generation identifiers\&. The \fIgi\fR argument is a generation counter for the v06 and v07 formats, and a set of UUIDs for v08 and beyond\&. Accepts the same syntax as in the \fBget\-gi\fR output\&. DRBD version 9\&.0\&.0 and beyond support multiple peers; use the \fI\-\-node\-id\fR option to define which peer\'s data generation identifiers to set\&. .RE .PP \fBrestore\-md\fR \fIdump_file\fR .RS 4 .\" drbdmeta: restore-md Replace the metadata on the device with the contents of \fIdump_file\fR\&. The dump file format is defined by the output of the \fBdump\-md\fR command\&. .RE .SH "VERSION" .sp This document was revised for version 9\&.0\&.0 of the DRBD distribution\&. .SH "AUTHOR" .sp Written by Philipp Reisner philipp\&.reisner@linbit\&.com and Lars Ellenberg lars\&.ellenberg@linbit\&.com\&. .SH "REPORTING BUGS" .sp Report bugs to drbd\-user@lists\&.linbit\&.com\&. .SH "COPYRIGHT" .sp Copyright 2001\-2008,2012 LINBIT Information Technologies, Philipp Reisner, Lars Ellenberg\&. This is free software; see the source for copying conditions\&. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE\&. .SH "SEE ALSO" .PP \fBdrbdadm\fR(8) \fBdrbd.conf\fR(5) drbd-utils-8.9.6/documentation/v9/drbd.80000644000175000017500000000434712654452460017736 0ustar apoikosapoikos'\" t .\" Title: drbd .\" Author: [see the "Author" section] .\" Generator: DocBook XSL Stylesheets v1.75.2 .\" Date: 24 June 2014 .\" Manual: System Administration .\" Source: DRBD 9.0.0 .\" Language: English .\" .TH "DRBD" "8" "24 June 2014" "DRBD 9.0.0" "System Administration" .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" drbd \- The start and stop script for DRBD .SH "SYNOPSIS" .HP \w'\fB/etc/init\&.d/drbd\fR\ 'u \fB/etc/init\&.d/drbd\fR {start | stop | status | reload | restart | force\-reload} .SH "INTRODUCTION" .PP The \fB/etc/init\&.d/drbd\fR script is used to start and stop drbd on a system V style init system\&. .PP When using a cluster resource manger such as Pacemaker, DRBD should usually \fInot\fR be started by the init system, but should typically be exclusively controlled by the cluster manager\&. You should not use, and disable, the init script in this case\&. \fBchmod \-x /etc/init\&.d/drbd\fR has proven most effective for this\&. .PP In order to use \fB/etc/init\&.d/drbd\fR, define a drbd configuration\&. See \fBdrbd.conf\fR(5) for details\&. .SH "VERSION" .sp This document was revised for version 9\&.0\&.0 of the DRBD distribution\&. .SH "AUTHOR" .sp Written by Philipp Reisner philipp\&.reisner@linbit\&.com and Lars Ellenberg lars\&.ellenberg@linbit\&.com\&. .SH "REPORTING BUGS" .sp Report bugs to drbd\-user@lists\&.linbit\&.com\&. .SH "COPYRIGHT" .sp Copyright 2001\-2014 LINBIT Information Technologies, Philipp Reisner, Lars Ellenberg\&. This is free software; see the source for copying conditions\&. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE\&. .SH "SEE ALSO" .PP \fBdrbd.conf\fR(5), \fBdrbdsetup\fR(8), \fBdrbdadm\fR(8), \m[blue]\fBDRBD Homepage\fR\m[]\&\s-2\u[1]\d\s+2 .SH "NOTES" .IP " 1." 4 DRBD Homepage .RS 4 \%http://www.drbd.org/ .RE drbd-utils-8.9.6/documentation/v9/drbd.conf.xsl0000644000175000017500000000165112466702073021313 0ustar apoikosapoikos drbd-utils-8.9.6/documentation/v9/drbdsetup.xml.in0000644000175000017500000012676112647177714022072 0ustar apoikosapoikos ]> &drbdsetup_options; 3 December 2011 DRBD 9.0.0 drbdsetup 8 System Administration drbdsetup Configure the DRBD kernel module drbdsetup drbdsetup command argument option Description The drbdsetup utility serves to configure the DRBD kernel module and to show its current configuration. Users usually interact with the drbdadm utility, which provides a more high-level interface to DRBD than drbdsetup. (See 's option to see how uses .) Some option arguments have a default scale which applies when a plain number is specified (for example Kilo, or 1024 times the numeric value). Such default scales can be overridden by using a suffix (for example, M for Mega). The common suffixes K = 2^10 = 1024, M = 1024 K, and G = 1024 M are supported. Commands drbdsetup disk The command attaches a lower-level device to an existing replicated device. The command changes the disk options of an attached lower-level device. In either case, the replicated device must have been created with drbdsetup new-minor. Both commands refer to the replicated device by its minor number. lower_dev is the name of the lower-level device. meta_data_dev is the name of the device containing the metadata, and may be the same as lower_dev. meta_data_index is either a numeric metadata index, or the keyword for internal metadata, or the keyword for variable-size external metadata. Available options: drbdsetup peer-device-options These are options that affect the peer's device. drbdsetup check-resize Remember the current size of the lower-level device of the specified replicated device. Used by drbdadm. The size information is stored in file /var/lib/drbd/drbd-minor-minor.lkbd. drbdsetup net The command creates a connection within a resource. The resource must have been created with drbdsetup new-resource. The command changes the network options of an existing connection. Before a connection can be activated with the command, at least one path need to added with the command. Available options: drbdsetup net The command creates a path within a connection. The connection must have been created with drbdsetup new-peer. Local_addr and remote_addr refer to the local and remote protocol, network address, and port in the format address-family:address:port. The address families , , (Dolphin Interconnect Solutions' "super sockets"), (Infiniband Sockets Direct Protocol), and are supported ( is an alias for ). If no address family is specified, is assumed. For all address families except , the address uses IPv4 address notation (for example, 1.2.3.4). For , the address is enclosed in brackets and uses IPv6 address notation (for example, [fd01:2345:6789:abcd::1]). The port defaults to 7788. drbdsetup net The command activates a connection. That means that the DRBD driver will bind and listen on all local addresses of the connection-'s paths. It will begin to try to establish one or more paths of the connection. Available options: drbdsetup net The command removes a connection from a resource. drbdsetup net The command removes a path from a connection. Please not that it fails if the path is necessary to keep a connected connection in tact. In order to remove all paths, disconnect the connection first. drbdsetup cstate Show the current state of a connection. The connection is identified by the node-id of the peer; see the drbdsetup connect command. Remove a replicated device. No lower-level device may be attached; see drbdsetup detach. Remove a resource. All volumes and connections must be removed first (drbdsetup del-minor, drbdsetup disconnect). Alternatively, drbdsetup down can be used to remove a resource together with all its volumes and connections. drbdsetup detach Detach the lower-level device of a replicated device. Available options: Force the detach and return immediately. This puts the lower-level device into failed state until all pending I/O has completed, and then detaches the device. Any I/O not yet submitted to the lower-level device (for example, because I/O on the device was suspended) is assumed to have failed. drbdsetup disconnect Remove a connection to a peer host. The connection is identified by the node-id of the peer; see the drbdsetup connect command. drbdsetup down Take a resource down by removing all volumes, connections, and the resource itself. drbdsetup dstate Show the current disk state of a lower-level device. drbdsetup events2 Show the current state of all configured DRBD objects, followed by all changes to the state. The output format is meant to be human as well as machine readable. The line starts with a word that indicates the kind of event: for an existing object; , , and if an object is created, destroyed, or changed; or or if an event handler is called or it returns. The second word indicates the object the event applies to: , , , , , or a dash () to indicate that the current state has been dumped completely. The remaining words identify the object and describe the state that he object is in. Available options: Terminate after reporting the current state. The default is to continuously listen and report state changes. Include statistics in the output. drbdsetup get-gi Show the data generation identifiers for a device on a particular connection. The device is identified by its volume number. The connection is identified by its endpoints; see the drbdsetup connect command. The output consists of the current UUID, bitmap UUID, and the first two history UUIDS, folowed by a set of flags. The current UUID and history UUIDs are device specific; the bitmap UUID and flags are peer device specific. This command only shows the first two history UUIDs. Internally, DRBD maintains one history UUID for each possible peer device. drbdsetup invalidate Replace the local data of a device with that of a peer. All the local data will be marked out-of-sync, and a resync with the specified peer device will be initialted. drbdsetup invalidate-remote Replace a peer device's data of a resource with the local data. The peer device's data will be marked out-of-sync, and a resync from the local node to the specified peer will be initiated. drbdsetup new-current-uuid Generate a new current UUID and rotates all other UUID values. This has at least two use cases, namely to skip the initial sync, and to reduce network bandwidth when starting in a single node configuration and then later (re-)integrating a remote site. Available option: Clears the sync bitmap in addition to generating a new current UUID. This can be used to skip the initial sync, if you want to start from scratch. This use-case does only work on "Just Created" meta data. Necessary steps: On both nodes, initialize meta data and configure the device. drbdadm create-md --force res They need to do the initial handshake, so they know their sizes. drbdadm up res They are now Connected Secondary/Secondary Inconsistent/Inconsistent. Generate a new current-uuid and clear the dirty bitmap. drbdadm --clear-bitmap new-current-uuid res They are now Connected Secondary/Secondary UpToDate/UpToDate. Make one side primary and create a file system. drbdadm primary res mkfs -t fs-type $(drbdadm sh-dev res) One obvious side-effect is that the replica is full of old garbage (unless you made them identical using other means), so any online-verify is expected to find any number of out-of-sync blocks. You must not use this on pre-existing data! Even though it may appear to work at first glance, once you switch to the other node, your data is toast, as it never got replicated. So do not leave out the mkfs (or equivalent). This can also be used to shorten the initial resync of a cluster where the second node is added after the first node is gone into production, by means of disk shipping. This use-case works on disconnected devices only, the device may be in primary or secondary role. The necessary steps on the current active server are: drbdsetup new-current-uuid --clear-bitmap minor Take the copy of the current active server. E.g. by pulling a disk out of the RAID1 controller, or by copying with dd. You need to copy the actual data, and the meta data. drbdsetup new-current-uuid minor Now add the disk to the new secondary node, and join it to the cluster. You will get a resync of that parts that were changed since the first call to drbdsetup in step 1. Create a new replicated device within a resource. The command creates a block device inode for the replicated device (by default, /dev/drbdminor). The volume number identifies the device within the resource. The command creates a new resource. The command changes the resource options of an existing resource. Available options: drbdsetup outdate Mark the data on a lower-level device as outdated. This is used for fencing, and prevents the resource the device is part of from becoming primary in the future. See the disk option. drbdsetup pause-sync Stop resynchronizing between a local and a peer device by setting the local pause flag. The resync can only resume if the pause flags on both sides of a connection are cleared. drbdsetup primary Change the role of a node in a resource to primary. This allows the replicated devices in this resource to be mounted or opened for writing. Available options: This option is an alias for the option. Force the resource to become primary even if some devices are not guaranteed to have up-to-date data. This option is used to turn one of the nodes in a newly created cluster into the primary node, or when manually recovering from a disaster. Note that this can lead to split-brain scenarios. Also, when forcefully turning an inconsistent device into an up-to-date device, it is highly recommended to use any integrity checks available (such as a filesystem check) to make sure that the device can at least be used without crashing the system. Note that DRBD usually only allows one node in a cluster to be in primary role at any time; this allows DRBD to coordinate access to the devices in a resource across nodes. The network option changes this; in that case, a mechanism outside of DRBD needs to coordinate device access. drbdsetup resize Reexamine the size of the lower-level devices of a replicated device on all nodes. This command is called after the lower-level devices on all nodes have been grown to adjust the size of the replicated device. Available options: Resize the device even if some of the peer devices are not connected at the moment. DRBD will try to resize the peer devices when they next connect. It will refuse to connect to a peer device which is too small. Do not resynchronize the added disk space; instead, assume that it is identical on all nodes. This option can be used when the disk space is uninitialized and differences do not matter, or when it is known to be identical on all nodes. See the drbdsetup verify command. This option can be used to online shrink the usable size of a drbd device. It's the users responsibility to make sure that a file system on the device is not truncated by that operation. These options may be used to change the layout of the activity log online. In case of internal meta data this may invovle shrinking the user visible size at the same time (unsing the ) or increasing the avalable space on the backing devices. drbdsetup resume-io Resume I/O on a replicated device. See the net option. drbdsetup resume-sync Allow resynchronization to resume by clearing the local sync pause flag. drbdsetup role Show the current role of a resource. drbdsetup secondary Change the role of a node in a resource to secondary. This command fails if the replicated device is in use. drbdsetup show Show the current configuration of a resource, or of all resources. Available options: Show all configuration parameters, even the ones with default values. Normally, parameters with default values are not shown. drbdsetup show-gi Show the data generation identifiers for a device on a particular connection. In addition, explain the output. The output otherwise is the same as in the drbdsetup get-gi command. drbdsetupstate drbdsetup state This is an alias for drbdsetup role. Deprecated. drbdsetup status Show the status of a resource, or of all resources. The output consists of one paragraph for each configured resource. Each paragraph contains one line for each resource, followed by one line for each device, and one line for each connection. The device and connection lines are indented. The connection lines are followed by one line for each peer device; these lines are indented against the connection line. Long lines are wrapped around at terminal width, and indented to indicate how the lines belongs together. Available options: Include more information in the output even when it is likely redundant or irrelevant. Include data transfer statistics in the output. Colorize the output. With , emits color codes only when standard output is connected to a terminal. For example, the non-verbose output for a resource with only one connection and only one volume could look like this: drbd0 role:Primary disk:UpToDate host2.example.com role:Secondary disk:UpToDate With the option, the same resource could be reported as: drbd0 node-id:1 role:Primary suspended:no volume:0 minor:1 disk:UpToDate blocked:no host2.example.com local:ipv4:192.168.123.4:7788 peer:ipv4:192.168.123.2:7788 node-id:0 connection:WFReportParams role:Secondary congested:no volume:0 replication:Connected disk:UpToDate resync-suspended:no drbdsetup suspend-io Suspend I/O on a replicated device. It is not usually necessary to use this command. drbdsetup verify Start online verification, change which part of the device will be verified, or stop online verification. The command requires the specified peer to be connected. Online verification compares each disk block on the local and peer node. Blocks which differ between the nodes are marked as out-of-sync, but they are not automatically brought back into sync. To bring them into sync, the resource must be disconnected and reconnected. Progress can be monitored in the output of drbdsetup status --statistics. Available options: Define where online verification should start. This parameter is ignored if online verification is already in progress. If the start parameter is not specified, online verification will continue where it was interrupted (if the connection to the peer was lost while verifying), after the previous stop sector (if the previous online verification has finished), or at the beginning of the device (if the end of the device was reached, or online verify has not run before). The position on disk is specified in disk sectors (512 bytes) by default. Define where online verification should stop. If online verification is already in progress, the stop position of the active online verification process is changed. Use this to stop online verification. The position on disk is specified in disk sectors (512 bytes) by default. Also see the notes on data integrity in the drbd.conf 5 manual page. drbdsetup wait-connect-volume wait-connect-connection wait-connect-resource drbdsetup wait-sync-volume wait-sync-connection wait-sync-resource The commands waits until a device on a peer is visible. The commands waits until a device on a peer is up to date. Available options for both commands: drbdsetup forget-peer The command removes all traces of a peer node from the meta-data. It frees a bitmap slot in the meta-data and make it avalable for futher bitmap slot allocation in case a so-far never seen node connects. The connection must be taken down before this command may be used. In case the peer re-connects at a later point a bit-map based resync will be turned into a full-sync. Examples Please see the DRBD User's Guide for examples. Version This document was revised for version 9.0.0 of the DRBD distribution. Author Written by Philipp Reisner philipp.reisner@linbit.com and Lars Ellenberg lars.ellenberg@linbit.com. Reporting Bugs Report bugs to drbd-user@lists.linbit.com. Copyright Copyright 2001-2012 LINBIT Information Technologies, Philipp Reisner, Lars Ellenberg. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See Also drbd.conf 5 , drbd 8 , drbddisk 8 , drbdadm 8 , DRBD User's Guide, DRBD Web Site drbd-utils-8.9.6/documentation/v9/drbd-overview.80000644000175000017500000000405112654452462021574 0ustar apoikosapoikos'\" t .\" Title: drbd-overview .\" Author: [see the "Author" section] .\" Generator: DocBook XSL Stylesheets v1.75.2 .\" Date: 24 June 2014 .\" Manual: System Administration .\" Source: DRBD 9.0.0 .\" Language: English .\" .TH "DRBD\-OVERVIEW" "8" "24 June 2014" "DRBD 9.0.0" "System Administration" .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" drbd-overview \- Overview of all configured DRBD resources .SH "SYNOPSIS" .HP \w'\fBdrbd\-overview\fR\ 'u \fBdrbd\-overview\fR .SH "DESCRIPTION" .PP drbd\-overview offers an overview of the state of all configured DRBD resources\&. It provides information about the connection status of each DRBD resource\&. It will also use auxiliary information provided by \fBdf\fR(1), \fBlvm\fR(8), \fBxm\fR(1) and \fBvirsh\fR(1) for DRBD resources used as mounted filesystems, LVM physical volumes, Xen domain backing disks and libvirt instance disks respectively\&. .SH "AUTHOR" .sp Written by Philipp Reisner philipp\&.reisner@linbit\&.com and Lars Ellenberg lars\&.ellenberg@linbit\&.com\&. Initial man\-page contributed by Apollon Oikonomopoulos apoikos@gmail\&.com\&. .SH "REPORTING BUGS" .sp Report bugs to drbd\-user@lists\&.linbit\&.com\&. .SH "COPYRIGHT" .sp Copyright 2008\-2014 LINBIT Information Technologies, Philipp Reisner, Lars Ellenberg\&. This is free software; see the source for copying conditions\&. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE\&. .SH "SEE ALSO" .PP \fBdrbd.conf\fR(5), \fBdrbdsetup\fR(8), \fBdrbdadm\fR(8), \m[blue]\fBDRBD Homepage\fR\m[]\&\s-2\u[1]\d\s+2 .SH "NOTES" .IP " 1." 4 DRBD Homepage .RS 4 \%http://www.drbd.org/ .RE drbd-utils-8.9.6/documentation/v9/drbdsetup.80000644000175000017500000017526412654452457021034 0ustar apoikosapoikos'\" t .\" Title: drbdsetup .\" Author: [see the "Author" section] .\" Generator: DocBook XSL Stylesheets v1.75.2 .\" Date: 3 December 2011 .\" Manual: System Administration .\" Source: DRBD 9.0.0 .\" Language: English .\" .TH "DRBDSETUP" "8" "3 December 2011" "DRBD 9.0.0" "System Administration" .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" drbdsetup \- Configure the DRBD kernel module.\" drbdsetup .SH "SYNOPSIS" .HP \w'\fBdrbdsetup\fR\ 'u \fBdrbdsetup\fR command {argument...} [option...] .SH "DESCRIPTION" .PP The \fBdrbdsetup\fR utility serves to configure the DRBD kernel module and to show its current configuration\&. Users usually interact with the \fBdrbdadm\fR utility, which provides a more high\-level interface to DRBD than \fBdrbdsetup\fR\&. (See \fBdrbdadm\fR\'s \fB\-\-dry\-run\fR option to see how \fBdrbdadm\fR uses \fBdrbdsetup\fR\&.) .PP Some option arguments have a default scale which applies when a plain number is specified (for example Kilo, or 1024 times the numeric value)\&. Such default scales can be overridden by using a suffix (for example, M for Mega)\&. The common suffixes K = 2^10 = 1024, M = 1024 K, and G = 1024 M are supported\&. .SH "COMMANDS" .PP \fBdrbdsetup\fR attach \fIminor\fR \fIlower_dev\fR \fImeta_data_dev\fR \fImeta_data_index\fR, .br \fBdrbdsetup\fR disk\-options \fIminor\fR .RS 4 .\" drbdsetup: disk The \fBattach\fR command attaches a lower\-level device to an existing replicated device\&. The \fBdisk\-options\fR command changes the disk options of an attached lower\-level device\&. In either case, the replicated device must have been created with \fBdrbdsetup new\-minor\fR\&. .sp Both commands refer to the replicated device by its \fIminor\fR number\&. \fIlower_dev\fR is the name of the lower\-level device\&. \fImeta_data_dev\fR is the name of the device containing the metadata, and may be the same as \fIlower_dev\fR\&. \fImeta_data_index\fR is either a numeric metadata index, or the keyword \fBinternal\fR for internal metadata, or the keyword \fBflexible\fR for variable\-size external metadata\&. Available options: .PP \fB\-\-al\-extents \fR\fB\fIextents\fR\fR .RS 4 DRBD automatically maintains a "hot" or "active" disk area likely to be written to again soon based on the recent write activity\&. The "active" disk area can be written to immediately, while "inactive" disk areas must be "activated" first, which requires a meta\-data write\&. We also refer to this active disk area as the "activity log"\&. .sp The activity log saves meta\-data writes, but the whole log must be resynced upon recovery of a failed node\&. The size of the activity log is a major factor of how long a resync will take and how fast a replicated disk will become consistent after a crash\&. .sp The activity log consists of a number of 4\-Megabyte segments; the \fIal\-extents\fR parameter determines how many of those segments can be active at the same time\&. The default value for \fIal\-extents\fR is 1237, with a minimum of 7 and a maximum of 65536\&. .sp Note that the effective maximum may be smaller, depending on how you created the device meta data, see also \fBdrbdmeta\fR(8) The effective maximum is 919 * (available on\-disk activity\-log ring\-buffer area/4kB \-1), the default 32kB ring\-buffer effects a maximum of 6433 (covers more than 25 GiB of data) We recommend to keep this well within the amount your backend storage and replication link are able to resync inside of about 5 minutes\&. .RE .PP \fB\-\-al\-updates \fR\fB{yes | no}\fR\fB \fR .RS 4 With this parameter, the activity log can be turned off entirely (see the \fBal\-extents\fR parameter)\&. This will speed up writes because fewer meta\-data writes will be necessary, but the entire device needs to be resynchronized opon recovery of a failed primary node\&. The default value for \fBal\-updates\fR is \fByes\fR\&. .RE .PP \fB\-\-disk\-barrier\fR, .br \fB\-\-disk\-flushes\fR, .br \fB\-\-disk\-drain\fR .RS 4 DRBD has three methods of handling the ordering of dependent write requests: .PP \fBdisk\-barrier\fR .RS 4 Use disk barriers to make sure that requests are written to disk in the right order\&. Barriers ensure that all requests submitted before a barrier make it to the disk before any requests submitted after the barrier\&. This is implemented using \'tagged command queuing\' on SCSI devices and \'native command queuing\' on SATA devices\&. Only some devices and device stacks support this method\&. The device mapper (LVM) only supports barriers in some configurations\&. .sp Note that on systems which do not support disk barriers, enabling this option can lead to data loss or corruption\&. Until DRBD 8\&.4\&.1, \fBdisk\-barrier\fR was turned on if the I/O stack below DRBD did support barriers\&. Kernels since linux\-2\&.6\&.36 (or 2\&.6\&.32 RHEL6) no longer allow to detect if barriers are supported\&. Since drbd\-8\&.4\&.2, this option is off by default and needs to be enabled explicitly\&. .RE .PP \fBdisk\-flushes\fR .RS 4 Use disk flushes between dependent write requests, also referred to as \'force unit access\' by drive vendors\&. This forces all data to disk\&. This option is enabled by default\&. .RE .PP \fBdisk\-drain\fR .RS 4 Wait for the request queue to "drain" (that is, wait for the requests to finish) before submitting a dependent write request\&. This method requires that requests are stable on disk when they finish\&. Before DRBD 8\&.0\&.9, this was the only method implemented\&. This option is enabled by default\&. Do not disable in production environments\&. .RE .sp From these three methods, drbd will use the first that is enabled and supported by the backing storage device\&. If all three of these options are turned off, DRBD will submit write requests without bothering about dependencies\&. Depending on the I/O stack, write requests can be reordered, and they can be submitted in a different order on different cluster nodes\&. This can result in data loss or corruption\&. Therefore, turning off all three methods of controlling write ordering is strongly discouraged\&. .sp A general guideline for configuring write ordering is to use disk barriers or disk flushes when using ordinary disks (or an ordinary disk array) with a volatile write cache\&. On storage without cache or with a battery backed write cache, disk draining can be a reasonable choice\&. .RE .PP \fB\-\-disk\-timeout\fR .RS 4 If the lower\-level device on which a DRBD device stores its data does not finish an I/O request within the defined \fBdisk\-timeout\fR, DRBD treats this as a failure\&. The lower\-level device is detached, and the device\'s disk state advances to Diskless\&. If DRBD is connected to one or more peers, the failed request is passed on to one of them\&. .sp This option is \fIdangerous and may lead to kernel panic!\fR .sp "Aborting" requests, or force\-detaching the disk, is intended for completely blocked/hung local backing devices which do no longer complete requests at all, not even do error completions\&. In this situation, usually a hard\-reset and failover is the only way out\&. .sp By "aborting", basically faking a local error\-completion, we allow for a more graceful swichover by cleanly migrating services\&. Still the affected node has to be rebooted "soon"\&. .sp By completing these requests, we allow the upper layers to re\-use the associated data pages\&. .sp If later the local backing device "recovers", and now DMAs some data from disk into the original request pages, in the best case it will just put random data into unused pages; but typically it will corrupt meanwhile completely unrelated data, causing all sorts of damage\&. .sp Which means delayed successful completion, especially for READ requests, is a reason to panic()\&. We assume that a delayed *error* completion is OK, though we still will complain noisily about it\&. .sp The default value of \fBdisk\-timeout\fR is 0, which stands for an infinite timeout\&. Timeouts are specified in units of 0\&.1 seconds\&. This option is available since DRBD 8\&.3\&.12\&. .RE .PP \fB\-\-md\-flushes\fR .RS 4 Enable disk flushes and disk barriers on the meta\-data device\&. This option is enabled by default\&. See the \fBdisk\-flushes\fR parameter\&. .RE .PP \fB\-\-on\-io\-error \fR\fB\fIhandler\fR\fR .RS 4 Configure how DRBD reacts to I/O errors on a lower\-level device\&. The following policies are defined: .PP \fBpass_on\fR .RS 4 Change the disk status to Inconsistent, mark the failed block as inconsistent in the bitmap, and retry the I/O operation on a remote cluster node\&. .RE .PP \fBcall\-local\-io\-error\fR .RS 4 Call the \fBlocal\-io\-error\fR handler (see the \fBhandlers\fR section)\&. .RE .PP \fBdetach\fR .RS 4 Detach the lower\-level device and continue in diskless mode\&. .RE .sp .RE .PP \fB\-\-read\-balancing \fR\fB\fIpolicy\fR\fR .RS 4 Distribute read requests among cluster nodes as defined by \fIpolicy\fR\&. The supported policies are \fBprefer\-local\fR (the default), \fBprefer\-remote\fR, \fBround\-robin\fR, \fBleast\-pending\fR, \fBwhen\-congested\-remote\fR, \fB32K\-striping\fR, \fB64K\-striping\fR, \fB128K\-striping\fR, \fB256K\-striping\fR, \fB512K\-striping\fR and \fB1M\-striping\fR\&. .sp This option is available since DRBD 8\&.4\&.1\&. .RE .PP \fBresync\-after \fR\fB\fIminor\fR\fR .RS 4 Define that a device should only resynchronize after the specified other device\&. By default, no order between devices is defined, and all devices will resynchronize in parallel\&. Depending on the configuration of the lower\-level devices, and the available network and disk bandwidth, this can slow down the overall resync process\&. This option can be used to form a chain or tree of dependencies among devices\&. .RE .PP \fB\-\-size \fR\fB\fIsize\fR\fR .RS 4 Specify the size of the lower\-level device explicitly instead of determining it automatically\&. The device size must be determined once and is remembered for the lifetime of the device\&. In order to determine it automatically, all the lower\-level devices on all nodes must be attached, and all nodes must be connected\&. If the size is specified explicitly, this is not necessary\&. The \fBsize\fR value is assumed to be in units of sectors (512 bytes) by default\&. .RE .PP \fB\-\-discard\-zeroes\-if\-aligned \fR\fB{yes | no}\fR .RS 4 There are several aspects to discard/trim/unmap support on linux block devices\&. Even if discard is supported in general, it may fail silently, or may partially ignore discard requests\&. Devices also announce whether reading from unmapped blocks returns defined data (usually zeroes), or undefined data (possibly old data, possibly garbage)\&. .sp If on different nodes, DRBD is backed by devices with differing discard characteristics, discards may lead to data divergence (old data or garbage left over on one backend, zeroes due to unmapped areas on the other backend)\&. Online verify would now potentially report tons of spurious differences\&. While probably harmless for most use cases (fstrim on a file system), DRBD cannot have that\&. .sp To play safe, we have to disable discard support, if our local backend (on a Primary) does not support "discard_zeroes_data=true"\&. We also have to translate discards to explicit zero\-out on the receiving side, unless the receiving side (Secondary) supports "discard_zeroes_data=true", thereby allocating areas what were supposed to be unmapped\&. .sp There are some devices (notably the LVM/DM thin provisioning) that are capable of discard, but announce discard_zeroes_data=false\&. In the case of DM\-thin, discards aligned to the chunk size will be unmapped, and reading from unmapped sectors will return zeroes\&. However, unaligned partial head or tail areas of discard requests will be silently ignored\&. .sp If we now add a helper to explicitly zero\-out these unaligned partial areas, while passing on the discard of the aligned full chunks, we effectively achieve discard_zeroes_data=true on such devices\&. .sp Setting \fBdiscard\-zeroes\-if\-aligned\fR to \fByes\fR will allow DRBD to use discards, and to announce discard_zeroes_data=true, even on backends that announce discard_zeroes_data=false\&. .sp Setting \fBdiscard\-zeroes\-if\-aligned\fR to \fBno\fR will cause DRBD to always fall\-back to zero\-out on the receiving side, and to not even announce discard capabilities on the Primary, if the respective backend announces discard_zeroes_data=false\&. .sp We used to ignore the discard_zeroes_data setting completely\&. To not break established and expected behaviour, and suddenly cause fstrim on thin\-provisioned LVs to run out\-of\-space instead of freeing up space, the default value is \fByes\fR\&. .sp This option is available since 8\&.4\&.7\&. .RE .PP \fB\-\-rs\-discard\-granularity \fR\fB\fIbyte\fR\fR .RS 4 When \fBrs\-discard\-granularity\fR is set to a non zero, positive value then DRBD tries to do a resync operation in requests of this size\&. In case such a block contains only zero bytes on the sync source node, the sync target node will issue a discard/trim/unmap command for the area\&. .sp The value is constrained by the discard granularity of the backing block device\&. In case \fBrs\-discard\-granularity\fR is not a multiplier of the discard granularity of the backing block device DRBD rounds it up\&. The feature only gets active if the backing block device reads back zeroes after a discard command\&. .sp The default value of is 0\&. This option is available since 8\&.4\&.7\&. .RE .RE .PP \fBdrbdsetup\fR peer\-device\-options \fIresource\fR \fIpeer_node_id\fR \fIvolume\fR .RS 4 .\" drbdsetup: peer-device-options These are options that affect the \fIpeer\fR\'s device\&. .PP \fB\-\-c\-delay\-target \fR\fB\fIdelay_target\fR\fR, .br \fB\-\-c\-fill\-target \fR\fB\fIfill_target\fR\fR, .br \fB\-\-c\-max\-rate \fR\fB\fImax_rate\fR\fR, .br \fB\-\-c\-plan\-ahead \fR\fB\fIplan_time\fR\fR .RS 4 Dynamically control the resync speed\&. This mechanism is enabled by setting the \fBc\-plan\-ahead\fR parameter to a positive value\&. The goal is to either fill the buffers along the data path with a defined amount of data if \fBc\-fill\-target\fR is defined, or to have a defined delay along the path if \fBc\-delay\-target\fR is defined\&. The maximum bandwidth is limited by the \fBc\-max\-rate\fR parameter\&. .sp The \fBc\-plan\-ahead\fR parameter defines how fast drbd adapts to changes in the resync speed\&. It should be set to five times the network round\-trip time or more\&. Common values for \fBc\-fill\-target\fR for "normal" data paths range from 4K to 100K\&. If drbd\-proxy is used, it is advised to use \fBc\-delay\-target\fR instead of \fBc\-fill\-target\fR\&. The \fBc\-delay\-target\fR parameter is used if the \fBc\-fill\-target\fR parameter is undefined or set to 0\&. The \fBc\-delay\-target\fR parameter should be set to five times the network round\-trip time or more\&. The \fBc\-max\-rate\fR option should be set to either the bandwidth available between the DRBD\-hosts and the machines hosting DRBD\-proxy, or to the available disk bandwidth\&. .sp The default values of these parameters are: \fBc\-plan\-ahead\fR = 20 (in units of 0\&.1 seconds), \fBc\-fill\-target\fR = 0 (in units of sectors), \fBc\-delay\-target\fR = 1 (in units of 0\&.1 seconds), and \fBc\-max\-rate\fR = 102400 (in units of KiB/s)\&. .sp Dynamic resync speed control is available since DRBD 8\&.3\&.9\&. .RE .PP .RS 4 .RE .PP .RS 4 .RE .PP \fB\-\-c\-min\-rate \fR\fB\fImin_rate\fR\fR .RS 4 A node which is primary and sync\-source has to schedule application I/O requests and resync I/O requests\&. The \fBc\-min\-rate\fR parameter limits how much bandwidth is available for resync I/O; the remaining bandwidth is used for application I/O\&. .sp A \fBc\-min\-rate\fR value of 0 means that there is no limit on the resync I/O bandwidth\&. This can slow down application I/O significantly\&. Use a value of 1 (1 KiB/s) for the lowest possible resync rate\&. .sp The default value of \fBc\-min\-rate\fR is 4096, in units of KiB/s\&. .RE .PP .RS 4 .RE .PP \fB\-\-resync\-rate \fR\fB\fIrate\fR\fR .RS 4 Define how much bandwidth DRBD may use for resynchronizing\&. DRBD allows "normal" application I/O even during a resync\&. If the resync takes up too much bandwidth, application I/O can become very slow\&. This parameter allows to avoid that\&. Please note this is option only works when the dynamic resync controller is disabled\&. .RE .RE .PP \fBdrbdsetup\fR check\-resize \fIminor\fR .RS 4 .\" drbdsetup: check-resize Remember the current size of the lower\-level device of the specified replicated device\&. Used by drbdadm\&. The size information is stored in file /var/lib/drbd/drbd\-minor\-\fIminor\fR\&.lkbd\&. .RE .PP \fBdrbdsetup\fR new\-peer \fIresource\fR \fIpeer_node_id\fR, .br \fBdrbdsetup\fR net\-options \fIresource\fR \fIpeer_node_id\fR .RS 4 .\" drbdsetup: net The \fBnew\-peer\fR command creates a connection within a \fIresource\fR\&. The resource must have been created with \fBdrbdsetup new\-resource\fR\&. The \fBnet\-options\fR command changes the network options of an existing connection\&. Before a connection can be activated with the \fBconnect\fR command, at least one path need to added with the \fBnew\-path\fR command\&. Available options: .PP \fB\-\-after\-sb\-0pri \fR\fB\fIpolicy\fR\fR .RS 4 Define how to react if a split\-brain scenario is detected and none of the two nodes is in primary role\&. (We detect split\-brain scenarios when two nodes connect; split\-brain decisions are always between two nodes\&.) The defined policies are: .PP \fBdisconnect\fR .RS 4 No automatic resynchronization; simply disconnect\&. .RE .PP \fBdiscard\-younger\-primary\fR, .br \fBdiscard\-older\-primary\fR .RS 4 Resynchronize from the node which became primary first (\fBdiscard\-younger\-primary\fR) or last (\fBdiscard\-older\-primary\fR)\&. If both nodes became primary independently, the \fBdiscard\-least\-changes\fR policy is used\&. .RE .PP \fBdiscard\-zero\-changes\fR .RS 4 If only one of the nodes wrote data since the split brain situation was detected, resynchronize from this node to the other\&. If both nodes wrote data, disconnect\&. .RE .PP \fBdiscard\-least\-changes\fR .RS 4 Resynchronize from the node with more modified blocks\&. .RE .PP \fBdiscard\-node\-\fR\fB\fInodename\fR\fR .RS 4 Always resynchronize to the named node\&. .RE .RE .PP \fB\-\-after\-sb\-1pri \fR\fB\fIpolicy\fR\fR .RS 4 Define how to react if a split\-brain scenario is detected, with one node in primary role and one node in secondary role\&. (We detect split\-brain scenarios when two nodes connect, so split\-brain decisions are always among two nodes\&.) The defined policies are: .PP \fBdisconnect\fR .RS 4 No automatic resynchronization, simply disconnect\&. .RE .PP \fBconsensus\fR .RS 4 Discard the data on the secondary node if the \fBafter\-sb\-0pri\fR algorithm would also discard the data on the secondary node\&. Otherwise, disconnect\&. .RE .PP \fBviolently\-as0p\fR .RS 4 Always take the decision of the \fBafter\-sb\-0pri\fR algorithm, even if it causes an erratic change of the primary\'s view of the data\&. This is only useful if a single\-node file system (i\&.e\&., not OCFS2 or GFS) with the \fBallow\-two\-primaries\fR flag is used\&. This option can cause the primary node to crash, and should not be used\&. .RE .PP \fBdiscard\-secondary\fR .RS 4 Discard the data on the secondary node\&. .RE .PP \fBcall\-pri\-lost\-after\-sb\fR .RS 4 Always take the decision of the \fBafter\-sb\-0pri\fR algorithm\&. If the decision is to discard the data on the primary node, call the \fBpri\-lost\-after\-sb\fR handler on the primary node\&. .RE .RE .PP \fB\-\-after\-sb\-2pri \fR\fB\fIpolicy\fR\fR .RS 4 Define how to react if a split\-brain scenario is detected and both nodes are in primary role\&. (We detect split\-brain scenarios when two nodes connect, so split\-brain decisions are always among two nodes\&.) The defined policies are: .PP \fBdisconnect\fR .RS 4 No automatic resynchronization, simply disconnect\&. .RE .PP \fBviolently\-as0p\fR .RS 4 See the \fBviolently\-as0p\fR policy for \fBafter\-sb\-1pri\fR\&. .RE .PP \fBcall\-pri\-lost\-after\-sb\fR .RS 4 Call the \fBpri\-lost\-after\-sb\fR helper program on one of the machines unless that machine can demote to secondary\&. The helper program is expected to reboot the machine, which brings the node into a secondary role\&. Which machine runs the helper program is determined by the \fBafter\-sb\-0pri\fR strategy\&. .RE .RE .PP \fB\-\-allow\-two\-primaries\fR .RS 4 The most common way to configure DRBD devices is to allow only one node to be primary (and thus writable) at a time\&. .sp In some scenarios it is preferable to allow two nodes to be primary at once; a mechanism outside of DRBD then must make sure that writes to the shared, replicated device happen in a coordinated way\&. This can be done with a shared\-storage cluster file system like OCFS2 and GFS, or with virtual machine images and a virtual machine manager that can migrate virtual machines between physical machines\&. .sp The \fBallow\-two\-primaries\fR parameter tells DRBD to allow two nodes to be primary at the same time\&. Never enable this option when using a non\-distributed file system; otherwise, data corruption and node crashes will result! .RE .PP \fB\-\-always\-asbp\fR .RS 4 Normally the automatic after\-split\-brain policies are only used if current states of the UUIDs do not indicate the presence of a third node\&. .sp With this option you request that the automatic after\-split\-brain policies are used as long as the data sets of the nodes are somehow related\&. This might cause a full sync, if the UUIDs indicate the presence of a third node\&. (Or double faults led to strange UUID sets\&.) .RE .PP \fB\-\-connect\-int \fR\fB\fItime\fR\fR .RS 4 As soon as a connection between two nodes is configured with \fBdrbdsetup connect\fR, DRBD immediately tries to establish the connection\&. If this fails, DRBD waits for \fBconnect\-int\fR seconds and then repeats\&. The default value of \fBconnect\-int\fR is 10 seconds\&. .RE .PP \fB\-\-cram\-hmac\-alg \fR\fB\fIhash\-algorithm\fR\fR .RS 4 Configure the hash\-based message authentication code (HMAC) or secure hash algorithm to use for peer authentication\&. The kernel supports a number of different algorithms, some of which may be loadable as kernel modules\&. See the shash algorithms listed in /proc/crypto\&. By default, \fBcram\-hmac\-alg\fR is unset\&. Peer authentication also requires a \fBshared\-secret\fR to be configured\&. .RE .PP \fB\-\-csums\-alg \fR\fB\fIhash\-algorithm\fR\fR .RS 4 Normally, when two nodes resynchronize, the sync target requests a piece of out\-of\-sync data from the sync source, and the sync source sends the data\&. With many usage patterns, a significant number of those blocks will actually be identical\&. .sp When a \fBcsums\-alg\fR algorithm is specified, when requesting a piece of out\-of\-sync data, the sync target also sends along a hash of the data it currently has\&. The sync source compares this hash with its own version of the data\&. It sends the sync target the new data if the hashes differ, and tells it that the data are the same otherwise\&. This reduces the network bandwidth required, at the cost of higher cpu utilization and possibly increased I/O on the sync target\&. .sp The \fBcsums\-alg\fR can be set to one of the secure hash algorithms supported by the kernel; see the shash algorithms listed in /proc/crypto\&. By default, \fBcsums\-alg\fR is unset\&. .RE .PP \fB\-\-csums\-after\-crash\-only\fR .RS 4 Enabling this option (and csums\-alg, above) makes it possible to use the checksum based resync only for the first resync after primary crash, but not for later "network hickups"\&. .sp In most cases, block that are marked as need\-to\-be\-resynced are in fact changed, so calculating checksums, and both reading and writing the blocks on the resync target is all effective overhead\&. .sp The advantage of checksum based resync is mostly after primary crash recovery, where the recovery marked larger areas (those covered by the activity log) as need\-to\-be\-resynced, just in case\&. Introduced in 8\&.4\&.5\&. .RE .PP \fB\-\-data\-integrity\-alg \fR \fIalg\fR .RS 4 DRBD normally relies on the data integrity checks built into the TCP/IP protocol, but if a data integrity algorithm is configured, it will additionally use this algorithm to make sure that the data received over the network match what the sender has sent\&. If a data integrity error is detected, DRBD will close the network connection and reconnect, which will trigger a resync\&. .sp The \fBdata\-integrity\-alg\fR can be set to one of the secure hash algorithms supported by the kernel; see the shash algorithms listed in /proc/crypto\&. By default, this mechanism is turned off\&. .sp Because of the CPU overhead involved, we recommend not to use this option in production environments\&. Also see the notes on data integrity below\&. .RE .PP \fB\-\-fencing \fR\fB\fIfencing_policy\fR\fR .RS 4 \fBFencing\fR is a preventive measure to avoid situations where both nodes are primary and disconnected\&. This is also known as a split\-brain situation\&. DRBD supports the following fencing policies: .PP \fBdont\-care\fR .RS 4 No fencing actions are taken\&. This is the default policy\&. .RE .PP \fBresource\-only\fR .RS 4 If a node becomes a disconnected primary, it tries to fence the peer\&. This is done by calling the \fBfence\-peer\fR handler\&. The handler is supposed to reach the peer over an alternative communication path and call \'\fBdrbdadm outdate minor\fR\' there\&. .RE .PP \fBresource\-and\-stonith\fR .RS 4 If a node becomes a disconnected primary, it freezes all its IO operations and calls its fence\-peer handler\&. The fence\-peer handler is supposed to reach the peer over an alternative communication path and call \'\fBdrbdadm outdate minor\fR\' there\&. In case it cannot do that, it should stonith the peer\&. IO is resumed as soon as the situation is resolved\&. In case the fence\-peer handler fails, I/O can be resumed manually with \'\fBdrbdadm resume\-io\fR\'\&. .RE .RE .PP \fB\-\-ko\-count \fR\fB\fInumber\fR\fR .RS 4 If a secondary node fails to complete a write request in \fBko\-count\fR times the \fBtimeout\fR parameter, it is excluded from the cluster\&. The primary node then sets the connection to this secondary node to Standalone\&. To disable this feature, you should explicitly set it to 0; defaults may change between versions\&. .RE .PP \fB\-\-max\-buffers \fR\fB\fInumber\fR\fR .RS 4 Limits the memory usage per DRBD minor device on the receiving side, or for internal buffers during resync or online\-verify\&. Unit is PAGE_SIZE, which is 4 KiB on most systems\&. The minimum possible setting is hard coded to 32 (=128 KiB)\&. These buffers are used to hold data blocks while they are written to/read from disk\&. To avoid possible distributed deadlocks on congestion, this setting is used as a throttle threshold rather than a hard limit\&. Once more than max\-buffers pages are in use, further allocation from this pool is throttled\&. You want to increase max\-buffers if you cannot saturate the IO backend on the receiving side\&. .RE .PP \fB\-\-max\-epoch\-size \fR\fB\fInumber\fR\fR .RS 4 Define the maximum number of write requests DRBD may issue before issuing a write barrier\&. The default value is 2048, with a minimum of 1 and a maximum of 20000\&. Setting this parameter to a value below 10 is likely to decrease performance\&. .RE .PP \fB\-\-on\-congestion \fR\fB\fIpolicy\fR\fR, .br \fB\-\-congestion\-fill \fR\fB\fIthreshold\fR\fR, .br \fB\-\-congestion\-extents \fR\fB\fIthreshold\fR\fR .RS 4 By default, DRBD blocks when the TCP send queue is full\&. This prevents applications from generating further write requests until more buffer space becomes available again\&. .sp When DRBD is used together with DRBD\-proxy, it can be better to use the \fBpull\-ahead\fR \fBon\-congestion\fR policy, which can switch DRBD into ahead/behind mode before the send queue is full\&. DRBD then records the differences between itself and the peer in its bitmap, but it no longer replicates them to the peer\&. When enough buffer space becomes available again, the node resynchronizes with the peer and switches back to normal replication\&. .sp This has the advantage of not blocking application I/O even when the queues fill up, and the disadvantage that peer nodes can fall behind much further\&. Also, while resynchronizing, peer nodes will become inconsistent\&. .sp The available congestion policies are \fBblock\fR (the default) and \fBpull\-ahead\fR\&. The \fBcongestion\-fill\fR parameter defines how much data is allowed to be "in flight" in this connection\&. The default value is 0, which disables this mechanism of congestion control, with a maximum of 10 GiBytes\&. The \fBcongestion\-extents\fR parameter defines how many bitmap extents may be active before switching into ahead/behind mode, with the same default and limits as the \fBal\-extents\fR parameter\&. The \fBcongestion\-extents\fR parameter is effective only when set to a value smaller than \fBal\-extents\fR\&. .sp Ahead/behind mode is available since DRBD 8\&.3\&.10\&. .RE .PP \fB\-\-ping\-int \fR\fB\fIinterval\fR\fR .RS 4 When the TCP/IP connection to a peer is idle for more than \fBping\-int\fR seconds, DRBD will send a keep\-alive packet to make sure that a failed peer or network connection is detected reasonably soon\&. The default value is 10 seconds, with a minimum of 1 and a maximum of 120 seconds\&. The unit is seconds\&. .RE .PP \fB\-\-ping\-timeout \fR\fB\fItimeout\fR\fR .RS 4 Define the timeout for replies to keep\-alive packets\&. If the peer does not reply within \fBping\-timeout\fR, DRBD will close and try to reestablish the connection\&. The default value is 0\&.5 seconds, with a minimum of 0\&.1 seconds and a maximum of 3 seconds\&. The unit is tenths of a second\&. .RE .PP \fB\-\-socket\-check\-timeout \fR\fB\fItimeout\fR\fR .RS 4 In setups involving a DRBD\-proxy and connections that experience a lot of buffer\-bloat it might be necessary to set \fBping\-timeout\fR to an unusual high value\&. By default DRBD uses the same value to wait if a newly established TCP\-connection is stable\&. Since the DRBD\-proxy is usually located in the same data center such a long wait time may hinder DRBD\'s connect process\&. .sp In such setups \fBsocket\-check\-timeout\fR should be set to at least to the round trip time between DRBD and DRBD\-proxy\&. I\&.e\&. in most cases to 1\&. .sp The default unit is tenths of a second, the default value is 0 (which causes DRBD to use the value of \fBping\-timeout\fR instead)\&. Introduced in 8\&.4\&.5\&. .RE .PP \fB\-\-protocol \fR\fB\fIname\fR\fR .RS 4 Use the specified protocol on this connection\&. The supported protocols are: .PP \fBA\fR .RS 4 Writes to the DRBD device complete as soon as they have reached the local disk and the TCP/IP send buffer\&. .RE .PP \fBB\fR .RS 4 Writes to the DRBD device complete as soon as they have reached the local disk, and all peers have acknowledged the receipt of the write requests\&. .RE .PP \fBC\fR .RS 4 Writes to the DRBD device complete as soon as they have reached the local and all remote disks\&. .RE .sp .RE .PP \fB\-\-rcvbuf\-size \fR\fB\fIsize\fR\fR .RS 4 Configure the size of the TCP/IP receive buffer\&. A value of 0 (the default) causes the buffer size to adjust dynamically\&. This parameter usually does not need to be set, but it can be set to a value up to 10 MiB\&. The default unit is bytes\&. .RE .PP \fB\-\-rr\-conflict\fR \fIpolicy\fR .RS 4 This option helps to solve the cases when the outcome of the resync decision is incompatible with the current role assignment in the cluster\&. The defined policies are: .PP \fBdisconnect\fR .RS 4 No automatic resynchronization, simply disconnect\&. .RE .PP \fBviolently\fR .RS 4 Resync to the primary node is allowed, violating the assumption that data on a block device are stable for one of the nodes\&. \fIDo not use this option, it is dangerous\&.\fR .RE .PP \fBcall\-pri\-lost\fR .RS 4 Call the \fBpri\-lost\fR handler on one of the machines\&. The handler is expected to reboot the machine, which puts it into secondary role\&. .RE .RE .PP \fB\-\-shared\-secret \fR\fB\fIsecret\fR\fR .RS 4 Configure the shared secret used for peer authentication\&. The secret is a string of up to 64 characters\&. Peer authentication also requires the \fBcram\-hmac\-alg\fR parameter to be set\&. .RE .PP \fB\-\-sndbuf\-size \fR\fB\fIsize\fR\fR .RS 4 Configure the size of the TCP/IP send buffer\&. Since DRBD 8\&.0\&.13 / 8\&.2\&.7, a value of 0 (the default) causes the buffer size to adjust dynamically\&. Values below 32 KiB are harmful to the throughput on this connection\&. Large buffer sizes can be useful especially when protocol A is used over high\-latency networks; the maximum value supported is 10 MiB\&. .RE .PP \fB\-\-tcp\-cork\fR .RS 4 By default, DRBD uses the TCP_CORK socket option to prevent the kernel from sending partial messages; this results in fewer and bigger packets on the network\&. Some network stacks can perform worse with this optimization\&. On these, the \fBtcp\-cork\fR parameter can be used to turn this optimization off\&. .RE .PP \fB\-\-timeout \fR\fB\fItime\fR\fR .RS 4 Define the timeout for replies over the network: if a peer node does not send an expected reply within the specified \fBtimeout\fR, it is considered dead and the TCP/IP connection is closed\&. The timeout value must be lower than \fBconnect\-int\fR and lower than \fBping\-int\fR\&. The default is 6 seconds; the value is specified in tenths of a second\&. .RE .PP \fB\-\-unplug\-watermark \fR\fB\fInumber\fR\fR .RS 4 Mainline kernels before version 2\&.6\&.39\-rc1 use an explicit plug / unplug mechanism to control when a block device starts processing queued requests\&. On those kernels, the \fBunplug\-watermark\fR parameter defines how many requests must be queued until a secondary node starts processing them\&. Some storage controllers perform best when \fBunplug\-watermark\fR is set to the same value as \fBmax\-buffers\fR; others are more efficient with smaller values\&. The default value for \fBunplug\-watermark\fR is 128, with a minimum of 16 and a maximum of 131072\&. .sp More recent kernels handle plugging and unplugging implicitly; on those kernels, this parameter has no effect\&. Note that some distributions have backported this feature to older kernel versions\&. .RE .PP \fB\-\-use\-rle\fR .RS 4 Each replicated device on a cluster node has a separate bitmap for each of its peer devices\&. The bitmaps are used for tracking the differences between the local and peer device: depending on the cluster state, a disk range can be marked as different from the peer in the device\'s bitmap, in the peer device\'s bitmap, or in both bitmaps\&. When two cluster nodes connect, they exchange each other\'s bitmaps, and they each compute the union of the local and peer bitmap to determine the overall differences\&. .sp Bitmaps of very large devices are also relatively large, but they usually compress very well using run\-length encoding\&. This can save time and bandwidth for the bitmap transfers\&. .sp The \fBuse\-rle\fR parameter determines if run\-length encoding should be used\&. It is on by default since DRBD 8\&.4\&.0\&. .RE .PP \fB\-\-verify\-alg \fR\fB\fIhash\-algorithm\fR\fR .RS 4 Online verification (\fBdrbdadm verify\fR) computes and compares checksums of disk blocks (i\&.e\&., hash values) in order to detect if they differ\&. The \fBverify\-alg\fR parameter determines which algorithm to use for these checksums\&. It must be set to one of the secure hash algorithms supported by the kernel before online verify can be used; see the shash algorithms listed in /proc/crypto\&. .sp We recommend to schedule online verifications regularly during low\-load periods, for example once a month\&. Also see the notes on data integrity below\&. .RE .RE .PP \fBdrbdsetup\fR new\-path \fIresource\fR \fIpeer_node_id\fR \fIlocal\-addr\fR \fIremote\-addr\fR .RS 4 .\" drbdsetup: net The \fBnew\-path\fR command creates a path within a \fIconnection\fR\&. The connection must have been created with \fBdrbdsetup new\-peer\fR\&. \fILocal_addr\fR and \fIremote_addr\fR refer to the local and remote protocol, network address, and port in the format [\fIaddress\-family\fR:]\fIaddress\fR[:\fIport\fR]\&. The address families \fBipv4\fR, \fBipv6\fR, \fBssocks\fR (Dolphin Interconnect Solutions\' "super sockets"), \fBsdp\fR (Infiniband Sockets Direct Protocol), and \fBsci\fR are supported (\fBsci\fR is an alias for \fBssocks\fR)\&. If no address family is specified, \fBipv4\fR is assumed\&. For all address families except \fBipv6\fR, the \fIaddress\fR uses IPv4 address notation (for example, 1\&.2\&.3\&.4)\&. For \fBipv6\fR, the address is enclosed in brackets and uses IPv6 address notation (for example, [fd01:2345:6789:abcd::1])\&. The \fIport\fR defaults to 7788\&. .RE .PP \fBdrbdsetup\fR connect \fIresource\fR \fIpeer_node_id\fR .RS 4 .\" drbdsetup: net The \fBconnect\fR command activates a connection\&. That means that the DRBD driver will bind and listen on all local addresses of the connection\-\'s paths\&. It will begin to try to establish one or more paths of the connection\&. Available options: .PP \fB\-\-tentative\fR .RS 4 Only determine if a connection to the peer can be established and if a resync is necessary (and in which direction) without actually establishing the connection or starting the resync\&. Check the system log to see what DRBD would do without the \fB\-\-tentative\fR option\&. .RE .PP \fB\-\-discard\-my\-data\fR .RS 4 Discard the local data and resynchronize with the peer that has the most up\-to\-data data\&. Use this option to manually recover from a split\-brain situation\&. .RE .RE .PP \fBdrbdsetup\fR del\-peer \fIresource\fR \fIpeer_node_id\fR .RS 4 .\" drbdsetup: net The \fBdel\-peer\fR command removes a connection from a \fIresource\fR\&. .RE .PP \fBdrbdsetup\fR del\-path \fIresource\fR \fIpeer_node_id\fR \fIlocal\-addr\fR \fIremote\-addr\fR .RS 4 .\" drbdsetup: net The \fBdel\-path\fR command removes a path from a \fIconnection\fR\&. Please not that it fails if the path is necessary to keep a connected connection in tact\&. In order to remove all paths, disconnect the connection first\&. .RE .PP \fBdrbdsetup\fR cstate \fIresource\fR \fIpeer_node_id\fR .RS 4 .\" drbdsetup: cstate Show the current state of a connection\&. The connection is identified by the node\-id of the peer; see the \fBdrbdsetup connect\fR command\&. .RE .PP \fBdrbdsetup\fR del\-minor \fIminor\fR .RS 4 Remove a replicated device\&. No lower\-level device may be attached; see \fBdrbdsetup detach\fR\&. .RE .PP \fBdrbdsetup\fR del\-resource \fIresource\fR .RS 4 Remove a resource\&. All volumes and connections must be removed first (\fBdrbdsetup del\-minor\fR, \fBdrbdsetup disconnect\fR)\&. Alternatively, \fBdrbdsetup down\fR can be used to remove a resource together with all its volumes and connections\&. .RE .PP \fBdrbdsetup\fR detach \fIminor\fR .RS 4 .\" drbdsetup: detach Detach the lower\-level device of a replicated device\&. Available options: .PP \fB\-\-force\fR .RS 4 Force the detach and return immediately\&. This puts the lower\-level device into failed state until all pending I/O has completed, and then detaches the device\&. Any I/O not yet submitted to the lower\-level device (for example, because I/O on the device was suspended) is assumed to have failed\&. .RE .sp .RE .PP \fBdrbdsetup\fR disconnect \fIresource\fR \fIpeer_node_id\fR .RS 4 .\" drbdsetup: disconnect Remove a connection to a peer host\&. The connection is identified by the node\-id of the peer; see the \fBdrbdsetup connect\fR command\&. .RE .PP \fBdrbdsetup\fR down {\fIresource\fR | \fIall\fR} .RS 4 .\" drbdsetup: down Take a resource down by removing all volumes, connections, and the resource itself\&. .RE .PP \fBdrbdsetup\fR dstate \fIminor\fR .RS 4 .\" drbdsetup: dstate Show the current disk state of a lower\-level device\&. .RE .PP \fBdrbdsetup\fR events2 {\fIresource\fR | \fIall\fR} .RS 4 .\" drbdsetup: events2 Show the current state of all configured DRBD objects, followed by all changes to the state\&. .sp The output format is meant to be human as well as machine readable\&. The line starts with a word that indicates the kind of event: \fBexists\fR for an existing object; \fBcreate\fR, \fBdestroy\fR, and \fBchange\fR if an object is created, destroyed, or changed; or \fBcall\fR or \fBresponse\fR if an event handler is called or it returns\&. The second word indicates the object the event applies to: \fBresource\fR, \fBdevice\fR, \fBconnection\fR, \fBpeer\-device\fR, \fBhelper\fR, or a dash (\fB\-\fR) to indicate that the current state has been dumped completely\&. .sp The remaining words identify the object and describe the state that he object is in\&. Available options: .PP \fB\-\-now\fR .RS 4 Terminate after reporting the current state\&. The default is to continuously listen and report state changes\&. .RE .PP \fB\-\-statistics\fR .RS 4 Include statistics in the output\&. .RE .sp .RE .PP \fBdrbdsetup\fR get\-gi \fIresource\fR \fIpeer_node_id\fR \fIvolume\fR .RS 4 .\" drbdsetup: get-gi Show the data generation identifiers for a device on a particular connection\&. The device is identified by its volume number\&. The connection is identified by its endpoints; see the \fBdrbdsetup connect\fR command\&. .sp The output consists of the current UUID, bitmap UUID, and the first two history UUIDS, folowed by a set of flags\&. The current UUID and history UUIDs are device specific; the bitmap UUID and flags are peer device specific\&. This command only shows the first two history UUIDs\&. Internally, DRBD maintains one history UUID for each possible peer device\&. .RE .PP \fBdrbdsetup\fR invalidate \fIminor\fR .RS 4 .\" drbdsetup: invalidate Replace the local data of a device with that of a peer\&. All the local data will be marked out\-of\-sync, and a resync with the specified peer device will be initialted\&. .RE .PP \fBdrbdsetup\fR invalidate\-remote \fIresource\fR \fIpeer_node_id\fR \fIvolume\fR .RS 4 .\" drbdsetup: invalidate-remote Replace a peer device\'s data of a resource with the local data\&. The peer device\'s data will be marked out\-of\-sync, and a resync from the local node to the specified peer will be initiated\&. .RE .PP \fBdrbdsetup\fR new\-current\-uuid \fIminor\fR .RS 4 .\" drbdsetup: new-current-uuid Generate a new current UUID and rotates all other UUID values\&. This has at least two use cases, namely to skip the initial sync, and to reduce network bandwidth when starting in a single node configuration and then later (re\-)integrating a remote site\&. .sp Available option: .PP \fB\-\-clear\-bitmap\fR .RS 4 Clears the sync bitmap in addition to generating a new current UUID\&. .RE .sp This can be used to skip the initial sync, if you want to start from scratch\&. This use\-case does only work on "Just Created" meta data\&. Necessary steps: .sp .RS 4 .ie n \{\ \h'-04' 1.\h'+01'\c .\} .el \{\ .sp -1 .IP " 1." 4.2 .\} On \fIboth\fR nodes, initialize meta data and configure the device\&. .sp \fBdrbdadm create\-md \-\-force \fR\fB\fIres\fR\fR .RE .sp .RS 4 .ie n \{\ \h'-04' 2.\h'+01'\c .\} .el \{\ .sp -1 .IP " 2." 4.2 .\} They need to do the initial handshake, so they know their sizes\&. .sp \fBdrbdadm up \fR\fB\fIres\fR\fR .RE .sp .RS 4 .ie n \{\ \h'-04' 3.\h'+01'\c .\} .el \{\ .sp -1 .IP " 3." 4.2 .\} They are now Connected Secondary/Secondary Inconsistent/Inconsistent\&. Generate a new current\-uuid and clear the dirty bitmap\&. .sp \fBdrbdadm \-\-clear\-bitmap new\-current\-uuid \fR\fB\fIres\fR\fR .RE .sp .RS 4 .ie n \{\ \h'-04' 4.\h'+01'\c .\} .el \{\ .sp -1 .IP " 4." 4.2 .\} They are now Connected Secondary/Secondary UpToDate/UpToDate\&. Make one side primary and create a file system\&. .sp \fBdrbdadm primary \fR\fB\fIres\fR\fR .sp \fBmkfs \-t \fR\fB\fIfs\-type\fR\fR\fB $(drbdadm sh\-dev \fR\fB\fIres\fR\fR\fB)\fR .RE .RS 4 .sp One obvious side\-effect is that the replica is full of old garbage (unless you made them identical using other means), so any online\-verify is expected to find any number of out\-of\-sync blocks\&. .sp \fIYou must not use this on pre\-existing data!\fR Even though it may appear to work at first glance, once you switch to the other node, your data is toast, as it never got replicated\&. So \fIdo not leave out the mkfs\fR (or equivalent)\&. .sp This can also be used to shorten the initial resync of a cluster where the second node is added after the first node is gone into production, by means of disk shipping\&. This use\-case works on disconnected devices only, the device may be in primary or secondary role\&. .sp The necessary steps on the current active server are: .sp .RS 4 .ie n \{\ \h'-04' 1.\h'+01'\c .\} .el \{\ .sp -1 .IP " 1." 4.2 .\} \fBdrbdsetup new\-current\-uuid \-\-clear\-bitmap \fR\fB\fIminor\fR\fR\fB \fR .RE .sp .RS 4 .ie n \{\ \h'-04' 2.\h'+01'\c .\} .el \{\ .sp -1 .IP " 2." 4.2 .\} Take the copy of the current active server\&. E\&.g\&. by pulling a disk out of the RAID1 controller, or by copying with dd\&. You need to copy the actual data, and the meta data\&. .RE .sp .RS 4 .ie n \{\ \h'-04' 3.\h'+01'\c .\} .el \{\ .sp -1 .IP " 3." 4.2 .\} \fBdrbdsetup new\-current\-uuid \fR\fB\fIminor\fR\fR\fB \fR .RE .RS 4 Now add the disk to the new secondary node, and join it to the cluster\&. You will get a resync of that parts that were changed since the first call to \fBdrbdsetup\fR in step 1\&. .RE .PP \fBdrbdsetup\fR new\-minor \fIresource\fR \fIminor\fR \fIvolume\fR .RS 4 Create a new replicated device within a resource\&. The command creates a block device inode for the replicated device (by default, /dev/drbd\fIminor\fR)\&. The \fIvolume\fR number identifies the device within the \fIresource\fR\&. .RE .PP \fBdrbdsetup\fR new\-resource \fIresource\fR \fInode_id\fR, .br \fBdrbdsetup\fR resource\-options \fIresource\fR .RS 4 The \fBnew\-resource\fR command creates a new resource\&. The \fBresource\-options\fR command changes the resource options of an existing resource\&. Available options: .PP \fB\-\-auto\-promote \fR\fB\fIbool\-value\fR\fR .RS 4 A resource must be promoted to primary role before any of its devices can be mounted or opened for writing\&. .sp Before DRBD 9, this could only be done explicitly ("drbdadm primary")\&. Since DRBD 9, the \fBauto\-promote\fR parameter allows to automatically promote a resource to primary role when one of its devices is mounted or opened for writing\&. As soon as all devices are unmounted or closed with no more remaining users, the role of the resource changes back to secondary\&. .sp Automatic promotion only succeeds if the cluster state allows it (that is, if an explicit \fBdrbdadm primary\fR command would succeed)\&. Otherwise, mounting or opening the device fails as it already did before DRBD 9: the \fBmount\fR(2) system call fails with errno set to EROFS (Read\-only file system); the \fBopen\fR(2) system call fails with errno set to EMEDIUMTYPE (wrong medium type)\&. .sp Irrespective of the \fBauto\-promote\fR parameter, if a device is promoted explicitly (\fBdrbdadm primary\fR), it also needs to be demoted explicitly (\fBdrbdadm secondary\fR)\&. .sp The \fBauto\-promote\fR parameter is available since DRBD 9\&.0\&.0, and defaults to \fByes\fR\&. .RE .PP \fB\-\-cpu\-mask \fR\fB\fIcpu\-mask\fR\fR .RS 4 Set the cpu affinity mask for DRBD kernel threads\&. The cpu mask is specified as a hexadecimal number\&. The default value is 0, which lets the scheduler decide which kernel threads run on which CPUs\&. CPU numbers in \fBcpu\-mask\fR which do not exist in the system are ignored\&. .RE .PP \fB\-\-on\-no\-data\-accessible \fR\fB\fIpolicy\fR\fR .RS 4 Determine how to deal with I/O requests when the requested data is not available locally or remotely (for example, when all disks have failed)\&. The defined policies are: .PP \fBio\-error\fR .RS 4 System calls fail with errno set to EIO\&. .RE .PP \fBsuspend\-io\fR .RS 4 The resource suspends I/O\&. I/O can be resumed by (re)attaching the lower\-level device, by connecting to a peer which has access to the data, or by forcing DRBD to resume I/O with \fBdrbdadm resume\-io \fR\fB\fIres\fR\fR\&. When no data is available, forcing I/O to resume will result in the same behavior as the \fBio\-error\fR policy\&. .RE .sp This setting is available since DRBD 8\&.3\&.9; the default policy is \fBio\-error\fR\&. .RE .PP \fB\-\-peer\-ack\-window \fR\fB\fIvalue\fR\fR .RS 4 On each node and for each device, DRBD maintains a bitmap of the differences between the local and remote data for each peer device\&. For example, in a three\-node setup (nodes A, B, C) each with a single device, every node maintains one bitmap for each of its peers\&. .sp When nodes receive write requests, they know how to update the bitmaps for the writing node, but not how to update the bitmaps between themselves\&. In this example, when a write request propagates from node A to B and C, nodes B and C know that they have the same data as node A, but not whether or not they both have the same data\&. .sp As a remedy, the writing node occasionally sends peer\-ack packets to its peers which tell them which state they are in relative to each other\&. .sp The \fBpeer\-ack\-window\fR parameter specifies how much data a primary node may send before sending a peer\-ack packet\&. A low value causes increased network traffic; a high value causes less network traffic but higher memory consumption on secondary nodes and higher resync times between the secondary nodes after primary node failures\&. (Note: peer\-ack packets may be sent due to other reasons as well, e\&.g\&. membership changes or expiry of the \fBpeer\-ack\-delay\fR timer\&.) .sp The default value for \fBpeer\-ack\-window\fR is 2 MiB, the default unit is sectors\&. This option is available since 9\&.0\&.0\&. .RE .PP \fB\-\-peer\-ack\-delay \fR\fB\fIexpiry\-time\fR\fR .RS 4 If after the last finished write request no new write request gets issued for \fIexpiry\-time\fR, then a peer\-ack packet is sent\&. If a new write request is issued before the timer expires, the timer gets reset to \fIexpiry\-time\fR\&. (Note: peer\-ack packets may be sent due to other reasons as well, e\&.g\&. membership changes or the \fBpeer\-ack\-window\fR option\&.) .sp This parameter may influence resync behavior on remote nodes\&. Peer nodes need to wait until they receive an peer\-ack for releasing a lock on an AL\-extent\&. Resync operations between peers may need to wait for for these locks\&. .sp The default value for \fBpeer\-ack\-delay\fR is 100 milliseconds, the default unit is milliseconds\&. This option is available since 9\&.0\&.0\&. .RE .sp .RE .PP \fBdrbdsetup\fR outdate \fIminor\fR .RS 4 .\" drbdsetup: outdate Mark the data on a lower\-level device as outdated\&. This is used for fencing, and prevents the resource the device is part of from becoming primary in the future\&. See the \fB\-\-fencing\fR disk option\&. .RE .PP \fBdrbdsetup\fR pause\-sync \fIresource\fR \fIpeer_node_id\fR \fIvolume\fR .RS 4 .\" drbdsetup: pause-sync Stop resynchronizing between a local and a peer device by setting the local pause flag\&. The resync can only resume if the pause flags on both sides of a connection are cleared\&. .RE .PP \fBdrbdsetup\fR primary \fIresource\fR .RS 4 .\" drbdsetup: primary Change the role of a node in a resource to primary\&. This allows the replicated devices in this resource to be mounted or opened for writing\&. Available options: .PP \fB\-\-overwrite\-data\-of\-peer\fR .RS 4 This option is an alias for the \fB\-\-force\fR option\&. .RE .PP \fB\-\-force\fR .RS 4 Force the resource to become primary even if some devices are not guaranteed to have up\-to\-date data\&. This option is used to turn one of the nodes in a newly created cluster into the primary node, or when manually recovering from a disaster\&. .sp Note that this can lead to split\-brain scenarios\&. Also, when forcefully turning an inconsistent device into an up\-to\-date device, it is highly recommended to use any integrity checks available (such as a filesystem check) to make sure that the device can at least be used without crashing the system\&. .RE .sp Note that DRBD usually only allows one node in a cluster to be in primary role at any time; this allows DRBD to coordinate access to the devices in a resource across nodes\&. The \fB\-\-allow\-two\-primaries\fR network option changes this; in that case, a mechanism outside of DRBD needs to coordinate device access\&. .RE .PP \fBdrbdsetup\fR resize \fIminor\fR .RS 4 .\" drbdsetup: resize Reexamine the size of the lower\-level devices of a replicated device on all nodes\&. This command is called after the lower\-level devices on all nodes have been grown to adjust the size of the replicated device\&. Available options: .PP \fB\-\-assume\-peer\-has\-space\fR .RS 4 Resize the device even if some of the peer devices are not connected at the moment\&. DRBD will try to resize the peer devices when they next connect\&. It will refuse to connect to a peer device which is too small\&. .RE .PP \fB\-\-assume\-clean\fR .RS 4 Do not resynchronize the added disk space; instead, assume that it is identical on all nodes\&. This option can be used when the disk space is uninitialized and differences do not matter, or when it is known to be identical on all nodes\&. See the \fBdrbdsetup verify\fR command\&. .RE .PP \fB\-\-size \fR\fB\fIval\fR\fR .RS 4 This option can be used to online shrink the usable size of a drbd device\&. It\'s the users responsibility to make sure that a file system on the device is not truncated by that operation\&. .RE .PP \fB\-\-al\-stripes \fR\fB\fIval\fR\fR \fB\-\-al\-stripes \fR\fB\fIval\fR\fR .RS 4 These options may be used to change the layout of the activity log online\&. In case of internal meta data this may invovle shrinking the user visible size at the same time (unsing the \fB\-\-size\fR) or increasing the avalable space on the backing devices\&. .RE .sp .RE .PP \fBdrbdsetup\fR resume\-io \fIminor\fR .RS 4 .\" drbdsetup: resume-io Resume I/O on a replicated device\&. See the \fB\-\-fencing\fR net option\&. .RE .PP \fBdrbdsetup\fR resume\-sync \fIresource\fR \fIpeer_node_id\fR \fIvolume\fR .RS 4 .\" drbdsetup: resume-sync Allow resynchronization to resume by clearing the local sync pause flag\&. .RE .PP \fBdrbdsetup\fR role \fIresource\fR .RS 4 .\" drbdsetup: role Show the current role of a resource\&. .RE .PP \fBdrbdsetup\fR secondary \fIresource\fR .RS 4 .\" drbdsetup: secondary Change the role of a node in a resource to secondary\&. This command fails if the replicated device is in use\&. .RE .PP \fBdrbdsetup\fR show {\fIresource\fR | \fIall\fR} .RS 4 .\" drbdsetup: show Show the current configuration of a resource, or of all resources\&. Available options: .PP \fB\-\-show\-defaults\fR .RS 4 Show all configuration parameters, even the ones with default values\&. Normally, parameters with default values are not shown\&. .RE .sp .RE .PP \fBdrbdsetup\fR show\-gi \fIresource\fR \fIpeer_node_id\fR \fIvolume\fR .RS 4 .\" drbdsetup: show-gi Show the data generation identifiers for a device on a particular connection\&. In addition, explain the output\&. The output otherwise is the same as in the \fBdrbdsetup get\-gi\fR command\&. .RE .PP \fBdrbdsetup\fR state .RS 4 .\" drbdsetup: state This is an alias for \fBdrbdsetup role\fR\&. Deprecated\&. .RE .PP \fBdrbdsetup\fR status {\fIresource\fR | \fIall\fR} .RS 4 .\" drbdsetup: status Show the status of a resource, or of all resources\&. The output consists of one paragraph for each configured resource\&. Each paragraph contains one line for each resource, followed by one line for each device, and one line for each connection\&. The device and connection lines are indented\&. The connection lines are followed by one line for each peer device; these lines are indented against the connection line\&. .sp Long lines are wrapped around at terminal width, and indented to indicate how the lines belongs together\&. Available options: .PP \fB\-\-verbose\fR .RS 4 Include more information in the output even when it is likely redundant or irrelevant\&. .RE .PP \fB\-\-statistics\fR .RS 4 Include data transfer statistics in the output\&. .RE .PP \fB\-\-color=\fR\fB{always | auto | never}\fR\fB \fR .RS 4 Colorize the output\&. With \fB\-\-color=auto\fR, \fBdrbdsetup\fR emits color codes only when standard output is connected to a terminal\&. .RE .sp For example, the non\-verbose output for a resource with only one connection and only one volume could look like this: .sp .if n \{\ .RS 4 .\} .nf drbd0 role:Primary disk:UpToDate host2\&.example\&.com role:Secondary disk:UpToDate .fi .if n \{\ .RE .\} .sp With the \fB\-\-verbose\fR option, the same resource could be reported as: .sp .if n \{\ .RS 4 .\} .nf drbd0 node\-id:1 role:Primary suspended:no volume:0 minor:1 disk:UpToDate blocked:no host2\&.example\&.com local:ipv4:192\&.168\&.123\&.4:7788 peer:ipv4:192\&.168\&.123\&.2:7788 node\-id:0 connection:WFReportParams role:Secondary congested:no volume:0 replication:Connected disk:UpToDate resync\-suspended:no .fi .if n \{\ .RE .\} .sp .RE .PP \fBdrbdsetup\fR suspend\-io \fIminor\fR .RS 4 .\" drbdsetup: suspend-io Suspend I/O on a replicated device\&. It is not usually necessary to use this command\&. .RE .PP \fBdrbdsetup\fR verify \fIresource\fR \fIpeer_node_id\fR \fIvolume\fR .RS 4 .\" drbdsetup: verify Start online verification, change which part of the device will be verified, or stop online verification\&. The command requires the specified peer to be connected\&. .sp Online verification compares each disk block on the local and peer node\&. Blocks which differ between the nodes are marked as out\-of\-sync, but they are \fInot\fR automatically brought back into sync\&. To bring them into sync, the resource must be disconnected and reconnected\&. Progress can be monitored in the output of \fBdrbdsetup status \-\-statistics\fR\&. Available options: .PP \fB\-\-start \fR\fB\fIposition\fR\fR .RS 4 Define where online verification should start\&. This parameter is ignored if online verification is already in progress\&. If the start parameter is not specified, online verification will continue where it was interrupted (if the connection to the peer was lost while verifying), after the previous stop sector (if the previous online verification has finished), or at the beginning of the device (if the end of the device was reached, or online verify has not run before)\&. .sp The position on disk is specified in disk sectors (512 bytes) by default\&. .RE .PP \fB\-\-stop \fR\fB\fIposition\fR\fR .RS 4 Define where online verification should stop\&. If online verification is already in progress, the stop position of the active online verification process is changed\&. Use this to stop online verification\&. .sp The position on disk is specified in disk sectors (512 bytes) by default\&. .RE .sp Also see the notes on data integrity in the \fBdrbd.conf\fR(5) manual page\&. .RE .PP \fBdrbdsetup\fR wait\-connect\-volume \fIresource\fR \fIpeer_node_id\fR \fIvolume\fR, .br \fBdrbdsetup\fR wait\-connect\-connection \fIresource\fR \fIpeer_node_id\fR, .br \fBdrbdsetup\fR wait\-connect\-resource \fIresource\fR, .br \fBdrbdsetup\fR wait\-sync\-volume \fIresource\fR \fIpeer_node_id\fR \fIvolume\fR, .br \fBdrbdsetup\fR wait\-sync\-connection \fIresource\fR \fIpeer_node_id\fR, .br \fBdrbdsetup\fR wait\-sync\-resource \fIresource\fR .RS 4 .\" drbdsetup: wait-connect-volume: wait-connect-connection: wait-connect-resource .\" drbdsetup: wait-sync-volume: wait-sync-connection: wait-sync-resource The \fBwait\-connect\-*\fR commands waits until a device on a peer is visible\&. The \fBwait\-sync\-*\fR commands waits until a device on a peer is up to date\&. Available options for both commands: .PP \fB\-\-degr\-wfc\-timeout \fR\fB\fItimeout\fR\fR .RS 4 Define how long to wait until all peers are connected in case the cluster consisted of a single node only when the system went down\&. This parameter is usually set to a value smaller than \fBwfc\-timeout\fR\&. The assumption here is that peers which were unreachable before a reboot are less likely to be be reachable after the reboot, so waiting is less likely to help\&. .sp The timeout is specified in seconds\&. The default value is 0, which stands for an infinite timeout\&. Also see the \fBwfc\-timeout\fR parameter\&. .RE .PP \fB\-\-outdated\-wfc\-timeout \fR\fB\fItimeout\fR\fR .RS 4 Define how long to wait until all peers are connected if all peers were outdated when the system went down\&. This parameter is usually set to a value smaller than \fBwfc\-timeout\fR\&. The assumption here is that an outdated peer cannot have become primary in the meantime, so we don\'t need to wait for it as long as for a node which was alive before\&. .sp The timeout is specified in seconds\&. The default value is 0, which stands for an infinite timeout\&. Also see the \fBwfc\-timeout\fR parameter\&. .RE .PP \fB\-\-wait\-after\-sb\fR .RS 4 This parameter causes DRBD to continue waiting in the init script even when a split\-brain situation has been detected, and the nodes therefore refuse to connect to each other\&. .RE .PP \fB\-\-wfc\-timeout \fR\fB\fItimeout\fR\fR .RS 4 Define how long the init script waits until all peers are connected\&. This can be useful in combination with a cluster manager which cannot manage DRBD resources: when the cluster manager starts, the DRBD resources will already be up and running\&. With a more capable cluster manager such as Pacemaker, it makes more sense to let the cluster manager control DRBD resources\&. The timeout is specified in seconds\&. The default value is 0, which stands for an infinite timeout\&. Also see the \fBdegr\-wfc\-timeout\fR parameter\&. .RE .sp .RE .PP \fBdrbdsetup\fR forget\-peer \fIresource\fR \fIpeer_node_id\fR .RS 4 .\" drbdsetup: forget-peer The \fBforget\-peer\fR command removes all traces of a peer node from the meta\-data\&. It frees a bitmap slot in the meta\-data and make it avalable for futher bitmap slot allocation in case a so\-far never seen node connects\&. .sp The connection must be taken down before this command may be used\&. In case the peer re\-connects at a later point a bit\-map based resync will be turned into a full\-sync\&. .RE .SH "EXAMPLES" .PP Please see the \m[blue]\fBDRBD User\'s Guide\fR\m[]\&\s-2\u[1]\d\s+2 for examples\&. .SH "VERSION" .sp This document was revised for version 9\&.0\&.0 of the DRBD distribution\&. .SH "AUTHOR" .sp Written by Philipp Reisner philipp\&.reisner@linbit\&.com and Lars Ellenberg lars\&.ellenberg@linbit\&.com\&. .SH "REPORTING BUGS" .sp Report bugs to drbd\-user@lists\&.linbit\&.com\&. .SH "COPYRIGHT" .sp Copyright 2001\-2012 LINBIT Information Technologies, Philipp Reisner, Lars Ellenberg\&. This is free software; see the source for copying conditions\&. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE\&. .SH "SEE ALSO" .PP \fBdrbd.conf\fR(5), \fBdrbd\fR(8), \fBdrbddisk\fR(8), \fBdrbdadm\fR(8), \m[blue]\fBDRBD User\'s Guide\fR\m[]\&\s-2\u[1]\d\s+2, \m[blue]\fBDRBD Web Site\fR\m[]\&\s-2\u[2]\d\s+2 .SH "NOTES" .IP " 1." 4 DRBD User's Guide .RS 4 \%http://www.drbd.org/users-guide/ .RE .IP " 2." 4 DRBD Web Site .RS 4 \%http://www.drbd.org/ .RE drbd-utils-8.9.6/documentation/v9/drbdadm.xml0000644000175000017500000007151412615625470021051 0ustar apoikosapoikos 6 December 2012 DRBD 9.0.0 drbdadm 8 System Administration drbdadm Utility for DRBD administration drbdadm drbdadm options --backend-options command context Description The utility is used for managing DRBD based on its configuration files, see drbd.conf 5 . It translates high-level commands into one or more lower-level commands for the and utilities, which control the kernel module and manipulate the on-disk metadata. Depending on the command, the utility operates on one or more resources, devices, connections, or peer devices. The following command contexts are defined: resource A resource specified by name, or the keyword for all defined resources. device A device, specified by minor number (minornumber, e.g. 0) or by resource and volume number (resource/volume). If only a resource is specified, the command iterates over all devices of that resource. connection A connection, specified by resource and connection name (resource:connection-name). If only a resource is specified, the command iterates over all connections of that resource. peer_device A peer device, specified by resource, connection name, and volume number (resource:connection-name/volume). If only a resource, device, or connection is specified, the command iterates over all peer devices of that resource, device, or connection. All options following a double-dash are passed through to the lower-level utilities as specified. In addition, understands most of the options of , and will pass them through even without the double-dash. Options , Show which commands would execute instead of actually executing them (for example, drbdadm -d up resource). This can be a useful way to learn how drbdsetup and drbdmeta are used. , file Use an alternative configuration file. By default, will use the the first of the following files that exists: , , , , , . , file Check an additional configuration file. This option is only allowed with the dump and the sh-nop commands. , file Specifies the full path to the program. If this option is omitted, drbdadm will look for it beneath itself first, and then in the PATH. , file Specifies the full path to the program. If this option is omitted, drbdadm will look for it beneath itself first, and then in the PATH. , Perform the command on a stacked resource. Commands adjust resource drbdadm adjust Adjust the configuration of the kernel module so that it matches the configuration files. The result should be the same as when stopping and restarting all resources (drbdadm down all followed by drbdadm up all), but without the interruptions. Note that the adjust command can misinterpret the configuration change in some cases. To be safe, check what the command would do (with the option) before running the actual command. adjust-with-progress resource drbdadm adjust-with-progress The same as , but with some more information about the command's progress. apply-al device drbdadm apply-al Apply the activity log of the specified device. See drbdmeta 8 for details. attach device Attach a lower-level device to an existing replicated device. See drbdsetup 8 for details. check-resize device drbdadm check-resize Call drbdmeta to eventually move internal meta data. If the backing device was resized, while DRBD was not running, meta data has to be moved to the end of the device, so that the next command can succeed. connect connection drbdadm connect Activate an exisiting connection to a peer. The connection needs to be created first with the command, and have at least one path created with the command. See drbdsetup 8 for details. create-md device drbdadm create-md Initialize the metadata of a device. This is necessary before a device can be attached; see drbdmeta 8 for details. cstate connection drbdadm cstate Show the current state of a connection. See drbdsetup 8 for details. detach device drbdadm detach Detach the lower-level device of a replicated device. See drbdsetup 8 for details. disconnect connection drbdadm disconnect Remove a connection to a peer host. See drbdsetup 8 for details. disk-options device drbdadm disk-options Cange the disk options of an attached lower-level device. See drbdsetup 8 for details. down resource drbdadm down Take a resource down by removing all volumes, connections, and the resource itself. See drbdsetup 8 for details. dstate device drbdadm dstate Show the current disk state of a lower-level device. See drbdsetup 8 for details. dump resource drbdadm dump Parse the configuration file and dump it to stdout. This will fail if the configuration file is syntactically incorrect. dump-md device drbdadm dump-md Dump the metadata of a device in text form, including the bitmap and activity log. See drbdmeta 8 for details. get-gi peer_device drbdadm get-gi Show the data generation identifiers for a device on a particular connection. Uses for attached devices and for unattached devices. See drbdsetup 8 for details. hidden-commands Shows all commands which are not explicitly documented. invalidate peer_device drbdadm invalidate Replace the local data of a device with that of a peer. See drbdsetup 8 for details. invalidate-remote peer_device drbdadm invalidate-remote Replace a peer device's data of a resource with the local data. See drbdsetup 8 for details. net-options connection drbdadm net-options Change the network options of an existing connection. See drbdsetup 8 for details. new-current-uuid device drbdadm new-current-uuid Generate a new currend UUID. See drbdsetup 8 for details. outdate device drbdadm outdate Mark the data on a lower-level device as outdated. See drbdsetup 8 for details. pause-sync peer_device drbdadm pause-sync Stop resynchronizing between a local and a peer device by setting the local pause flag. See drbdsetup 8 for details. primary resource drbdadm primary Change the role of a node in a resource to primary. See drbdsetup 8 for details. resize device drbdadm resize Resize the lower-level devices of a replicated device on all nodes. This combines the and lower-level commands; see drbdsetup 8 for details. resource-options resource drbdadm resource-options Change the resource options of an existing resource. See drbdsetup 8 for details. resume-sync peer_device drbdadm resume-sync Allow resynchronization to resume by clearing the local sync pause flag. See drbdsetup 8 for details. role resource drbdadm role Show the current role of a resource. secondary resource drbdadm secondary Change the role of a node in a resource to secondary. This command fails if the replicated device is in use. show-gi peer_device drbdadm show-gi Show the data generation identifiers for a device on a particular connection. In addition, explain the output. See drbdsetup 8 for details. state resource drbdadm state This is an alias for drbdsetup role. Deprecated. up resource drbdadm up Bring up a resource by applying the activity log of all volumes, creating the resource, creating the replicated devices, attaching the lower-level devices, and connecting to all peers. See the drbdmeta command and the , , , , and drbdsetup commands. verify peer_device drbdadm verify Start online verification, change which part of the device will be verified, or stop online verification. See drbdsetup 8 for details. wait-connect device connection resource drbdadm wait-connect Wait until a device on a peer, all devices over a connection, or all devices on all peers are visible. See drbdsetup 8 for details. wait-sync device connection resource drbdadm wait-sync Wait until a device is connected and has finished eventual resync operation. Also available on connection and resource level. See drbdsetup 8 for details. wipe-md device drbdadm wipe-md Wipe out the DRBD metadata of a device. See drbdmeta 8 for details. forget-peer connection drbdadm forget-peer Completely remove any reference to a unconnected peer from meta-data. See drbdmeta 8 for details. Version This document was revised for version 9.0.0 of the DRBD distribution. Author Written by Philipp Reisner philipp.reisner@linbit.com and Lars Ellenberg lars.ellenberg@linbit.com Reporting Bugs Report bugs to drbd-user@lists.linbit.com. Copyright Copyright 2001-2012 LINBIT Information Technologies, Philipp Reisner, Lars Ellenberg. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See Also drbd.conf 5 , drbd 8 , drbddisk 8 , drbdsetup 8 , drbdmeta 8 and the DRBD project web site drbd-utils-8.9.6/documentation/v9/drbd.conf.xml.in0000644000175000017500000012433412647177715021730 0ustar apoikosapoikos ]> &drbdsetup_options; 3 December 2012 DRBD 9.0.0 drbd.conf 5 Configuration Files drbd.conf DRBD Configuration Files drbd.conf Introduction DRBD implements block devices which replicate their data to all nodes of a cluster. The actual data and associated metadata are usually stored redundantly on "ordinary" block devices on each cluster node. Replicated block devices are called by default. They are grouped into resources, with one or more devices per resource. Replication among the devices in a resource takes place in chronological order. With DRBD, we refer to the devices inside a resource as volumes. In DRBD 9, a resource can be replicated between two or more cluster nodes. The connections between cluster nodes are point-to-point links, and use TCP or a TCP-like protocol. All nodes must be directly connected. DRBD consists of low-level user-space components which interact with the kernel and perform basic operations (, ), a high-level user-space component which understands and processes the DRBD configuration and translates it into basic operations of the low-level components (), and a kernel component. The default DRBD configuration consists of and of additional files included from there, usually and all files inside . It has turned out to be useful to define each resource in a separate file. The configuration files are designed so that each cluster node can contain an identical copy of the entire cluster configuration. The host name of each node determines which parts of the configuration apply (). It is highly recommended to keep the cluster configuration on all nodes in sync by manually copying it to all nodes, or by automating the process with or a similar tool. Example Configuration File resource r0 { net { cram-hmac-alg sha1; shared-secret "FooFunFactory"; } volume 0 { device /dev/drbd1; disk /dev/sda7; meta-disk internal; } on alice { node-id 0; address 10.1.1.31:7000; } on bob { node-id 1; address 10.1.1.32:7000; } connection { host alice port 7000; host bob port 7000; net { protocol C; } } } This example defines a resource which contains a single replicated device with volume number 0. The resource is replicated among hosts and , which have the IPv4 addresses and and the node identifiers 0 and 1, respectively. On both hosts, the replicated device is called , and the actual data and metadata are stored on the lower-level device . The connection between the hosts uses protocol C. Please refer to the DRBD User's Guide for more examples. File Format DRBD configuration files consist of sections, which contain other sections and parameters depending on the section types. Each section consists of one or more keywords, sometimes a section name, an opening brace ({), the section's contents, and a closing brace (}). Parameters inside a section consist of a keyword, followed by one or more keywords or values, and a semicolon (;). Some parameter values have a default scale which applies when a plain number is specified (for example Kilo, or 1024 times the numeric value). Such default scales can be overridden by using a suffix (for example, for Mega). The common suffixes = 2^10 = 1024, = 1024 K, and = 1024 M are supported. Comments start with a hash sign (#) and extend to the end of the line. In addition, any section can be prefixed with the keyword , which causes the section and any sub-sections to be ignored. Additional files can be included with the statement (see glob7 for the expressions supported in file-pattern). Include statements are only allowed outside of sections. The following sections are defined (indentation indicates in which context): common [disk] [handlers] [net] [options] [startup] global resource connection path net connection-mesh net [disk] floating handlers [net] on volume disk [disk] options stacked-on-top-of startup Sections in brackets affect other parts of the configuration: inside the section, they apply to all resources. A section inside a or section applies to all volumes of that resource, and a section inside a section applies to all connections of that resource. This allows to avoid repeating identical options for each resource, connection, or volume. Options can be overridden in a more specific , , , or section. Sections drbd.conf common This section can contain each a , , , , and section. All resources inherit the parameters in these sections as their default values. drbd.conf connection Define a connection between two hosts. This section must contain two parameters or multiple . The optional name is used to refer to the connection in the system log and in other messages. If no name is specified, the peer's host name is used instead. drbd.conf path Define a path between two hosts. This section must contain two parameters. drbd.conf connection-mesh Define a connection mesh between multiple hosts. This section must contain a parameter, which has the host names as arguments. This section is a shortcut to define many connections which share the same network options. drbd.conf disk Define parameters for a volume. All parameters in this section are optional. drbd.conf floating Like the section, except that instead of the host name a network address is used to determine if it matches a section. The parameter in this section is required. If the parameter is not provided, no connections to peers will be created by default. The , , and parameters must be defined in, or inherited by, this section. drbd.conf global Define some global parameters. All parameters in this section are optional. Only one section is allowed in the configuration. drbd.conf handlers Define handlers to be invoked when certain events occur. The kernel passes the resource name in the first command-line argument and sets the following environment variables depending on the event's context: For events related to a particular device: the device's minor number in , the device's volume number in . For events related to a particular device on a particular peer: the connection endpoints in , , , and ; the device's local minor number in , and the device's volume number in . For events related to a particular connection: the connection endpoints in , , , and ; and, for each device defined for that connection: the device's minor number in . For events that identify a device, if a lower-level device is attached, the lower-level device's device name is passed in (or ). All parameters in this section are optional. Only a single handler can be defined for each event; if no handler is defined, nothing will happen. drbd.conf net Define parameters for a connection. All parameters in this section are optional. ... drbd.conf on Define the properties of a resource on a particular host or set of hosts. Specifying more than one host name can make sense in a setup with IP address failover, for example. The host-name argument must match the Linux host name (). Usually contains or inherits at least one section. The and parameters must be defined in this section. The , , and parameters must be defined in, or inherited by, this section. A normal configuration file contains two or more sections for each resource. Also see the section. drbd.conf options Define parameters for a resource. All parameters in this section are optional. drbd.conf resource Define a resource. Usually contains at least two sections and at least one section. drbd.conf stacked-on-top-of Used instead of an section for configuring a stacked resource with three to four nodes. Starting with DRBD 9, stacking is deprecated. It is advised to use resources which are replicated among more than two nodes instead. drbd.conf startup The parameters in this section determine the behavior of a resource at startup time. drbd.conf volume Define a volume within a resource. The volume numbers in the various sections of a resource define which devices on which hosts form a replicated device. Section <option>connection</option> Parameters drbd.conf host Defines an endpoint for a connection. Each statement refers to an section in a resource. If a port number is defined, this endpoint will use the specified port instead of the port defined in the section. Each section must contain exactly two parameters. Instead of two parameters the connection may contain multiple sections. Section <option>path</option> Parameters drbd.conf host Defines an endpoint for a connection. Each statement refers to an section in a resource. If a port number is defined, this endpoint will use the specified port instead of the port defined in the section. Each section must contain exactly two parameters. Section <option>connection-mesh</option> Parameters drbd.conf host Defines all nodes of a mesh. Each refers to an section in a resource. The port that is defined in the section will be used. Section <option>disk</option> Parameters Section <option>global</option> Parameters Section <option>handlers</option> Parameters drbd.conf after-resync-target Called on a resync target when a node state changes from to when a resync finishes. This handler can be used for removing the snapshot created in the handler. drbd.conf before-resync-target Called on a resync target before a resync begins. This handler can be used for creating a snapshot of the lower-level device for the duration of the resync: if the resync source becomes unavailable during a resync, reverting to the snapshot can restore a consistent state. drbd.conf fence-peer Called when a node should fence a resource on a particular peer. The handler should not use the same communication path that DRBD uses for talking to the peer. drbd.conf unfence-peer Called when a node should remove fencing constraints from other nodes. drbd.conf initial-split-brain Called when DRBD connects to a peer and detects that the peer is in a split-brain state with the local node. This handler is also called for split-brain scenarios which will be resolved automatically. drbd.conf local-io-error Called when an I/O error occurs on a lower-level device. drbd.conf pri-lost The local node is currently primary, but DRBD believes that it should become a sync target. The node should give up its primary role. drbd.conf pri-lost-after-sb The local node is currently primary, but it has lost the after-split-brain auto recovery procedure. The node should be abandoned. drbd.conf pri-on-incon-degr The local node is primary, and neither the local lower-level device nor a lower-level device on a peer is up to date. (The primary has no device to read from or to write to.) drbd.conf split-brain DRBD has detected a split-brain situation which could not be resolved automatically. Manual recovery is necessary. This handler can be used to call for administrator attention. Section <option>net</option> Parameters Section <option>on</option> Parameters drbd.conf address Defines the address family, address, and port of a connection endpoint. The address families , , (Dolphin Interconnect Solutions' "super sockets"), (Infiniband Sockets Direct Protocol), and are supported ( is an alias for ). If no address family is specified, is assumed. For all address families except , the address is specified in IPV4 address notation (for example, 1.2.3.4). For , the address is enclosed in brackets and uses IPv6 address notation (for example, [fd01:2345:6789:abcd::1]). The port is always specified as a decimal number from 1 to 65535. On each host, the port numbers must be unique for each address; ports cannot be shared. drbd.conf node-id Defines the unique node identifier for a node in the cluster. Node identifiers are used to identify individual nodes in the network protocol, and to assign bitmap slots to nodes in the metadata. Node identifiers can only be reasssigned in a cluster when the cluster is down. It is essential that the node identifiers in the configuration and in the device metadata are changed consistently on all hosts. To change the metadata, dump the current state with drbdmeta dump-md, adjust the bitmap slot assignment, and update the metadata with drbdmeta restore-md. The parameter exists since DRBD 9. Its value ranges from 0 to 16; there is no default. Section <option>options</option> Parameters (Resource Options) Section <option>startup</option> Parameters The parameters in this section define the behavior of DRBD at system startup time, in the DRBD init script. They have no effect once the system is up and running. On stacked devices, the and parameters in the configuration are usually ignored, and both timeouts are set to twice the timeout. The parameter tells DRBD to use the and parameters as defined in the configuration, even on stacked devices. Only use this parameter if the peer of the stacked resource is usually not available, or will not become primary. Incorrect use of this parameter can lead to unexpected split-brain scenarios. Section <option>volume</option> Parameters drbd.conf device Define the device name and minor number of a replicated block device. This is the device that applications are supposed to access; in most cases, the device is not used directly, but as a file system. This parameter is required and the standard device naming convention is assumed. In addition to this device, udev will create and symlinks to the device. disk drbd.conf disk Define the lower-level block device that DRBD will use for storing the actual data. While the replicated drbd device is configured, the lower-level device must not be used directly. Even read-only access with tools like dumpe2fs 8 and similar is not allowed. The keyword specifies that no lower-level block device is configured; this also overrides inheritance of the lower-level device. drbd.conf meta-disk Define where the metadata of a replicated block device resides: it can be , meaning that the lower-level device contains both the data and the metadata, or on a separate device. When the index form of this parameter is used, multiple replicated devices can share the same metadata device, each using a separate index. Each index occupies 128 MiB of data, which corresponds to a replicated device size of at most 4 TiB with two cluster nodes. We recommend not to share metadata devices anymore, and to instead use the lvm volume manager for creating metadata devices as needed. When the index form of this parameter is not used, the size of the lower-level device determines the size of the metadata. The size needed is 36 KiB + (size of lower-level device) / 32K * (number of nodes - 1). If the metadata device is bigger than that, the extra space is not used. This parameter is required if a other than is specified, and ignored if is set to . A parameter without a parameter is not allowed. Notes on data integrity DRBD supports two different mechanisms for data integrity checking: first, the network parameter allows to add a checksum to the data sent over the network. Second, the online verification mechanism (drbdadm verify and the parameter) allows to check for differences in the on-disk data. Both mechanisms can produce false positives if the data is modified during I/O (i.e., while it is being sent over the network or written to disk). This does not always indicate a problem: for example, some file systems and applications do modify data under I/O for certain operations. Swap space can also undergo changes while under I/O. Network data integrity checking tries to identify data modification during I/O by verifying the checksums on the sender side after sending the data. If it detects a mismatch, it logs an error. The receiver also logs an error when it detects a mismatch. Thus, an error logged only on the receiver side indicates an error on the network, and an error logged on both sides indicates data modification under I/O. The most recent example of systematic data corruption was identified as a bug in the TCP offloading engine and driver of a certain type of GBit NIC in 2007: the data corruption happened on the DMA transfer from core memory to the card. Because the TCP checksum were calculated on the card, the TCP/IP protocol checksums did not reveal this problem. Version This document was revised for version 9.0.0 of the DRBD distribution. Author Written by Philipp Reisner philipp.reisner@linbit.com and Lars Ellenberg lars.ellenberg@linbit.com. Reporting Bugs Report bugs to drbd-user@lists.linbit.com. Copyright Copyright 2001-2012 LINBIT Information Technologies, Philipp Reisner, Lars Ellenberg. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See Also drbd 8 , drbddisk 8 , drbdsetup 8 , drbdadm 8 , DRBD User's Guide, DRBD Web Site drbd-utils-8.9.6/documentation/v9/drbdmeta.xml0000644000175000017500000003237312466702073021235 0ustar apoikosapoikos 6 December 2012 DRBD 9.0.0 drbdmeta 8 System Administration drbdmeta Manipulate the DRBD on-disk metadata drbdmeta drbdmeta --force --ignore-sanity-checks device v06 minor v07 meta_dev index v08 meta_dev index v09 meta_dev index command cmd args Description The utility is used for creating, displaying, and modifying DRBD's on-disk metadata. Users usually interact with the utility, which provides a more high-level interface to DRBD than . (See 's option to see how uses .) This utility can only be used on devices which are not currently in use by the kernel. The first argument (device) specifies the drbd device associated with a volume, or - if no device is associated with that volume. If the drbd device is specified, the utility makes sure that the drbd device does not currently have a volume attached to prevent meta-data of an active volume from being destroyed. The second argument specifies the metadata version to use (v06, v07, v08, v09). In most metadata versions, the third argument (meta_dev) specifies the device which contains the metadata; this argument can be the same as device. The fourth argument (index) can be one of the keywords (for internal metadata), (in v07 for variable-sized metadata; v07 otherwise defaults to fixed-size internal metadata), (for variable-sized external metadata), or a numeric matadata index (for fixed-size external metadata). See the parameter in drbd.conf 5 . Options --force drbdmeta--force Assume yes as the answer to all questions drbdmeta would ask. --ignore-sanity-checks drbdmeta--ignore-sanity-checks Normally, performs some sanity checks before writing to the metadata device: for example, if the device appears to contain a file system, it refuses to destroy the file system by writing into it. Use this option to ignore these checks. Commands val (metadata versions v06, v07, and v08) number-of-bitmap-slots val val val (metadata version v09) drbdmetacreate-md Initialize the metadata. This is necessary before a DRBD resource can be attached. If finds an older version of DRBD metadata on the device, it asks if the format should be converted. When calls 's command for a device, it sets the number-of-bitmap-slots argument to the number of peers in the resource. To reserve additional bitmap slots (which allows to add more peers in the future), call directly instead. When a device is used before being connected to its peers the first time, DRBD assumes that peers can only handle 4 KiB requests by default. The option allows to set more optimistic values; use this if the versions of DRBD that this device will connect to are known. DRBD supports a maximum bio size of 32 KiB since version 8.3.8, of 128 KiB since version 8.3.9, and of 1 MiB since version 8.4.0. If you want to use more than 6433 activity log extents, or live on top of a spriped RAID, you may specify the number of stripes (, default 1), and the stripe size (, default 32). To just use a larger linear on-disk ring-buffer, leave the number of stripes at 1, and increase the size only: drbdmeta 0 v08 /dev/vg23/lv42 internal create-md --al-stripe-size 1M To avoid a single "spindle" from becoming a bottleneck, increase the number of stripes, to achieve an interleaved layout of the on-disk activity-log transactions. What you give as "stripe-size" should be what is a.k.a. "chunk size" or "granularity" or "strip unit": the minimum skip to the next "spindle". drbdmeta 0 v08 /dev/vg23/lv42 internal create-md --al-stripes 7 --al-stripe-size 64 id drbdmetaget-gi Show the data generation identifiers for a device on a particular connection. DRBD version 9.0.0 and beyond support multiple peers; use the node-id option to define which peer's data generation identifiers to show. id drbdmetashow-gi Similar to , but with explanatory information. drbdmetadump-md Dump the metadata of a device in text form, including the bitmap and activity log. Mark the data on a lower-level device as outdated. See drbdsetup 8 for details. Show the current disk state of a lower-level device. drbdmetacheck-resize Examine the device size of a lower-level device and its last known device size (saved in by ). For internal metadata, if the size of the lower-level device has changed and the metadata can be found at the previous position, move the metadata to the new position at the end of the block device. drbdmetaapply-al Apply the activity log of the specified device. This is necessary before the device can be attached by the kernel again. Expert commands The utility can be used to fine tune metdata. Please note that this can lead to destroyed metadata or even silent data corruption; use with great care only. gi id drbdmetaset-gi Set the generation identifiers. The gi argument is a generation counter for the v06 and v07 formats, and a set of UUIDs for v08 and beyond. Accepts the same syntax as in the output. DRBD version 9.0.0 and beyond support multiple peers; use the --node-id option to define which peer's data generation identifiers to set. dump_file drbdmetarestore-md Replace the metadata on the device with the contents of dump_file. The dump file format is defined by the output of the command. Version This document was revised for version 9.0.0 of the DRBD distribution. Author Written by Philipp Reisner philipp.reisner@linbit.com and Lars Ellenberg lars.ellenberg@linbit.com. Reporting Bugs Report bugs to drbd-user@lists.linbit.com. Copyright Copyright 2001-2008,2012 LINBIT Information Technologies, Philipp Reisner, Lars Ellenberg. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See Also drbdadm 8 drbd.conf 5 drbd-utils-8.9.6/documentation/v9/Makefile.in0000644000175000017500000001370512634271674021001 0ustar apoikosapoikos# Makefile in documentation directory # # This file is part of DRBD by Philipp Reisner and Lars Ellenberg. # # drbd is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # drbd is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with drbd; see the file COPYING. If not, write to # the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. # variables set by configure DISTRO = @DISTRO@ prefix = @prefix@ exec_prefix = @exec_prefix@ localstatedir = @localstatedir@ datarootdir = @datarootdir@ datadir = @datadir@ sbindir = @sbindir@ sysconfdir = @sysconfdir@ mandir = @mandir@ BASH_COMPLETION_SUFFIX = @BASH_COMPLETION_SUFFIX@ UDEV_RULE_SUFFIX = @UDEV_RULE_SUFFIX@ INITDIR = @INITDIR@ LIBDIR = @prefix@/lib/@PACKAGE_TARNAME@ CC = @CC@ CFLAGS = @CFLAGS@ XSLTPROC = @XSLTPROC@ # features enabled or disabled by configure WITH_83_SUPPORT = @WITH_83_SUPPORT@ WITH_84_SUPPORT = @WITH_84_SUPPORT@ WITH_UDEV = @WITH_UDEV@ WITH_XEN = @WITH_XEN@ WITH_PACEMAKER = @WITH_PACEMAKER@ WITH_RGMANAGER = @WITH_RGMANAGER@ WITH_BASHCOMPLETION = @WITH_BASHCOMPLETION@ # variables meant to be overridden from the make command line DESTDIR ?= / CREATE_MAN_LINK ?= yes MANPAGES := drbdsetup.8 drbd.conf.5 drbd.8 drbdadm.8 drbdmeta.8 MANPAGES += drbd-overview.8 STYLESHEET_PREFIX ?= http://docbook.sourceforge.net/release/xsl/current MANPAGES_STYLESHEET ?= $(STYLESHEET_PREFIX)/manpages/docbook.xsl HTML_STYLESHEET ?= $(STYLESHEET_PREFIX)/xhtml/docbook.xsl FO_STYLESHEET ?= $(STYLESHEET_PREFIX)/fo/docbook.xsl XSLTPROC_OPTIONS ?= --xinclude XSLTPROC_OPTIONS += --stringparam variablelist.term.break.after 1 #XSLTPROC_OPTIONS += --stringparam variablelist.term.separator "" XSLTPROC_MANPAGES_OPTIONS ?= $(XSLTPROC_OPTIONS) XSLTPROC_HTML_OPTIONS ?= $(XSLTPROC_OPTIONS) XSLTPROC_FO_OPTIONS ?= $(XSLTPROC_OPTIONS) DRBDSETUP_CMDS = new-resource new-minor del-resource del-minor DRBDSETUP_CMDS += new-peer new-path del-peer del-path DRBDSETUP_CMDS += attach connect disk-options net-options resource-options peer-device-options DRBDSETUP_CMDS += disconnect detach primary secondary verify invalidate invalidate-remote DRBDSETUP_CMDS += down role cstate dstate DRBDSETUP_CMDS += resize check-resize pause-sync resume-sync DRBDSETUP_CMDS += outdate show-gi get-gi show events2 DRBDSETUP_CMDS += status suspend-io resume-io new-current-uuid DRBDSETUP_CMDS += wait-connect-volume wait-connect-connection wait-connect-resource DRBDSETUP_CMDS += wait-sync-volume wait-sync-connection wait-sync-resource DRBDSETUP_CMDS += forget-peer make_doc := $(shell $(XSLTPROC) \ $(XSLTPROC_MANPAGES_OPTIONS) \ $(MANPAGES_STYLESHEET) < /dev/null > /dev/null 2>&1 && echo doc ) ifeq ($(make_doc),doc) all: doc else all: @echo "To (re)make the documentation: make doc" endif clean: @echo "To clean the documentation: make doc-clean" .PHONY: all clean doc man doc-clean distclean .PHONY: install uninstall html pdf ps doc: man ifeq ($(WITH_84_SUPPORT),yes) MAN_LINK=8.4 else MAN_LINK=9.0 endif doc-clean: distclean ####### Implicit rules .SUFFIXES: .sgml .5 .8 .html .pdf .ps %.5 %.8: %.xml $(XSLTPROC) \ $(XSLTPROC_MANPAGES_OPTIONS) \ $(MANPAGES_STYLESHEET) $< %.html: %.xml $(XSLTPROC) -o $@ \ $(XSLTPROC_HTML_OPTIONS) \ $(HTML_STYLESHEET) $< %.fo: %.xml $(XSLTPROC) -o $@ \ $(XSLTPROC_FO_OPTIONS) \ $(FO_STYLESHEET) $< ../../user/v9/drbdsetup.o: FORCE $(MAKE) -C $(@D) drbdsetup .PHONY: FORCE FORCE: # Don't try to re-make files tracked in git FILES_IN_GIT := # $(shell git ls-files) FILES_IN_GIT += Makefile.in drbd-overview.xml drbd.conf.xml.in drbd.conf.xsl FILES_IN_GIT += drbd.xml drbdadm.xml drbdmeta.xml drbdsetup-options.xml FILES_IN_GIT += drbdsetup.xml.in drbdsetup.xsl xml-usage-to-docbook.xsl $(FILES_IN_GIT): ; drbdsetup_X.xml := $(patsubst %,drbdsetup_%.xml,$(DRBDSETUP_CMDS)) drbdsetup_xml-help_X.xml := $(patsubst %,drbdsetup_xml-help_%.xml,$(DRBDSETUP_CMDS)) $(drbdsetup_xml-help_X.xml): ../../user/v9/drbdsetup.o $(drbdsetup_X.xml): xml-usage-to-docbook.xsl drbdsetup_xml-help_%.xml: ../../user/v9/drbdsetup xml-help $* > $@ drbdsetup_%.xml: drbdsetup_xml-help_%.xml $(XSLTPROC) -o $@ xml-usage-to-docbook.xsl $< drbd.conf.xml: drbd.conf.xml.in drbd.conf.xsl drbdsetup-options.xml $(XSLTPROC) -o $@ drbd.conf.xsl $< drbdsetup.xml: drbdsetup.xml.in drbdsetup.xsl drbdsetup-options.xml $(XSLTPROC) -o $@ drbdsetup.xsl $< distclean: ifeq ($(make_doc),doc) rm -f *.[58] manpage.links manpage.refs *~ manpage.log endif rm -f *.ps.gz *.pdf *.ps *.html pod2htm* rm -f drbdsetup_*.xml rm -f drbd.conf.xml drbdsetup.xml .PRECIOUS: drbd.conf.xml drbdsetup.xml ####### man: $(MANPAGES) install: @ok=true; for f in $(MANPAGES) ; \ do [ -e $$f ] || { echo $$f missing ; ok=false; } ; \ done ; $$ok set -e; for f in $(MANPAGES) ; do \ s=$${f##*.}; \ b=$${f%.[0-9]}; \ install -v -D -m 644 $$f $(DESTDIR)$(mandir)/man$$s/$$b-9.0.$$s ; \ if [ "$(CREATE_MAN_LINK)" = "yes" ]; then \ ln -sf $$b-$(MAN_LINK).$$s $(DESTDIR)$(mandir)/man$$s/$$f ; \ fi \ done uninstall: @ set -e; for f in $(MANPAGES) ; do \ s=$${f##*.}; \ b=$${f%.[0-9]}; \ rm -vf $(DESTDIR)$(mandir)/man$$s/$$b-9.0.$$s ; \ rm -vf $(DESTDIR)$(mandir)/man$$s/$$f ; \ done html: $(MANPAGES:.8=.html) pdf: $(MANPAGES:.8=.pdf) ps: $(MANPAGES:.8=.ps) drbdsetup.8: drbdsetup.xml $(drbdsetup_X.xml) .PHONY: install uninstall clean distclean ../../configure: @echo "please (re-)run ./autogen.sh with appropriate arguments"; exit 1 ../../config.status: ../../configure @echo "please (re-)run ./configure with appropriate arguments"; exit 1 Makefile: Makefile.in ../../config.status cd ../.. && ./config.status documentation/v9/Makefile drbd-utils-8.9.6/documentation/v9/drbd.xml0000644000175000017500000000617312466702073020365 0ustar apoikosapoikos drbd The start and stop script for DRBD DRBD 9.0.0 24 June 2014 drbd 8 System Administration /etc/init.d/drbd start stop status reload restart force-reload Introduction The /etc/init.d/drbd script is used to start and stop drbd on a system V style init system. When using a cluster resource manger such as Pacemaker, DRBD should usually not be started by the init system, but should typically be exclusively controlled by the cluster manager. You should not use, and disable, the init script in this case. chmod -x /etc/init.d/drbd has proven most effective for this. In order to use /etc/init.d/drbd, define a drbd configuration. See drbd.conf5 for details. Version This document was revised for version 9.0.0 of the DRBD distribution. Author Written by Philipp Reisner philipp.reisner@linbit.com and Lars Ellenberg lars.ellenberg@linbit.com. Reporting Bugs Report bugs to drbd-user@lists.linbit.com. Copyright Copyright 2001-2014 LINBIT Information Technologies, Philipp Reisner, Lars Ellenberg. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See Also drbd.conf5, drbdsetup8, drbdadm8, DRBD Homepage drbd-utils-8.9.6/documentation/v9/drbdadm.80000644000175000017500000002745012654452461020421 0ustar apoikosapoikos'\" t .\" Title: drbdadm .\" Author: [see the "Author" section] .\" Generator: DocBook XSL Stylesheets v1.75.2 .\" Date: 6 December 2012 .\" Manual: System Administration .\" Source: DRBD 9.0.0 .\" Language: English .\" .TH "DRBDADM" "8" "6 December 2012" "DRBD 9.0.0" "System Administration" .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" drbdadm \- Utility for DRBD administration.\" drbdadm .SH "SYNOPSIS" .HP \w'\fBdrbdadm\fR\ 'u \fBdrbdadm\fR [options...] [\-\-\ [\fIbackend\-options\fR...]] {\fIcommand\fR} {\fIcontext\fR...} .SH "DESCRIPTION" .PP The \fBdrbdadm\fR utility is used for managing DRBD based on its configuration files, see \fBdrbd.conf\fR(5)\&. It translates high\-level commands into one or more lower\-level commands for the \fBdrbdsetup\fR and \fBdrbdmeta\fR utilities, which control the kernel module and manipulate the on\-disk metadata\&. .PP Depending on the command, the \fBdrbdadm\fR utility operates on one or more resources, devices, connections, or peer devices\&. The following command contexts are defined: .PP .PP \fIresource\fR .RS 4 A resource specified by name, or the keyword \fBall\fR for all defined resources\&. .RE .PP \fIdevice\fR .RS 4 A device, specified by minor number (\fBminor\-\fR\fIminornumber\fR, e\&.g\&. \fBminor\-\fR\fI0\fR) or by resource and volume number (\fIresource\fR/\fIvolume\fR)\&. If only a \fIresource\fR is specified, the command iterates over all devices of that resource\&. .RE .PP \fIconnection\fR .RS 4 A connection, specified by resource and connection name (\fIresource\fR:\fIconnection\-name\fR)\&. If only a \fIresource\fR is specified, the command iterates over all connections of that resource\&. .RE .PP \fIpeer_device\fR .RS 4 A peer device, specified by resource, connection name, and volume number (\fIresource\fR:\fIconnection\-name\fR/\fIvolume\fR)\&. If only a \fIresource\fR, \fIdevice\fR, or \fIconnection\fR is specified, the command iterates over all peer devices of that resource, device, or connection\&. .RE .PP All options following a double\-dash are passed through to the lower\-level utilities as specified\&. In addition, \fBdrbdadm\fR understands most of the options of \fBdrbdsetup\fR, and will pass them through even without the double\-dash\&. .SH "OPTIONS" .PP \fB\-d\fR, \fB\-\-dry\-run\fR .RS 4 Show which commands \fBdrbdadm\fR would execute instead of actually executing them (for example, \fBdrbdadm \-d up \fR\fB\fIresource\fR\fR)\&. This can be a useful way to learn how \fBdrbdsetup\fR and \fBdrbdmeta\fR are used\&. .RE .PP \fB\-c\fR, \fB\-\-config\-file\fR \fIfile\fR .RS 4 Use an alternative configuration file\&. By default, \fBdrbdadm\fR will use the the first of the following files that exists: \fB/etc/drbd\-90\&.conf\fR, \fB/etc/drbd\-84\&.conf\fR, \fB/etc/drbd\-83\&.conf\fR, \fB/etc/drbd\-82\&.conf\fR, \fB/etc/drbd\-08\&.conf\fR, \fB/etc/drbd\&.conf\fR\&. .RE .PP \fB\-t\fR, \fB\-\-config\-to\-test\fR \fIfile\fR .RS 4 Check an additional configuration file\&. This option is only allowed with the dump and the sh\-nop commands\&. .RE .PP \fB\-s\fR, \fB\-\-drbdsetup\fR \fIfile\fR .RS 4 Specifies the full path to the \fBdrbdsetup\fR program\&. If this option is omitted, drbdadm will look for it beneath itself first, and then in the PATH\&. .RE .PP \fB\-m\fR, \fB\-\-drbdmeta\fR \fIfile\fR .RS 4 Specifies the full path to the \fBdrbdmeta\fR program\&. If this option is omitted, drbdadm will look for it beneath itself first, and then in the PATH\&. .RE .PP \fB\-S\fR, \fB\-\-stacked\fR .RS 4 Perform the command on a stacked resource\&. .RE .SH "COMMANDS" .PP adjust {\fIresource\fR} .RS 4 .\" drbdadm: adjust Adjust the configuration of the kernel module so that it matches the configuration files\&. The result should be the same as when stopping and restarting all resources (\fBdrbdadm down all\fR followed by \fBdrbdadm up all\fR), but without the interruptions\&. .sp Note that the adjust command can misinterpret the configuration change in some cases\&. To be safe, check what the command would do (with the \fB\-\-dry\-run\fR option) before running the actual command\&. .RE .PP adjust\-with\-progress {\fIresource\fR} .RS 4 .\" drbdadm: adjust-with-progress The same as \fBadjust\fR, but with some more information about the command\'s progress\&. .RE .PP apply\-al {\fIdevice\fR} .RS 4 .\" drbdadm: apply-al Apply the activity log of the specified device\&. See \fBdrbdmeta\fR(8) for details\&. .RE .PP attach {\fIdevice\fR} .RS 4 Attach a lower\-level device to an existing replicated device\&. See \fBdrbdsetup\fR(8) for details\&. .RE .PP check\-resize {\fIdevice\fR} .RS 4 .\" drbdadm: check-resize Call drbdmeta to eventually move internal meta data\&. If the backing device was resized, while DRBD was not running, meta data has to be moved to the end of the device, so that the next \fBattach\fR command can succeed\&. .RE .PP connect {\fIconnection\fR} .RS 4 .\" drbdadm: connect Activate an exisiting connection to a peer\&. The connection needs to be created first with the \fBnew\-peer\fR command, and have at least one path created with the \fBnew\-path\fR command\&. See \fBdrbdsetup\fR(8) for details\&. .RE .PP create\-md {\fIdevice\fR} .RS 4 .\" drbdadm: create-md Initialize the metadata of a device\&. This is necessary before a device can be attached; see \fBdrbdmeta\fR(8) for details\&. .RE .PP cstate {\fIconnection\fR} .RS 4 .\" drbdadm: cstate Show the current state of a connection\&. See \fBdrbdsetup\fR(8) for details\&. .RE .PP detach {\fIdevice\fR} .RS 4 .\" drbdadm: detach Detach the lower\-level device of a replicated device\&. See \fBdrbdsetup\fR(8) for details\&. .RE .PP disconnect {\fIconnection\fR} .RS 4 .\" drbdadm: disconnect Remove a connection to a peer host\&. See \fBdrbdsetup\fR(8) for details\&. .RE .PP disk\-options {\fIdevice\fR} .RS 4 .\" drbdadm: disk-options Cange the disk options of an attached lower\-level device\&. See \fBdrbdsetup\fR(8) for details\&. .RE .PP down {\fIresource\fR} .RS 4 .\" drbdadm: down Take a resource down by removing all volumes, connections, and the resource itself\&. See \fBdrbdsetup\fR(8) for details\&. .RE .PP dstate {\fIdevice\fR} .RS 4 .\" drbdadm: dstate Show the current disk state of a lower\-level device\&. See \fBdrbdsetup\fR(8) for details\&. .RE .PP dump {\fIresource\fR} .RS 4 .\" drbdadm: dump Parse the configuration file and dump it to stdout\&. This will fail if the configuration file is syntactically incorrect\&. .RE .PP dump\-md {\fIdevice\fR} .RS 4 .\" drbdadm: dump-md Dump the metadata of a device in text form, including the bitmap and activity log\&. See \fBdrbdmeta\fR(8) for details\&. .RE .PP get\-gi {\fIpeer_device\fR} .RS 4 .\" drbdadm: get-gi Show the data generation identifiers for a device on a particular connection\&. Uses \fBdrbdsetup\fR for attached devices and \fBdrbdmeta\fR for unattached devices\&. See \fBdrbdsetup\fR(8) for details\&. .RE .PP hidden\-commands .RS 4 Shows all commands which are not explicitly documented\&. .RE .PP invalidate {\fIpeer_device\fR} .RS 4 .\" drbdadm: invalidate Replace the local data of a device with that of a peer\&. See \fBdrbdsetup\fR(8) for details\&. .RE .PP invalidate\-remote {\fIpeer_device\fR} .RS 4 .\" drbdadm: invalidate-remote Replace a peer device\'s data of a resource with the local data\&. See \fBdrbdsetup\fR(8) for details\&. .RE .PP net\-options {\fIconnection\fR} .RS 4 .\" drbdadm: net-options Change the network options of an existing connection\&. See \fBdrbdsetup\fR(8) for details\&. .RE .PP new\-current\-uuid {\fIdevice\fR} .RS 4 .\" drbdadm: new-current-uuid Generate a new currend UUID\&. See \fBdrbdsetup\fR(8) for details\&. .RE .PP outdate {\fIdevice\fR} .RS 4 .\" drbdadm: outdate Mark the data on a lower\-level device as outdated\&. See \fBdrbdsetup\fR(8) for details\&. .RE .PP pause\-sync {\fIpeer_device\fR} .RS 4 .\" drbdadm: pause-sync Stop resynchronizing between a local and a peer device by setting the local pause flag\&. See \fBdrbdsetup\fR(8) for details\&. .RE .PP primary {\fIresource\fR} .RS 4 .\" drbdadm: primary Change the role of a node in a resource to primary\&. See \fBdrbdsetup\fR(8) for details\&. .RE .PP resize {\fIdevice\fR} .RS 4 .\" drbdadm: resize Resize the lower\-level devices of a replicated device on all nodes\&. This combines the \fBcheck\-resize\fR and \fBresize\fR lower\-level commands; see \fBdrbdsetup\fR(8) for details\&. .RE .PP resource\-options {\fIresource\fR} .RS 4 .\" drbdadm: resource-options Change the resource options of an existing resource\&. See \fBdrbdsetup\fR(8) for details\&. .RE .PP resume\-sync {\fIpeer_device\fR} .RS 4 .\" drbdadm: resume-sync Allow resynchronization to resume by clearing the local sync pause flag\&. See \fBdrbdsetup\fR(8) for details\&. .RE .PP role {\fIresource\fR} .RS 4 .\" drbdadm: role Show the current role of a resource\&. .RE .PP secondary {\fIresource\fR} .RS 4 .\" drbdadm: secondary Change the role of a node in a resource to secondary\&. This command fails if the replicated device is in use\&. .RE .PP show\-gi {\fIpeer_device\fR} .RS 4 .\" drbdadm: show-gi Show the data generation identifiers for a device on a particular connection\&. In addition, explain the output\&. See \fBdrbdsetup\fR(8) for details\&. .RE .PP state {\fIresource\fR} .RS 4 .\" drbdadm: state This is an alias for \fBdrbdsetup role\fR\&. Deprecated\&. .RE .PP up {\fIresource\fR} .RS 4 .\" drbdadm: up Bring up a resource by applying the activity log of all volumes, creating the resource, creating the replicated devices, attaching the lower\-level devices, and connecting to all peers\&. See the \fBapply\-al\fR drbdmeta command and the \fBnew\-resource\fR, \fBnew\-device\fR, \fBnew\-minor\fR, \fBattach\fR, and \fBconnect\fR drbdsetup commands\&. .RE .PP verify {\fIpeer_device\fR} .RS 4 .\" drbdadm: verify Start online verification, change which part of the device will be verified, or stop online verification\&. See \fBdrbdsetup\fR(8) for details\&. .RE .PP wait\-connect {[\fIdevice\fR] | [\fIconnection\fR] | [\fIresource\fR]} .RS 4 .\" drbdadm: wait-connect Wait until a device on a peer, all devices over a connection, or all devices on all peers are visible\&. See \fBdrbdsetup\fR(8) for details\&. .RE .PP wait\-sync {[\fIdevice\fR] | [\fIconnection\fR] | [\fIresource\fR]} .RS 4 .\" drbdadm: wait-sync Wait until a device is connected and has finished eventual resync operation\&. Also available on connection and resource level\&. See \fBdrbdsetup\fR(8) for details\&. .RE .PP wipe\-md {\fIdevice\fR} .RS 4 .\" drbdadm: wipe-md Wipe out the DRBD metadata of a device\&. See \fBdrbdmeta\fR(8) for details\&. .RE .PP forget\-peer {\fIconnection\fR} .RS 4 .\" drbdadm: forget-peer Completely remove any reference to a unconnected peer from meta\-data\&. See \fBdrbdmeta\fR(8) for details\&. .RE .SH "VERSION" .sp This document was revised for version 9\&.0\&.0 of the DRBD distribution\&. .SH "AUTHOR" .sp Written by Philipp Reisner philipp\&.reisner@linbit\&.com and Lars Ellenberg lars\&.ellenberg@linbit\&.com .SH "REPORTING BUGS" .sp Report bugs to drbd\-user@lists\&.linbit\&.com\&. .SH "COPYRIGHT" .sp Copyright 2001\-2012 LINBIT Information Technologies, Philipp Reisner, Lars Ellenberg\&. This is free software; see the source for copying conditions\&. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE\&. .SH "SEE ALSO" .PP \fBdrbd.conf\fR(5), \fBdrbd\fR(8), \fBdrbddisk\fR(8), \fBdrbdsetup\fR(8), \fBdrbdmeta\fR(8) and the \m[blue]\fBDRBD project web site\fR\m[]\&\s-2\u[1]\d\s+2 .SH "NOTES" .IP " 1." 4 DRBD project web site .RS 4 \%http://www.drbd.org/ .RE drbd-utils-8.9.6/documentation/v9/drbd.conf.50000644000175000017500000017614212654452460020662 0ustar apoikosapoikos'\" t .\" Title: drbd.conf .\" Author: [see the "Author" section] .\" Generator: DocBook XSL Stylesheets v1.75.2 .\" Date: 3 December 2012 .\" Manual: Configuration Files .\" Source: DRBD 9.0.0 .\" Language: English .\" .TH "DRBD\&.CONF" "5" "3 December 2012" "DRBD 9.0.0" "Configuration Files" .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" drbd.conf \- DRBD Configuration Files.\" drbd.conf .SH "INTRODUCTION" .PP DRBD implements block devices which replicate their data to all nodes of a cluster\&. The actual data and associated metadata are usually stored redundantly on "ordinary" block devices on each cluster node\&. .PP Replicated block devices are called \fB/dev/drbd\fR\fB\fIminor\fR\fR by default\&. They are grouped into resources, with one or more devices per resource\&. Replication among the devices in a resource takes place in chronological order\&. With DRBD, we refer to the devices inside a resource as \fIvolumes\fR\&. .PP In DRBD 9, a resource can be replicated between two or more cluster nodes\&. The connections between cluster nodes are point\-to\-point links, and use TCP or a TCP\-like protocol\&. All nodes must be directly connected\&. .PP DRBD consists of low\-level user\-space components which interact with the kernel and perform basic operations (\fBdrbdsetup\fR, \fBdrbdmeta\fR), a high\-level user\-space component which understands and processes the DRBD configuration and translates it into basic operations of the low\-level components (\fBdrbdadm\fR), and a kernel component\&. .PP The default DRBD configuration consists of \fB/etc/drbd\&.conf\fR and of additional files included from there, usually \fBglobal_common\&.conf\fR and all \fB\fI*\fR\fR\fB\&.res\fR files inside \fB/etc/drbd\&.d/\fR\&. It has turned out to be useful to define each resource in a separate \fB\fI*\fR\fR\fB\&.res\fR file\&. .PP The configuration files are designed so that each cluster node can contain an identical copy of the entire cluster configuration\&. The host name of each node determines which parts of the configuration apply (\fBuname \-n\fR)\&. It is highly recommended to keep the cluster configuration on all nodes in sync by manually copying it to all nodes, or by automating the process with \fBcsync2\fR or a similar tool\&. .SH "EXAMPLE CONFIGURATION FILE" .PP .sp .if n \{\ .RS 4 .\} .nf resource r0 { net { cram\-hmac\-alg sha1; shared\-secret "FooFunFactory"; } volume 0 { device /dev/drbd1; disk /dev/sda7; meta\-disk internal; } on alice { node\-id 0; address 10\&.1\&.1\&.31:7000; } on bob { node\-id 1; address 10\&.1\&.1\&.32:7000; } connection { host alice port 7000; host bob port 7000; net { protocol C; } } } .fi .if n \{\ .RE .\} .sp This example defines a resource \fBr0\fR which contains a single replicated device with volume number 0\&. The resource is replicated among hosts \fBalice\fR and \fBbob\fR, which have the IPv4 addresses \fB10\&.1\&.1\&.31\fR and \fB10\&.1\&.1\&.32\fR and the node identifiers 0 and 1, respectively\&. On both hosts, the replicated device is called \fB/dev/drbd1\fR, and the actual data and metadata are stored on the lower\-level device \fB/dev/sda7\fR\&. The connection between the hosts uses protocol C\&. .PP Please refer to the \m[blue]\fBDRBD User\'s Guide\fR\m[]\&\s-2\u[1]\d\s+2 for more examples\&. .SH "FILE FORMAT" .PP DRBD configuration files consist of sections, which contain other sections and parameters depending on the section types\&. Each section consists of one or more keywords, sometimes a section name, an opening brace (\(lq{\(rq), the section\'s contents, and a closing brace (\(lq}\(rq)\&. Parameters inside a section consist of a keyword, followed by one or more keywords or values, and a semicolon (\(lq;\(rq)\&. .PP Some parameter values have a default scale which applies when a plain number is specified (for example Kilo, or 1024 times the numeric value)\&. Such default scales can be overridden by using a suffix (for example, \fBM\fR for Mega)\&. The common suffixes \fBK\fR = 2^10 = 1024, \fBM\fR = 1024 K, and \fBG\fR = 1024 M are supported\&. .PP Comments start with a hash sign (\(lq#\(rq) and extend to the end of the line\&. In addition, any section can be prefixed with the keyword \fBskip\fR, which causes the section and any sub\-sections to be ignored\&. .PP Additional files can be included with the \fBinclude \fR\fB\fIfile\-pattern\fR\fR statement (see \fBglob\fR(7) for the expressions supported in \fIfile\-pattern\fR)\&. Include statements are only allowed outside of sections\&. .PP The following sections are defined (indentation indicates in which context): .sp .if n \{\ .RS 4 .\} .nf common [disk] [handlers] [net] [options] [startup] global resource connection path net connection\-mesh net [disk] floating handlers [net] on volume disk [disk] options stacked\-on\-top\-of startup .fi .if n \{\ .RE .\} .sp Sections in brackets affect other parts of the configuration: inside the \fBcommon\fR section, they apply to all resources\&. A \fBdisk\fR section inside a \fBresource\fR or \fBon\fR section applies to all volumes of that resource, and a \fBnet\fR section inside a \fBresource\fR section applies to all connections of that resource\&. This allows to avoid repeating identical options for each resource, connection, or volume\&. Options can be overridden in a more specific \fBresource\fR, \fBconnection\fR, \fBon\fR, or \fBvolume\fR section\&. .SS "Sections" .PP \fBcommon\fR .RS 4 .\" drbd.conf: common This section can contain each a \fBdisk\fR, \fBhandlers\fR, \fBnet\fR, \fBoptions\fR, and \fBstartup\fR section\&. All resources inherit the parameters in these sections as their default values\&. .RE .PP \fBconnection \fR\fB\fI[name]\fR\fR .RS 4 .\" drbd.conf: connection Define a connection between two hosts\&. This section must contain two \fBhost\fR parameters or multiple \fBpath sections\fR\&. The optional \fIname\fR is used to refer to the connection in the system log and in other messages\&. If no name is specified, the peer\'s host name is used instead\&. .RE .PP \fBpath\fR .RS 4 .\" drbd.conf: path Define a path between two hosts\&. This section must contain two \fBhost\fR parameters\&. .RE .PP \fBconnection\-mesh\fR .RS 4 .\" drbd.conf: connection-mesh Define a connection mesh between multiple hosts\&. This section must contain a \fBhosts\fR parameter, which has the host names as arguments\&. This section is a shortcut to define many connections which share the same network options\&. .RE .PP \fBdisk\fR .RS 4 .\" drbd.conf: disk Define parameters for a volume\&. All parameters in this section are optional\&. .RE .PP \fBfloating \fR\fB\fI[address\-family]\fR\fR\fB \fR\fB\fIaddr\fR\fR\fB:\fR\fB\fIport\fR\fR .RS 4 .\" drbd.conf: floating Like the \fBon\fR section, except that instead of the host name a network address is used to determine if it matches a \fBfloating\fR section\&. .sp The \fBnode\-id\fR parameter in this section is required\&. If the \fBaddress\fR parameter is not provided, no connections to peers will be created by default\&. The \fBdevice\fR, \fBdisk\fR, and \fBmeta\-disk\fR parameters must be defined in, or inherited by, this section\&. .RE .PP \fBglobal\fR .RS 4 .\" drbd.conf: global Define some global parameters\&. All parameters in this section are optional\&. Only one \fBglobal\fR section is allowed in the configuration\&. .RE .PP \fBhandlers\fR .RS 4 .\" drbd.conf: handlers Define handlers to be invoked when certain events occur\&. The kernel passes the resource name in the first command\-line argument and sets the following environment variables depending on the event\'s context: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} For events related to a particular device: the device\'s minor number in \fBDRBD_MINOR\fR, the device\'s volume number in \fBDRBD_VOLUME\fR\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} For events related to a particular device on a particular peer: the connection endpoints in \fBDRBD_MY_ADDRESS\fR, \fBDRBD_MY_AF\fR, \fBDRBD_PEER_ADDRESS\fR, and \fBDRBD_PEER_AF\fR; the device\'s local minor number in \fBDRBD_MINOR\fR, and the device\'s volume number in \fBDRBD_VOLUME\fR\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} For events related to a particular connection: the connection endpoints in \fBDRBD_MY_ADDRESS\fR, \fBDRBD_MY_AF\fR, \fBDRBD_PEER_ADDRESS\fR, and \fBDRBD_PEER_AF\fR; and, for each device defined for that connection: the device\'s minor number in \fBDRBD_MINOR_\fR\fB\fIvolume\-number\fR\fR\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} For events that identify a device, if a lower\-level device is attached, the lower\-level device\'s device name is passed in \fBDRBD_BACKING_DEV\fR (or \fBDRBD_BACKING_DEV_\fR\fB\fIvolume\-number\fR\fR)\&. .RE .RS 4 .sp All parameters in this section are optional\&. Only a single handler can be defined for each event; if no handler is defined, nothing will happen\&. .RE .PP \fBnet\fR .RS 4 .\" drbd.conf: net Define parameters for a connection\&. All parameters in this section are optional\&. .RE .PP \fBon\fR \fB\fIhost\-name\fR\fR \fI[\&.\&.\&.]\fR .RS 4 .\" drbd.conf: on Define the properties of a resource on a particular host or set of hosts\&. Specifying more than one host name can make sense in a setup with IP address failover, for example\&. The \fIhost\-name\fR argument must match the Linux host name (\fBuname \-n\fR)\&. .sp Usually contains or inherits at least one \fBvolume\fR section\&. The \fBnode\-id\fR and \fBaddress\fR parameters must be defined in this section\&. The \fBdevice\fR, \fBdisk\fR, and \fBmeta\-disk\fR parameters must be defined in, or inherited by, this section\&. .sp A normal configuration file contains two or more \fBon\fR sections for each resource\&. Also see the \fBfloating\fR section\&. .RE .PP \fBoptions\fR .RS 4 .\" drbd.conf: options Define parameters for a resource\&. All parameters in this section are optional\&. .RE .PP \fBresource\fR \fB\fIname\fR\fR .RS 4 .\" drbd.conf: resource Define a resource\&. Usually contains at least two \fBon\fR sections and at least one \fBconnection\fR section\&. .RE .PP \fBstacked\-on\-top\-of \fR\fB\fIresource\fR\fR .RS 4 .\" drbd.conf: stacked-on-top-of Used instead of an \fBon\fR section for configuring a stacked resource with three to four nodes\&. .sp Starting with DRBD 9, stacking is deprecated\&. It is advised to use resources which are replicated among more than two nodes instead\&. .RE .PP \fBstartup\fR .RS 4 .\" drbd.conf: startup The parameters in this section determine the behavior of a resource at startup time\&. .RE .PP \fBvolume\fR \fB\fIvolume\-number\fR\fR .RS 4 .\" drbd.conf: volume Define a volume within a resource\&. The volume numbers in the various \fBvolume\fR sections of a resource define which devices on which hosts form a replicated device\&. .RE .SS "Section connection Parameters" .PP \fBhost \fR\fB\fIname\fR\fR [\fBaddress \fR\fB[address\-family]\fR\fB \fR\fB\fIaddress\fR\fR] [\fBport \fR\fB\fIport\-number\fR\fR] .RS 4 .\" drbd.conf: host Defines an endpoint for a connection\&. Each \fBhost\fR statement refers to an \fBon\fR section in a resource\&. If a port number is defined, this endpoint will use the specified port instead of the port defined in the \fBon\fR section\&. Each \fBconnection\fR section must contain exactly two \fBhost\fR parameters\&. Instead of two \fBhost\fR parameters the connection may contain multiple \fBpath\fR sections\&. .RE .SS "Section path Parameters" .PP \fBhost \fR\fB\fIname\fR\fR [\fBaddress \fR\fB[address\-family]\fR\fB \fR\fB\fIaddress\fR\fR] [\fBport \fR\fB\fIport\-number\fR\fR] .RS 4 .\" drbd.conf: host Defines an endpoint for a connection\&. Each \fBhost\fR statement refers to an \fBon\fR section in a resource\&. If a port number is defined, this endpoint will use the specified port instead of the port defined in the \fBon\fR section\&. Each \fBpath\fR section must contain exactly two \fBhost\fR parameters\&. .RE .SS "Section connection\-mesh Parameters" .PP \fBhosts \fR\fB\fIname\fR...\fR .RS 4 .\" drbd.conf: host Defines all nodes of a mesh\&. Each \fB\fIname\fR\fR refers to an \fBon\fR section in a resource\&. The port that is defined in the \fBon\fR section will be used\&. .RE .SS "Section disk Parameters" .PP \fBal\-extents \fR\fB\fIextents\fR\fR .RS 4 .\" drbd.conf: al-extents DRBD automatically maintains a "hot" or "active" disk area likely to be written to again soon based on the recent write activity\&. The "active" disk area can be written to immediately, while "inactive" disk areas must be "activated" first, which requires a meta\-data write\&. We also refer to this active disk area as the "activity log"\&. .sp The activity log saves meta\-data writes, but the whole log must be resynced upon recovery of a failed node\&. The size of the activity log is a major factor of how long a resync will take and how fast a replicated disk will become consistent after a crash\&. .sp The activity log consists of a number of 4\-Megabyte segments; the \fIal\-extents\fR parameter determines how many of those segments can be active at the same time\&. The default value for \fIal\-extents\fR is 1237, with a minimum of 7 and a maximum of 65536\&. .sp Note that the effective maximum may be smaller, depending on how you created the device meta data, see also \fBdrbdmeta\fR(8) The effective maximum is 919 * (available on\-disk activity\-log ring\-buffer area/4kB \-1), the default 32kB ring\-buffer effects a maximum of 6433 (covers more than 25 GiB of data) We recommend to keep this well within the amount your backend storage and replication link are able to resync inside of about 5 minutes\&. .RE .PP \fBal\-updates \fR\fB{yes | no}\fR\fB \fR .RS 4 .\" drbd.conf: al-updates With this parameter, the activity log can be turned off entirely (see the \fBal\-extents\fR parameter)\&. This will speed up writes because fewer meta\-data writes will be necessary, but the entire device needs to be resynchronized opon recovery of a failed primary node\&. The default value for \fBal\-updates\fR is \fByes\fR\&. .RE .PP \fBc\-delay\-target \fR\fB\fIdelay_target\fR\fR, .br \fBc\-fill\-target \fR\fB\fIfill_target\fR\fR, .br \fBc\-max\-rate \fR\fB\fImax_rate\fR\fR, .br \fBc\-plan\-ahead \fR\fB\fIplan_time\fR\fR .RS 4 Dynamically control the resync speed\&. This mechanism is enabled by setting the \fBc\-plan\-ahead\fR parameter to a positive value\&. The goal is to either fill the buffers along the data path with a defined amount of data if \fBc\-fill\-target\fR is defined, or to have a defined delay along the path if \fBc\-delay\-target\fR is defined\&. The maximum bandwidth is limited by the \fBc\-max\-rate\fR parameter\&. .sp The \fBc\-plan\-ahead\fR parameter defines how fast drbd adapts to changes in the resync speed\&. It should be set to five times the network round\-trip time or more\&. Common values for \fBc\-fill\-target\fR for "normal" data paths range from 4K to 100K\&. If drbd\-proxy is used, it is advised to use \fBc\-delay\-target\fR instead of \fBc\-fill\-target\fR\&. The \fBc\-delay\-target\fR parameter is used if the \fBc\-fill\-target\fR parameter is undefined or set to 0\&. The \fBc\-delay\-target\fR parameter should be set to five times the network round\-trip time or more\&. The \fBc\-max\-rate\fR option should be set to either the bandwidth available between the DRBD\-hosts and the machines hosting DRBD\-proxy, or to the available disk bandwidth\&. .sp The default values of these parameters are: \fBc\-plan\-ahead\fR = 20 (in units of 0\&.1 seconds), \fBc\-fill\-target\fR = 0 (in units of sectors), \fBc\-delay\-target\fR = 1 (in units of 0\&.1 seconds), and \fBc\-max\-rate\fR = 102400 (in units of KiB/s)\&. .sp Dynamic resync speed control is available since DRBD 8\&.3\&.9\&. .RE .PP \fBc\-min\-rate \fR\fB\fImin_rate\fR\fR .RS 4 A node which is primary and sync\-source has to schedule application I/O requests and resync I/O requests\&. The \fBc\-min\-rate\fR parameter limits how much bandwidth is available for resync I/O; the remaining bandwidth is used for application I/O\&. .sp A \fBc\-min\-rate\fR value of 0 means that there is no limit on the resync I/O bandwidth\&. This can slow down application I/O significantly\&. Use a value of 1 (1 KiB/s) for the lowest possible resync rate\&. .sp The default value of \fBc\-min\-rate\fR is 4096, in units of KiB/s\&. .RE .PP \fBdisk\-barrier\fR, .br \fBdisk\-flushes\fR, .br \fBdisk\-drain\fR .RS 4 .\" drbd.conf: disk-barrier .\" drbd.conf: disk-flushes .\" drbd.conf: disk-drain DRBD has three methods of handling the ordering of dependent write requests: .PP \fBdisk\-barrier\fR .RS 4 Use disk barriers to make sure that requests are written to disk in the right order\&. Barriers ensure that all requests submitted before a barrier make it to the disk before any requests submitted after the barrier\&. This is implemented using \'tagged command queuing\' on SCSI devices and \'native command queuing\' on SATA devices\&. Only some devices and device stacks support this method\&. The device mapper (LVM) only supports barriers in some configurations\&. .sp Note that on systems which do not support disk barriers, enabling this option can lead to data loss or corruption\&. Until DRBD 8\&.4\&.1, \fBdisk\-barrier\fR was turned on if the I/O stack below DRBD did support barriers\&. Kernels since linux\-2\&.6\&.36 (or 2\&.6\&.32 RHEL6) no longer allow to detect if barriers are supported\&. Since drbd\-8\&.4\&.2, this option is off by default and needs to be enabled explicitly\&. .RE .PP \fBdisk\-flushes\fR .RS 4 Use disk flushes between dependent write requests, also referred to as \'force unit access\' by drive vendors\&. This forces all data to disk\&. This option is enabled by default\&. .RE .PP \fBdisk\-drain\fR .RS 4 Wait for the request queue to "drain" (that is, wait for the requests to finish) before submitting a dependent write request\&. This method requires that requests are stable on disk when they finish\&. Before DRBD 8\&.0\&.9, this was the only method implemented\&. This option is enabled by default\&. Do not disable in production environments\&. .RE .sp From these three methods, drbd will use the first that is enabled and supported by the backing storage device\&. If all three of these options are turned off, DRBD will submit write requests without bothering about dependencies\&. Depending on the I/O stack, write requests can be reordered, and they can be submitted in a different order on different cluster nodes\&. This can result in data loss or corruption\&. Therefore, turning off all three methods of controlling write ordering is strongly discouraged\&. .sp A general guideline for configuring write ordering is to use disk barriers or disk flushes when using ordinary disks (or an ordinary disk array) with a volatile write cache\&. On storage without cache or with a battery backed write cache, disk draining can be a reasonable choice\&. .RE .PP \fBdisk\-timeout\fR .RS 4 .\" drbd.conf: disk-timeout If the lower\-level device on which a DRBD device stores its data does not finish an I/O request within the defined \fBdisk\-timeout\fR, DRBD treats this as a failure\&. The lower\-level device is detached, and the device\'s disk state advances to Diskless\&. If DRBD is connected to one or more peers, the failed request is passed on to one of them\&. .sp This option is \fIdangerous and may lead to kernel panic!\fR .sp "Aborting" requests, or force\-detaching the disk, is intended for completely blocked/hung local backing devices which do no longer complete requests at all, not even do error completions\&. In this situation, usually a hard\-reset and failover is the only way out\&. .sp By "aborting", basically faking a local error\-completion, we allow for a more graceful swichover by cleanly migrating services\&. Still the affected node has to be rebooted "soon"\&. .sp By completing these requests, we allow the upper layers to re\-use the associated data pages\&. .sp If later the local backing device "recovers", and now DMAs some data from disk into the original request pages, in the best case it will just put random data into unused pages; but typically it will corrupt meanwhile completely unrelated data, causing all sorts of damage\&. .sp Which means delayed successful completion, especially for READ requests, is a reason to panic()\&. We assume that a delayed *error* completion is OK, though we still will complain noisily about it\&. .sp The default value of \fBdisk\-timeout\fR is 0, which stands for an infinite timeout\&. Timeouts are specified in units of 0\&.1 seconds\&. This option is available since DRBD 8\&.3\&.12\&. .RE .PP \fBfencing \fR\fB\fIfencing_policy\fR\fR .RS 4 .\" drbd.conf: fencing \fBFencing\fR is a preventive measure to avoid situations where both nodes are primary and disconnected\&. This is also known as a split\-brain situation\&. DRBD supports the following fencing policies: .PP \fBdont\-care\fR .RS 4 No fencing actions are taken\&. This is the default policy\&. .RE .PP \fBresource\-only\fR .RS 4 If a node becomes a disconnected primary, it tries to fence the peer\&. This is done by calling the \fBfence\-peer\fR handler\&. The handler is supposed to reach the peer over an alternative communication path and call \'\fBdrbdadm outdate minor\fR\' there\&. .RE .PP \fBresource\-and\-stonith\fR .RS 4 If a node becomes a disconnected primary, it freezes all its IO operations and calls its fence\-peer handler\&. The fence\-peer handler is supposed to reach the peer over an alternative communication path and call \'\fBdrbdadm outdate minor\fR\' there\&. In case it cannot do that, it should stonith the peer\&. IO is resumed as soon as the situation is resolved\&. In case the fence\-peer handler fails, I/O can be resumed manually with \'\fBdrbdadm resume\-io\fR\'\&. .RE .RE .PP \fBmd\-flushes\fR .RS 4 .\" drbd.conf: md-flushes Enable disk flushes and disk barriers on the meta\-data device\&. This option is enabled by default\&. See the \fBdisk\-flushes\fR parameter\&. .RE .PP \fBon\-io\-error \fR\fB\fIhandler\fR\fR .RS 4 .\" drbd.conf: on-io-error Configure how DRBD reacts to I/O errors on a lower\-level device\&. The following policies are defined: .PP \fBpass_on\fR .RS 4 Change the disk status to Inconsistent, mark the failed block as inconsistent in the bitmap, and retry the I/O operation on a remote cluster node\&. .RE .PP \fBcall\-local\-io\-error\fR .RS 4 Call the \fBlocal\-io\-error\fR handler (see the \fBhandlers\fR section)\&. .RE .PP \fBdetach\fR .RS 4 Detach the lower\-level device and continue in diskless mode\&. .RE .sp .RE .PP \fBread\-balancing \fR\fB\fIpolicy\fR\fR .RS 4 .\" drbd.conf: read-balancing Distribute read requests among cluster nodes as defined by \fIpolicy\fR\&. The supported policies are \fBprefer\-local\fR (the default), \fBprefer\-remote\fR, \fBround\-robin\fR, \fBleast\-pending\fR, \fBwhen\-congested\-remote\fR, \fB32K\-striping\fR, \fB64K\-striping\fR, \fB128K\-striping\fR, \fB256K\-striping\fR, \fB512K\-striping\fR and \fB1M\-striping\fR\&. .sp This option is available since DRBD 8\&.4\&.1\&. .RE .PP \fBresync\-after \fR\fB\fIres\-name\fR\fR\fB/\fR\fB\fIvolume\fR\fR .RS 4 .\" drbd.conf: resync-after Define that a device should only resynchronize after the specified other device\&. By default, no order between devices is defined, and all devices will resynchronize in parallel\&. Depending on the configuration of the lower\-level devices, and the available network and disk bandwidth, this can slow down the overall resync process\&. This option can be used to form a chain or tree of dependencies among devices\&. .RE .PP \fBresync\-rate \fR\fB\fIrate\fR\fR .RS 4 .\" drbd.conf: resync-rate Define how much bandwidth DRBD may use for resynchronizing\&. DRBD allows "normal" application I/O even during a resync\&. If the resync takes up too much bandwidth, application I/O can become very slow\&. This parameter allows to avoid that\&. Please note this is option only works when the dynamic resync controller is disabled\&. .RE .PP \fBrs\-discard\-granularity \fR\fB\fIbyte\fR\fR .RS 4 .\" drbd.conf: rs-discard-granularity When \fBrs\-discard\-granularity\fR is set to a non zero, positive value then DRBD tries to do a resync operation in requests of this size\&. In case such a block contains only zero bytes on the sync source node, the sync target node will issue a discard/trim/unmap command for the area\&. .sp The value is constrained by the discard granularity of the backing block device\&. In case \fBrs\-discard\-granularity\fR is not a multiplier of the discard granularity of the backing block device DRBD rounds it up\&. The feature only gets active if the backing block device reads back zeroes after a discard command\&. .sp The default value of is 0\&. This option is available since 8\&.4\&.7\&. .RE .PP \fBdiscard\-zeroes\-if\-aligned \fR\fB{yes | no}\fR .RS 4 .\" drbd.conf: discard-zeroes-if-aligned There are several aspects to discard/trim/unmap support on linux block devices\&. Even if discard is supported in general, it may fail silently, or may partially ignore discard requests\&. Devices also announce whether reading from unmapped blocks returns defined data (usually zeroes), or undefined data (possibly old data, possibly garbage)\&. .sp If on different nodes, DRBD is backed by devices with differing discard characteristics, discards may lead to data divergence (old data or garbage left over on one backend, zeroes due to unmapped areas on the other backend)\&. Online verify would now potentially report tons of spurious differences\&. While probably harmless for most use cases (fstrim on a file system), DRBD cannot have that\&. .sp To play safe, we have to disable discard support, if our local backend (on a Primary) does not support "discard_zeroes_data=true"\&. We also have to translate discards to explicit zero\-out on the receiving side, unless the receiving side (Secondary) supports "discard_zeroes_data=true", thereby allocating areas what were supposed to be unmapped\&. .sp There are some devices (notably the LVM/DM thin provisioning) that are capable of discard, but announce discard_zeroes_data=false\&. In the case of DM\-thin, discards aligned to the chunk size will be unmapped, and reading from unmapped sectors will return zeroes\&. However, unaligned partial head or tail areas of discard requests will be silently ignored\&. .sp If we now add a helper to explicitly zero\-out these unaligned partial areas, while passing on the discard of the aligned full chunks, we effectively achieve discard_zeroes_data=true on such devices\&. .sp Setting \fBdiscard\-zeroes\-if\-aligned\fR to \fByes\fR will allow DRBD to use discards, and to announce discard_zeroes_data=true, even on backends that announce discard_zeroes_data=false\&. .sp Setting \fBdiscard\-zeroes\-if\-aligned\fR to \fBno\fR will cause DRBD to always fall\-back to zero\-out on the receiving side, and to not even announce discard capabilities on the Primary, if the respective backend announces discard_zeroes_data=false\&. .sp We used to ignore the discard_zeroes_data setting completely\&. To not break established and expected behaviour, and suddenly cause fstrim on thin\-provisioned LVs to run out\-of\-space instead of freeing up space, the default value is \fByes\fR\&. .sp This option is available since 8\&.4\&.7\&. .RE .SS "Section global Parameters" .PP \fBdialog\-refresh \fR\fB\fItime\fR\fR .RS 4 .\" drbd.conf: dialog-refresh The DRBD init script can be used to configure and start DRBD devices, which can involve waiting for other cluster nodes\&. While waiting, the init script shows the remaining waiting time\&. The \fBdialog\-refresh\fR defines the number of seconds between updates of that countdown\&. The default value is 1; a value of 0 turns off the countdown\&. .RE .PP \fBdisable\-ip\-verification\fR .RS 4 .\" drbd.conf: disable-ip-verification Normally, DRBD verifies that the IP addresses in the configuration match the host names\&. Use the \fBdisable\-ip\-verification\fR parameter to disable these checks\&. .RE .PP \fBusage\-count \fR\fB{yes | no | ask}\fR\fB \fR .RS 4 .\" drbd.conf: usage-count A explained on DRBD\'s \m[blue]\fBOnline Usage Counter\fR\m[]\&\s-2\u[2]\d\s+2 web page, DRBD includes a mechanism for anonymously counting how many installations are using which versions of DRBD\&. The results are available on the web page for anyone to see\&. .sp This parameter defines if a cluster node participates in the usage counter; the supported values are \fByes\fR, \fBno\fR, and \fBask\fR (ask the user, the default)\&. .sp We would like to ask users to participate in the online usage counter as this provides us valuable feedback for steering the development of DRBD\&. .RE .SS "Section handlers Parameters" .PP \fBafter\-resync\-target \fR\fB\fIcmd\fR\fR .RS 4 .\" drbd.conf: after-resync-target Called on a resync target when a node state changes from \fBInconsistent\fR to \fBConsistent\fR when a resync finishes\&. This handler can be used for removing the snapshot created in the \fBbefore\-resync\-target\fR handler\&. .RE .PP \fBbefore\-resync\-target \fR\fB\fIcmd\fR\fR .RS 4 .\" drbd.conf: before-resync-target Called on a resync target before a resync begins\&. This handler can be used for creating a snapshot of the lower\-level device for the duration of the resync: if the resync source becomes unavailable during a resync, reverting to the snapshot can restore a consistent state\&. .RE .PP \fBfence\-peer \fR\fB\fIcmd\fR\fR .RS 4 .\" drbd.conf: fence-peer Called when a node should fence a resource on a particular peer\&. The handler should not use the same communication path that DRBD uses for talking to the peer\&. .RE .PP \fBunfence\-peer \fR\fB\fIcmd\fR\fR .RS 4 .\" drbd.conf: unfence-peer Called when a node should remove fencing constraints from other nodes\&. .RE .PP \fBinitial\-split\-brain \fR\fB\fIcmd\fR\fR .RS 4 .\" drbd.conf: initial-split-brain Called when DRBD connects to a peer and detects that the peer is in a split\-brain state with the local node\&. This handler is also called for split\-brain scenarios which will be resolved automatically\&. .RE .PP \fBlocal\-io\-error \fR\fB\fIcmd\fR\fR .RS 4 .\" drbd.conf: local-io-error Called when an I/O error occurs on a lower\-level device\&. .RE .PP \fBpri\-lost \fR\fB\fIcmd\fR\fR .RS 4 .\" drbd.conf: pri-lost The local node is currently primary, but DRBD believes that it should become a sync target\&. The node should give up its primary role\&. .RE .PP \fBpri\-lost\-after\-sb \fR\fB\fIcmd\fR\fR .RS 4 .\" drbd.conf: pri-lost-after-sb The local node is currently primary, but it has lost the after\-split\-brain auto recovery procedure\&. The node should be abandoned\&. .RE .PP \fBpri\-on\-incon\-degr \fR\fB\fIcmd\fR\fR .RS 4 .\" drbd.conf: pri-on-incon-degr The local node is primary, and neither the local lower\-level device nor a lower\-level device on a peer is up to date\&. (The primary has no device to read from or to write to\&.) .RE .PP \fBsplit\-brain \fR\fB\fIcmd\fR\fR .RS 4 .\" drbd.conf: split-brain DRBD has detected a split\-brain situation which could not be resolved automatically\&. Manual recovery is necessary\&. This handler can be used to call for administrator attention\&. .RE .SS "Section net Parameters" .PP \fBafter\-sb\-0pri \fR\fB\fIpolicy\fR\fR .RS 4 .\" drbd.conf: after-sb-0pri Define how to react if a split\-brain scenario is detected and none of the two nodes is in primary role\&. (We detect split\-brain scenarios when two nodes connect; split\-brain decisions are always between two nodes\&.) The defined policies are: .PP \fBdisconnect\fR .RS 4 No automatic resynchronization; simply disconnect\&. .RE .PP \fBdiscard\-younger\-primary\fR, .br \fBdiscard\-older\-primary\fR .RS 4 Resynchronize from the node which became primary first (\fBdiscard\-younger\-primary\fR) or last (\fBdiscard\-older\-primary\fR)\&. If both nodes became primary independently, the \fBdiscard\-least\-changes\fR policy is used\&. .RE .PP \fBdiscard\-zero\-changes\fR .RS 4 If only one of the nodes wrote data since the split brain situation was detected, resynchronize from this node to the other\&. If both nodes wrote data, disconnect\&. .RE .PP \fBdiscard\-least\-changes\fR .RS 4 Resynchronize from the node with more modified blocks\&. .RE .PP \fBdiscard\-node\-\fR\fB\fInodename\fR\fR .RS 4 Always resynchronize to the named node\&. .RE .RE .PP \fBafter\-sb\-1pri \fR\fB\fIpolicy\fR\fR .RS 4 .\" drbd.conf: after-sb-1pri Define how to react if a split\-brain scenario is detected, with one node in primary role and one node in secondary role\&. (We detect split\-brain scenarios when two nodes connect, so split\-brain decisions are always among two nodes\&.) The defined policies are: .PP \fBdisconnect\fR .RS 4 No automatic resynchronization, simply disconnect\&. .RE .PP \fBconsensus\fR .RS 4 Discard the data on the secondary node if the \fBafter\-sb\-0pri\fR algorithm would also discard the data on the secondary node\&. Otherwise, disconnect\&. .RE .PP \fBviolently\-as0p\fR .RS 4 Always take the decision of the \fBafter\-sb\-0pri\fR algorithm, even if it causes an erratic change of the primary\'s view of the data\&. This is only useful if a single\-node file system (i\&.e\&., not OCFS2 or GFS) with the \fBallow\-two\-primaries\fR flag is used\&. This option can cause the primary node to crash, and should not be used\&. .RE .PP \fBdiscard\-secondary\fR .RS 4 Discard the data on the secondary node\&. .RE .PP \fBcall\-pri\-lost\-after\-sb\fR .RS 4 Always take the decision of the \fBafter\-sb\-0pri\fR algorithm\&. If the decision is to discard the data on the primary node, call the \fBpri\-lost\-after\-sb\fR handler on the primary node\&. .RE .RE .PP \fBafter\-sb\-2pri \fR\fB\fIpolicy\fR\fR .RS 4 .\" drbd.conf: after-sb-2pri Define how to react if a split\-brain scenario is detected and both nodes are in primary role\&. (We detect split\-brain scenarios when two nodes connect, so split\-brain decisions are always among two nodes\&.) The defined policies are: .PP \fBdisconnect\fR .RS 4 No automatic resynchronization, simply disconnect\&. .RE .PP \fBviolently\-as0p\fR .RS 4 See the \fBviolently\-as0p\fR policy for \fBafter\-sb\-1pri\fR\&. .RE .PP \fBcall\-pri\-lost\-after\-sb\fR .RS 4 Call the \fBpri\-lost\-after\-sb\fR helper program on one of the machines unless that machine can demote to secondary\&. The helper program is expected to reboot the machine, which brings the node into a secondary role\&. Which machine runs the helper program is determined by the \fBafter\-sb\-0pri\fR strategy\&. .RE .RE .PP \fBallow\-two\-primaries\fR .RS 4 .\" drbd.conf: allow-two-primaries The most common way to configure DRBD devices is to allow only one node to be primary (and thus writable) at a time\&. .sp In some scenarios it is preferable to allow two nodes to be primary at once; a mechanism outside of DRBD then must make sure that writes to the shared, replicated device happen in a coordinated way\&. This can be done with a shared\-storage cluster file system like OCFS2 and GFS, or with virtual machine images and a virtual machine manager that can migrate virtual machines between physical machines\&. .sp The \fBallow\-two\-primaries\fR parameter tells DRBD to allow two nodes to be primary at the same time\&. Never enable this option when using a non\-distributed file system; otherwise, data corruption and node crashes will result! .RE .PP \fBalways\-asbp\fR .RS 4 Normally the automatic after\-split\-brain policies are only used if current states of the UUIDs do not indicate the presence of a third node\&. .sp With this option you request that the automatic after\-split\-brain policies are used as long as the data sets of the nodes are somehow related\&. This might cause a full sync, if the UUIDs indicate the presence of a third node\&. (Or double faults led to strange UUID sets\&.) .RE .PP \fBconnect\-int \fR\fB\fItime\fR\fR .RS 4 .\" drbd.conf: connect-int As soon as a connection between two nodes is configured with \fBdrbdsetup connect\fR, DRBD immediately tries to establish the connection\&. If this fails, DRBD waits for \fBconnect\-int\fR seconds and then repeats\&. The default value of \fBconnect\-int\fR is 10 seconds\&. .RE .PP \fBcram\-hmac\-alg \fR\fB\fIhash\-algorithm\fR\fR .RS 4 .\" drbd.conf: cram-hmac-alg Configure the hash\-based message authentication code (HMAC) or secure hash algorithm to use for peer authentication\&. The kernel supports a number of different algorithms, some of which may be loadable as kernel modules\&. See the shash algorithms listed in /proc/crypto\&. By default, \fBcram\-hmac\-alg\fR is unset\&. Peer authentication also requires a \fBshared\-secret\fR to be configured\&. .RE .PP \fBcsums\-alg \fR\fB\fIhash\-algorithm\fR\fR .RS 4 .\" drbd.conf: csums-alg Normally, when two nodes resynchronize, the sync target requests a piece of out\-of\-sync data from the sync source, and the sync source sends the data\&. With many usage patterns, a significant number of those blocks will actually be identical\&. .sp When a \fBcsums\-alg\fR algorithm is specified, when requesting a piece of out\-of\-sync data, the sync target also sends along a hash of the data it currently has\&. The sync source compares this hash with its own version of the data\&. It sends the sync target the new data if the hashes differ, and tells it that the data are the same otherwise\&. This reduces the network bandwidth required, at the cost of higher cpu utilization and possibly increased I/O on the sync target\&. .sp The \fBcsums\-alg\fR can be set to one of the secure hash algorithms supported by the kernel; see the shash algorithms listed in /proc/crypto\&. By default, \fBcsums\-alg\fR is unset\&. .RE .PP \fBcsums\-after\-crash\-only\fR .RS 4 .\" drbd.conf: csums-after-crash-only Enabling this option (and csums\-alg, above) makes it possible to use the checksum based resync only for the first resync after primary crash, but not for later "network hickups"\&. .sp In most cases, block that are marked as need\-to\-be\-resynced are in fact changed, so calculating checksums, and both reading and writing the blocks on the resync target is all effective overhead\&. .sp The advantage of checksum based resync is mostly after primary crash recovery, where the recovery marked larger areas (those covered by the activity log) as need\-to\-be\-resynced, just in case\&. Introduced in 8\&.4\&.5\&. .RE .PP \fBdata\-integrity\-alg \fR \fIalg\fR .RS 4 .\" drbd.conf: data-integrity-alg DRBD normally relies on the data integrity checks built into the TCP/IP protocol, but if a data integrity algorithm is configured, it will additionally use this algorithm to make sure that the data received over the network match what the sender has sent\&. If a data integrity error is detected, DRBD will close the network connection and reconnect, which will trigger a resync\&. .sp The \fBdata\-integrity\-alg\fR can be set to one of the secure hash algorithms supported by the kernel; see the shash algorithms listed in /proc/crypto\&. By default, this mechanism is turned off\&. .sp Because of the CPU overhead involved, we recommend not to use this option in production environments\&. Also see the notes on data integrity below\&. .RE .PP \fBko\-count \fR\fB\fInumber\fR\fR .RS 4 .\" drbd.conf: ko-count If a secondary node fails to complete a write request in \fBko\-count\fR times the \fBtimeout\fR parameter, it is excluded from the cluster\&. The primary node then sets the connection to this secondary node to Standalone\&. To disable this feature, you should explicitly set it to 0; defaults may change between versions\&. .RE .PP \fBmax\-buffers \fR\fB\fInumber\fR\fR .RS 4 .\" drbd.conf: max-buffers Limits the memory usage per DRBD minor device on the receiving side, or for internal buffers during resync or online\-verify\&. Unit is PAGE_SIZE, which is 4 KiB on most systems\&. The minimum possible setting is hard coded to 32 (=128 KiB)\&. These buffers are used to hold data blocks while they are written to/read from disk\&. To avoid possible distributed deadlocks on congestion, this setting is used as a throttle threshold rather than a hard limit\&. Once more than max\-buffers pages are in use, further allocation from this pool is throttled\&. You want to increase max\-buffers if you cannot saturate the IO backend on the receiving side\&. .RE .PP \fBmax\-epoch\-size \fR\fB\fInumber\fR\fR .RS 4 .\" drbd.conf: max-epoch-size Define the maximum number of write requests DRBD may issue before issuing a write barrier\&. The default value is 2048, with a minimum of 1 and a maximum of 20000\&. Setting this parameter to a value below 10 is likely to decrease performance\&. .RE .PP \fBon\-congestion \fR\fB\fIpolicy\fR\fR, .br \fBcongestion\-fill \fR\fB\fIthreshold\fR\fR, .br \fBcongestion\-extents \fR\fB\fIthreshold\fR\fR .RS 4 By default, DRBD blocks when the TCP send queue is full\&. This prevents applications from generating further write requests until more buffer space becomes available again\&. .sp When DRBD is used together with DRBD\-proxy, it can be better to use the \fBpull\-ahead\fR \fBon\-congestion\fR policy, which can switch DRBD into ahead/behind mode before the send queue is full\&. DRBD then records the differences between itself and the peer in its bitmap, but it no longer replicates them to the peer\&. When enough buffer space becomes available again, the node resynchronizes with the peer and switches back to normal replication\&. .sp This has the advantage of not blocking application I/O even when the queues fill up, and the disadvantage that peer nodes can fall behind much further\&. Also, while resynchronizing, peer nodes will become inconsistent\&. .sp The available congestion policies are \fBblock\fR (the default) and \fBpull\-ahead\fR\&. The \fBcongestion\-fill\fR parameter defines how much data is allowed to be "in flight" in this connection\&. The default value is 0, which disables this mechanism of congestion control, with a maximum of 10 GiBytes\&. The \fBcongestion\-extents\fR parameter defines how many bitmap extents may be active before switching into ahead/behind mode, with the same default and limits as the \fBal\-extents\fR parameter\&. The \fBcongestion\-extents\fR parameter is effective only when set to a value smaller than \fBal\-extents\fR\&. .sp Ahead/behind mode is available since DRBD 8\&.3\&.10\&. .RE .PP \fBping\-int \fR\fB\fIinterval\fR\fR .RS 4 .\" drbd.conf: ping-int When the TCP/IP connection to a peer is idle for more than \fBping\-int\fR seconds, DRBD will send a keep\-alive packet to make sure that a failed peer or network connection is detected reasonably soon\&. The default value is 10 seconds, with a minimum of 1 and a maximum of 120 seconds\&. The unit is seconds\&. .RE .PP \fBping\-timeout \fR\fB\fItimeout\fR\fR .RS 4 .\" drbd.conf: ping-timeout Define the timeout for replies to keep\-alive packets\&. If the peer does not reply within \fBping\-timeout\fR, DRBD will close and try to reestablish the connection\&. The default value is 0\&.5 seconds, with a minimum of 0\&.1 seconds and a maximum of 3 seconds\&. The unit is tenths of a second\&. .RE .PP \fBsocket\-check\-timeout \fR\fB\fItimeout\fR\fR .RS 4 .\" drbd.conf: socket-check-timeoutIn setups involving a DRBD\-proxy and connections that experience a lot of buffer\-bloat it might be necessary to set \fBping\-timeout\fR to an unusual high value\&. By default DRBD uses the same value to wait if a newly established TCP\-connection is stable\&. Since the DRBD\-proxy is usually located in the same data center such a long wait time may hinder DRBD\'s connect process\&. .sp In such setups \fBsocket\-check\-timeout\fR should be set to at least to the round trip time between DRBD and DRBD\-proxy\&. I\&.e\&. in most cases to 1\&. .sp The default unit is tenths of a second, the default value is 0 (which causes DRBD to use the value of \fBping\-timeout\fR instead)\&. Introduced in 8\&.4\&.5\&. .RE .PP \fBprotocol \fR\fB\fIname\fR\fR .RS 4 .\" drbd.conf: protocol Use the specified protocol on this connection\&. The supported protocols are: .PP \fBA\fR .RS 4 Writes to the DRBD device complete as soon as they have reached the local disk and the TCP/IP send buffer\&. .RE .PP \fBB\fR .RS 4 Writes to the DRBD device complete as soon as they have reached the local disk, and all peers have acknowledged the receipt of the write requests\&. .RE .PP \fBC\fR .RS 4 Writes to the DRBD device complete as soon as they have reached the local and all remote disks\&. .RE .sp .RE .PP \fBrcvbuf\-size \fR\fB\fIsize\fR\fR .RS 4 .\" drbd.conf: rcvbuf-size Configure the size of the TCP/IP receive buffer\&. A value of 0 (the default) causes the buffer size to adjust dynamically\&. This parameter usually does not need to be set, but it can be set to a value up to 10 MiB\&. The default unit is bytes\&. .RE .PP \fBrr\-conflict\fR \fIpolicy\fR .RS 4 .\" drbd.conf: rr-conflict This option helps to solve the cases when the outcome of the resync decision is incompatible with the current role assignment in the cluster\&. The defined policies are: .PP \fBdisconnect\fR .RS 4 No automatic resynchronization, simply disconnect\&. .RE .PP \fBviolently\fR .RS 4 Resync to the primary node is allowed, violating the assumption that data on a block device are stable for one of the nodes\&. \fIDo not use this option, it is dangerous\&.\fR .RE .PP \fBcall\-pri\-lost\fR .RS 4 Call the \fBpri\-lost\fR handler on one of the machines\&. The handler is expected to reboot the machine, which puts it into secondary role\&. .RE .RE .PP \fBshared\-secret \fR\fB\fIsecret\fR\fR .RS 4 .\" drbd.conf: shared-secret Configure the shared secret used for peer authentication\&. The secret is a string of up to 64 characters\&. Peer authentication also requires the \fBcram\-hmac\-alg\fR parameter to be set\&. .RE .PP \fBsndbuf\-size \fR\fB\fIsize\fR\fR .RS 4 .\" drbd.conf: sndbuf-size Configure the size of the TCP/IP send buffer\&. Since DRBD 8\&.0\&.13 / 8\&.2\&.7, a value of 0 (the default) causes the buffer size to adjust dynamically\&. Values below 32 KiB are harmful to the throughput on this connection\&. Large buffer sizes can be useful especially when protocol A is used over high\-latency networks; the maximum value supported is 10 MiB\&. .RE .PP \fBtcp\-cork\fR .RS 4 .\" drbd.conf: tcp-cork By default, DRBD uses the TCP_CORK socket option to prevent the kernel from sending partial messages; this results in fewer and bigger packets on the network\&. Some network stacks can perform worse with this optimization\&. On these, the \fBtcp\-cork\fR parameter can be used to turn this optimization off\&. .RE .PP \fBtimeout \fR\fB\fItime\fR\fR .RS 4 .\" drbd.conf: timeout Define the timeout for replies over the network: if a peer node does not send an expected reply within the specified \fBtimeout\fR, it is considered dead and the TCP/IP connection is closed\&. The timeout value must be lower than \fBconnect\-int\fR and lower than \fBping\-int\fR\&. The default is 6 seconds; the value is specified in tenths of a second\&. .RE .PP \fBunplug\-watermark \fR\fB\fInumber\fR\fR .RS 4 .\" drbd.conf: unplug-watermark Mainline kernels before version 2\&.6\&.39\-rc1 use an explicit plug / unplug mechanism to control when a block device starts processing queued requests\&. On those kernels, the \fBunplug\-watermark\fR parameter defines how many requests must be queued until a secondary node starts processing them\&. Some storage controllers perform best when \fBunplug\-watermark\fR is set to the same value as \fBmax\-buffers\fR; others are more efficient with smaller values\&. The default value for \fBunplug\-watermark\fR is 128, with a minimum of 16 and a maximum of 131072\&. .sp More recent kernels handle plugging and unplugging implicitly; on those kernels, this parameter has no effect\&. Note that some distributions have backported this feature to older kernel versions\&. .RE .PP \fBuse\-rle\fR .RS 4 .\" drbd.conf: use-rle Each replicated device on a cluster node has a separate bitmap for each of its peer devices\&. The bitmaps are used for tracking the differences between the local and peer device: depending on the cluster state, a disk range can be marked as different from the peer in the device\'s bitmap, in the peer device\'s bitmap, or in both bitmaps\&. When two cluster nodes connect, they exchange each other\'s bitmaps, and they each compute the union of the local and peer bitmap to determine the overall differences\&. .sp Bitmaps of very large devices are also relatively large, but they usually compress very well using run\-length encoding\&. This can save time and bandwidth for the bitmap transfers\&. .sp The \fBuse\-rle\fR parameter determines if run\-length encoding should be used\&. It is on by default since DRBD 8\&.4\&.0\&. .RE .PP \fBverify\-alg \fR\fB\fIhash\-algorithm\fR\fR .RS 4 Online verification (\fBdrbdadm verify\fR) computes and compares checksums of disk blocks (i\&.e\&., hash values) in order to detect if they differ\&. The \fBverify\-alg\fR parameter determines which algorithm to use for these checksums\&. It must be set to one of the secure hash algorithms supported by the kernel before online verify can be used; see the shash algorithms listed in /proc/crypto\&. .sp We recommend to schedule online verifications regularly during low\-load periods, for example once a month\&. Also see the notes on data integrity below\&. .RE .SS "Section on Parameters" .PP \fBaddress \fR\fB\fI[address\-family]\fR\fR\fB \fR\fB\fIaddress\fR\fR\fB:\fR\fB\fIport\fR\fR .RS 4 .\" drbd.conf: address Defines the address family, address, and port of a connection endpoint\&. .sp The address families \fBipv4\fR, \fBipv6\fR, \fBssocks\fR (Dolphin Interconnect Solutions\' "super sockets"), \fBsdp\fR (Infiniband Sockets Direct Protocol), and \fBsci\fR are supported (\fBsci\fR is an alias for \fBssocks\fR)\&. If no address family is specified, \fBipv4\fR is assumed\&. For all address families except \fBipv6\fR, the address is specified in IPV4 address notation (for example, 1\&.2\&.3\&.4)\&. For \fBipv6\fR, the address is enclosed in brackets and uses IPv6 address notation (for example, [fd01:2345:6789:abcd::1])\&. The port is always specified as a decimal number from 1 to 65535\&. .sp On each host, the port numbers must be unique for each address; ports cannot be shared\&. .RE .PP \fBnode\-id \fR\fB\fIvalue\fR\fR .RS 4 .\" drbd.conf: node-id Defines the unique node identifier for a node in the cluster\&. Node identifiers are used to identify individual nodes in the network protocol, and to assign bitmap slots to nodes in the metadata\&. .sp Node identifiers can only be reasssigned in a cluster when the cluster is down\&. It is essential that the node identifiers in the configuration and in the device metadata are changed consistently on all hosts\&. To change the metadata, dump the current state with \fBdrbdmeta dump\-md\fR, adjust the bitmap slot assignment, and update the metadata with \fBdrbdmeta restore\-md\fR\&. .sp The \fBnode\-id\fR parameter exists since DRBD 9\&. Its value ranges from 0 to 16; there is no default\&. .RE .SS "Section options Parameters (Resource Options)" .PP \fBauto\-promote \fR\fB\fIbool\-value\fR\fR .RS 4 .\" drbd.conf: auto-promote A resource must be promoted to primary role before any of its devices can be mounted or opened for writing\&. .sp Before DRBD 9, this could only be done explicitly ("drbdadm primary")\&. Since DRBD 9, the \fBauto\-promote\fR parameter allows to automatically promote a resource to primary role when one of its devices is mounted or opened for writing\&. As soon as all devices are unmounted or closed with no more remaining users, the role of the resource changes back to secondary\&. .sp Automatic promotion only succeeds if the cluster state allows it (that is, if an explicit \fBdrbdadm primary\fR command would succeed)\&. Otherwise, mounting or opening the device fails as it already did before DRBD 9: the \fBmount\fR(2) system call fails with errno set to EROFS (Read\-only file system); the \fBopen\fR(2) system call fails with errno set to EMEDIUMTYPE (wrong medium type)\&. .sp Irrespective of the \fBauto\-promote\fR parameter, if a device is promoted explicitly (\fBdrbdadm primary\fR), it also needs to be demoted explicitly (\fBdrbdadm secondary\fR)\&. .sp The \fBauto\-promote\fR parameter is available since DRBD 9\&.0\&.0, and defaults to \fByes\fR\&. .RE .PP \fBcpu\-mask \fR\fB\fIcpu\-mask\fR\fR .RS 4 .\" drbd.conf: cpu-mask Set the cpu affinity mask for DRBD kernel threads\&. The cpu mask is specified as a hexadecimal number\&. The default value is 0, which lets the scheduler decide which kernel threads run on which CPUs\&. CPU numbers in \fBcpu\-mask\fR which do not exist in the system are ignored\&. .RE .PP \fBon\-no\-data\-accessible \fR\fB\fIpolicy\fR\fR .RS 4 Determine how to deal with I/O requests when the requested data is not available locally or remotely (for example, when all disks have failed)\&. The defined policies are: .PP \fBio\-error\fR .RS 4 System calls fail with errno set to EIO\&. .RE .PP \fBsuspend\-io\fR .RS 4 The resource suspends I/O\&. I/O can be resumed by (re)attaching the lower\-level device, by connecting to a peer which has access to the data, or by forcing DRBD to resume I/O with \fBdrbdadm resume\-io \fR\fB\fIres\fR\fR\&. When no data is available, forcing I/O to resume will result in the same behavior as the \fBio\-error\fR policy\&. .RE .sp This setting is available since DRBD 8\&.3\&.9; the default policy is \fBio\-error\fR\&. .RE .PP \fBpeer\-ack\-window \fR\fB\fIvalue\fR\fR .RS 4 .\" drbd.conf: peer-ack-window On each node and for each device, DRBD maintains a bitmap of the differences between the local and remote data for each peer device\&. For example, in a three\-node setup (nodes A, B, C) each with a single device, every node maintains one bitmap for each of its peers\&. .sp When nodes receive write requests, they know how to update the bitmaps for the writing node, but not how to update the bitmaps between themselves\&. In this example, when a write request propagates from node A to B and C, nodes B and C know that they have the same data as node A, but not whether or not they both have the same data\&. .sp As a remedy, the writing node occasionally sends peer\-ack packets to its peers which tell them which state they are in relative to each other\&. .sp The \fBpeer\-ack\-window\fR parameter specifies how much data a primary node may send before sending a peer\-ack packet\&. A low value causes increased network traffic; a high value causes less network traffic but higher memory consumption on secondary nodes and higher resync times between the secondary nodes after primary node failures\&. (Note: peer\-ack packets may be sent due to other reasons as well, e\&.g\&. membership changes or expiry of the \fBpeer\-ack\-delay\fR timer\&.) .sp The default value for \fBpeer\-ack\-window\fR is 2 MiB, the default unit is sectors\&. This option is available since 9\&.0\&.0\&. .RE .PP \fBpeer\-ack\-delay \fR\fB\fIexpiry\-time\fR\fR .RS 4 .\" drbd.conf: peer-ack-delay If after the last finished write request no new write request gets issued for \fIexpiry\-time\fR, then a peer\-ack packet is sent\&. If a new write request is issued before the timer expires, the timer gets reset to \fIexpiry\-time\fR\&. (Note: peer\-ack packets may be sent due to other reasons as well, e\&.g\&. membership changes or the \fBpeer\-ack\-window\fR option\&.) .sp This parameter may influence resync behavior on remote nodes\&. Peer nodes need to wait until they receive an peer\-ack for releasing a lock on an AL\-extent\&. Resync operations between peers may need to wait for for these locks\&. .sp The default value for \fBpeer\-ack\-delay\fR is 100 milliseconds, the default unit is milliseconds\&. This option is available since 9\&.0\&.0\&. .RE .SS "Section startup Parameters" .PP The parameters in this section define the behavior of DRBD at system startup time, in the DRBD init script\&. They have no effect once the system is up and running\&. .PP \fBdegr\-wfc\-timeout \fR\fB\fItimeout\fR\fR .RS 4 .\" drbd.conf: degr-wfc-timeout Define how long to wait until all peers are connected in case the cluster consisted of a single node only when the system went down\&. This parameter is usually set to a value smaller than \fBwfc\-timeout\fR\&. The assumption here is that peers which were unreachable before a reboot are less likely to be be reachable after the reboot, so waiting is less likely to help\&. .sp The timeout is specified in seconds\&. The default value is 0, which stands for an infinite timeout\&. Also see the \fBwfc\-timeout\fR parameter\&. .RE .PP \fBoutdated\-wfc\-timeout \fR\fB\fItimeout\fR\fR .RS 4 .\" drbd.conf: outdated-wfc-timeout Define how long to wait until all peers are connected if all peers were outdated when the system went down\&. This parameter is usually set to a value smaller than \fBwfc\-timeout\fR\&. The assumption here is that an outdated peer cannot have become primary in the meantime, so we don\'t need to wait for it as long as for a node which was alive before\&. .sp The timeout is specified in seconds\&. The default value is 0, which stands for an infinite timeout\&. Also see the \fBwfc\-timeout\fR parameter\&. .RE .PP \fBstacked\-timeouts\fR .RS 4 On stacked devices, the \fBwfc\-timeout\fR and \fBdegr\-wfc\-timeout\fR parameters in the configuration are usually ignored, and both timeouts are set to twice the \fBconnect\-int\fR timeout\&. The \fBstacked\-timeouts\fR parameter tells DRBD to use the \fBwfc\-timeout\fR and \fBdegr\-wfc\-timeout\fR parameters as defined in the configuration, even on stacked devices\&. Only use this parameter if the peer of the stacked resource is usually not available, or will not become primary\&. Incorrect use of this parameter can lead to unexpected split\-brain scenarios\&. .RE .PP \fBwait\-after\-sb\fR .RS 4 This parameter causes DRBD to continue waiting in the init script even when a split\-brain situation has been detected, and the nodes therefore refuse to connect to each other\&. .RE .PP \fBwfc\-timeout \fR\fB\fItimeout\fR\fR .RS 4 .\" drbd.conf: wfc-timeout Define how long the init script waits until all peers are connected\&. This can be useful in combination with a cluster manager which cannot manage DRBD resources: when the cluster manager starts, the DRBD resources will already be up and running\&. With a more capable cluster manager such as Pacemaker, it makes more sense to let the cluster manager control DRBD resources\&. The timeout is specified in seconds\&. The default value is 0, which stands for an infinite timeout\&. Also see the \fBdegr\-wfc\-timeout\fR parameter\&. .RE .SS "Section volume Parameters" .PP \fBdevice /dev/drbd\fR\fB\fIminor\-number\fR\fR .RS 4 .\" drbd.conf: device Define the device name and minor number of a replicated block device\&. This is the device that applications are supposed to access; in most cases, the device is not used directly, but as a file system\&. This parameter is required and the standard device naming convention is assumed\&. .sp In addition to this device, udev will create \fB/dev/drbd/by\-res/\fR\fB\fIresource\fR\fR\fB/\fR\fB\fIvolume\fR\fR and \fB/dev/drbd/by\-disk/\fR\fB\fIlower\-level\-device\fR\fR symlinks to the device\&. .RE .PP \fBdisk\fR {[disk] | \fBnone\fR} .RS 4 .\" drbd.conf: disk Define the lower\-level block device that DRBD will use for storing the actual data\&. While the replicated drbd device is configured, the lower\-level device must not be used directly\&. Even read\-only access with tools like \fBdumpe2fs\fR(8) and similar is not allowed\&. The keyword \fBnone\fR specifies that no lower\-level block device is configured; this also overrides inheritance of the lower\-level device\&. .RE .PP \fBmeta\-disk internal\fR, .br \fBmeta\-disk \fR\fB\fIdevice\fR\fR, .br \fBmeta\-disk \fR\fB\fIdevice\fR\fR\fB [\fR\fB\fIindex\fR\fR\fB]\fR .RS 4 .\" drbd.conf: meta-disk Define where the metadata of a replicated block device resides: it can be \fBinternal\fR, meaning that the lower\-level device contains both the data and the metadata, or on a separate device\&. .sp When the \fIindex\fR form of this parameter is used, multiple replicated devices can share the same metadata device, each using a separate index\&. Each index occupies 128 MiB of data, which corresponds to a replicated device size of at most 4 TiB with two cluster nodes\&. We recommend not to share metadata devices anymore, and to instead use the lvm volume manager for creating metadata devices as needed\&. .sp When the \fIindex\fR form of this parameter is not used, the size of the lower\-level device determines the size of the metadata\&. The size needed is 36 KiB + (size of lower\-level device) / 32K * (number of nodes \- 1)\&. If the metadata device is bigger than that, the extra space is not used\&. .sp This parameter is required if a \fBdisk\fR other than \fBnone\fR is specified, and ignored if \fBdisk\fR is set to \fBnone\fR\&. A \fBmeta\-disk\fR parameter without a \fBdisk\fR parameter is not allowed\&. .RE .SH "NOTES ON DATA INTEGRITY" .PP DRBD supports two different mechanisms for data integrity checking: first, the \fBdata\-integrity\-alg\fR network parameter allows to add a checksum to the data sent over the network\&. Second, the online verification mechanism (\fBdrbdadm verify\fR and the \fBverify\-alg\fR parameter) allows to check for differences in the on\-disk data\&. .PP Both mechanisms can produce false positives if the data is modified during I/O (i\&.e\&., while it is being sent over the network or written to disk)\&. This does not always indicate a problem: for example, some file systems and applications do modify data under I/O for certain operations\&. Swap space can also undergo changes while under I/O\&. .PP Network data integrity checking tries to identify data modification during I/O by verifying the checksums on the sender side after sending the data\&. If it detects a mismatch, it logs an error\&. The receiver also logs an error when it detects a mismatch\&. Thus, an error logged only on the receiver side indicates an error on the network, and an error logged on both sides indicates data modification under I/O\&. .PP The most recent example of systematic data corruption was identified as a bug in the TCP offloading engine and driver of a certain type of GBit NIC in 2007: the data corruption happened on the DMA transfer from core memory to the card\&. Because the TCP checksum were calculated on the card, the TCP/IP protocol checksums did not reveal this problem\&. .SH "VERSION" .sp This document was revised for version 9\&.0\&.0 of the DRBD distribution\&. .SH "AUTHOR" .sp Written by Philipp Reisner philipp\&.reisner@linbit\&.com and Lars Ellenberg lars\&.ellenberg@linbit\&.com\&. .SH "REPORTING BUGS" .sp Report bugs to drbd\-user@lists\&.linbit\&.com\&. .SH "COPYRIGHT" .sp Copyright 2001\-2012 LINBIT Information Technologies, Philipp Reisner, Lars Ellenberg\&. This is free software; see the source for copying conditions\&. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE\&. .SH "SEE ALSO" .PP \fBdrbd\fR(8), \fBdrbddisk\fR(8), \fBdrbdsetup\fR(8), \fBdrbdadm\fR(8), \m[blue]\fBDRBD User\'s Guide\fR\m[]\&\s-2\u[1]\d\s+2, \m[blue]\fBDRBD Web Site\fR\m[]\&\s-2\u[3]\d\s+2 .SH "NOTES" .IP " 1." 4 DRBD User's Guide .RS 4 \%http://www.drbd.org/users-guide/ .RE .IP " 2." 4 Online Usage Counter .RS 4 \%http://usage.drbd.org .RE .IP " 3." 4 DRBD Web Site .RS 4 \%http://www.drbd.org/ .RE drbd-utils-8.9.6/documentation/v9/xml-usage-to-docbook.xsl0000644000175000017500000000175612466702073023422 0ustar apoikosapoikos drbdsetup drbd-utils-8.9.6/documentation/v9/drbdsetup-options.xml0000644000175000017500000020176112654402323023131 0ustar apoikosapoikos drbd.conf al-extents DRBD automatically maintains a "hot" or "active" disk area likely to be written to again soon based on the recent write activity. The "active" disk area can be written to immediately, while "inactive" disk areas must be "activated" first, which requires a meta-data write. We also refer to this active disk area as the "activity log". The activity log saves meta-data writes, but the whole log must be resynced upon recovery of a failed node. The size of the activity log is a major factor of how long a resync will take and how fast a replicated disk will become consistent after a crash. The activity log consists of a number of 4-Megabyte segments; the al-extents parameter determines how many of those segments can be active at the same time. The default value for al-extents is 1237, with a minimum of 7 and a maximum of 65536. Note that the effective maximum may be smaller, depending on how you created the device meta data, see also drbdmeta8 The effective maximum is 919 * (available on-disk activity-log ring-buffer area/4kB -1), the default 32kB ring-buffer effects a maximum of 6433 (covers more than 25 GiB of data) We recommend to keep this well within the amount your backend storage and replication link are able to resync inside of about 5 minutes. drbd.conf al-updates With this parameter, the activity log can be turned off entirely (see the parameter). This will speed up writes because fewer meta-data writes will be necessary, but the entire device needs to be resynchronized opon recovery of a failed primary node. The default value for is . Dynamically control the resync speed. This mechanism is enabled by setting the parameter to a positive value. The goal is to either fill the buffers along the data path with a defined amount of data if is defined, or to have a defined delay along the path if is defined. The maximum bandwidth is limited by the parameter. The parameter defines how fast drbd adapts to changes in the resync speed. It should be set to five times the network round-trip time or more. Common values for for "normal" data paths range from 4K to 100K. If drbd-proxy is used, it is advised to use instead of . The parameter is used if the parameter is undefined or set to 0. The parameter should be set to five times the network round-trip time or more. The option should be set to either the bandwidth available between the DRBD-hosts and the machines hosting DRBD-proxy, or to the available disk bandwidth. The default values of these parameters are: = 20 (in units of 0.1 seconds), = 0 (in units of sectors), = 1 (in units of 0.1 seconds), and = 102400 (in units of KiB/s). Dynamic resync speed control is available since DRBD 8.3.9. A node which is primary and sync-source has to schedule application I/O requests and resync I/O requests. The parameter limits how much bandwidth is available for resync I/O; the remaining bandwidth is used for application I/O. A value of 0 means that there is no limit on the resync I/O bandwidth. This can slow down application I/O significantly. Use a value of 1 (1 KiB/s) for the lowest possible resync rate. The default value of is 4096, in units of KiB/s. drbd.conf disk-barrier drbd.conf disk-flushes drbd.conf disk-drain DRBD has three methods of handling the ordering of dependent write requests: Use disk barriers to make sure that requests are written to disk in the right order. Barriers ensure that all requests submitted before a barrier make it to the disk before any requests submitted after the barrier. This is implemented using 'tagged command queuing' on SCSI devices and 'native command queuing' on SATA devices. Only some devices and device stacks support this method. The device mapper (LVM) only supports barriers in some configurations. Note that on systems which do not support disk barriers, enabling this option can lead to data loss or corruption. Until DRBD 8.4.1, was turned on if the I/O stack below DRBD did support barriers. Kernels since linux-2.6.36 (or 2.6.32 RHEL6) no longer allow to detect if barriers are supported. Since drbd-8.4.2, this option is off by default and needs to be enabled explicitly. Use disk flushes between dependent write requests, also referred to as 'force unit access' by drive vendors. This forces all data to disk. This option is enabled by default. Wait for the request queue to "drain" (that is, wait for the requests to finish) before submitting a dependent write request. This method requires that requests are stable on disk when they finish. Before DRBD 8.0.9, this was the only method implemented. This option is enabled by default. Do not disable in production environments. From these three methods, drbd will use the first that is enabled and supported by the backing storage device. If all three of these options are turned off, DRBD will submit write requests without bothering about dependencies. Depending on the I/O stack, write requests can be reordered, and they can be submitted in a different order on different cluster nodes. This can result in data loss or corruption. Therefore, turning off all three methods of controlling write ordering is strongly discouraged. A general guideline for configuring write ordering is to use disk barriers or disk flushes when using ordinary disks (or an ordinary disk array) with a volatile write cache. On storage without cache or with a battery backed write cache, disk draining can be a reasonable choice. drbd.conf disk-timeout If the lower-level device on which a DRBD device stores its data does not finish an I/O request within the defined , DRBD treats this as a failure. The lower-level device is detached, and the device's disk state advances to Diskless. If DRBD is connected to one or more peers, the failed request is passed on to one of them. This option is dangerous and may lead to kernel panic! "Aborting" requests, or force-detaching the disk, is intended for completely blocked/hung local backing devices which do no longer complete requests at all, not even do error completions. In this situation, usually a hard-reset and failover is the only way out. By "aborting", basically faking a local error-completion, we allow for a more graceful swichover by cleanly migrating services. Still the affected node has to be rebooted "soon". By completing these requests, we allow the upper layers to re-use the associated data pages. If later the local backing device "recovers", and now DMAs some data from disk into the original request pages, in the best case it will just put random data into unused pages; but typically it will corrupt meanwhile completely unrelated data, causing all sorts of damage. Which means delayed successful completion, especially for READ requests, is a reason to panic(). We assume that a delayed *error* completion is OK, though we still will complain noisily about it. The default value of is 0, which stands for an infinite timeout. Timeouts are specified in units of 0.1 seconds. This option is available since DRBD 8.3.12. drbd.conf fencing is a preventive measure to avoid situations where both nodes are primary and disconnected. This is also known as a split-brain situation. DRBD supports the following fencing policies: No fencing actions are taken. This is the default policy. If a node becomes a disconnected primary, it tries to fence the peer. This is done by calling the handler. The handler is supposed to reach the peer over an alternative communication path and call '' there. If a node becomes a disconnected primary, it freezes all its IO operations and calls its fence-peer handler. The fence-peer handler is supposed to reach the peer over an alternative communication path and call '' there. In case it cannot do that, it should stonith the peer. IO is resumed as soon as the situation is resolved. In case the fence-peer handler fails, I/O can be resumed manually with ''. drbd.conf md-flushes Enable disk flushes and disk barriers on the meta-data device. This option is enabled by default. See the parameter. drbd.conf on-io-error Configure how DRBD reacts to I/O errors on a lower-level device. The following policies are defined: Change the disk status to Inconsistent, mark the failed block as inconsistent in the bitmap, and retry the I/O operation on a remote cluster node. Call the handler (see the section). Detach the lower-level device and continue in diskless mode. drbd.conf read-balancing Distribute read requests among cluster nodes as defined by policy. The supported policies are (the default), , , , , , , , , and . This option is available since DRBD 8.4.1. drbd.conf discard-zeroes-if-aligned There are several aspects to discard/trim/unmap support on linux block devices. Even if discard is supported in general, it may fail silently, or may partially ignore discard requests. Devices also announce whether reading from unmapped blocks returns defined data (usually zeroes), or undefined data (possibly old data, possibly garbage). If on different nodes, DRBD is backed by devices with differing discard characteristics, discards may lead to data divergence (old data or garbage left over on one backend, zeroes due to unmapped areas on the other backend). Online verify would now potentially report tons of spurious differences. While probably harmless for most use cases (fstrim on a file system), DRBD cannot have that. To play safe, we have to disable discard support, if our local backend (on a Primary) does not support "discard_zeroes_data=true". We also have to translate discards to explicit zero-out on the receiving side, unless the receiving side (Secondary) supports "discard_zeroes_data=true", thereby allocating areas what were supposed to be unmapped. There are some devices (notably the LVM/DM thin provisioning) that are capable of discard, but announce discard_zeroes_data=false. In the case of DM-thin, discards aligned to the chunk size will be unmapped, and reading from unmapped sectors will return zeroes. However, unaligned partial head or tail areas of discard requests will be silently ignored. If we now add a helper to explicitly zero-out these unaligned partial areas, while passing on the discard of the aligned full chunks, we effectively achieve discard_zeroes_data=true on such devices. Setting to will allow DRBD to use discards, and to announce discard_zeroes_data=true, even on backends that announce discard_zeroes_data=false. Setting to will cause DRBD to always fall-back to zero-out on the receiving side, and to not even announce discard capabilities on the Primary, if the respective backend announces discard_zeroes_data=false. We used to ignore the discard_zeroes_data setting completely. To not break established and expected behaviour, and suddenly cause fstrim on thin-provisioned LVs to run out-of-space instead of freeing up space, the default value is . This option is available since 8.4.7. drbd.conf rs-discard-granularity When is set to a non zero, positive value then DRBD tries to do a resync operation in requests of this size. In case such a block contains only zero bytes on the sync source node, the sync target node will issue a discard/trim/unmap command for the area. The value is constrained by the discard granularity of the backing block device. In case is not a multiplier of the discard granularity of the backing block device DRBD rounds it up. The feature only gets active if the backing block device reads back zeroes after a discard command. The default value of is 0. This option is available since 8.4.7. drbd.conf resync-after Define that a device should only resynchronize after the specified other device. By default, no order between devices is defined, and all devices will resynchronize in parallel. Depending on the configuration of the lower-level devices, and the available network and disk bandwidth, this can slow down the overall resync process. This option can be used to form a chain or tree of dependencies among devices. drbd.conf resync-rate Define how much bandwidth DRBD may use for resynchronizing. DRBD allows "normal" application I/O even during a resync. If the resync takes up too much bandwidth, application I/O can become very slow. This parameter allows to avoid that. Please note this is option only works when the dynamic resync controller is disabled. Specify the size of the lower-level device explicitly instead of determining it automatically. The device size must be determined once and is remembered for the lifetime of the device. In order to determine it automatically, all the lower-level devices on all nodes must be attached, and all nodes must be connected. If the size is specified explicitly, this is not necessary. The value is assumed to be in units of sectors (512 bytes) by default. drbd.conf dialog-refresh The DRBD init script can be used to configure and start DRBD devices, which can involve waiting for other cluster nodes. While waiting, the init script shows the remaining waiting time. The defines the number of seconds between updates of that countdown. The default value is 1; a value of 0 turns off the countdown. drbd.conf disable-ip-verification Normally, DRBD verifies that the IP addresses in the configuration match the host names. Use the parameter to disable these checks. drbd.conf usage-count A explained on DRBD's Online Usage Counter web page, DRBD includes a mechanism for anonymously counting how many installations are using which versions of DRBD. The results are available on the web page for anyone to see. This parameter defines if a cluster node participates in the usage counter; the supported values are , , and (ask the user, the default). We would like to ask users to participate in the online usage counter as this provides us valuable feedback for steering the development of DRBD. drbd.conf after-sb-0pri Define how to react if a split-brain scenario is detected and none of the two nodes is in primary role. (We detect split-brain scenarios when two nodes connect; split-brain decisions are always between two nodes.) The defined policies are: No automatic resynchronization; simply disconnect. Resynchronize from the node which became primary first () or last (). If both nodes became primary independently, the policy is used. If only one of the nodes wrote data since the split brain situation was detected, resynchronize from this node to the other. If both nodes wrote data, disconnect. Resynchronize from the node with more modified blocks. Always resynchronize to the named node. drbd.conf after-sb-1pri Define how to react if a split-brain scenario is detected, with one node in primary role and one node in secondary role. (We detect split-brain scenarios when two nodes connect, so split-brain decisions are always among two nodes.) The defined policies are: No automatic resynchronization, simply disconnect. Discard the data on the secondary node if the algorithm would also discard the data on the secondary node. Otherwise, disconnect. Always take the decision of the algorithm, even if it causes an erratic change of the primary's view of the data. This is only useful if a single-node file system (i.e., not OCFS2 or GFS) with the flag is used. This option can cause the primary node to crash, and should not be used. Discard the data on the secondary node. Always take the decision of the algorithm. If the decision is to discard the data on the primary node, call the handler on the primary node. drbd.conf after-sb-2pri Define how to react if a split-brain scenario is detected and both nodes are in primary role. (We detect split-brain scenarios when two nodes connect, so split-brain decisions are always among two nodes.) The defined policies are: No automatic resynchronization, simply disconnect. See the policy for . Call the helper program on one of the machines unless that machine can demote to secondary. The helper program is expected to reboot the machine, which brings the node into a secondary role. Which machine runs the helper program is determined by the strategy. drbd.conf allow-two-primaries The most common way to configure DRBD devices is to allow only one node to be primary (and thus writable) at a time. In some scenarios it is preferable to allow two nodes to be primary at once; a mechanism outside of DRBD then must make sure that writes to the shared, replicated device happen in a coordinated way. This can be done with a shared-storage cluster file system like OCFS2 and GFS, or with virtual machine images and a virtual machine manager that can migrate virtual machines between physical machines. The parameter tells DRBD to allow two nodes to be primary at the same time. Never enable this option when using a non-distributed file system; otherwise, data corruption and node crashes will result! Normally the automatic after-split-brain policies are only used if current states of the UUIDs do not indicate the presence of a third node. With this option you request that the automatic after-split-brain policies are used as long as the data sets of the nodes are somehow related. This might cause a full sync, if the UUIDs indicate the presence of a third node. (Or double faults led to strange UUID sets.) drbd.conf connect-int As soon as a connection between two nodes is configured with drbdsetup connect, DRBD immediately tries to establish the connection. If this fails, DRBD waits for seconds and then repeats. The default value of is 10 seconds. drbd.conf cram-hmac-alg Configure the hash-based message authentication code (HMAC) or secure hash algorithm to use for peer authentication. The kernel supports a number of different algorithms, some of which may be loadable as kernel modules. See the shash algorithms listed in /proc/crypto. By default, is unset. Peer authentication also requires a to be configured. drbd.conf csums-alg Normally, when two nodes resynchronize, the sync target requests a piece of out-of-sync data from the sync source, and the sync source sends the data. With many usage patterns, a significant number of those blocks will actually be identical. When a algorithm is specified, when requesting a piece of out-of-sync data, the sync target also sends along a hash of the data it currently has. The sync source compares this hash with its own version of the data. It sends the sync target the new data if the hashes differ, and tells it that the data are the same otherwise. This reduces the network bandwidth required, at the cost of higher cpu utilization and possibly increased I/O on the sync target. The can be set to one of the secure hash algorithms supported by the kernel; see the shash algorithms listed in /proc/crypto. By default, is unset. drbd.conf csums-after-crash-only Enabling this option (and csums-alg, above) makes it possible to use the checksum based resync only for the first resync after primary crash, but not for later "network hickups". In most cases, block that are marked as need-to-be-resynced are in fact changed, so calculating checksums, and both reading and writing the blocks on the resync target is all effective overhead. The advantage of checksum based resync is mostly after primary crash recovery, where the recovery marked larger areas (those covered by the activity log) as need-to-be-resynced, just in case. Introduced in 8.4.5. alg drbd.conf data-integrity-alg DRBD normally relies on the data integrity checks built into the TCP/IP protocol, but if a data integrity algorithm is configured, it will additionally use this algorithm to make sure that the data received over the network match what the sender has sent. If a data integrity error is detected, DRBD will close the network connection and reconnect, which will trigger a resync. The can be set to one of the secure hash algorithms supported by the kernel; see the shash algorithms listed in /proc/crypto. By default, this mechanism is turned off. Because of the CPU overhead involved, we recommend not to use this option in production environments. Also see the notes on data integrity below. drbd.conf ko-count If a secondary node fails to complete a write request in times the parameter, it is excluded from the cluster. The primary node then sets the connection to this secondary node to Standalone. To disable this feature, you should explicitly set it to 0; defaults may change between versions. drbd.conf max-buffers Limits the memory usage per DRBD minor device on the receiving side, or for internal buffers during resync or online-verify. Unit is PAGE_SIZE, which is 4 KiB on most systems. The minimum possible setting is hard coded to 32 (=128 KiB). These buffers are used to hold data blocks while they are written to/read from disk. To avoid possible distributed deadlocks on congestion, this setting is used as a throttle threshold rather than a hard limit. Once more than max-buffers pages are in use, further allocation from this pool is throttled. You want to increase max-buffers if you cannot saturate the IO backend on the receiving side. drbd.conf max-epoch-size Define the maximum number of write requests DRBD may issue before issuing a write barrier. The default value is 2048, with a minimum of 1 and a maximum of 20000. Setting this parameter to a value below 10 is likely to decrease performance. By default, DRBD blocks when the TCP send queue is full. This prevents applications from generating further write requests until more buffer space becomes available again. When DRBD is used together with DRBD-proxy, it can be better to use the policy, which can switch DRBD into ahead/behind mode before the send queue is full. DRBD then records the differences between itself and the peer in its bitmap, but it no longer replicates them to the peer. When enough buffer space becomes available again, the node resynchronizes with the peer and switches back to normal replication. This has the advantage of not blocking application I/O even when the queues fill up, and the disadvantage that peer nodes can fall behind much further. Also, while resynchronizing, peer nodes will become inconsistent. The available congestion policies are (the default) and . The parameter defines how much data is allowed to be "in flight" in this connection. The default value is 0, which disables this mechanism of congestion control, with a maximum of 10 GiBytes. The parameter defines how many bitmap extents may be active before switching into ahead/behind mode, with the same default and limits as the parameter. The parameter is effective only when set to a value smaller than . Ahead/behind mode is available since DRBD 8.3.10. drbd.conf ping-int When the TCP/IP connection to a peer is idle for more than seconds, DRBD will send a keep-alive packet to make sure that a failed peer or network connection is detected reasonably soon. The default value is 10 seconds, with a minimum of 1 and a maximum of 120 seconds. The unit is seconds. drbd.conf ping-timeout Define the timeout for replies to keep-alive packets. If the peer does not reply within , DRBD will close and try to reestablish the connection. The default value is 0.5 seconds, with a minimum of 0.1 seconds and a maximum of 3 seconds. The unit is tenths of a second. drbd.conf socket-check-timeout In setups involving a DRBD-proxy and connections that experience a lot of buffer-bloat it might be necessary to set to an unusual high value. By default DRBD uses the same value to wait if a newly established TCP-connection is stable. Since the DRBD-proxy is usually located in the same data center such a long wait time may hinder DRBD's connect process. In such setups should be set to at least to the round trip time between DRBD and DRBD-proxy. I.e. in most cases to 1. The default unit is tenths of a second, the default value is 0 (which causes DRBD to use the value of instead). Introduced in 8.4.5. drbd.conf protocol Use the specified protocol on this connection. The supported protocols are: Writes to the DRBD device complete as soon as they have reached the local disk and the TCP/IP send buffer. Writes to the DRBD device complete as soon as they have reached the local disk, and all peers have acknowledged the receipt of the write requests. Writes to the DRBD device complete as soon as they have reached the local and all remote disks. drbd.conf rcvbuf-size Configure the size of the TCP/IP receive buffer. A value of 0 (the default) causes the buffer size to adjust dynamically. This parameter usually does not need to be set, but it can be set to a value up to 10 MiB. The default unit is bytes. policy drbd.conf rr-conflict This option helps to solve the cases when the outcome of the resync decision is incompatible with the current role assignment in the cluster. The defined policies are: No automatic resynchronization, simply disconnect. Resync to the primary node is allowed, violating the assumption that data on a block device are stable for one of the nodes. Do not use this option, it is dangerous. Call the handler on one of the machines. The handler is expected to reboot the machine, which puts it into secondary role. drbd.conf shared-secret Configure the shared secret used for peer authentication. The secret is a string of up to 64 characters. Peer authentication also requires the parameter to be set. drbd.conf sndbuf-size Configure the size of the TCP/IP send buffer. Since DRBD 8.0.13 / 8.2.7, a value of 0 (the default) causes the buffer size to adjust dynamically. Values below 32 KiB are harmful to the throughput on this connection. Large buffer sizes can be useful especially when protocol A is used over high-latency networks; the maximum value supported is 10 MiB. drbd.conf tcp-cork By default, DRBD uses the TCP_CORK socket option to prevent the kernel from sending partial messages; this results in fewer and bigger packets on the network. Some network stacks can perform worse with this optimization. On these, the parameter can be used to turn this optimization off. drbd.conf timeout Define the timeout for replies over the network: if a peer node does not send an expected reply within the specified , it is considered dead and the TCP/IP connection is closed. The timeout value must be lower than and lower than . The default is 6 seconds; the value is specified in tenths of a second. drbd.conf unplug-watermark Mainline kernels before version 2.6.39-rc1 use an explicit plug / unplug mechanism to control when a block device starts processing queued requests. On those kernels, the parameter defines how many requests must be queued until a secondary node starts processing them. Some storage controllers perform best when is set to the same value as ; others are more efficient with smaller values. The default value for is 128, with a minimum of 16 and a maximum of 131072. More recent kernels handle plugging and unplugging implicitly; on those kernels, this parameter has no effect. Note that some distributions have backported this feature to older kernel versions. drbd.conf use-rle Each replicated device on a cluster node has a separate bitmap for each of its peer devices. The bitmaps are used for tracking the differences between the local and peer device: depending on the cluster state, a disk range can be marked as different from the peer in the device's bitmap, in the peer device's bitmap, or in both bitmaps. When two cluster nodes connect, they exchange each other's bitmaps, and they each compute the union of the local and peer bitmap to determine the overall differences. Bitmaps of very large devices are also relatively large, but they usually compress very well using run-length encoding. This can save time and bandwidth for the bitmap transfers. The parameter determines if run-length encoding should be used. It is on by default since DRBD 8.4.0. Online verification (drbdadm verify) computes and compares checksums of disk blocks (i.e., hash values) in order to detect if they differ. The parameter determines which algorithm to use for these checksums. It must be set to one of the secure hash algorithms supported by the kernel before online verify can be used; see the shash algorithms listed in /proc/crypto. We recommend to schedule online verifications regularly during low-load periods, for example once a month. Also see the notes on data integrity below. Discard the local data and resynchronize with the peer that has the most up-to-data data. Use this option to manually recover from a split-brain situation. Only determine if a connection to the peer can be established and if a resync is necessary (and in which direction) without actually establishing the connection or starting the resync. Check the system log to see what DRBD would do without the option. drbd.conf auto-promote A resource must be promoted to primary role before any of its devices can be mounted or opened for writing. Before DRBD 9, this could only be done explicitly ("drbdadm primary"). Since DRBD 9, the parameter allows to automatically promote a resource to primary role when one of its devices is mounted or opened for writing. As soon as all devices are unmounted or closed with no more remaining users, the role of the resource changes back to secondary. Automatic promotion only succeeds if the cluster state allows it (that is, if an explicit drbdadm primary command would succeed). Otherwise, mounting or opening the device fails as it already did before DRBD 9: the mount2 system call fails with errno set to EROFS (Read-only file system); the open2 system call fails with errno set to EMEDIUMTYPE (wrong medium type). Irrespective of the parameter, if a device is promoted explicitly (drbdadm primary), it also needs to be demoted explicitly (drbdadm secondary). The parameter is available since DRBD 9.0.0, and defaults to yes. drbd.conf cpu-mask Set the cpu affinity mask for DRBD kernel threads. The cpu mask is specified as a hexadecimal number. The default value is 0, which lets the scheduler decide which kernel threads run on which CPUs. CPU numbers in which do not exist in the system are ignored. Determine how to deal with I/O requests when the requested data is not available locally or remotely (for example, when all disks have failed). The defined policies are: System calls fail with errno set to EIO. The resource suspends I/O. I/O can be resumed by (re)attaching the lower-level device, by connecting to a peer which has access to the data, or by forcing DRBD to resume I/O with drbdadm resume-io res. When no data is available, forcing I/O to resume will result in the same behavior as the policy. This setting is available since DRBD 8.3.9; the default policy is . drbd.conf peer-ack-window On each node and for each device, DRBD maintains a bitmap of the differences between the local and remote data for each peer device. For example, in a three-node setup (nodes A, B, C) each with a single device, every node maintains one bitmap for each of its peers. When nodes receive write requests, they know how to update the bitmaps for the writing node, but not how to update the bitmaps between themselves. In this example, when a write request propagates from node A to B and C, nodes B and C know that they have the same data as node A, but not whether or not they both have the same data. As a remedy, the writing node occasionally sends peer-ack packets to its peers which tell them which state they are in relative to each other. The parameter specifies how much data a primary node may send before sending a peer-ack packet. A low value causes increased network traffic; a high value causes less network traffic but higher memory consumption on secondary nodes and higher resync times between the secondary nodes after primary node failures. (Note: peer-ack packets may be sent due to other reasons as well, e.g. membership changes or expiry of the timer.) The default value for is 2 MiB, the default unit is sectors. This option is available since 9.0.0. drbd.conf peer-ack-delay If after the last finished write request no new write request gets issued for expiry-time, then a peer-ack packet is sent. If a new write request is issued before the timer expires, the timer gets reset to expiry-time. (Note: peer-ack packets may be sent due to other reasons as well, e.g. membership changes or the option.) This parameter may influence resync behavior on remote nodes. Peer nodes need to wait until they receive an peer-ack for releasing a lock on an AL-extent. Resync operations between peers may need to wait for for these locks. The default value for is 100 milliseconds, the default unit is milliseconds. This option is available since 9.0.0. drbd.conf degr-wfc-timeout Define how long to wait until all peers are connected in case the cluster consisted of a single node only when the system went down. This parameter is usually set to a value smaller than . The assumption here is that peers which were unreachable before a reboot are less likely to be be reachable after the reboot, so waiting is less likely to help. The timeout is specified in seconds. The default value is 0, which stands for an infinite timeout. Also see the parameter. drbd.conf outdated-wfc-timeout Define how long to wait until all peers are connected if all peers were outdated when the system went down. This parameter is usually set to a value smaller than . The assumption here is that an outdated peer cannot have become primary in the meantime, so we don't need to wait for it as long as for a node which was alive before. The timeout is specified in seconds. The default value is 0, which stands for an infinite timeout. Also see the parameter. This parameter causes DRBD to continue waiting in the init script even when a split-brain situation has been detected, and the nodes therefore refuse to connect to each other. drbd.conf wfc-timeout Define how long the init script waits until all peers are connected. This can be useful in combination with a cluster manager which cannot manage DRBD resources: when the cluster manager starts, the DRBD resources will already be up and running. With a more capable cluster manager such as Pacemaker, it makes more sense to let the cluster manager control DRBD resources. The timeout is specified in seconds. The default value is 0, which stands for an infinite timeout. Also see the parameter. drbd-utils-8.9.6/documentation/v9/drbd-overview.xml0000644000175000017500000000537312466702073022232 0ustar apoikosapoikos drbd-overview Overview of all configured DRBD resources DRBD 9.0.0 24 June 2014 drbd-overview 8 System Administration drbd-overview Description drbd-overview offers an overview of the state of all configured DRBD resources. It provides information about the connection status of each DRBD resource. It will also use auxiliary information provided by df1, lvm8, xm1 and virsh1 for DRBD resources used as mounted filesystems, LVM physical volumes, Xen domain backing disks and libvirt instance disks respectively. Author Written by Philipp Reisner philipp.reisner@linbit.com and Lars Ellenberg lars.ellenberg@linbit.com. Initial man-page contributed by Apollon Oikonomopoulos apoikos@gmail.com. Reporting Bugs Report bugs to drbd-user@lists.linbit.com. Copyright Copyright 2008-2014 LINBIT Information Technologies, Philipp Reisner, Lars Ellenberg. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See Also drbd.conf5, drbdsetup8, drbdadm8, DRBD Homepage drbd-utils-8.9.6/configure0000755000175000017500000043440112654447466015442 0ustar apoikosapoikos#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69 for DRBD 8.9.6. # # Report bugs to . # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org and $0: drbd-dev@lists.linbit.com about your system, including $0: any error possibly output before this message. Then $0: install a modern shell, or manually run the script $0: under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='DRBD' PACKAGE_TARNAME='drbd' PACKAGE_VERSION='8.9.6' PACKAGE_STRING='DRBD 8.9.6' PACKAGE_BUGREPORT='drbd-dev@lists.linbit.com' PACKAGE_URL='' ac_subst_vars='LTLIBOBJS LIBOBJS DRBD_CONFIG_DIR DRBD_LOCK_DIR DRBD_RUN_DIR DRBD_LIB_DIR RPM_REQ_CHKCONFIG_PREUN RPM_REQ_CHKCONFIG_POST RPM_REQ_XEN RPM_REQ_BASH_COMPLETION RPM_REQ_HEARTBEAT RPM_REQ_PACEMAKER RPM_SUBPACKAGE_NOARCH RPM_BUILDREQ_DEFAULT RPM_DIST_TAG UDEV_RULE_SUFFIX BASH_COMPLETION_SUFFIX INITDIR DISTRO UDEVINFO UDEVADM DPKG_BUILDPACKAGE GIT TAR XSLTPROC RPMBUILD FLEX GREP SED LN_S OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC initscripttype udevrulesdir udevdir tmpfilesdir systemdunitdir PKG_CONFIG WITH_MANUAL WITH_BASHCOMPLETION WITH_RGMANAGER WITH_HEARTBEAT WITH_PACEMAKER WITH_XEN WITH_UDEV WITH_84_SUPPORT WITH_83_SUPPORT target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir runstatedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking with_83support with_84support with_udev with_xen with_pacemaker with_heartbeat with_rgmanager with_bashcompletion with_distro with_initdir with_noarchsubpkg enable_spec with_manual with_systemdunitdir with_tmpfilesdir with_initscripttype ' ac_precious_vars='build_alias host_alias target_alias PKG_CONFIG CC CFLAGS LDFLAGS LIBS CPPFLAGS' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -runstatedir | --runstatedir | --runstatedi | --runstated \ | --runstate | --runstat | --runsta | --runst | --runs \ | --run | --ru | --r) ac_prev=runstatedir ;; -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ | --run=* | --ru=* | --r=*) runstatedir=$ac_optarg ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures DRBD 8.9.6 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/drbd] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of DRBD 8.9.6:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-spec Rather than creating Makefiles, create an RPM spec file only Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --without-83support Do not include support for drbd driver/module <= 8.3 --without-84support Do not include support for drbd driver/module 8.4 --with-udev Enable udev integration --with-xen Enable Xen integration --with-pacemaker Enable Pacemaker integration --with-heartbeat Enable Heartbeat v1 haresources integration scripts --with-rgmanager Enable Red Hat Cluster Suite integration --with-bashcompletion Enable programmable bash completion --with-distro Configure for a specific distribution (supported values: generic, redhat, suse, debian, gentoo, slackware; default is to autodetect) --with-initdir Override directory for init scripts (default is distribution-specific) --with-noarchsubpkg Build subpackages that support it for the "noarch" architecture (makes sense only with --enable-spec, supported by RPM from 4.6.0 forward) --without-manual Do not include manual pages --with-systemdunitdir=DIR Directory for systemd service files [Auto] --with-tmpfilesdir=DIR install configuration files for management of volatile files and directories in DIR [[PREFIX/lib/tmpfiles.d]] --with-initscripttype=INIT_SCRIPT_TYPE Type of init script to install (sysv|systemd|both). [auto] Some influential environment variables: PKG_CONFIG path to pkg-config utility CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to . _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF DRBD configure 8.9.6 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by DRBD $as_me 8.9.6, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test "$prefix" = "NONE"; then prefix=$ac_default_prefix fi exec_prefix=$prefix prefix="`eval echo ${prefix}`" exec_prefix="`eval echo ${exec_prefix}`" bindir="`eval echo ${bindir}`" sbindir="`eval echo ${sbindir}`" libexecdir="`eval echo ${libexecdir}`" datarootdir="`eval echo ${datarootdir}`" datadir="`eval echo ${datadir}`" sysconfdir="`eval echo ${sysconfdir}`" sharedstatedir="`eval echo ${sharedstatedir}`" localstatedir="`eval echo ${localstatedir}`" libdir="`eval echo ${libdir}`" includedir="`eval echo ${includedir}`" oldincludedir="`eval echo ${oldincludedir}`" infodir="`eval echo ${infodir}`" mandir="`eval echo ${mandir}`" docdir="`eval echo ${docdir}`" WITH_83_SUPPORT=yes WITH_84_SUPPORT=yes WITH_UDEV=yes WITH_XEN=yes WITH_PACEMAKER=yes WITH_HEARTBEAT=yes WITH_RGMANAGER=no WITH_BASHCOMPLETION=yes WITH_NOARCH_SUBPACKAGES=no WITH_MANUAL=yes # Check whether --with-83support was given. if test "${with_83support+set}" = set; then : withval=$with_83support; WITH_83_SUPPORT=$withval fi # Check whether --with-84support was given. if test "${with_84support+set}" = set; then : withval=$with_84support; WITH_84_SUPPORT=$withval fi # Check whether --with-udev was given. if test "${with_udev+set}" = set; then : withval=$with_udev; WITH_UDEV=$withval fi # Check whether --with-xen was given. if test "${with_xen+set}" = set; then : withval=$with_xen; WITH_XEN=$withval fi # Check whether --with-pacemaker was given. if test "${with_pacemaker+set}" = set; then : withval=$with_pacemaker; WITH_PACEMAKER=$withval fi # Check whether --with-heartbeat was given. if test "${with_heartbeat+set}" = set; then : withval=$with_heartbeat; WITH_HEARTBEAT=$withval fi # Check whether --with-rgmanager was given. if test "${with_rgmanager+set}" = set; then : withval=$with_rgmanager; WITH_RGMANAGER=$withval fi # Check whether --with-bashcompletion was given. if test "${with_bashcompletion+set}" = set; then : withval=$with_bashcompletion; WITH_BASHCOMPLETION=$withval fi # Check whether --with-distro was given. if test "${with_distro+set}" = set; then : withval=$with_distro; DISTRO=$withval fi # Check whether --with-initdir was given. if test "${with_initdir+set}" = set; then : withval=$with_initdir; INITDIR=$withval fi # Check whether --with-noarchsubpkg was given. if test "${with_noarchsubpkg+set}" = set; then : withval=$with_noarchsubpkg; WITH_NOARCH_SUBPACKAGES=$withval fi # Check whether --enable-spec was given. if test "${enable_spec+set}" = set; then : enableval=$enable_spec; SPECMODE=$enableval else SPECMODE="" fi # Check whether --with-manual was given. if test "${with_manual+set}" = set; then : withval=$with_manual; WITH_MANUAL=$withval fi if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_PKG_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi PKG_CONFIG=$ac_cv_path_PKG_CONFIG if test -n "$PKG_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 $as_echo "$PKG_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_path_PKG_CONFIG"; then ac_pt_PKG_CONFIG=$PKG_CONFIG # Extract the first word of "pkg-config", so it can be a program name with args. set dummy pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $ac_pt_PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG if test -n "$ac_pt_PKG_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 $as_echo "$ac_pt_PKG_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_pt_PKG_CONFIG" = x; then PKG_CONFIG="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac PKG_CONFIG=$ac_pt_PKG_CONFIG fi else PKG_CONFIG="$ac_cv_path_PKG_CONFIG" fi fi if test -n "$PKG_CONFIG"; then _pkg_min_version=0.9.0 { $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5 $as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; } if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } PKG_CONFIG="" fi fi # Check whether --with-systemdunitdir was given. if test "${with_systemdunitdir+set}" = set; then : withval=$with_systemdunitdir; WITH_SYSTEMD_UNIT_DIR=$withval fi if test x"$with_systemdunitdir" = x || \ test x"$with_systemdunitdir" = xyes ; then if test x"$PKG_CONFIG" != x; then systemdunitdir=$($PKG_CONFIG --variable=systemdsystemunitdir systemd) fi if test x"$systemdunitdir" = x; then { $as_echo "$as_me:${as_lineno-$LINENO}: Could not detect systemd unit directory" >&5 $as_echo "$as_me: Could not detect systemd unit directory" >&6;} fi else systemdunitdir=$with_systemdunitdir fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: Using systemd unit directory: $systemdunitdir" >&5 $as_echo "Using systemd unit directory: $systemdunitdir" >&6; } # Check whether --with-tmpfilesdir was given. if test "${with_tmpfilesdir+set}" = set; then : withval=$with_tmpfilesdir; tmpfilesdir=$withval else tmpfilesdir='${prefix}/lib/tmpfiles.d' fi # set default early default_udevdir=/lib/udev if test x"$with_udev" = x || \ test x"$with_udev" = xyes ; then if test x"$PKG_CONFIG" != x; then udevdir=$($PKG_CONFIG --variable=udevdir udev) fi if test x"$udevdir" = x; then { $as_echo "$as_me:${as_lineno-$LINENO}: Could not detect udev rules directory, using default" >&5 $as_echo "$as_me: Could not detect udev rules directory, using default" >&6;} udevdir=$default_udevdir fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: Using udev rules directory: $udevdir" >&5 $as_echo "Using udev rules directory: $udevdir" >&6; } else udevdir=$default_udevdir fi udevrulesdir=$udevdir/rules.d # Check whether --with-initscripttype was given. if test "${with_initscripttype+set}" = set; then : withval=$with_initscripttype; fi case "$with_initscripttype" in "") if grep -ql systemd /sbin/init ; then initscripttype=systemd else initscripttype=sysv fi ;; sysv|systemd|both) initscripttype=$with_initscripttype ;; *) as_fn_error $? "Illegal value -$with_initscripttype- for option --with-initscripttype" "$LINENO" 5 ;; esac ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 $as_echo_n "checking whether ln -s works... " >&6; } LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 $as_echo "no, using $LN_S" >&6; } fi # Extract the first word of "sed", so it can be a program name with args. set dummy sed; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_SED+:} false; then : $as_echo_n "(cached) " >&6 else case $SED in [\\/]* | ?:[\\/]*) ac_cv_path_SED="$SED" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_SED="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi SED=$ac_cv_path_SED if test -n "$SED"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $SED" >&5 $as_echo "$SED" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "grep", so it can be a program name with args. set dummy grep; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else case $GREP in [\\/]* | ?:[\\/]*) ac_cv_path_GREP="$GREP" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_GREP="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi GREP=$ac_cv_path_GREP if test -n "$GREP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GREP" >&5 $as_echo "$GREP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "flex", so it can be a program name with args. set dummy flex; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_FLEX+:} false; then : $as_echo_n "(cached) " >&6 else case $FLEX in [\\/]* | ?:[\\/]*) ac_cv_path_FLEX="$FLEX" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_FLEX="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi FLEX=$ac_cv_path_FLEX if test -n "$FLEX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $FLEX" >&5 $as_echo "$FLEX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "rpmbuild", so it can be a program name with args. set dummy rpmbuild; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_RPMBUILD+:} false; then : $as_echo_n "(cached) " >&6 else case $RPMBUILD in [\\/]* | ?:[\\/]*) ac_cv_path_RPMBUILD="$RPMBUILD" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_RPMBUILD="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi RPMBUILD=$ac_cv_path_RPMBUILD if test -n "$RPMBUILD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RPMBUILD" >&5 $as_echo "$RPMBUILD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "xsltproc", so it can be a program name with args. set dummy xsltproc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_XSLTPROC+:} false; then : $as_echo_n "(cached) " >&6 else case $XSLTPROC in [\\/]* | ?:[\\/]*) ac_cv_path_XSLTPROC="$XSLTPROC" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_XSLTPROC="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi XSLTPROC=$ac_cv_path_XSLTPROC if test -n "$XSLTPROC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $XSLTPROC" >&5 $as_echo "$XSLTPROC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "tar", so it can be a program name with args. set dummy tar; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_TAR+:} false; then : $as_echo_n "(cached) " >&6 else case $TAR in [\\/]* | ?:[\\/]*) ac_cv_path_TAR="$TAR" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_TAR="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi TAR=$ac_cv_path_TAR if test -n "$TAR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $TAR" >&5 $as_echo "$TAR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "git", so it can be a program name with args. set dummy git; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_GIT+:} false; then : $as_echo_n "(cached) " >&6 else case $GIT in [\\/]* | ?:[\\/]*) ac_cv_path_GIT="$GIT" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_GIT="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi GIT=$ac_cv_path_GIT if test -n "$GIT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GIT" >&5 $as_echo "$GIT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "dpkg-buildpackage", so it can be a program name with args. set dummy dpkg-buildpackage; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_DPKG_BUILDPACKAGE+:} false; then : $as_echo_n "(cached) " >&6 else case $DPKG_BUILDPACKAGE in [\\/]* | ?:[\\/]*) ac_cv_path_DPKG_BUILDPACKAGE="$DPKG_BUILDPACKAGE" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_DPKG_BUILDPACKAGE="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi DPKG_BUILDPACKAGE=$ac_cv_path_DPKG_BUILDPACKAGE if test -n "$DPKG_BUILDPACKAGE"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DPKG_BUILDPACKAGE" >&5 $as_echo "$DPKG_BUILDPACKAGE" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "udevadm", so it can be a program name with args. set dummy udevadm; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_UDEVADM+:} false; then : $as_echo_n "(cached) " >&6 else case $UDEVADM in [\\/]* | ?:[\\/]*) ac_cv_path_UDEVADM="$UDEVADM" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in /sbin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_UDEVADM="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_UDEVADM" && ac_cv_path_UDEVADM="false" ;; esac fi UDEVADM=$ac_cv_path_UDEVADM if test -n "$UDEVADM"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $UDEVADM" >&5 $as_echo "$UDEVADM" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "udevinfo", so it can be a program name with args. set dummy udevinfo; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_UDEVINFO+:} false; then : $as_echo_n "(cached) " >&6 else case $UDEVINFO in [\\/]* | ?:[\\/]*) ac_cv_path_UDEVINFO="$UDEVINFO" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in /sbin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_UDEVINFO="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_UDEVINFO" && ac_cv_path_UDEVINFO="false" ;; esac fi UDEVINFO=$ac_cv_path_UDEVINFO if test -n "$UDEVINFO"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $UDEVINFO" >&5 $as_echo "$UDEVINFO" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test -z "$CC"; then as_fn_error $? "Cannot build utils without a C compiler." "$LINENO" 5 fi if test -z $FLEX; then as_fn_error $? "Cannot build utils without flex." "$LINENO" 5 fi if test -z $RPMBUILD; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: No rpmbuild found, building RPM packages is disabled." >&5 $as_echo "$as_me: WARNING: No rpmbuild found, building RPM packages is disabled." >&2;} fi if test -z $DPKG_BUILDPACKAGE; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: No dpkg-buildpackage found, building Debian packages is disabled." >&5 $as_echo "$as_me: WARNING: No dpkg-buildpackage found, building Debian packages is disabled." >&2;} fi if test -z $XSLTPROC; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Cannot build man pages without xsltproc. You may safely ignore this warning when building from a tarball." >&5 $as_echo "$as_me: WARNING: Cannot build man pages without xsltproc. You may safely ignore this warning when building from a tarball." >&2;} XSLTPROC=xsltproc fi if test -z $GIT; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Cannot update buildtag without git. You may safely ignore this warning when building from a tarball." >&5 $as_echo "$as_me: WARNING: Cannot update buildtag without git. You may safely ignore this warning when building from a tarball." >&2;} fi if test $UDEVADM = false && test $UDEVINFO = false; then if test "$WITH_UDEV" = "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: udev support enabled, but neither udevadm nor udevinfo found on this system." >&5 $as_echo "$as_me: WARNING: udev support enabled, but neither udevadm nor udevinfo found on this system." >&2;} fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include static unsigned int dummy = CTRL_CMD_DELMCAST_GRP; _ACEOF if ac_fn_c_try_compile "$LINENO"; then : $as_echo "#define HAVE_CTRL_CMD_DELMCAST_GRP 1" >>confdefs.h fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext BASH_COMPLETION_SUFFIX="" UDEV_RULE_SUFFIX="" RPM_DIST_TAG="" RPM_BUILDREQ_DEFAULT="gcc flex glibc-devel make" RPM_SUBPACKAGE_NOARCH="" RPM_REQ_PACEMAKER="" RPM_REQ_HEARTBEAT="" RPM_REQ_BASH_COMPLETION="" RPM_REQ_XEN="" RPM_REQ_CHKCONFIG_POST="" RPM_REQ_CHKCONFIG_PREUN="" if test -z $DISTRO; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for /etc/gentoo-release" >&5 $as_echo_n "checking for /etc/gentoo-release... " >&6; } if ${ac_cv_file__etc_gentoo_release+:} false; then : $as_echo_n "(cached) " >&6 else test "$cross_compiling" = yes && as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5 if test -r "/etc/gentoo-release"; then ac_cv_file__etc_gentoo_release=yes else ac_cv_file__etc_gentoo_release=no fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_file__etc_gentoo_release" >&5 $as_echo "$ac_cv_file__etc_gentoo_release" >&6; } if test "x$ac_cv_file__etc_gentoo_release" = xyes; then : DISTRO="gentoo" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for /etc/redhat-release" >&5 $as_echo_n "checking for /etc/redhat-release... " >&6; } if ${ac_cv_file__etc_redhat_release+:} false; then : $as_echo_n "(cached) " >&6 else test "$cross_compiling" = yes && as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5 if test -r "/etc/redhat-release"; then ac_cv_file__etc_redhat_release=yes else ac_cv_file__etc_redhat_release=no fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_file__etc_redhat_release" >&5 $as_echo "$ac_cv_file__etc_redhat_release" >&6; } if test "x$ac_cv_file__etc_redhat_release" = xyes; then : DISTRO="redhat" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for /etc/slackware-version" >&5 $as_echo_n "checking for /etc/slackware-version... " >&6; } if ${ac_cv_file__etc_slackware_version+:} false; then : $as_echo_n "(cached) " >&6 else test "$cross_compiling" = yes && as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5 if test -r "/etc/slackware-version"; then ac_cv_file__etc_slackware_version=yes else ac_cv_file__etc_slackware_version=no fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_file__etc_slackware_version" >&5 $as_echo "$ac_cv_file__etc_slackware_version" >&6; } if test "x$ac_cv_file__etc_slackware_version" = xyes; then : DISTRO="slackware" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for /etc/debian_version" >&5 $as_echo_n "checking for /etc/debian_version... " >&6; } if ${ac_cv_file__etc_debian_version+:} false; then : $as_echo_n "(cached) " >&6 else test "$cross_compiling" = yes && as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5 if test -r "/etc/debian_version"; then ac_cv_file__etc_debian_version=yes else ac_cv_file__etc_debian_version=no fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_file__etc_debian_version" >&5 $as_echo "$ac_cv_file__etc_debian_version" >&6; } if test "x$ac_cv_file__etc_debian_version" = xyes; then : DISTRO="debian" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for /etc/SuSE-release" >&5 $as_echo_n "checking for /etc/SuSE-release... " >&6; } if ${ac_cv_file__etc_SuSE_release+:} false; then : $as_echo_n "(cached) " >&6 else test "$cross_compiling" = yes && as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5 if test -r "/etc/SuSE-release"; then ac_cv_file__etc_SuSE_release=yes else ac_cv_file__etc_SuSE_release=no fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_file__etc_SuSE_release" >&5 $as_echo "$ac_cv_file__etc_SuSE_release" >&6; } if test "x$ac_cv_file__etc_SuSE_release" = xyes; then : DISTRO="suse" fi fi case "$DISTRO" in gentoo) { $as_echo "$as_me:${as_lineno-$LINENO}: configured for Gentoo." >&5 $as_echo "$as_me: configured for Gentoo." >&6;} ;; redhat) test -z $INITDIR && INITDIR="$sysconfdir/rc.d/init.d" RPM_DIST_TAG="%{?dist}" RPM_BUILDREQ_DEFAULT="flex" RPM_REQ_CHKCONFIG_POST="Requires(post): chkconfig" RPM_REQ_CHKCONFIG_PREUN="Requires(preun): chkconfig" { $as_echo "$as_me:${as_lineno-$LINENO}: configured for Red Hat (includes Fedora, RHEL, CentOS)." >&5 $as_echo "$as_me: configured for Red Hat (includes Fedora, RHEL, CentOS)." >&6;} { $as_echo "$as_me:${as_lineno-$LINENO}: checking for /etc/fedora-release" >&5 $as_echo_n "checking for /etc/fedora-release... " >&6; } if ${ac_cv_file__etc_fedora_release+:} false; then : $as_echo_n "(cached) " >&6 else test "$cross_compiling" = yes && as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5 if test -r "/etc/fedora-release"; then ac_cv_file__etc_fedora_release=yes else ac_cv_file__etc_fedora_release=no fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_file__etc_fedora_release" >&5 $as_echo "$ac_cv_file__etc_fedora_release" >&6; } if test "x$ac_cv_file__etc_fedora_release" = xyes; then : SUB_DISTRO="fedora" else SUB_DISTRO="RHEL" fi if test "$SUB_DISTRO" = "fedora"; then # pacemaker, heartbeat and bash-completion are not available in RHEL # Xen: Be relaxed on RHEL (hassle free update). Be strict on Fedora RPM_REQ_PACEMAKER="Requires: pacemaker" RPM_REQ_HEARTBEAT="Requires: heartbeat" RPM_REQ_BASH_COMPLETION="Requires: bash-completion" RPM_REQ_XEN="Requires: xen" fi ;; slackware) test -z $INITDIR && INITDIR="$sysconfdir/rc.d" { $as_echo "$as_me:${as_lineno-$LINENO}: configured for Slackware." >&5 $as_echo "$as_me: configured for Slackware." >&6;} ;; debian) { $as_echo "$as_me:${as_lineno-$LINENO}: configured for Debian (includes Ubuntu)." >&5 $as_echo "$as_me: configured for Debian (includes Ubuntu)." >&6;} ;; suse) BASH_COMPLETION_SUFFIX=".sh" # RPM_REQ_CHKCONFIG_POST="" chkconfig is part of aaa_base on suse # RPM_REQ_CHKCONFIG_PREUN="" chkconfig is part of aaa_base on suse { $as_echo "$as_me:${as_lineno-$LINENO}: configured for SUSE (includes openSUSE, SLES)." >&5 $as_echo "$as_me: configured for SUSE (includes openSUSE, SLES)." >&6;} RPM_REQ_BASH_COMPLETION="Requires: bash" # The following are disabled for hassle free updates: # RPM_REQ_XEN="Requires: xen" # RPM_REQ_PACEMAKER="Requires: pacemaker" # RPM_REQ_HEARTBEAT="Requires: heartbeat" # Unfortunately gcc on SLES9 is broken with -O2. Works with -O1 if grep -q 'VERSION = 9' /etc/SuSE-release; then CFLAGS="-g -O1" fi ;; "") { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to determine what distribution we are running on. Distribution-specific features will be disabled." >&5 $as_echo "$as_me: WARNING: Unable to determine what distribution we are running on. Distribution-specific features will be disabled." >&2;} ;; esac test -z $INITDIR && INITDIR="$sysconfdir/init.d" if test "$WITH_UDEV" = "yes"; then udev_version=`$UDEVADM version 2>/dev/null` || udev_version=`$UDEVINFO -V | cut -d " " -f 3` if test -z $udev_version || test $udev_version -lt 85; then UDEV_RULE_SUFFIX=".disabled" { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Obsolete or unknown udev version. Installing disabled udev rules." >&5 $as_echo "$as_me: WARNING: Obsolete or unknown udev version. Installing disabled udev rules." >&2;} fi fi if test "$WITH_NOARCH_SUBPACKAGES" = "yes"; then RPM_SUBPACKAGE_NOARCH="BuildArch: noarch" fi DRBD_LIB_DIR=$localstatedir/lib/$PACKAGE_TARNAME DRBD_RUN_DIR=$localstatedir/run/$PACKAGE_TARNAME DRBD_LOCK_DIR=$localstatedir/lock DRBD_CONFIG_DIR=$sysconfdir cat >>confdefs.h <<_ACEOF #define DRBD_LIB_DIR "$DRBD_LIB_DIR" _ACEOF cat >>confdefs.h <<_ACEOF #define DRBD_RUN_DIR "$DRBD_RUN_DIR" _ACEOF cat >>confdefs.h <<_ACEOF #define DRBD_LOCK_DIR "$DRBD_LOCK_DIR" _ACEOF cat >>confdefs.h <<_ACEOF #define DRBD_CONFIG_DIR "$DRBD_CONFIG_DIR" _ACEOF if test "$WITH_83_SUPPORT" = "yes"; then $as_echo "#define DRBD_LEGACY_83 1" >>confdefs.h fi if test "$WITH_84_SUPPORT" = "yes"; then $as_echo "#define DRBD_LEGACY_84 1" >>confdefs.h fi if test -z $SPECMODE; then ac_config_files="$ac_config_files Makefile user/shared/Makefile user/v9/Makefile user/v83/Makefile user/v84/Makefile scripts/Makefile documentation/v9/Makefile documentation/v83/Makefile documentation/v84/Makefile scripts/drbd.rules" ac_config_headers="$ac_config_headers user/shared/config.h" else ac_config_files="$ac_config_files drbd.spec" fi cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by DRBD $as_me 8.9.6, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ DRBD config.status 8.9.6 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "user/shared/Makefile") CONFIG_FILES="$CONFIG_FILES user/shared/Makefile" ;; "user/v9/Makefile") CONFIG_FILES="$CONFIG_FILES user/v9/Makefile" ;; "user/v83/Makefile") CONFIG_FILES="$CONFIG_FILES user/v83/Makefile" ;; "user/v84/Makefile") CONFIG_FILES="$CONFIG_FILES user/v84/Makefile" ;; "scripts/Makefile") CONFIG_FILES="$CONFIG_FILES scripts/Makefile" ;; "documentation/v9/Makefile") CONFIG_FILES="$CONFIG_FILES documentation/v9/Makefile" ;; "documentation/v83/Makefile") CONFIG_FILES="$CONFIG_FILES documentation/v83/Makefile" ;; "documentation/v84/Makefile") CONFIG_FILES="$CONFIG_FILES documentation/v84/Makefile" ;; "scripts/drbd.rules") CONFIG_FILES="$CONFIG_FILES scripts/drbd.rules" ;; "user/shared/config.h") CONFIG_HEADERS="$CONFIG_HEADERS user/shared/config.h" ;; "drbd.spec") CONFIG_FILES="$CONFIG_FILES drbd.spec" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_tt=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS " shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi drbd-utils-8.9.6/ChangeLog0000644000175000017500000001137012654447436015276 0ustar apoikosapoikosLatest: ------ For even more detail, use "git log" or visit http://git.drbd.org/. 8.9.6 -------- * Call "drbdsetup resize" only as often as necessary on "drbdadm resize" * Disconnect connection first on single path deletion from connection * Add unfence-peer handler * Fix "drbdadm adjust" for proxy configurations 8.9.5 -------- * add support for new disk option 'rs-discard-granularity' (module v8.4.7) * add support for new disk option 'discard-zeroes-if-aligned' (module v8.4.7) * add support for v9 "path" commands * doc improvements/corrections * improvements to drbd ocf resource agent and pacemaker "constraint based fencing" (crm-fence-peer.sh) * drbd-overview improvements 8.9.4 -------- * Add an autoconf switch for building without man pages * Fix compatibility with the musl C library * Introduce the concept of paths within a connection to the config file; add support for paths to drbdadm adjust * Allow multiple connection-mesh statements within one resource * Document peer-device-options on the drbd-9.0 man pages * increase the lower boundary for al-extents from 7 to 67; drbdadm clamps al-extents to 67 implicitly if you configures something lower than 67 * Document the events2 command on the drbd-8.4 man page * Fix environment variables for handlers 8.9.3 -------- * Support for the new new-peer, add-path, connect, del-path, disconnect and del-peer commands of drbd-9.0.0; drbdadm support for the new commands * New configuration file directive template-file; with that a dedicated file for the common section of a resource can be specified * Rewrite the parser for configure options; reuse the data structures describing drbdsetup options * No longer try to set peer-device-options with the connect or attach commands; Only do it with the up and attach commands * Fixed issues with stderr messages might go into arbitrary FDs * Allow recursive includes; drbdadm includes each config file only once * Fix parsing cut-off proxy sections * When converting 8.4 to 9.0 meta-data produce meta-data the drbd9 kernel driver will accept * Obey max-peers for all volumes when creating meta-data * Do not re-register at usage.drbd.org when the module is not loaded when drbdadm is invoked 8.9.2 -------- * change systemd unit file: basically just call the init script * make some previously hardcoded timeouts configurable * drbdadm: New command peer-device-options * drbd 9: Move max_buffers to net_conf * drbd 9: Log errors to syslog if stderr is not available * init script: fixes for stacked resources * fix regression corner cases in bitmap size calculation * allow create-md to initialize peer-max-bio-size to 1M * drbd 9: make transport selectable * fix aggregating drbdsetup / drbdmeta exit statii * some documentation fixes (content and build) * added direct-connect command * incompatible drbd-9 metadata format change. use: node_id as index for peer_md instead of the bitmap_index * drbdadm/meta/usage_cnt: ensure output is visible * drbdsetup: fix arguments for all commands expecting a peer_device * exit codes: redefine E_USAGE to 1 (not 3) * some build changes * init script: on start, first try to load the module * drbdsetup events2: Improve how timestamps are assigned * udev rules (symlinks in /dev/by-res and by-disk) got fixed * Fixed upper limit for drbd-8.4 activity log entries * many fixes to drbdadm adjust and proxy commands for drbd-9 * rhcs_fence: Do not invoke fence agents in parallel, rewrite in bash * drbdsetup events2 is now also available in drbd-8.4 (backported from drbd-9) * reorganized the repository have common code for drbd-9, drbd-8.4 and drbd-8.3 only once * Fix drbd.ocf for resources without volume 0 8.9.1 -------- * add DRBD systemd service * new configuration options socket-check-timeout and csums-after-crash-only * update xen block-drbd helper: allow for type "phy" * update udev rules and move from /etc/ to /lib/ * fix various regressions/fallout from the kernel/userland package split, re-add scripts drbddisk and drbdupper, re-add "become-on-primary" feature to init script * crm-fence-peer.sh: improve detection of "clean down" * updated fencing scripts stonith_admin-fence-peer.sh and rhcs_fence * improved "proxy" configuration section parsing * added manpage for drbd-overview, minor review of man pages * build: various changes in configure.ac, makefiles, debian/* and spec file 8.9.0 -------- * Initial release of unified drbd-utils * Supports drbd drivers 8.3, 8.4 and 9.0 * Ships with man page links defaulting to 8.4 * Fixed offline resizing in drbdmeta; A regression that causes data loss, since meta-data was written with wrong offset. The regression was introduced with 8.4.3 drbd-utils-8.9.6/autogen.sh0000755000175000017500000000046112466702073015514 0ustar apoikosapoikos#!/bin/sh # for those that expect an autogen.sh, # here it is. aclocal autoheader autoconf echo " suggested configure parameters: # prepare for rpmbuild, only generate spec files ./configure --enable-spec # or prepare for direct build ./configure --prefix=/usr --localstatedir=/var --sysconfdir=/etc " drbd-utils-8.9.6/drbd-headers/0000755000175000017500000000000012654475367016052 5ustar apoikosapoikosdrbd-utils-8.9.6/drbd-headers/drbd_protocol.h0000644000175000017500000003346612650365606021061 0ustar apoikosapoikos#ifndef __DRBD_PROTOCOL_H #define __DRBD_PROTOCOL_H #ifdef __KERNEL__ #include #else #include #endif #ifndef ARRAY_SIZE #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) #endif enum drbd_packet { /* receiver (data socket) */ P_DATA = 0x00, P_DATA_REPLY = 0x01, /* Response to P_DATA_REQUEST */ P_RS_DATA_REPLY = 0x02, /* Response to P_RS_DATA_REQUEST */ P_BARRIER = 0x03, P_BITMAP = 0x04, P_BECOME_SYNC_TARGET = 0x05, P_BECOME_SYNC_SOURCE = 0x06, P_UNPLUG_REMOTE = 0x07, /* Used at various times to hint the peer */ P_DATA_REQUEST = 0x08, /* Used to ask for a data block */ P_RS_DATA_REQUEST = 0x09, /* Used to ask for a data block for resync */ P_SYNC_PARAM = 0x0a, P_PROTOCOL = 0x0b, P_UUIDS = 0x0c, P_SIZES = 0x0d, P_STATE = 0x0e, P_SYNC_UUID = 0x0f, P_AUTH_CHALLENGE = 0x10, P_AUTH_RESPONSE = 0x11, P_STATE_CHG_REQ = 0x12, /* asender (meta socket */ P_PING = 0x13, P_PING_ACK = 0x14, P_RECV_ACK = 0x15, /* Used in protocol B */ P_WRITE_ACK = 0x16, /* Used in protocol C */ P_RS_WRITE_ACK = 0x17, /* Is a P_WRITE_ACK, additionally call set_in_sync(). */ P_SUPERSEDED = 0x18, /* Used in proto C, two-primaries conflict detection */ P_NEG_ACK = 0x19, /* Sent if local disk is unusable */ P_NEG_DREPLY = 0x1a, /* Local disk is broken... */ P_NEG_RS_DREPLY = 0x1b, /* Local disk is broken... */ P_BARRIER_ACK = 0x1c, P_STATE_CHG_REPLY = 0x1d, /* "new" commands, no longer fitting into the ordering scheme above */ P_OV_REQUEST = 0x1e, /* data socket */ P_OV_REPLY = 0x1f, P_OV_RESULT = 0x20, /* meta socket */ P_CSUM_RS_REQUEST = 0x21, /* data socket */ P_RS_IS_IN_SYNC = 0x22, /* meta socket */ P_SYNC_PARAM89 = 0x23, /* data socket, protocol version 89 replacement for P_SYNC_PARAM */ P_COMPRESSED_BITMAP = 0x24, /* compressed or otherwise encoded bitmap transfer */ /* P_CKPT_FENCE_REQ = 0x25, * currently reserved for protocol D */ /* P_CKPT_DISABLE_REQ = 0x26, * currently reserved for protocol D */ P_DELAY_PROBE = 0x27, /* is used on BOTH sockets */ P_OUT_OF_SYNC = 0x28, /* Mark as out of sync (Outrunning), data socket */ P_RS_CANCEL = 0x29, /* meta: Used to cancel RS_DATA_REQUEST packet by SyncSource */ P_CONN_ST_CHG_REQ = 0x2a, /* data sock: state change request */ P_CONN_ST_CHG_REPLY = 0x2b, /* meta sock: state change reply */ P_RETRY_WRITE = 0x2c, /* Protocol C: retry conflicting write request */ P_PROTOCOL_UPDATE = 0x2d, /* data sock: is used in established connections */ P_TWOPC_PREPARE = 0x2e, /* data sock: prepare state change */ P_TWOPC_ABORT = 0x2f, /* data sock: abort state change */ P_DAGTAG = 0x30, /* data sock: set the current dagtag */ /* REQ_DISCARD. We used "discard" in different contexts before, * which is why I chose TRIM here, to disambiguate. */ P_TRIM = 0x31, /* Only use these two if both support FF_THIN_RESYNC */ P_RS_THIN_REQ = 0x32, /* Request a block for resync or reply P_RS_DEALLOCATED */ P_RS_DEALLOCATED = 0x33, /* Contains only zeros on sync source node */ /* REQ_WRITE_SAME. * On a receiving side without REQ_WRITE_SAME, * we may fall back to an opencoded loop instead. */ P_WSAME = 0x34, P_PEER_ACK = 0x40, /* meta sock: tell which nodes have acked a request */ P_PEERS_IN_SYNC = 0x41, /* data sock: Mark area as in sync */ P_UUIDS110 = 0x42, /* data socket */ P_PEER_DAGTAG = 0x43, /* data socket, used to trigger reconciliation resync */ P_CURRENT_UUID = 0x44, /* data socket */ P_TWOPC_YES = 0x45, /* meta sock: allow two-phase commit */ P_TWOPC_NO = 0x46, /* meta sock: reject two-phase commit */ P_TWOPC_COMMIT = 0x47, /* data sock: commit state change */ P_TWOPC_RETRY = 0x48, /* meta sock: retry two-phase commit */ P_MAY_IGNORE = 0x100, /* Flag to test if (cmd > P_MAY_IGNORE) ... */ /* special command ids for handshake */ P_INITIAL_META = 0xfff1, /* First Packet on the MetaSock */ P_INITIAL_DATA = 0xfff2, /* First Packet on the Socket */ P_CONNECTION_FEATURES = 0xfffe /* FIXED for the next century! */ }; #ifndef __packed #define __packed __attribute__((packed)) #endif /* This is the layout for a packet on the wire. * The byteorder is the network byte order. * (except block_id and barrier fields. * these are pointers to local structs * and have no relevance for the partner, * which just echoes them as received.) * * NOTE that the payload starts at a long aligned offset, * regardless of 32 or 64 bit arch! */ struct p_header80 { uint32_t magic; uint16_t command; uint16_t length; /* bytes of data after this header */ } __packed; /* Header for big packets, Used for data packets exceeding 64kB */ struct p_header95 { uint16_t magic; /* use DRBD_MAGIC_BIG here */ uint16_t command; uint32_t length; } __packed; struct p_header100 { uint32_t magic; uint16_t volume; uint16_t command; uint32_t length; uint32_t pad; } __packed; /* These defines must not be changed without changing the protocol version. * New defines may only be introduced together with protocol version bump or * new protocol feature flags. */ #define DP_HARDBARRIER 1 /* no longer used */ #define DP_RW_SYNC 2 /* equals REQ_SYNC */ #define DP_MAY_SET_IN_SYNC 4 #define DP_UNPLUG 8 /* equals REQ_UNPLUG (compat) */ #define DP_FUA 16 /* equals REQ_FUA */ #define DP_FLUSH 32 /* equals REQ_FLUSH */ #define DP_DISCARD 64 /* equals REQ_DISCARD */ #define DP_SEND_RECEIVE_ACK 128 /* This is a proto B write request */ #define DP_SEND_WRITE_ACK 256 /* This is a proto C write request */ #define DP_WSAME 512 /* equiv. REQ_WRITE_SAME */ struct p_data { uint64_t sector; /* 64 bits sector number */ uint64_t block_id; /* to identify the request in protocol B&C */ uint32_t seq_num; uint32_t dp_flags; } __packed; struct p_trim { struct p_data p_data; uint32_t size; /* == bio->bi_size */ } __packed; struct p_wsame { struct p_data p_data; uint32_t size; /* == bio->bi_size */ } __packed; /* * commands which share a struct: * p_block_ack: * P_RECV_ACK (proto B), P_WRITE_ACK (proto C), * P_SUPERSEDED (proto C, two-primaries conflict detection) * p_block_req: * P_DATA_REQUEST, P_RS_DATA_REQUEST */ struct p_block_ack { uint64_t sector; uint64_t block_id; uint32_t blksize; uint32_t seq_num; } __packed; struct p_block_req { uint64_t sector; uint64_t block_id; uint32_t blksize; uint32_t pad; /* to multiple of 8 Byte */ } __packed; /* * commands with their own struct for additional fields: * P_CONNECTION_FEATURES * P_BARRIER * P_BARRIER_ACK * P_SYNC_PARAM * ReportParams */ /* supports TRIM/DISCARD on the "wire" protocol */ #define DRBD_FF_TRIM 1 /* Detect all-zeros during resync, and rather TRIM/UNMAP/DISCARD those blocks * instead of fully allocate a supposedly thin volume on initial resync */ #define DRBD_FF_THIN_RESYNC 2 /* supports REQ_WRITE_SAME on the "wire" protocol. * Note: this flag is overloaded, * its presence also * - indicates support for 128 MiB "batch bios", * max discard size of 128 MiB * instead of 4M before that. * - indicates that we exchange additional settings in p_sizes * drbd_send_sizes()/receive_sizes() */ #define DRBD_FF_WSAME 4 struct p_connection_features { uint32_t protocol_min; uint32_t feature_flags; uint32_t protocol_max; uint32_t sender_node_id; uint32_t receiver_node_id; /* should be more than enough for future enhancements * for now, feature_flags and the reserved array shall be zero. */ uint32_t _pad; uint64_t reserved[6]; } __packed; struct p_barrier { uint32_t barrier; /* barrier number _handle_ only */ uint32_t pad; /* to multiple of 8 Byte */ } __packed; struct p_barrier_ack { uint32_t barrier; uint32_t set_size; } __packed; struct p_rs_param { uint32_t resync_rate; /* Since protocol version 88 and higher. */ char verify_alg[0]; } __packed; struct p_rs_param_89 { uint32_t resync_rate; /* protocol version 89: */ char verify_alg[SHARED_SECRET_MAX]; char csums_alg[SHARED_SECRET_MAX]; } __packed; struct p_rs_param_95 { uint32_t resync_rate; char verify_alg[SHARED_SECRET_MAX]; char csums_alg[SHARED_SECRET_MAX]; uint32_t c_plan_ahead; uint32_t c_delay_target; uint32_t c_fill_target; uint32_t c_max_rate; } __packed; enum drbd_conn_flags { CF_DISCARD_MY_DATA = 1, CF_DRY_RUN = 2, }; struct p_protocol { uint32_t protocol; uint32_t after_sb_0p; uint32_t after_sb_1p; uint32_t after_sb_2p; uint32_t conn_flags; uint32_t two_primaries; /* Since protocol version 87 and higher. */ char integrity_alg[0]; } __packed; #define UUID_FLAG_DISCARD_MY_DATA 1 #define UUID_FLAG_CRASHED_PRIMARY 2 #define UUID_FLAG_INCONSISTENT 4 #define UUID_FLAG_SKIP_INITIAL_SYNC 8 #define UUID_FLAG_NEW_DATAGEN 16 #define UUID_FLAG_STABLE 32 #define UUID_FLAG_GOT_STABLE 64 /* send UUIDs */ #define UUID_FLAG_RESYNC 128 /* compare UUIDs and eventually start resync */ #define UUID_FLAG_RECONNECT 256 #define UUID_FLAG_DISKLESS_PRIMARY 512 /* Use with UUID_FLAG_RESYNC if a diskless primary is the reason */ struct p_uuids { uint64_t current_uuid; uint64_t bitmap_uuid; uint64_t history_uuids[HISTORY_UUIDS_V08]; uint64_t dirty_bits; uint64_t uuid_flags; } __packed; struct p_uuids110 { uint64_t current_uuid; uint64_t dirty_bits; uint64_t uuid_flags; uint64_t node_mask; /* weak_nodes when UUID_FLAG_NEW_DATAGEN is set ; authoritative nodes when UUID_FLAG_STABLE not set */ uint64_t bitmap_uuids_mask; /* non zero bitmap UUIDS for these nodes */ uint64_t other_uuids[0]; /* the first hweight(bitmap_uuids_mask) slots carry bitmap uuids. The node with the lowest node_id first. The remaining slots carry history uuids */ } __packed; struct p_current_uuid { uint64_t uuid; uint64_t weak_nodes; } __packed; struct p_uuid { uint64_t uuid; } __packed; /* optional queue_limits if (agreed_features & DRBD_FF_WSAME) * see also struct queue_limits, as of late 2015 */ struct o_qlim { /* we don't need it yet, but we may as well communicate it now */ uint32_t physical_block_size; /* so the original in struct queue_limits is unsigned short, * but I'd have to put in padding anyways. */ uint32_t logical_block_size; /* One incoming bio becomes one DRBD request, * which may be translated to several bio on the receiving side. * We don't need to communicate chunk/boundary/segment ... limits. */ /* various IO hints may be useful with "diskless client" setups */ uint32_t alignment_offset; uint32_t io_min; uint32_t io_opt; /* We may need to communicate integrity stuff at some point, * but let's not get ahead of ourselves. */ /* Backend discard capabilities. * Receiving side uses "blkdev_issue_discard()", no need to communicate * more specifics. If the backend cannot do discards, the DRBD peer * may fall back to blkdev_issue_zeroout(). */ uint8_t discard_enabled; uint8_t discard_zeroes_data; uint8_t write_same_capable; uint8_t _pad; } __packed; struct p_sizes { uint64_t d_size; /* size of disk */ uint64_t u_size; /* user requested size */ uint64_t c_size; /* current exported size */ uint32_t max_bio_size; /* Maximal size of a BIO */ uint16_t queue_order_type; /* not yet implemented in DRBD*/ uint16_t dds_flags; /* use enum dds_flags here. */ /* optional queue_limits if (agreed_features & DRBD_FF_WSAME) */ struct o_qlim qlim[0]; } __packed; struct p_state { uint32_t state; } __packed; struct p_req_state { uint32_t mask; uint32_t val; } __packed; struct p_req_state_reply { uint32_t retcode; } __packed; struct p_twopc_request { uint32_t tid; /* transaction identifier */ uint32_t initiator_node_id; /* initiator of the transaction */ uint32_t target_node_id; /* target of the transaction (or -1) */ uint64_t nodes_to_reach; uint64_t primary_nodes; uint32_t mask; uint32_t val; } __packed; struct p_twopc_reply { uint32_t tid; /* transaction identifier */ uint32_t initiator_node_id; /* initiator of the transaction */ uint64_t reachable_nodes; uint64_t primary_nodes; uint64_t weak_nodes; } __packed; struct p_drbd06_param { uint64_t size; uint32_t state; uint32_t blksize; uint32_t protocol; uint32_t version; uint32_t gen_cnt[5]; uint32_t bit_map_gen[5]; } __packed; struct p_block_desc { uint64_t sector; uint32_t blksize; uint32_t pad; /* to multiple of 8 Byte */ } __packed; /* Valid values for the encoding field. * Bump proto version when changing this. */ enum drbd_bitmap_code { /* RLE_VLI_Bytes = 0, * and other bit variants had been defined during * algorithm evaluation. */ RLE_VLI_Bits = 2, }; struct p_compressed_bm { /* (encoding & 0x0f): actual encoding, see enum drbd_bitmap_code * (encoding & 0x80): polarity (set/unset) of first runlength * ((encoding >> 4) & 0x07): pad_bits, number of trailing zero bits * used to pad up to head.length bytes */ uint8_t encoding; uint8_t code[0]; } __packed; struct p_delay_probe93 { uint32_t seq_num; /* sequence number to match the two probe packets */ uint32_t offset; /* usecs the probe got sent after the reference time point */ } __packed; struct p_dagtag { uint64_t dagtag; } __packed; struct p_peer_ack { uint64_t mask; uint64_t dagtag; } __packed; struct p_peer_block_desc { uint64_t sector; uint64_t mask; uint32_t size; uint32_t pad; /* to multiple of 8 Byte */ } __packed; struct p_peer_dagtag { uint64_t dagtag; uint32_t node_id; } __packed; /* * Bitmap packets need to fit within a single page on the sender and receiver, * so we are limited to 4 KiB (and not to PAGE_SIZE, which can be bigger). */ #define DRBD_SOCKET_BUFFER_SIZE 4096 #endif /* __DRBD_PROTOCOL_H */ drbd-utils-8.9.6/drbd-headers/drbd_strings.c0000644000175000017500000002140712654447447020704 0ustar apoikosapoikos/* drbd.h This file is part of DRBD by Philipp Reisner and Lars Ellenberg. Copyright (C) 2003-2008, LINBIT Information Technologies GmbH. Copyright (C) 2003-2008, Philipp Reisner . Copyright (C) 2003-2008, Lars Ellenberg . drbd is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. drbd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with drbd; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include "drbd_strings.h" #include "drbd_protocol.h" static const char * const __conn_state_names[] = { [C_STANDALONE] = "StandAlone", [C_DISCONNECTING] = "Disconnecting", [C_UNCONNECTED] = "Unconnected", [C_TIMEOUT] = "Timeout", [C_BROKEN_PIPE] = "BrokenPipe", [C_NETWORK_FAILURE] = "NetworkFailure", [C_PROTOCOL_ERROR] = "ProtocolError", [C_TEAR_DOWN] = "TearDown", [C_CONNECTING] = "Connecting", [C_CONNECTED] = "Connected", }; struct state_names drbd_conn_state_names = { .names = __conn_state_names, .size = sizeof __conn_state_names / sizeof __conn_state_names[0], }; static const char * const __repl_state_names[] = { [L_OFF] = "Off", [L_ESTABLISHED] = "Established", [L_STARTING_SYNC_S] = "StartingSyncS", [L_STARTING_SYNC_T] = "StartingSyncT", [L_WF_BITMAP_S] = "WFBitMapS", [L_WF_BITMAP_T] = "WFBitMapT", [L_WF_SYNC_UUID] = "WFSyncUUID", [L_SYNC_SOURCE] = "SyncSource", [L_SYNC_TARGET] = "SyncTarget", [L_VERIFY_S] = "VerifyS", [L_VERIFY_T] = "VerifyT", [L_PAUSED_SYNC_S] = "PausedSyncS", [L_PAUSED_SYNC_T] = "PausedSyncT", [L_AHEAD] = "Ahead", [L_BEHIND] = "Behind", }; struct state_names drbd_repl_state_names = { .names = __repl_state_names, .size = sizeof __repl_state_names / sizeof __repl_state_names[0], }; static const char * const __role_state_names[] = { [R_UNKNOWN] = "Unknown", [R_PRIMARY] = "Primary", [R_SECONDARY] = "Secondary", }; struct state_names drbd_role_state_names = { .names = __role_state_names, .size = sizeof __role_state_names / sizeof __role_state_names[0], }; static const char * const __disk_state_names[] = { [D_DISKLESS] = "Diskless", [D_ATTACHING] = "Attaching", [D_DETACHING] = "Detaching", [D_FAILED] = "Failed", [D_NEGOTIATING] = "Negotiating", [D_INCONSISTENT] = "Inconsistent", [D_OUTDATED] = "Outdated", [D_UNKNOWN] = "DUnknown", [D_CONSISTENT] = "Consistent", [D_UP_TO_DATE] = "UpToDate", }; struct state_names drbd_disk_state_names = { .names = __disk_state_names, .size = sizeof __disk_state_names / sizeof __disk_state_names[0], }; static const char * const __error_messages[] = { [-SS_TWO_PRIMARIES] = "Multiple primaries not allowed by config", [-SS_NO_UP_TO_DATE_DISK] = "Need access to UpToDate data", [-SS_NO_LOCAL_DISK] = "Can not resync without local disk", [-SS_NO_REMOTE_DISK] = "Can not resync without remote disk", [-SS_CONNECTED_OUTDATES] = "Refusing to be Outdated while Connected", [-SS_PRIMARY_NOP] = "Refusing to be Primary while peer is not outdated", [-SS_RESYNC_RUNNING] = "Can not start OV/resync since it is already active", [-SS_ALREADY_STANDALONE] = "Can not disconnect a StandAlone device", [-SS_CW_FAILED_BY_PEER] = "State change was refused by peer node", [-SS_IS_DISKLESS] = "Device is diskless, the requested operation requires a disk", [-SS_DEVICE_IN_USE] = "Device is held open by someone", [-SS_NO_NET_CONFIG] = "Have no net/connection configuration", [-SS_NO_VERIFY_ALG] = "Need a verify algorithm to start online verify", [-SS_NEED_CONNECTION] = "Need a connection to start verify or resync", [-SS_NOT_SUPPORTED] = "Peer does not support protocol", [-SS_LOWER_THAN_OUTDATED] = "Disk state is lower than outdated", [-SS_IN_TRANSIENT_STATE] = "In transient state, retry after next state change", [-SS_CONCURRENT_ST_CHG] = "Concurrent state changes detected and aborted", [-SS_O_VOL_PEER_PRI] = "Other vol primary on peer not allowed by config", [-SS_PRIMARY_READER] = "Peer may not become primary while device is opened read-only", [-SS_INTERRUPTED] = "Interrupted state change", [-SS_TIMEOUT] = "Timeout in operation", [-SS_WEAKLY_CONNECTED] = "Primary nodes must be strongly connected among each other", }; struct state_names drbd_error_messages = { .names = __error_messages, .size = sizeof __error_messages / sizeof __error_messages[0], }; static const char * const __packet_names[] = { [P_DATA] = "P_DATA", [P_WSAME] = "P_WSAME", [P_TRIM] = "P_TRIM", [P_DATA_REPLY] = "P_DATA_REPLY", [P_RS_DATA_REPLY] = "P_RS_DATA_REPLY", [P_BARRIER] = "P_BARRIER", [P_BITMAP] = "P_BITMAP", [P_BECOME_SYNC_TARGET] = "P_BECOME_SYNC_TARGET", [P_BECOME_SYNC_SOURCE] = "P_BECOME_SYNC_SOURCE", [P_UNPLUG_REMOTE] = "P_UNPLUG_REMOTE", [P_DATA_REQUEST] = "P_DATA_REQUEST", [P_RS_DATA_REQUEST] = "P_RS_DATA_REQUEST", [P_SYNC_PARAM] = "P_SYNC_PARAM", [P_SYNC_PARAM89] = "P_SYNC_PARAM89", [P_PROTOCOL] = "P_PROTOCOL", [P_UUIDS] = "P_UUIDS", [P_SIZES] = "P_SIZES", [P_STATE] = "P_STATE", [P_SYNC_UUID] = "P_SYNC_UUID", [P_AUTH_CHALLENGE] = "P_AUTH_CHALLENGE", [P_AUTH_RESPONSE] = "P_AUTH_RESPONSE", [P_PING] = "P_PING", [P_PING_ACK] = "P_PING_ACK", [P_RECV_ACK] = "P_RECV_ACK", [P_WRITE_ACK] = "P_WRITE_ACK", [P_RS_WRITE_ACK] = "P_RS_WRITE_ACK", [P_SUPERSEDED] = "P_SUPERSEDED", [P_NEG_ACK] = "P_NEG_ACK", [P_NEG_DREPLY] = "P_NEG_DREPLY", [P_NEG_RS_DREPLY] = "P_NEG_RS_DREPLY", [P_BARRIER_ACK] = "P_BARRIER_ACK", [P_STATE_CHG_REQ] = "P_STATE_CHG_REQ", [P_STATE_CHG_REPLY] = "P_STATE_CHG_REPLY", [P_OV_REQUEST] = "P_OV_REQUEST", [P_OV_REPLY] = "P_OV_REPLY", [P_OV_RESULT] = "P_OV_RESULT", [P_CSUM_RS_REQUEST] = "P_CSUM_RS_REQUEST", [P_RS_IS_IN_SYNC] = "P_RS_IS_IN_SYNC", [P_COMPRESSED_BITMAP] = "P_COMPRESSED_BITMAP", [P_DELAY_PROBE] = "P_DELAY_PROBE", [P_OUT_OF_SYNC] = "P_OUT_OF_SYNC", [P_RETRY_WRITE] = "P_RETRY_WRITE", [P_RS_CANCEL] = "P_RS_CANCEL", [P_CONN_ST_CHG_REQ] = "P_CONN_ST_CHG_REQ", [P_CONN_ST_CHG_REPLY] = "P_CONN_ST_CHG_REPLY", [P_RETRY_WRITE] = "P_RETRY_WRITE", [P_PROTOCOL_UPDATE] = "P_PROTOCOL_UPDATE", [P_TWOPC_PREPARE] = "P_TWOPC_PREPARE", [P_TWOPC_ABORT] = "P_TWOPC_ABORT", [P_DAGTAG] = "P_DAGTAG", [P_PEER_ACK] = "P_PEER_ACK", [P_PEERS_IN_SYNC] = "P_PEERS_IN_SYNC", [P_UUIDS110] = "P_UUIDS110", [P_PEER_DAGTAG] = "P_PEER_DAGTAG", [P_CURRENT_UUID] = "P_CURRENT_UUID", [P_TWOPC_COMMIT] = "P_TWOPC_COMMIT", [P_TWOPC_YES] = "P_TWOPC_YES", [P_TWOPC_NO] = "P_TWOPC_NO", [P_TWOPC_RETRY] = "P_TWOPC_RETRY", /* enum drbd_packet, but not commands - obsoleted flags: * P_MAY_IGNORE * P_MAX_OPT_CMD */ }; struct state_names drbd_packet_names = { .names = __packet_names, .size = sizeof __packet_names / sizeof __packet_names[0], }; const char *drbd_repl_str(enum drbd_repl_state s) { return (s < 0 || s >= drbd_repl_state_names.size || !drbd_repl_state_names.names[s]) ? "?" : drbd_repl_state_names.names[s]; } const char *drbd_conn_str(enum drbd_conn_state s) { return (s < 0 || s >= drbd_conn_state_names.size || !drbd_conn_state_names.names[s]) ? "?" : drbd_conn_state_names.names[s]; } const char *drbd_role_str(enum drbd_role s) { return (s < 0 || s >= drbd_role_state_names.size || !drbd_role_state_names.names[s]) ? "?" : drbd_role_state_names.names[s]; } const char *drbd_disk_str(enum drbd_disk_state s) { return (s < 0 || s >= drbd_disk_state_names.size || !drbd_disk_state_names.names[s]) ? "?" : drbd_disk_state_names.names[s]; } const char *drbd_set_st_err_str(enum drbd_state_rv err) { return (-err < 0 || -err >= drbd_error_messages.size || !drbd_error_messages.names[-err]) ? "?" : drbd_error_messages.names[-err]; } const char *drbd_packet_name(enum drbd_packet cmd) { /* too big for the array: 0xfffX */ if (cmd == P_INITIAL_META) return "InitialMeta"; if (cmd == P_INITIAL_DATA) return "InitialData"; if (cmd == P_CONNECTION_FEATURES) return "ConnectionFeatures"; return (cmd < 0 || cmd >= ARRAY_SIZE(__packet_names) || !__packet_names[cmd]) ? "?" : __packet_names[cmd]; } drbd-utils-8.9.6/drbd-headers/linux/0000755000175000017500000000000012654475367017211 5ustar apoikosapoikosdrbd-utils-8.9.6/drbd-headers/linux/genl_magic_func.h0000644000175000017500000002546012477341210022447 0ustar apoikosapoikos#ifndef GENL_MAGIC_FUNC_H #define GENL_MAGIC_FUNC_H #include /* * Magic: declare tla policy {{{1 * Magic: declare nested policies * {{{2 */ #undef GENL_mc_group #define GENL_mc_group(group) #undef GENL_notification #define GENL_notification(op_name, op_num, mcast_group, tla_list) #undef GENL_op #define GENL_op(op_name, op_num, handler, tla_list) #undef GENL_struct #define GENL_struct(tag_name, tag_number, s_name, s_fields) \ [tag_name] = { .type = NLA_NESTED }, static struct nla_policy CONCAT_(GENL_MAGIC_FAMILY, _tla_nl_policy)[] \ __attribute__((unused)) = { #include GENL_MAGIC_INCLUDE_FILE }; #undef GENL_struct #define GENL_struct(tag_name, tag_number, s_name, s_fields) \ static struct nla_policy s_name ## _nl_policy[] __read_mostly = \ { s_fields }; #undef __field #define __field(attr_nr, attr_flag, name, nla_type, _type, __get, \ __put, __is_signed) \ [attr_nr] = { .type = nla_type }, #undef __array #define __array(attr_nr, attr_flag, name, nla_type, _type, maxlen, \ __get, __put, __is_signed) \ [attr_nr] = { .type = nla_type, \ .len = maxlen - (nla_type == NLA_NUL_STRING) }, #include GENL_MAGIC_INCLUDE_FILE #ifndef __KERNEL__ #ifndef pr_info #define pr_info(args...) fprintf(stderr, args); #endif #endif #ifdef GENL_MAGIC_DEBUG static void dprint_field(const char *dir, int nla_type, const char *name, void *valp) { __u64 val = valp ? *(__u32 *)valp : 1; switch (nla_type) { case NLA_U8: val = (__u8)val; case NLA_U16: val = (__u16)val; case NLA_U32: val = (__u32)val; pr_info("%s attr %s: %d 0x%08x\n", dir, name, (int)val, (unsigned)val); break; case NLA_U64: val = *(__u64*)valp; pr_info("%s attr %s: %lld 0x%08llx\n", dir, name, (long long)val, (unsigned long long)val); break; case NLA_FLAG: if (val) pr_info("%s attr %s: set\n", dir, name); break; } } static void dprint_array(const char *dir, int nla_type, const char *name, const char *val, unsigned len) { switch (nla_type) { case NLA_NUL_STRING: if (len && val[len-1] == '\0') len--; pr_info("%s attr %s: [len:%u] '%s'\n", dir, name, len, val); break; default: /* we can always show 4 byte, * thats what nlattr are aligned to. */ pr_info("%s attr %s: [len:%u] %02x%02x%02x%02x ...\n", dir, name, len, val[0], val[1], val[2], val[3]); } } #define DPRINT_TLA(a, op, b) pr_info("%s %s %s\n", a, op, b); /* Name is a member field name of the struct s. * If s is NULL (only parsing, no copy requested in *_from_attrs()), * nla is supposed to point to the attribute containing the information * corresponding to that struct member. */ #define DPRINT_FIELD(dir, nla_type, name, s, nla) \ do { \ if (s) \ dprint_field(dir, nla_type, #name, &s->name); \ else if (nla) \ dprint_field(dir, nla_type, #name, \ (nla_type == NLA_FLAG) ? NULL \ : nla_data(nla)); \ } while (0) #define DPRINT_ARRAY(dir, nla_type, name, s, nla) \ do { \ if (s) \ dprint_array(dir, nla_type, #name, \ s->name, s->name ## _len); \ else if (nla) \ dprint_array(dir, nla_type, #name, \ nla_data(nla), nla_len(nla)); \ } while (0) #else #define DPRINT_TLA(a, op, b) do {} while (0) #define DPRINT_FIELD(dir, nla_type, name, s, nla) do {} while (0) #define DPRINT_ARRAY(dir, nla_type, name, s, nla) do {} while (0) #endif /* * Magic: provide conversion functions {{{1 * populate struct from attribute table: * {{{2 */ /* processing of generic netlink messages is serialized. * use one static buffer for parsing of nested attributes */ static struct nlattr *nested_attr_tb[128]; #undef GENL_struct #define GENL_struct(tag_name, tag_number, s_name, s_fields) \ static int __ ## s_name ## _from_attrs(struct s_name *s, \ struct genl_info *info, bool exclude_invariants) \ { \ const int maxtype = ARRAY_SIZE(s_name ## _nl_policy)-1; \ struct nlattr *tla = info->attrs[tag_number]; \ struct nlattr **ntb = nested_attr_tb; \ struct nlattr *nla; \ int err; \ BUILD_BUG_ON(ARRAY_SIZE(s_name ## _nl_policy) > ARRAY_SIZE(nested_attr_tb)); \ if (!tla) \ return -ENOMSG; \ DPRINT_TLA(#s_name, "<=-", #tag_name); \ err = drbd_nla_parse_nested(ntb, maxtype, tla, s_name ## _nl_policy); \ if (err) \ return err; \ \ s_fields \ return 0; \ } __attribute__((unused)) \ static int s_name ## _from_attrs(struct s_name *s, \ struct genl_info *info) \ { \ return __ ## s_name ## _from_attrs(s, info, false); \ } __attribute__((unused)) \ static int s_name ## _from_attrs_for_change(struct s_name *s, \ struct genl_info *info) \ { \ return __ ## s_name ## _from_attrs(s, info, true); \ } __attribute__((unused)) \ #define __assign(attr_nr, attr_flag, name, nla_type, type, assignment...) \ nla = ntb[attr_nr]; \ if (nla) { \ if (exclude_invariants && !!((attr_flag) & DRBD_F_INVARIANT)) { \ pr_info("<< must not change invariant attr: %s\n", #name); \ return -EEXIST; \ } \ assignment; \ } else if (exclude_invariants && !!((attr_flag) & DRBD_F_INVARIANT)) { \ /* attribute missing from payload, */ \ /* which was expected */ \ } else if ((attr_flag) & DRBD_F_REQUIRED) { \ pr_info("<< missing attr: %s\n", #name); \ return -ENOMSG; \ } #undef __field #define __field(attr_nr, attr_flag, name, nla_type, type, __get, __put, \ __is_signed) \ __assign(attr_nr, attr_flag, name, nla_type, type, \ if (s) \ s->name = __get(nla); \ DPRINT_FIELD("<<", nla_type, name, s, nla)) /* validate_nla() already checked nla_len <= maxlen appropriately. */ #undef __array #define __array(attr_nr, attr_flag, name, nla_type, type, maxlen, \ __get, __put, __is_signed) \ __assign(attr_nr, attr_flag, name, nla_type, type, \ if (s) \ s->name ## _len = \ __get(s->name, nla, maxlen); \ DPRINT_ARRAY("<<", nla_type, name, s, nla)) #include GENL_MAGIC_INCLUDE_FILE #undef GENL_struct #define GENL_struct(tag_name, tag_number, s_name, s_fields) /* * Magic: define op number to op name mapping {{{1 * {{{2 */ static const char *CONCAT_(GENL_MAGIC_FAMILY, _genl_cmd_to_str)(__u8 cmd) __attribute__ ((unused)); static const char *CONCAT_(GENL_MAGIC_FAMILY, _genl_cmd_to_str)(__u8 cmd) { switch (cmd) { #undef GENL_op #define GENL_op(op_name, op_num, handler, tla_list) \ case op_num: return #op_name; #include GENL_MAGIC_INCLUDE_FILE default: return "unknown"; } } #ifdef __KERNEL__ #include /* * Magic: define genl_ops {{{1 * {{{2 */ #undef GENL_op #define GENL_op(op_name, op_num, handler, tla_list) \ { \ handler \ .cmd = op_name, \ .policy = CONCAT_(GENL_MAGIC_FAMILY, _tla_nl_policy), \ }, #define ZZZ_genl_ops CONCAT_(GENL_MAGIC_FAMILY, _genl_ops) static struct genl_ops ZZZ_genl_ops[] __read_mostly = { #include GENL_MAGIC_INCLUDE_FILE }; #undef GENL_op #define GENL_op(op_name, op_num, handler, tla_list) /* * Define the genl_family, multicast groups, {{{1 * and provide register/unregister functions. * {{{2 */ #define ZZZ_genl_family CONCAT_(GENL_MAGIC_FAMILY, _genl_family) static struct genl_family ZZZ_genl_family __read_mostly = { .id = GENL_ID_GENERATE, .name = __stringify(GENL_MAGIC_FAMILY), .version = GENL_MAGIC_VERSION, #ifdef GENL_MAGIC_FAMILY_HDRSZ .hdrsize = NLA_ALIGN(GENL_MAGIC_FAMILY_HDRSZ), #endif .maxattr = ARRAY_SIZE(drbd_tla_nl_policy)-1, }; /* * Magic: define multicast groups * Magic: define multicast group registration helper */ /* COMPAT * See linux 3.13, * genetlink: make multicast groups const, prevent abuse * genetlink: pass family to functions using groups * genetlink: only pass array to genl_register_family_with_ops() * which are commits c53ed742..2a94fe48 */ #ifdef genl_register_family_with_ops_groups #include #else #include #endif /* * Magic: provide conversion functions {{{1 * populate skb from struct. * {{{2 */ #undef GENL_op #define GENL_op(op_name, op_num, handler, tla_list) #undef GENL_struct #define GENL_struct(tag_name, tag_number, s_name, s_fields) \ static int s_name ## _to_skb(struct sk_buff *skb, struct s_name *s, \ const bool exclude_sensitive) \ { \ struct nlattr *tla = nla_nest_start(skb, tag_number); \ if (!tla) \ goto nla_put_failure; \ DPRINT_TLA(#s_name, "-=>", #tag_name); \ s_fields \ nla_nest_end(skb, tla); \ return 0; \ \ nla_put_failure: \ if (tla) \ nla_nest_cancel(skb, tla); \ return -EMSGSIZE; \ } \ static inline int s_name ## _to_priv_skb(struct sk_buff *skb, \ struct s_name *s) \ { \ return s_name ## _to_skb(skb, s, 0); \ } \ static inline int s_name ## _to_unpriv_skb(struct sk_buff *skb, \ struct s_name *s) \ { \ return s_name ## _to_skb(skb, s, 1); \ } #undef __field #define __field(attr_nr, attr_flag, name, nla_type, type, __get, __put, \ __is_signed) \ if (!exclude_sensitive || !((attr_flag) & DRBD_F_SENSITIVE)) { \ DPRINT_FIELD(">>", nla_type, name, s, NULL); \ if (__put(skb, attr_nr, s->name)) \ goto nla_put_failure; \ } #undef __array #define __array(attr_nr, attr_flag, name, nla_type, type, maxlen, \ __get, __put, __is_signed) \ if (!exclude_sensitive || !((attr_flag) & DRBD_F_SENSITIVE)) { \ DPRINT_ARRAY(">>",nla_type, name, s, NULL); \ if (__put(skb, attr_nr, min_t(int, maxlen, \ s->name ## _len + (nla_type == NLA_NUL_STRING)),\ s->name)) \ goto nla_put_failure; \ } #include GENL_MAGIC_INCLUDE_FILE /* Functions for initializing structs to default values. */ #undef __field #define __field(attr_nr, attr_flag, name, nla_type, type, __get, __put, \ __is_signed) #undef __array #define __array(attr_nr, attr_flag, name, nla_type, type, maxlen, \ __get, __put, __is_signed) #undef __u32_field_def #define __u32_field_def(attr_nr, attr_flag, name, default) \ x->name = default; #undef __s32_field_def #define __s32_field_def(attr_nr, attr_flag, name, default) \ x->name = default; #undef __flg_field_def #define __flg_field_def(attr_nr, attr_flag, name, default) \ x->name = default; #undef __str_field_def #define __str_field_def(attr_nr, attr_flag, name, maxlen) \ memset(x->name, 0, sizeof(x->name)); \ x->name ## _len = 0; #undef GENL_struct #define GENL_struct(tag_name, tag_number, s_name, s_fields) \ static void set_ ## s_name ## _defaults(struct s_name *x) __attribute__((unused)); \ static void set_ ## s_name ## _defaults(struct s_name *x) { \ s_fields \ } #include GENL_MAGIC_INCLUDE_FILE #endif /* __KERNEL__ */ /* }}}1 */ #endif /* GENL_MAGIC_FUNC_H */ /* vim: set foldmethod=marker foldlevel=1 nofoldenable : */ drbd-utils-8.9.6/drbd-headers/linux/drbd_genl.h0000644000175000017500000005333012634301701021260 0ustar apoikosapoikos/* * General overview: * full generic netlink message: * |nlmsghdr|genlmsghdr| * * payload: * |optional fixed size family header| * * sequence of netlink attributes: * I chose to have all "top level" attributes NLA_NESTED, * corresponding to some real struct. * So we have a sequence of |tla, len| * * nested nla sequence: * may be empty, or contain a sequence of netlink attributes * representing the struct fields. * * The tag number of any field (regardless of containing struct) * will be available as T_ ## field_name, * so you cannot have the same field name in two differnt structs. * * The tag numbers themselves are per struct, though, * so should always begin at 1 (not 0, that is the special "NLA_UNSPEC" type, * which we won't use here). * The tag numbers are used as index in the respective nla_policy array. * * GENL_struct(tag_name, tag_number, struct name, struct fields) - struct and policy * genl_magic_struct.h * generates the struct declaration, * generates an entry in the tla enum, * genl_magic_func.h * generates an entry in the static tla policy * with .type = NLA_NESTED * generates the static _nl_policy definition, * and static conversion functions * * genl_magic_func.h * * GENL_mc_group(group) * genl_magic_struct.h * does nothing * genl_magic_func.h * defines and registers the mcast group, * and provides a send helper * * GENL_notification(op_name, op_num, mcast_group, tla list) * These are notifications to userspace. * * genl_magic_struct.h * generates an entry in the genl_ops enum, * genl_magic_func.h * does nothing * * mcast group: the name of the mcast group this notification should be * expected on * tla list: the list of expected top level attributes, * for documentation and sanity checking. * * GENL_op(op_name, op_num, flags and handler, tla list) - "genl operations" * These are requests from userspace. * * _op and _notification share the same "number space", * op_nr will be assigned to "genlmsghdr->cmd" * * genl_magic_struct.h * generates an entry in the genl_ops enum, * genl_magic_func.h * generates an entry in the static genl_ops array, * and static register/unregister functions to * genl_register_family_with_ops(). * * flags and handler: * GENL_op_init( .doit = x, .dumpit = y, .flags = something) * GENL_doit(x) => .dumpit = NULL, .flags = GENL_ADMIN_PERM * tla list: the list of expected top level attributes, * for documentation and sanity checking. */ /* * STRUCTS */ /* this is sent kernel -> userland on various error conditions, and contains * informational textual info, which is supposedly human readable. * The computer relevant return code is in the drbd_genlmsghdr. */ GENL_struct(DRBD_NLA_CFG_REPLY, 1, drbd_cfg_reply, /* "arbitrary" size strings, nla_policy.len = 0 */ __str_field(1, DRBD_GENLA_F_MANDATORY, info_text, 0) ) /* Configuration requests typically need a context to operate on. * Possible keys are device minor (fits in the drbd_genlmsghdr), * the replication link (aka connection) name, * and/or the replication group (aka resource) name, * and the volume id within the resource. */ GENL_struct(DRBD_NLA_CFG_CONTEXT, 2, drbd_cfg_context, __u32_field(6, DRBD_GENLA_F_MANDATORY, ctx_peer_node_id) __u32_field(1, DRBD_GENLA_F_MANDATORY, ctx_volume) __str_field(2, DRBD_GENLA_F_MANDATORY, ctx_resource_name, 128) __bin_field(3, DRBD_GENLA_F_MANDATORY, ctx_my_addr, 128) __bin_field(4, DRBD_GENLA_F_MANDATORY, ctx_peer_addr, 128) __str_field_def(5, 0, ctx_conn_name, SHARED_SECRET_MAX) ) GENL_struct(DRBD_NLA_DISK_CONF, 3, disk_conf, __str_field(1, DRBD_F_REQUIRED | DRBD_F_INVARIANT, backing_dev, 128) __str_field(2, DRBD_F_REQUIRED | DRBD_F_INVARIANT, meta_dev, 128) __s32_field(3, DRBD_F_REQUIRED | DRBD_F_INVARIANT, meta_dev_idx) /* use the resize command to try and change the disk_size */ __u64_field(4, DRBD_GENLA_F_MANDATORY | DRBD_F_INVARIANT, disk_size) /*__u32_field(5, DRBD_GENLA_F_MANDATORY | DRBD_F_INVARIANT, max_bio_bvecs)*/ __u32_field_def(6, DRBD_GENLA_F_MANDATORY, on_io_error, DRBD_ON_IO_ERROR_DEF) /*__u32_field_def(7, DRBD_GENLA_F_MANDATORY, fencing_policy, DRBD_FENCING_DEF)*/ __s32_field_def(9, DRBD_GENLA_F_MANDATORY, resync_after, DRBD_MINOR_NUMBER_DEF) __u32_field_def(10, DRBD_GENLA_F_MANDATORY, al_extents, DRBD_AL_EXTENTS_DEF) __flg_field_def(16, DRBD_GENLA_F_MANDATORY, disk_barrier, DRBD_DISK_BARRIER_DEF) __flg_field_def(17, DRBD_GENLA_F_MANDATORY, disk_flushes, DRBD_DISK_FLUSHES_DEF) __flg_field_def(18, DRBD_GENLA_F_MANDATORY, disk_drain, DRBD_DISK_DRAIN_DEF) __flg_field_def(19, DRBD_GENLA_F_MANDATORY, md_flushes, DRBD_MD_FLUSHES_DEF) __u32_field_def(20, DRBD_GENLA_F_MANDATORY, disk_timeout, DRBD_DISK_TIMEOUT_DEF) __u32_field_def(21, DRBD_GENLA_F_MANDATORY, read_balancing, DRBD_READ_BALANCING_DEF) __u32_field_def(22, DRBD_GENLA_F_MANDATORY, unplug_watermark, DRBD_UNPLUG_WATERMARK_DEF) __u32_field_def(25, 0 /* OPTIONAL */, rs_discard_granularity, DRBD_RS_DISCARD_GRANULARITY_DEF) __flg_field_def(23, 0 /* OPTIONAL */, al_updates, DRBD_AL_UPDATES_DEF) __flg_field_def(24, 0 /* OPTIONAL */, discard_zeroes_if_aligned, DRBD_DISCARD_ZEROES_IF_ALIGNED_DEF) ) GENL_struct(DRBD_NLA_RESOURCE_OPTS, 4, res_opts, __str_field_def(1, DRBD_GENLA_F_MANDATORY, cpu_mask, DRBD_CPU_MASK_SIZE) __u32_field_def(2, DRBD_GENLA_F_MANDATORY, on_no_data, DRBD_ON_NO_DATA_DEF) __flg_field_def(3, DRBD_GENLA_F_MANDATORY, auto_promote, DRBD_AUTO_PROMOTE_DEF) __u32_field(4, DRBD_F_REQUIRED | DRBD_F_INVARIANT, node_id) __u32_field_def(5, DRBD_GENLA_F_MANDATORY, peer_ack_window, DRBD_PEER_ACK_WINDOW_DEF) __u32_field_def(6, DRBD_GENLA_F_MANDATORY, twopc_timeout, DRBD_TWOPC_TIMEOUT_DEF) __u32_field_def(7, DRBD_GENLA_F_MANDATORY, twopc_retry_timeout, DRBD_TWOPC_RETRY_TIMEOUT_DEF) __u32_field_def(8, 0 /* OPTIONAL */, peer_ack_delay, DRBD_PEER_ACK_DELAY_DEF) __u32_field_def(9, 0 /* OPTIONAL */, auto_promote_timeout, DRBD_AUTO_PROMOTE_TIMEOUT_DEF) ) GENL_struct(DRBD_NLA_NET_CONF, 5, net_conf, __str_field_def(1, DRBD_GENLA_F_MANDATORY | DRBD_F_SENSITIVE, shared_secret, SHARED_SECRET_MAX) __str_field_def(2, DRBD_GENLA_F_MANDATORY, cram_hmac_alg, SHARED_SECRET_MAX) __str_field_def(3, DRBD_GENLA_F_MANDATORY, integrity_alg, SHARED_SECRET_MAX) __str_field_def(4, DRBD_GENLA_F_MANDATORY, verify_alg, SHARED_SECRET_MAX) __str_field_def(5, DRBD_GENLA_F_MANDATORY, csums_alg, SHARED_SECRET_MAX) __u32_field_def(6, DRBD_GENLA_F_MANDATORY, wire_protocol, DRBD_PROTOCOL_DEF) __u32_field_def(7, DRBD_GENLA_F_MANDATORY, connect_int, DRBD_CONNECT_INT_DEF) __u32_field_def(8, DRBD_GENLA_F_MANDATORY, timeout, DRBD_TIMEOUT_DEF) __u32_field_def(9, DRBD_GENLA_F_MANDATORY, ping_int, DRBD_PING_INT_DEF) __u32_field_def(10, DRBD_GENLA_F_MANDATORY, ping_timeo, DRBD_PING_TIMEO_DEF) __u32_field_def(11, DRBD_GENLA_F_MANDATORY, sndbuf_size, DRBD_SNDBUF_SIZE_DEF) __u32_field_def(12, DRBD_GENLA_F_MANDATORY, rcvbuf_size, DRBD_RCVBUF_SIZE_DEF) __u32_field_def(13, DRBD_GENLA_F_MANDATORY, ko_count, DRBD_KO_COUNT_DEF) __u32_field_def(15, DRBD_GENLA_F_MANDATORY, max_epoch_size, DRBD_MAX_EPOCH_SIZE_DEF) __u32_field_def(17, DRBD_GENLA_F_MANDATORY, after_sb_0p, DRBD_AFTER_SB_0P_DEF) __u32_field_def(18, DRBD_GENLA_F_MANDATORY, after_sb_1p, DRBD_AFTER_SB_1P_DEF) __u32_field_def(19, DRBD_GENLA_F_MANDATORY, after_sb_2p, DRBD_AFTER_SB_2P_DEF) __u32_field_def(20, DRBD_GENLA_F_MANDATORY, rr_conflict, DRBD_RR_CONFLICT_DEF) __u32_field_def(21, DRBD_GENLA_F_MANDATORY, on_congestion, DRBD_ON_CONGESTION_DEF) __u32_field_def(22, DRBD_GENLA_F_MANDATORY, cong_fill, DRBD_CONG_FILL_DEF) __u32_field_def(23, DRBD_GENLA_F_MANDATORY, cong_extents, DRBD_CONG_EXTENTS_DEF) __flg_field_def(24, DRBD_GENLA_F_MANDATORY, two_primaries, DRBD_ALLOW_TWO_PRIMARIES_DEF) __flg_field_def(26, DRBD_GENLA_F_MANDATORY, tcp_cork, DRBD_TCP_CORK_DEF) __flg_field_def(27, DRBD_GENLA_F_MANDATORY, always_asbp, DRBD_ALWAYS_ASBP_DEF) __flg_field_def(29, DRBD_GENLA_F_MANDATORY, use_rle, DRBD_USE_RLE_DEF) __u32_field_def(30, DRBD_GENLA_F_MANDATORY, fencing_policy, DRBD_FENCING_DEF) __str_field_def(31, DRBD_GENLA_F_MANDATORY, name, SHARED_SECRET_MAX) /* moved into ctx_peer_node_id: __u32_field(32, DRBD_F_REQUIRED | DRBD_F_INVARIANT, peer_node_id) */ __flg_field_def(33, 0 /* OPTIONAL */, csums_after_crash_only, DRBD_CSUMS_AFTER_CRASH_ONLY_DEF) __u32_field_def(34, 0 /* OPTIONAL */, sock_check_timeo, DRBD_SOCKET_CHECK_TIMEO_DEF) __str_field_def(35, DRBD_F_INVARIANT, transport_name, SHARED_SECRET_MAX) __u32_field_def(36, 0 /* OPTIONAL */, max_buffers, DRBD_MAX_BUFFERS_DEF) ) GENL_struct(DRBD_NLA_SET_ROLE_PARMS, 6, set_role_parms, __flg_field(1, DRBD_GENLA_F_MANDATORY, assume_uptodate) ) GENL_struct(DRBD_NLA_RESIZE_PARMS, 7, resize_parms, __u64_field(1, DRBD_GENLA_F_MANDATORY, resize_size) __flg_field(2, DRBD_GENLA_F_MANDATORY, resize_force) __flg_field(3, DRBD_GENLA_F_MANDATORY, no_resync) __u32_field_def(4, 0 /* OPTIONAL */, al_stripes, DRBD_AL_STRIPES_DEF) __u32_field_def(5, 0 /* OPTIONAL */, al_stripe_size, DRBD_AL_STRIPE_SIZE_DEF) ) GENL_struct(DRBD_NLA_START_OV_PARMS, 9, start_ov_parms, __u64_field(1, DRBD_GENLA_F_MANDATORY, ov_start_sector) __u64_field(2, DRBD_GENLA_F_MANDATORY, ov_stop_sector) ) GENL_struct(DRBD_NLA_NEW_C_UUID_PARMS, 10, new_c_uuid_parms, __flg_field(1, DRBD_GENLA_F_MANDATORY, clear_bm) ) GENL_struct(DRBD_NLA_TIMEOUT_PARMS, 11, timeout_parms, __u32_field(1, DRBD_F_REQUIRED, timeout_type) ) GENL_struct(DRBD_NLA_DISCONNECT_PARMS, 12, disconnect_parms, __flg_field(1, DRBD_GENLA_F_MANDATORY, force_disconnect) ) GENL_struct(DRBD_NLA_DETACH_PARMS, 13, detach_parms, __flg_field(1, DRBD_GENLA_F_MANDATORY, force_detach) ) GENL_struct(DRBD_NLA_DEVICE_CONF, 14, device_conf, __u32_field_def(1, DRBD_F_INVARIANT, max_bio_size, DRBD_MAX_BIO_SIZE_DEF) ) GENL_struct(DRBD_NLA_RESOURCE_INFO, 15, resource_info, __u32_field(1, 0, res_role) __flg_field(2, 0, res_susp) __flg_field(3, 0, res_susp_nod) __flg_field(4, 0, res_susp_fen) ) GENL_struct(DRBD_NLA_DEVICE_INFO, 16, device_info, __u32_field(1, 0, dev_disk_state) ) GENL_struct(DRBD_NLA_CONNECTION_INFO, 17, connection_info, __u32_field(1, 0, conn_connection_state) __u32_field(2, 0, conn_role) ) GENL_struct(DRBD_NLA_PEER_DEVICE_INFO, 18, peer_device_info, __u32_field(1, 0, peer_repl_state) __u32_field(2, 0, peer_disk_state) __u32_field(3, 0, peer_resync_susp_user) __u32_field(4, 0, peer_resync_susp_peer) __u32_field(5, 0, peer_resync_susp_dependency) ) GENL_struct(DRBD_NLA_RESOURCE_STATISTICS, 19, resource_statistics, __u32_field(1, 0, res_stat_write_ordering) ) GENL_struct(DRBD_NLA_DEVICE_STATISTICS, 20, device_statistics, __u64_field(1, 0, dev_size) /* (sectors) */ __u64_field(2, 0, dev_read) /* (sectors) */ __u64_field(3, 0, dev_write) /* (sectors) */ __u64_field(4, 0, dev_al_writes) /* activity log writes (count) */ __u64_field(5, 0, dev_bm_writes) /* bitmap writes (count) */ __u32_field(6, 0, dev_upper_pending) /* application requests in progress */ __u32_field(7, 0, dev_lower_pending) /* backing device requests in progress */ __flg_field(8, 0, dev_upper_blocked) __flg_field(9, 0, dev_lower_blocked) __flg_field(10, 0, dev_al_suspended) /* activity log suspended */ __u64_field(11, 0, dev_exposed_data_uuid) __u64_field(12, 0, dev_current_uuid) __u32_field(13, 0, dev_disk_flags) __bin_field(14, 0, history_uuids, HISTORY_UUIDS * sizeof(__u64)) ) GENL_struct(DRBD_NLA_CONNECTION_STATISTICS, 21, connection_statistics, __flg_field(1, 0, conn_congested) ) GENL_struct(DRBD_NLA_PEER_DEVICE_STATISTICS, 22, peer_device_statistics, __u64_field(1, 0, peer_dev_received) /* sectors */ __u64_field(2, 0, peer_dev_sent) /* sectors */ __u32_field(3, 0, peer_dev_pending) /* number of requests */ __u32_field(4, 0, peer_dev_unacked) /* number of requests */ __u64_field(5, 0, peer_dev_out_of_sync) /* sectors */ __u64_field(6, 0, peer_dev_resync_failed) /* sectors */ __u64_field(7, 0, peer_dev_bitmap_uuid) __u32_field(9, 0, peer_dev_flags) ) GENL_struct(DRBD_NLA_NOTIFICATION_HEADER, 23, drbd_notification_header, __u32_field(1, DRBD_GENLA_F_MANDATORY, nh_type) ) GENL_struct(DRBD_NLA_HELPER, 24, drbd_helper_info, __str_field(1, DRBD_GENLA_F_MANDATORY, helper_name, 32) __u32_field(2, DRBD_GENLA_F_MANDATORY, helper_status) ) GENL_struct(DRBD_NLA_INVALIDATE_PARMS, 25, invalidate_parms, __s32_field_def(1, DRBD_GENLA_F_MANDATORY, sync_from_peer_node_id, DRBD_SYNC_FROM_NID_DEF) ) GENL_struct(DRBD_NLA_FORGET_PEER_PARMS, 26, forget_peer_parms, __s32_field_def(1, DRBD_GENLA_F_MANDATORY, forget_peer_node_id, DRBD_SYNC_FROM_NID_DEF) ) GENL_struct(DRBD_NLA_PEER_DEVICE_OPTS, 27, peer_device_conf, __u32_field_def(1, DRBD_GENLA_F_MANDATORY, resync_rate, DRBD_RESYNC_RATE_DEF) __u32_field_def(2, DRBD_GENLA_F_MANDATORY, c_plan_ahead, DRBD_C_PLAN_AHEAD_DEF) __u32_field_def(3, DRBD_GENLA_F_MANDATORY, c_delay_target, DRBD_C_DELAY_TARGET_DEF) __u32_field_def(4, DRBD_GENLA_F_MANDATORY, c_fill_target, DRBD_C_FILL_TARGET_DEF) __u32_field_def(5, DRBD_GENLA_F_MANDATORY, c_max_rate, DRBD_C_MAX_RATE_DEF) __u32_field_def(6, DRBD_GENLA_F_MANDATORY, c_min_rate, DRBD_C_MIN_RATE_DEF) ) GENL_struct(DRBD_NLA_PATH_PARMS, 28, path_parms, __bin_field(1, DRBD_GENLA_F_MANDATORY, my_addr, 128) __bin_field(2, DRBD_GENLA_F_MANDATORY, peer_addr, 128) ) GENL_struct(DRBD_NLA_CONNECT_PARMS, 29, connect_parms, __flg_field_def(1, DRBD_GENLA_F_MANDATORY, tentative, 0) __flg_field_def(2, DRBD_GENLA_F_MANDATORY, discard_my_data, 0) ) GENL_struct(DRBD_NLA_PATH_INFO, 30, drbd_path_info, __flg_field(1, 0, path_established) ) /* * Notifications and commands (genlmsghdr->cmd) */ GENL_mc_group(events) /* add DRBD minor devices as volumes to resources */ GENL_op(DRBD_ADM_NEW_MINOR, 5, GENL_doit(drbd_adm_new_minor), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_DEVICE_CONF, DRBD_GENLA_F_MANDATORY)) GENL_op(DRBD_ADM_DEL_MINOR, 6, GENL_doit(drbd_adm_del_minor), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED)) /* add or delete resources */ GENL_op(DRBD_ADM_NEW_RESOURCE, 7, GENL_doit(drbd_adm_new_resource), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED)) GENL_op(DRBD_ADM_DEL_RESOURCE, 8, GENL_doit(drbd_adm_del_resource), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED)) GENL_op(DRBD_ADM_RESOURCE_OPTS, 9, GENL_doit(drbd_adm_resource_opts), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_RESOURCE_OPTS, DRBD_GENLA_F_MANDATORY) ) GENL_op(DRBD_ADM_NEW_PEER, 44, GENL_doit(drbd_adm_new_peer), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_NET_CONF, DRBD_GENLA_F_MANDATORY) ) GENL_op(DRBD_ADM_NEW_PATH, 45, GENL_doit(drbd_adm_new_path), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_PATH_PARMS, DRBD_F_REQUIRED) ) GENL_op(DRBD_ADM_DEL_PEER, 46, GENL_doit(drbd_adm_del_peer), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_DISCONNECT_PARMS, DRBD_GENLA_F_MANDATORY) ) GENL_op(DRBD_ADM_DEL_PATH, 47, GENL_doit(drbd_adm_del_path), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_PATH_PARMS, DRBD_F_REQUIRED) ) GENL_op(DRBD_ADM_CONNECT, 10, GENL_doit(drbd_adm_connect), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_CONNECT_PARMS, DRBD_GENLA_F_MANDATORY) ) GENL_op( DRBD_ADM_CHG_NET_OPTS, 29, GENL_doit(drbd_adm_net_opts), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_NET_CONF, DRBD_F_REQUIRED) ) GENL_op(DRBD_ADM_DISCONNECT, 11, GENL_doit(drbd_adm_disconnect), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_DISCONNECT_PARMS, DRBD_GENLA_F_MANDATORY) ) GENL_op(DRBD_ADM_ATTACH, 12, GENL_doit(drbd_adm_attach), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_DISK_CONF, DRBD_F_REQUIRED) ) GENL_op(DRBD_ADM_CHG_DISK_OPTS, 28, GENL_doit(drbd_adm_disk_opts), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_DISK_OPTS, DRBD_F_REQUIRED) ) GENL_op( DRBD_ADM_RESIZE, 13, GENL_doit(drbd_adm_resize), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_RESIZE_PARMS, DRBD_GENLA_F_MANDATORY) ) GENL_op( DRBD_ADM_PRIMARY, 14, GENL_doit(drbd_adm_set_role), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_SET_ROLE_PARMS, DRBD_F_REQUIRED) ) GENL_op( DRBD_ADM_SECONDARY, 15, GENL_doit(drbd_adm_set_role), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_SET_ROLE_PARMS, DRBD_F_REQUIRED) ) GENL_op( DRBD_ADM_NEW_C_UUID, 16, GENL_doit(drbd_adm_new_c_uuid), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_NEW_C_UUID_PARMS, DRBD_GENLA_F_MANDATORY) ) GENL_op( DRBD_ADM_START_OV, 17, GENL_doit(drbd_adm_start_ov), GENL_tla_expected(DRBD_NLA_START_OV_PARMS, DRBD_GENLA_F_MANDATORY) ) GENL_op(DRBD_ADM_DETACH, 18, GENL_doit(drbd_adm_detach), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_DETACH_PARMS, DRBD_GENLA_F_MANDATORY)) GENL_op(DRBD_ADM_INVALIDATE, 19, GENL_doit(drbd_adm_invalidate), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_INVALIDATE_PARMS, DRBD_F_REQUIRED)) GENL_op(DRBD_ADM_INVAL_PEER, 20, GENL_doit(drbd_adm_invalidate_peer), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED)) GENL_op(DRBD_ADM_PAUSE_SYNC, 21, GENL_doit(drbd_adm_pause_sync), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED)) GENL_op(DRBD_ADM_RESUME_SYNC, 22, GENL_doit(drbd_adm_resume_sync), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED)) GENL_op(DRBD_ADM_SUSPEND_IO, 23, GENL_doit(drbd_adm_suspend_io), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED)) GENL_op(DRBD_ADM_RESUME_IO, 24, GENL_doit(drbd_adm_resume_io), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED)) GENL_op(DRBD_ADM_OUTDATE, 25, GENL_doit(drbd_adm_outdate), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED)) GENL_op(DRBD_ADM_GET_TIMEOUT_TYPE, 26, GENL_doit(drbd_adm_get_timeout_type), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED)) GENL_op(DRBD_ADM_DOWN, 27, GENL_doit(drbd_adm_down), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED)) GENL_op(DRBD_ADM_GET_RESOURCES, 30, GENL_op_init( .dumpit = drbd_adm_dump_resources, ), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_GENLA_F_MANDATORY) GENL_tla_expected(DRBD_NLA_RESOURCE_INFO, DRBD_GENLA_F_MANDATORY) GENL_tla_expected(DRBD_NLA_RESOURCE_STATISTICS, DRBD_GENLA_F_MANDATORY)) GENL_op(DRBD_ADM_GET_DEVICES, 31, GENL_op_init( .dumpit = drbd_adm_dump_devices, .done = drbd_adm_dump_devices_done, ), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_GENLA_F_MANDATORY) GENL_tla_expected(DRBD_NLA_DEVICE_INFO, DRBD_GENLA_F_MANDATORY) GENL_tla_expected(DRBD_NLA_DEVICE_STATISTICS, DRBD_GENLA_F_MANDATORY)) GENL_op(DRBD_ADM_GET_CONNECTIONS, 32, GENL_op_init( .dumpit = drbd_adm_dump_connections, .done = drbd_adm_dump_connections_done, ), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_GENLA_F_MANDATORY) GENL_tla_expected(DRBD_NLA_CONNECTION_INFO, DRBD_GENLA_F_MANDATORY) GENL_tla_expected(DRBD_NLA_CONNECTION_STATISTICS, DRBD_GENLA_F_MANDATORY)) GENL_op(DRBD_ADM_GET_PEER_DEVICES, 33, GENL_op_init( .dumpit = drbd_adm_dump_peer_devices, .done = drbd_adm_dump_peer_devices_done, ), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_GENLA_F_MANDATORY) GENL_tla_expected(DRBD_NLA_PEER_DEVICE_INFO, DRBD_GENLA_F_MANDATORY) GENL_tla_expected(DRBD_NLA_PEER_DEVICE_STATISTICS, DRBD_GENLA_F_MANDATORY)) GENL_notification( DRBD_RESOURCE_STATE, 34, events, GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_NOTIFICATION_HEADER, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_RESOURCE_INFO, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_RESOURCE_STATISTICS, DRBD_F_REQUIRED)) GENL_notification( DRBD_DEVICE_STATE, 35, events, GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_NOTIFICATION_HEADER, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_DEVICE_INFO, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_DEVICE_STATISTICS, DRBD_F_REQUIRED)) GENL_notification( DRBD_CONNECTION_STATE, 36, events, GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_NOTIFICATION_HEADER, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_PATH_PARMS, DRBD_GENLA_F_MANDATORY) GENL_tla_expected(DRBD_NLA_CONNECTION_INFO, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_CONNECTION_STATISTICS, DRBD_F_REQUIRED)) GENL_notification( DRBD_PEER_DEVICE_STATE, 37, events, GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_NOTIFICATION_HEADER, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_PEER_DEVICE_INFO, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_PEER_DEVICE_STATISTICS, DRBD_F_REQUIRED)) GENL_op( DRBD_ADM_GET_INITIAL_STATE, 38, GENL_op_init( .dumpit = drbd_adm_get_initial_state, ), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_GENLA_F_MANDATORY)) GENL_notification( DRBD_HELPER, 40, events, GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_HELPER, DRBD_F_REQUIRED)) GENL_notification( DRBD_INITIAL_STATE_DONE, 41, events, GENL_tla_expected(DRBD_NLA_NOTIFICATION_HEADER, DRBD_F_REQUIRED)) GENL_op(DRBD_ADM_FORGET_PEER, 42, GENL_doit(drbd_adm_forget_peer), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_FORGET_PEER_PARMS, DRBD_F_REQUIRED)) GENL_op(DRBD_ADM_CHG_PEER_DEVICE_OPTS, 43, GENL_doit(drbd_adm_peer_device_opts), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_PEER_DEVICE_OPTS, DRBD_F_REQUIRED)) GENL_notification( DRBD_PATH_STATE, 48, events, GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_PATH_INFO, DRBD_F_REQUIRED)) drbd-utils-8.9.6/drbd-headers/linux/genl_magic_struct.h0000644000175000017500000001673012477341210023040 0ustar apoikosapoikos#ifndef GENL_MAGIC_STRUCT_H #define GENL_MAGIC_STRUCT_H #ifndef GENL_MAGIC_FAMILY # error "you need to define GENL_MAGIC_FAMILY before inclusion" #endif #ifndef GENL_MAGIC_VERSION # error "you need to define GENL_MAGIC_VERSION before inclusion" #endif #ifndef GENL_MAGIC_INCLUDE_FILE # error "you need to define GENL_MAGIC_INCLUDE_FILE before inclusion" #endif #include #include #include #define CONCAT__(a,b) a ## b #define CONCAT_(a,b) CONCAT__(a,b) extern int CONCAT_(GENL_MAGIC_FAMILY, _genl_register)(void); extern void CONCAT_(GENL_MAGIC_FAMILY, _genl_unregister)(void); /* * Extension of genl attribute validation policies {{{2 */ /* * @DRBD_GENLA_F_MANDATORY: By default, netlink ignores attributes it does not * know about. This flag can be set in nlattr->nla_type to indicate that this * attribute must not be ignored. * * We check and remove this flag in drbd_nla_check_mandatory() before * validating the attribute types and lengths via nla_parse_nested(). */ #define DRBD_GENLA_F_MANDATORY (1 << 14) /* * Flags specific to drbd and not visible at the netlink layer, used in * _from_attrs and _to_skb: * * @DRBD_F_REQUIRED: Attribute is required; a request without this attribute is * invalid. * * @DRBD_F_SENSITIVE: Attribute includes sensitive information and must not be * included in unpriviledged get requests or broadcasts. * * @DRBD_F_INVARIANT: Attribute is set when an object is initially created, but * cannot subsequently be changed. */ #define DRBD_F_REQUIRED (1 << 0) #define DRBD_F_SENSITIVE (1 << 1) #define DRBD_F_INVARIANT (1 << 2) #define __nla_type(x) ((__u16)((x) & NLA_TYPE_MASK & ~DRBD_GENLA_F_MANDATORY)) /* }}}1 * MAGIC * multi-include macro expansion magic starts here */ /* MAGIC helpers {{{2 */ /* possible field types */ #define __flg_field(attr_nr, attr_flag, name) \ __field(attr_nr, attr_flag, name, NLA_U8, char, \ nla_get_u8, nla_put_u8, false) #define __u8_field(attr_nr, attr_flag, name) \ __field(attr_nr, attr_flag, name, NLA_U8, unsigned char, \ nla_get_u8, nla_put_u8, false) #define __u16_field(attr_nr, attr_flag, name) \ __field(attr_nr, attr_flag, name, NLA_U16, __u16, \ nla_get_u16, nla_put_u16, false) #define __u32_field(attr_nr, attr_flag, name) \ __field(attr_nr, attr_flag, name, NLA_U32, __u32, \ nla_get_u32, nla_put_u32, false) #define __s32_field(attr_nr, attr_flag, name) \ __field(attr_nr, attr_flag, name, NLA_U32, __s32, \ nla_get_u32, nla_put_u32, true) #define __u64_field(attr_nr, attr_flag, name) \ __field(attr_nr, attr_flag, name, NLA_U64, __u64, \ nla_get_u64, nla_put_u64, false) #define __str_field(attr_nr, attr_flag, name, maxlen) \ __array(attr_nr, attr_flag, name, NLA_NUL_STRING, char, maxlen, \ nla_strlcpy, nla_put, false) #define __bin_field(attr_nr, attr_flag, name, maxlen) \ __array(attr_nr, attr_flag, name, NLA_BINARY, char, maxlen, \ nla_memcpy, nla_put, false) /* fields with default values */ #define __flg_field_def(attr_nr, attr_flag, name, default) \ __flg_field(attr_nr, attr_flag, name) #define __u32_field_def(attr_nr, attr_flag, name, default) \ __u32_field(attr_nr, attr_flag, name) #define __s32_field_def(attr_nr, attr_flag, name, default) \ __s32_field(attr_nr, attr_flag, name) #define __str_field_def(attr_nr, attr_flag, name, maxlen) \ __str_field(attr_nr, attr_flag, name, maxlen) #define GENL_op_init(args...) args #define GENL_doit(handler) \ .doit = handler, \ .flags = GENL_ADMIN_PERM, #define GENL_dumpit(handler) \ .dumpit = handler, \ .flags = GENL_ADMIN_PERM, /* }}}1 * Magic: define the enum symbols for genl_ops * Magic: define the enum symbols for top level attributes * Magic: define the enum symbols for nested attributes * {{{2 */ #undef GENL_struct #define GENL_struct(tag_name, tag_number, s_name, s_fields) #undef GENL_mc_group #define GENL_mc_group(group) #undef GENL_notification #define GENL_notification(op_name, op_num, mcast_group, tla_list) \ op_name = op_num, #undef GENL_op #define GENL_op(op_name, op_num, handler, tla_list) \ op_name = op_num, enum { #include GENL_MAGIC_INCLUDE_FILE }; #undef GENL_notification #define GENL_notification(op_name, op_num, mcast_group, tla_list) #undef GENL_op #define GENL_op(op_name, op_num, handler, attr_list) #undef GENL_struct #define GENL_struct(tag_name, tag_number, s_name, s_fields) \ tag_name = tag_number, enum { #include GENL_MAGIC_INCLUDE_FILE }; #undef GENL_struct #define GENL_struct(tag_name, tag_number, s_name, s_fields) \ enum { \ s_fields \ }; #undef __field #define __field(attr_nr, attr_flag, name, nla_type, type, \ __get, __put, __is_signed) \ T_ ## name = (__u16)(attr_nr | ((attr_flag) & DRBD_GENLA_F_MANDATORY)), #undef __array #define __array(attr_nr, attr_flag, name, nla_type, type, \ maxlen, __get, __put, __is_signed) \ T_ ## name = (__u16)(attr_nr | ((attr_flag) & DRBD_GENLA_F_MANDATORY)), #include GENL_MAGIC_INCLUDE_FILE /* }}}1 * Magic: compile time assert unique numbers for operations * Magic: -"- unique numbers for top level attributes * Magic: -"- unique numbers for nested attributes * {{{2 */ #undef GENL_struct #define GENL_struct(tag_name, tag_number, s_name, s_fields) #undef GENL_op #define GENL_op(op_name, op_num, handler, attr_list) \ case op_name: #undef GENL_notification #define GENL_notification(op_name, op_num, mcast_group, tla_list) \ case op_name: static inline void ct_assert_unique_operations(void) { switch (0) { #include GENL_MAGIC_INCLUDE_FILE ; } } #undef GENL_op #define GENL_op(op_name, op_num, handler, attr_list) #undef GENL_notification #define GENL_notification(op_name, op_num, mcast_group, tla_list) #undef GENL_struct #define GENL_struct(tag_name, tag_number, s_name, s_fields) \ case tag_number: static inline void ct_assert_unique_top_level_attributes(void) { switch (0) { #include GENL_MAGIC_INCLUDE_FILE ; } } #undef GENL_struct #define GENL_struct(tag_name, tag_number, s_name, s_fields) \ static inline void ct_assert_unique_ ## s_name ## _attributes(void) \ { \ switch (0) { \ s_fields \ ; \ } \ } #undef __field #define __field(attr_nr, attr_flag, name, nla_type, type, __get, __put, \ __is_signed) \ case attr_nr: #undef __array #define __array(attr_nr, attr_flag, name, nla_type, type, maxlen, \ __get, __put, __is_signed) \ case attr_nr: #include GENL_MAGIC_INCLUDE_FILE /* }}}1 * Magic: declare structs * struct { * fields * }; * {{{2 */ #undef GENL_struct #define GENL_struct(tag_name, tag_number, s_name, s_fields) \ struct s_name { s_fields }; #undef __field #define __field(attr_nr, attr_flag, name, nla_type, type, __get, __put, \ __is_signed) \ type name; #undef __array #define __array(attr_nr, attr_flag, name, nla_type, type, maxlen, \ __get, __put, __is_signed) \ type name[maxlen]; \ __u32 name ## _len; #include GENL_MAGIC_INCLUDE_FILE #undef GENL_struct #define GENL_struct(tag_name, tag_number, s_name, s_fields) \ enum { \ s_fields \ }; #undef __field #define __field(attr_nr, attr_flag, name, nla_type, type, __get, __put, \ is_signed) \ F_ ## name ## _IS_SIGNED = is_signed, #undef __array #define __array(attr_nr, attr_flag, name, nla_type, type, maxlen, \ __get, __put, is_signed) \ F_ ## name ## _IS_SIGNED = is_signed, #include GENL_MAGIC_INCLUDE_FILE /* }}}1 */ #endif /* GENL_MAGIC_STRUCT_H */ /* vim: set foldmethod=marker nofoldenable : */ drbd-utils-8.9.6/drbd-headers/linux/drbd.h0000644000175000017500000002634512654447447020305 0ustar apoikosapoikos/* drbd.h Kernel module for 2.6.x Kernels This file is part of DRBD by Philipp Reisner and Lars Ellenberg. Copyright (C) 2001-2008, LINBIT Information Technologies GmbH. Copyright (C) 2001-2008, Philipp Reisner . Copyright (C) 2001-2008, Lars Ellenberg . drbd is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. drbd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with drbd; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef DRBD_H #define DRBD_H #include #ifdef __KERNEL__ #include #include #else #include #include #include /* Although the Linux source code makes a difference between generic endianness and the bitfields' endianness, there is no architecture as of Linux-2.6.24-rc4 where the bitfields' endianness does not match the generic endianness. */ #if __BYTE_ORDER == __LITTLE_ENDIAN #define __LITTLE_ENDIAN_BITFIELD #elif __BYTE_ORDER == __BIG_ENDIAN #define __BIG_ENDIAN_BITFIELD #else # error "sorry, weird endianness on this box" #endif #endif enum drbd_io_error_p { EP_PASS_ON, /* FIXME should the better be named "Ignore"? */ EP_CALL_HELPER, EP_DETACH }; enum drbd_fencing_policy { FP_DONT_CARE = 0, FP_RESOURCE, FP_STONITH }; enum drbd_disconnect_p { DP_RECONNECT, DP_DROP_NET_CONF, DP_FREEZE_IO }; enum drbd_after_sb_p { ASB_DISCONNECT, ASB_DISCARD_YOUNGER_PRI, ASB_DISCARD_OLDER_PRI, ASB_DISCARD_ZERO_CHG, ASB_DISCARD_LEAST_CHG, ASB_DISCARD_LOCAL, ASB_DISCARD_REMOTE, ASB_CONSENSUS, ASB_DISCARD_SECONDARY, ASB_CALL_HELPER, ASB_VIOLENTLY }; enum drbd_on_no_data { OND_IO_ERROR, OND_SUSPEND_IO }; enum drbd_on_congestion { OC_BLOCK, OC_PULL_AHEAD, OC_DISCONNECT, }; enum drbd_read_balancing { RB_PREFER_LOCAL, RB_PREFER_REMOTE, RB_ROUND_ROBIN, RB_LEAST_PENDING, RB_CONGESTED_REMOTE, RB_32K_STRIPING, RB_64K_STRIPING, RB_128K_STRIPING, RB_256K_STRIPING, RB_512K_STRIPING, RB_1M_STRIPING, }; /* KEEP the order, do not delete or insert. Only append. */ enum drbd_ret_code { ERR_CODE_BASE = 100, NO_ERROR = 101, ERR_LOCAL_ADDR = 102, ERR_PEER_ADDR = 103, ERR_OPEN_DISK = 104, ERR_OPEN_MD_DISK = 105, ERR_DISK_NOT_BDEV = 107, ERR_MD_NOT_BDEV = 108, ERR_DISK_TOO_SMALL = 111, ERR_MD_DISK_TOO_SMALL = 112, ERR_BDCLAIM_DISK = 114, ERR_BDCLAIM_MD_DISK = 115, ERR_MD_IDX_INVALID = 116, ERR_IO_MD_DISK = 118, ERR_MD_INVALID = 119, ERR_AUTH_ALG = 120, ERR_AUTH_ALG_ND = 121, ERR_NOMEM = 122, ERR_DISCARD_IMPOSSIBLE = 123, ERR_DISK_CONFIGURED = 124, ERR_NET_CONFIGURED = 125, ERR_MANDATORY_TAG = 126, ERR_MINOR_INVALID = 127, ERR_INTR = 129, /* EINTR */ ERR_RESIZE_RESYNC = 130, ERR_NO_PRIMARY = 131, ERR_RESYNC_AFTER = 132, ERR_RESYNC_AFTER_CYCLE = 133, ERR_PAUSE_IS_SET = 134, ERR_PAUSE_IS_CLEAR = 135, ERR_PACKET_NR = 137, ERR_NO_DISK = 138, ERR_NOT_PROTO_C = 139, ERR_NOMEM_BITMAP = 140, ERR_INTEGRITY_ALG = 141, /* DRBD 8.2 only */ ERR_INTEGRITY_ALG_ND = 142, /* DRBD 8.2 only */ ERR_CPU_MASK_PARSE = 143, /* DRBD 8.2 only */ ERR_CSUMS_ALG = 144, /* DRBD 8.2 only */ ERR_CSUMS_ALG_ND = 145, /* DRBD 8.2 only */ ERR_VERIFY_ALG = 146, /* DRBD 8.2 only */ ERR_VERIFY_ALG_ND = 147, /* DRBD 8.2 only */ ERR_CSUMS_RESYNC_RUNNING= 148, /* DRBD 8.2 only */ ERR_VERIFY_RUNNING = 149, /* DRBD 8.2 only */ ERR_DATA_NOT_CURRENT = 150, ERR_CONNECTED = 151, /* DRBD 8.3 only */ ERR_PERM = 152, ERR_NEED_APV_93 = 153, ERR_STONITH_AND_PROT_A = 154, ERR_CONG_NOT_PROTO_A = 155, ERR_PIC_AFTER_DEP = 156, ERR_PIC_PEER_DEP = 157, ERR_RES_NOT_KNOWN = 158, ERR_RES_IN_USE = 159, ERR_MINOR_CONFIGURED = 160, ERR_MINOR_OR_VOLUME_EXISTS = 161, ERR_INVALID_REQUEST = 162, ERR_NEED_APV_100 = 163, ERR_NEED_ALLOW_TWO_PRI = 164, ERR_MD_UNCLEAN = 165, ERR_MD_LAYOUT_CONNECTED = 166, ERR_MD_LAYOUT_TOO_BIG = 167, ERR_MD_LAYOUT_TOO_SMALL = 168, ERR_MD_LAYOUT_NO_FIT = 169, ERR_IMPLICIT_SHRINK = 170, ERR_INVALID_PEER_NODE_ID = 171, ERR_CREATE_TRANSPORT = 172, ERR_LOCAL_AND_PEER_ADDR = 173, /* insert new ones above this line */ AFTER_LAST_ERR_CODE }; #define DRBD_PROT_A 1 #define DRBD_PROT_B 2 #define DRBD_PROT_C 3 enum drbd_role { R_UNKNOWN = 0, R_PRIMARY = 1, /* role */ R_SECONDARY = 2, /* role */ R_MASK = 3, }; /* The order of these constants is important. * The lower ones (< C_CONNECTED) indicate * that there is no socket! * >= C_CONNECTED ==> There is a socket */ enum drbd_conn_state { C_STANDALONE, C_DISCONNECTING, /* Temporary state on the way to C_STANDALONE. */ C_UNCONNECTED, /* >= C_UNCONNECTED -> inc_net() succeeds */ /* These temporary states are used on the way * from C_CONNECTED to C_UNCONNECTED. * The 'disconnect reason' states * I do not allow to change between them. */ C_TIMEOUT, C_BROKEN_PIPE, C_NETWORK_FAILURE, C_PROTOCOL_ERROR, C_TEAR_DOWN, C_CONNECTING, C_CONNECTED, /* we have a socket */ C_MASK = 31, }; enum drbd_repl_state { L_NEGOTIATING = C_CONNECTED, /* used for peer_device->negotiation_result only */ L_OFF = C_CONNECTED, L_ESTABLISHED, /* we have introduced each other */ L_STARTING_SYNC_S, /* starting full sync by admin request. */ L_STARTING_SYNC_T, /* starting full sync by admin request. */ L_WF_BITMAP_S, L_WF_BITMAP_T, L_WF_SYNC_UUID, /* All SyncStates are tested with this comparison * xx >= L_SYNC_SOURCE && xx <= L_PAUSED_SYNC_T */ L_SYNC_SOURCE, L_SYNC_TARGET, L_VERIFY_S, L_VERIFY_T, L_PAUSED_SYNC_S, L_PAUSED_SYNC_T, L_AHEAD, L_BEHIND, L_NEG_NO_RESULT = L_BEHIND, /* used for peer_device->negotiation_result only */ }; enum drbd_disk_state { D_DISKLESS, D_ATTACHING, /* In the process of reading the meta-data */ D_DETACHING, /* Added in protocol version 110 */ D_FAILED, /* Becomes D_DISKLESS as soon as we told it the peer */ /* when >= D_FAILED it is legal to access device->ldev */ D_NEGOTIATING, /* Late attaching state, we need to talk to the peer */ D_INCONSISTENT, D_OUTDATED, D_UNKNOWN, /* Only used for the peer, never for myself */ D_CONSISTENT, /* Might be D_OUTDATED, might be D_UP_TO_DATE ... */ D_UP_TO_DATE, /* Only this disk state allows applications' IO ! */ D_MASK = 15 }; union drbd_state { /* According to gcc's docs is the ... * The order of allocation of bit-fields within a unit (C90 6.5.2.1, C99 6.7.2.1). * Determined by ABI. * pointed out by Maxim Uvarov q * even though we transmit as "cpu_to_be32(state)", * the offsets of the bitfields still need to be swapped * on different endianness. */ struct { #if defined(__LITTLE_ENDIAN_BITFIELD) unsigned role:2 ; /* 3/4 primary/secondary/unknown */ unsigned peer:2 ; /* 3/4 primary/secondary/unknown */ unsigned conn:5 ; /* 17/32 cstates */ unsigned disk:4 ; /* 8/16 from D_DISKLESS to D_UP_TO_DATE */ unsigned pdsk:4 ; /* 8/16 from D_DISKLESS to D_UP_TO_DATE */ unsigned susp:1 ; /* 2/2 IO suspended no/yes (by user) */ unsigned aftr_isp:1 ; /* isp .. imposed sync pause */ unsigned peer_isp:1 ; unsigned user_isp:1 ; unsigned susp_nod:1 ; /* IO suspended because no data */ unsigned susp_fen:1 ; /* IO suspended because fence peer handler runs*/ unsigned _pad:9; /* 0 unused */ #elif defined(__BIG_ENDIAN_BITFIELD) unsigned _pad:9; unsigned susp_fen:1 ; unsigned susp_nod:1 ; unsigned user_isp:1 ; unsigned peer_isp:1 ; unsigned aftr_isp:1 ; /* isp .. imposed sync pause */ unsigned susp:1 ; /* 2/2 IO suspended no/yes */ unsigned pdsk:4 ; /* 8/16 from D_DISKLESS to D_UP_TO_DATE */ unsigned disk:4 ; /* 8/16 from D_DISKLESS to D_UP_TO_DATE */ unsigned conn:5 ; /* 17/32 cstates */ unsigned peer:2 ; /* 3/4 primary/secondary/unknown */ unsigned role:2 ; /* 3/4 primary/secondary/unknown */ #else # error "this endianness is not supported" #endif }; unsigned int i; }; enum drbd_state_rv { SS_CW_NO_NEED = 4, SS_CW_SUCCESS = 3, SS_NOTHING_TO_DO = 2, SS_SUCCESS = 1, SS_UNKNOWN_ERROR = 0, /* Used to sleep longer in _drbd_request_state */ SS_TWO_PRIMARIES = -1, SS_NO_UP_TO_DATE_DISK = -2, SS_NO_LOCAL_DISK = -4, SS_NO_REMOTE_DISK = -5, SS_CONNECTED_OUTDATES = -6, SS_PRIMARY_NOP = -7, SS_RESYNC_RUNNING = -8, SS_ALREADY_STANDALONE = -9, SS_CW_FAILED_BY_PEER = -10, SS_IS_DISKLESS = -11, SS_DEVICE_IN_USE = -12, SS_NO_NET_CONFIG = -13, SS_NO_VERIFY_ALG = -14, /* drbd-8.2 only */ SS_NEED_CONNECTION = -15, SS_LOWER_THAN_OUTDATED = -16, SS_NOT_SUPPORTED = -17, SS_IN_TRANSIENT_STATE = -18, /* Retry after the next state change */ SS_CONCURRENT_ST_CHG = -19, /* Concurrent cluster side state change! */ SS_O_VOL_PEER_PRI = -20, SS_INTERRUPTED = -21, /* interrupted in stable_state_change() */ SS_PRIMARY_READER = -22, SS_TIMEOUT = -23, SS_WEAKLY_CONNECTED = -24, SS_AFTER_LAST_ERROR = -25, /* Keep this at bottom */ }; #define SHARED_SECRET_MAX 64 enum mdf_flag { MDF_CONSISTENT = 1 << 0, MDF_PRIMARY_IND = 1 << 1, MDF_WAS_UP_TO_DATE = 1 << 4, MDF_CRASHED_PRIMARY = 1 << 6, MDF_AL_CLEAN = 1 << 7, MDF_AL_DISABLED = 1 << 8, }; enum mdf_peer_flag { MDF_PEER_CONNECTED = 1 << 0, MDF_PEER_OUTDATED = 1 << 1, MDF_PEER_FENCING = 1 << 2, MDF_PEER_FULL_SYNC = 1 << 3, MDF_NODE_EXISTS = 1 << 16, /* */ }; #define DRBD_PEERS_MAX 32 #define DRBD_NODE_ID_MAX DRBD_PEERS_MAX enum drbd_uuid_index { UI_CURRENT, UI_BITMAP, UI_HISTORY_START, UI_HISTORY_END, UI_SIZE, /* nl-packet: number of dirty bits */ UI_FLAGS, /* nl-packet: flags */ UI_EXTENDED_SIZE /* Everything. */ }; #define HISTORY_UUIDS_V08 (UI_HISTORY_END - UI_HISTORY_START + 1) #define HISTORY_UUIDS DRBD_PEERS_MAX enum drbd_timeout_flag { UT_DEFAULT = 0, UT_DEGRADED = 1, UT_PEER_OUTDATED = 2, }; #define UUID_JUST_CREATED ((__u64)4) #define UUID_PRIMARY ((__u64)1) enum write_ordering_e { WO_NONE, WO_DRAIN_IO, WO_BDEV_FLUSH, WO_BIO_BARRIER }; enum drbd_notification_type { NOTIFY_EXISTS, NOTIFY_CREATE, NOTIFY_CHANGE, NOTIFY_DESTROY, NOTIFY_CALL, NOTIFY_RESPONSE, NOTIFY_CONTINUES = 0x8000, NOTIFY_FLAGS = NOTIFY_CONTINUES, }; /* These values are part of the ABI! */ enum drbd_peer_state { P_INCONSISTENT = 3, P_OUTDATED = 4, P_DOWN = 5, P_PRIMARY = 6, P_FENCING = 7, }; /* magic numbers used in meta data and network packets */ #define DRBD_MAGIC 0x83740267 #define DRBD_MAGIC_BIG 0x835a #define DRBD_MAGIC_100 0x8620ec20 #define DRBD_MD_MAGIC_07 (DRBD_MAGIC+3) #define DRBD_MD_MAGIC_08 (DRBD_MAGIC+4) #define DRBD_MD_MAGIC_84_UNCLEAN (DRBD_MAGIC+5) #define DRBD_MD_MAGIC_09 (DRBD_MAGIC+6) /* how I came up with this magic? * base64 decode "actlog==" ;) */ #define DRBD_AL_MAGIC 0x69cb65a2 /* these are of type "int" */ #define DRBD_MD_INDEX_INTERNAL -1 #define DRBD_MD_INDEX_FLEX_EXT -2 #define DRBD_MD_INDEX_FLEX_INT -3 #define DRBD_CPU_MASK_SIZE 32 #define DRBD_MAX_BIO_SIZE (1U << 20) #endif drbd-utils-8.9.6/drbd-headers/linux/drbd_limits.h0000644000175000017500000002221612634301741021637 0ustar apoikosapoikos/* drbd_limits.h This file is part of DRBD by Philipp Reisner and Lars Ellenberg. */ /* * Our current limitations. * Some of them are hard limits, * some of them are arbitrary range limits, that make it easier to provide * feedback about nonsense settings for certain configurable values. */ #ifndef DRBD_LIMITS_H #define DRBD_LIMITS_H 1 #define DEBUG_RANGE_CHECK 0 #define DRBD_MINOR_COUNT_MIN 1 #define DRBD_MINOR_COUNT_MAX 255 #define DRBD_MINOR_COUNT_DEF 32 #define DRBD_MINOR_COUNT_SCALE '1' #define DRBD_VOLUME_MAX 65535 #define DRBD_DIALOG_REFRESH_MIN 0 #define DRBD_DIALOG_REFRESH_MAX 600 #define DRBD_DIALOG_REFRESH_SCALE '1' /* valid port number */ #define DRBD_PORT_MIN 1 #define DRBD_PORT_MAX 0xffff #define DRBD_PORT_SCALE '1' /* startup { */ /* if you want more than 3.4 days, disable */ #define DRBD_WFC_TIMEOUT_MIN 0 #define DRBD_WFC_TIMEOUT_MAX 300000 #define DRBD_WFC_TIMEOUT_DEF 0 #define DRBD_WFC_TIMEOUT_SCALE '1' #define DRBD_DEGR_WFC_TIMEOUT_MIN 0 #define DRBD_DEGR_WFC_TIMEOUT_MAX 300000 #define DRBD_DEGR_WFC_TIMEOUT_DEF 0 #define DRBD_DEGR_WFC_TIMEOUT_SCALE '1' #define DRBD_OUTDATED_WFC_TIMEOUT_MIN 0 #define DRBD_OUTDATED_WFC_TIMEOUT_MAX 300000 #define DRBD_OUTDATED_WFC_TIMEOUT_DEF 0 #define DRBD_OUTDATED_WFC_TIMEOUT_SCALE '1' /* }*/ /* net { */ /* timeout, unit centi seconds * more than one minute timeout is not useful */ #define DRBD_TIMEOUT_MIN 1 #define DRBD_TIMEOUT_MAX 600 #define DRBD_TIMEOUT_DEF 60 /* 6 seconds */ #define DRBD_TIMEOUT_SCALE '1' /* If backing disk takes longer than disk_timeout, mark the disk as failed */ #define DRBD_DISK_TIMEOUT_MIN 0 /* 0 = disabled */ #define DRBD_DISK_TIMEOUT_MAX 6000 /* 10 Minutes */ #define DRBD_DISK_TIMEOUT_DEF 0 /* disabled */ #define DRBD_DISK_TIMEOUT_SCALE '1' /* active connection retries when C_CONNECTING */ #define DRBD_CONNECT_INT_MIN 1 #define DRBD_CONNECT_INT_MAX 120 #define DRBD_CONNECT_INT_DEF 10 /* seconds */ #define DRBD_CONNECT_INT_SCALE '1' /* keep-alive probes when idle */ #define DRBD_PING_INT_MIN 1 #define DRBD_PING_INT_MAX 120 #define DRBD_PING_INT_DEF 10 #define DRBD_PING_INT_SCALE '1' /* timeout for the ping packets.*/ #define DRBD_PING_TIMEO_MIN 1 #define DRBD_PING_TIMEO_MAX 300 #define DRBD_PING_TIMEO_DEF 5 #define DRBD_PING_TIMEO_SCALE '1' /* max number of write requests between write barriers */ #define DRBD_MAX_EPOCH_SIZE_MIN 1 #define DRBD_MAX_EPOCH_SIZE_MAX 20000 #define DRBD_MAX_EPOCH_SIZE_DEF 2048 #define DRBD_MAX_EPOCH_SIZE_SCALE '1' /* I don't think that a tcp send buffer of more than 10M is useful */ #define DRBD_SNDBUF_SIZE_MIN 0 #define DRBD_SNDBUF_SIZE_MAX (10<<20) #define DRBD_SNDBUF_SIZE_DEF 0 #define DRBD_SNDBUF_SIZE_SCALE '1' #define DRBD_RCVBUF_SIZE_MIN 0 #define DRBD_RCVBUF_SIZE_MAX (10<<20) #define DRBD_RCVBUF_SIZE_DEF 0 #define DRBD_RCVBUF_SIZE_SCALE '1' /* @4k PageSize -> 128kB - 512MB */ #define DRBD_MAX_BUFFERS_MIN 32 #define DRBD_MAX_BUFFERS_MAX 131072 #define DRBD_MAX_BUFFERS_DEF 2048 #define DRBD_MAX_BUFFERS_SCALE '1' /* @4k PageSize -> 4kB - 512MB */ #define DRBD_UNPLUG_WATERMARK_MIN 1 #define DRBD_UNPLUG_WATERMARK_MAX 131072 #define DRBD_UNPLUG_WATERMARK_DEF (DRBD_MAX_BUFFERS_DEF/16) #define DRBD_UNPLUG_WATERMARK_SCALE '1' /* 0 is disabled. * 200 should be more than enough even for very short timeouts */ #define DRBD_KO_COUNT_MIN 0 #define DRBD_KO_COUNT_MAX 200 #define DRBD_KO_COUNT_DEF 7 #define DRBD_KO_COUNT_SCALE '1' /* } */ /* syncer { */ /* FIXME allow rate to be zero? */ #define DRBD_RESYNC_RATE_MIN 1 /* channel bonding 10 GbE, or other hardware */ #define DRBD_RESYNC_RATE_MAX (4 << 20) #define DRBD_RESYNC_RATE_DEF 250 #define DRBD_RESYNC_RATE_SCALE 'k' /* kilobytes */ /* less than 67 would hit performance unnecessarily. */ #define DRBD_AL_EXTENTS_MIN 67 /* we use u16 as "slot number", (u16)~0 is "FREE". * If you use >= 292 kB on-disk ring buffer, * this is the maximum you can use: */ #define DRBD_AL_EXTENTS_MAX 0xfffe #define DRBD_AL_EXTENTS_DEF 1237 #define DRBD_AL_EXTENTS_SCALE '1' #define DRBD_MINOR_NUMBER_MIN -1 #define DRBD_MINOR_NUMBER_MAX ((1 << 20) - 1) #define DRBD_MINOR_NUMBER_DEF -1 #define DRBD_MINOR_NUMBER_SCALE '1' /* } */ /* drbdsetup XY resize -d Z * you are free to reduce the device size to nothing, if you want to. * the upper limit with 64bit kernel, enough ram and flexible meta data * is 1 PiB, currently. */ /* DRBD_MAX_SECTORS */ #define DRBD_DISK_SIZE_MIN 0 #define DRBD_DISK_SIZE_MAX (1 * (2LLU << 40)) #define DRBD_DISK_SIZE_DEF 0 /* = disabled = no user size... */ #define DRBD_DISK_SIZE_SCALE 's' /* sectors */ #define DRBD_ON_IO_ERROR_DEF EP_DETACH #define DRBD_FENCING_DEF FP_DONT_CARE #define DRBD_AFTER_SB_0P_DEF ASB_DISCONNECT #define DRBD_AFTER_SB_1P_DEF ASB_DISCONNECT #define DRBD_AFTER_SB_2P_DEF ASB_DISCONNECT #define DRBD_RR_CONFLICT_DEF ASB_DISCONNECT #define DRBD_ON_NO_DATA_DEF OND_IO_ERROR #define DRBD_ON_CONGESTION_DEF OC_BLOCK #define DRBD_READ_BALANCING_DEF RB_PREFER_LOCAL #define DRBD_MAX_BIO_BVECS_MIN 0 #define DRBD_MAX_BIO_BVECS_MAX 128 #define DRBD_MAX_BIO_BVECS_DEF 0 #define DRBD_MAX_BIO_BVECS_SCALE '1' #define DRBD_C_PLAN_AHEAD_MIN 0 #define DRBD_C_PLAN_AHEAD_MAX 300 #define DRBD_C_PLAN_AHEAD_DEF 20 #define DRBD_C_PLAN_AHEAD_SCALE '1' #define DRBD_C_DELAY_TARGET_MIN 1 #define DRBD_C_DELAY_TARGET_MAX 100 #define DRBD_C_DELAY_TARGET_DEF 10 #define DRBD_C_DELAY_TARGET_SCALE '1' #define DRBD_C_FILL_TARGET_MIN 0 #define DRBD_C_FILL_TARGET_MAX (1<<20) /* 500MByte in sec */ #define DRBD_C_FILL_TARGET_DEF 100 /* Try to place 50KiB in socket send buffer during resync */ #define DRBD_C_FILL_TARGET_SCALE 's' /* sectors */ #define DRBD_C_MAX_RATE_MIN 250 #define DRBD_C_MAX_RATE_MAX (4 << 20) #define DRBD_C_MAX_RATE_DEF 102400 #define DRBD_C_MAX_RATE_SCALE 'k' /* kilobytes */ #define DRBD_C_MIN_RATE_MIN 0 #define DRBD_C_MIN_RATE_MAX (4 << 20) #define DRBD_C_MIN_RATE_DEF 250 #define DRBD_C_MIN_RATE_SCALE 'k' /* kilobytes */ #define DRBD_CONG_FILL_MIN 0 #define DRBD_CONG_FILL_MAX (10<<21) /* 10GByte in sectors */ #define DRBD_CONG_FILL_DEF 0 #define DRBD_CONG_FILL_SCALE 's' /* sectors */ #define DRBD_CONG_EXTENTS_MIN DRBD_AL_EXTENTS_MIN #define DRBD_CONG_EXTENTS_MAX DRBD_AL_EXTENTS_MAX #define DRBD_CONG_EXTENTS_DEF DRBD_AL_EXTENTS_DEF #define DRBD_CONG_EXTENTS_SCALE DRBD_AL_EXTENTS_SCALE #define DRBD_PROTOCOL_DEF DRBD_PROT_C #define DRBD_DISK_BARRIER_DEF 0 #define DRBD_DISK_FLUSHES_DEF 1 #define DRBD_DISK_DRAIN_DEF 1 #define DRBD_MD_FLUSHES_DEF 1 #define DRBD_TCP_CORK_DEF 1 #define DRBD_AL_UPDATES_DEF 1 /* We used to ignore the discard_zeroes_data setting. * To not change established (and expected) behaviour, * by default assume that, for discard_zeroes_data=0, * we can make that an effective discard_zeroes_data=1, * if we only explicitly zero-out unaligned partial chunks. */ #define DRBD_DISCARD_ZEROES_IF_ALIGNED_DEF 1 #define DRBD_ALLOW_TWO_PRIMARIES_DEF 0 #define DRBD_ALWAYS_ASBP_DEF 0 #define DRBD_USE_RLE_DEF 1 #define DRBD_CSUMS_AFTER_CRASH_ONLY_DEF 0 #define DRBD_AUTO_PROMOTE_DEF 1 #define DRBD_MAX_BIO_SIZE_DEF DRBD_MAX_BIO_SIZE #define DRBD_MAX_BIO_SIZE_MIN (1 << 9) #define DRBD_MAX_BIO_SIZE_MAX DRBD_MAX_BIO_SIZE #define DRBD_MAX_BIO_SIZE_SCALE '1' #define DRBD_NODE_ID_DEF 0 #define DRBD_NODE_ID_MIN 0 #ifndef DRBD_NODE_ID_MAX /* Is also defined in drbd.h */ #define DRBD_NODE_ID_MAX DRBD_PEERS_MAX #endif #define DRBD_NODE_ID_SCALE '1' #define DRBD_PEER_ACK_WINDOW_DEF 4096 /* 2 MiByte */ #define DRBD_PEER_ACK_WINDOW_MIN 2048 /* 1 MiByte */ #define DRBD_PEER_ACK_WINDOW_MAX 204800 /* 100 MiByte */ #define DRBD_PEER_ACK_WINDOW_SCALE 's' /* sectors*/ #define DRBD_PEER_ACK_DELAY_DEF 100 /* 100ms */ #define DRBD_PEER_ACK_DELAY_MIN 1 #define DRBD_PEER_ACK_DELAY_MAX 10000 /* 10 seconds */ #define DRBD_PEER_ACK_DELAY_SCALE '1' /* milliseconds */ /* Two-phase commit timeout (1/10 seconds). */ #define DRBD_TWOPC_TIMEOUT_MIN 50 #define DRBD_TWOPC_TIMEOUT_MAX 600 #define DRBD_TWOPC_TIMEOUT_DEF 300 #define DRBD_TWOPC_TIMEOUT_SCALE '1' #define DRBD_TWOPC_RETRY_TIMEOUT_MIN 1 #define DRBD_TWOPC_RETRY_TIMEOUT_MAX 50 #define DRBD_TWOPC_RETRY_TIMEOUT_DEF 1 #define DRBD_TWOPC_RETRY_TIMEOUT_SCALE '1' #define DRBD_SYNC_FROM_NID_DEF -1 #define DRBD_SYNC_FROM_NID_MIN -1 #define DRBD_SYNC_FROM_NID_MAX DRBD_PEERS_MAX #define DRBD_SYNC_FROM_NID_SCALE '1' #define DRBD_AL_STRIPES_MIN 1 #define DRBD_AL_STRIPES_MAX 1024 #define DRBD_AL_STRIPES_DEF 1 #define DRBD_AL_STRIPES_SCALE '1' #define DRBD_AL_STRIPE_SIZE_MIN 4 #define DRBD_AL_STRIPE_SIZE_MAX 16777216 #define DRBD_AL_STRIPE_SIZE_DEF 32 #define DRBD_AL_STRIPE_SIZE_SCALE 'k' /* kilobytes */ #define DRBD_SOCKET_CHECK_TIMEO_MIN 0 #define DRBD_SOCKET_CHECK_TIMEO_MAX DRBD_PING_TIMEO_MAX #define DRBD_SOCKET_CHECK_TIMEO_DEF 0 #define DRBD_SOCKET_CHECK_TIMEO_SCALE '1' /* Auto promote timeout (1/10 seconds). */ #define DRBD_AUTO_PROMOTE_TIMEOUT_MIN 0 #define DRBD_AUTO_PROMOTE_TIMEOUT_MAX 600 #define DRBD_AUTO_PROMOTE_TIMEOUT_DEF 20 #define DRBD_AUTO_PROMOTE_TIMEOUT_SCALE '1' #define DRBD_RS_DISCARD_GRANULARITY_MIN 0 #define DRBD_RS_DISCARD_GRANULARITY_MAX (1<<20) /* 1MiByte */ #define DRBD_RS_DISCARD_GRANULARITY_DEF 0 /* disabled by default */ #define DRBD_RS_DISCARD_GRANULARITY_SCALE '1' /* bytes */ #endif drbd-utils-8.9.6/drbd-headers/linux/drbd_genl_api.h0000644000175000017500000000234612540016517022116 0ustar apoikosapoikos#ifndef DRBD_GENL_STRUCT_H #define DRBD_GENL_STRUCT_H /** * struct drbd_genlmsghdr - DRBD specific header used in NETLINK_GENERIC requests * @minor: * For admin requests (user -> kernel): which minor device to operate on. * For (unicast) replies or informational (broadcast) messages * (kernel -> user): which minor device the information is about. * If we do not operate on minors, but on connections or resources, * the minor value shall be (~0), and the attribute DRBD_NLA_CFG_CONTEXT * is used instead. * @flags: possible operation modifiers (relevant only for user->kernel): * DRBD_GENL_F_SET_DEFAULTS * @ret_code: kernel->userland unicast cfg reply return code (union with flags); */ struct drbd_genlmsghdr { __u32 minor; union { __u32 flags; __s32 ret_code; }; }; /* To be used in drbd_genlmsghdr.flags */ enum { DRBD_GENL_F_SET_DEFAULTS = 1, }; /* hack around predefined gcc/cpp "linux=1", * we cannot possibly include <1/drbd_genl.h> */ #undef linux #include #define GENL_MAGIC_VERSION 2 #define GENL_MAGIC_FAMILY drbd #define GENL_MAGIC_FAMILY_HDRSZ sizeof(struct drbd_genlmsghdr) #define GENL_MAGIC_INCLUDE_FILE #include #endif drbd-utils-8.9.6/drbd-headers/drbd_transport.h0000644000175000017500000002766112654447447021264 0ustar apoikosapoikos#ifndef DRBD_TRANSPORT_H #define DRBD_TRANSPORT_H #include #include #include #include /* Whenever touch this file in a non-trivial way, increase the DRBD_TRANSPORT_API_VERSION So that transport compiled against an older version of this header will no longer load in a module that assumes a newer version. */ #define DRBD_TRANSPORT_API_VERSION 14 /* MSG_MSG_DONTROUTE and MSG_PROBE are not used by DRBD. I.e. we can reuse these flags for our purposes */ #define CALLER_BUFFER MSG_DONTROUTE #define GROW_BUFFER MSG_PROBE /* * gfp_mask for allocating memory with no write-out. * * When drbd allocates memory on behalf of the peer, we prevent it from causing * write-out because in a criss-cross setup, the write-out could lead to memory * pressure on the peer, eventually leading to deadlock. */ #define GFP_TRY (__GFP_HIGHMEM | __GFP_NOWARN | __GFP_RECLAIM) #define tr_printk(level, transport, fmt, args...) ({ \ rcu_read_lock(); \ printk(level "drbd %s %s:%s: " fmt, \ (transport)->log_prefix, \ (transport)->class->name, \ rcu_dereference((transport)->net_conf)->name, \ ## args); \ rcu_read_unlock(); \ }) #define tr_err(transport, fmt, args...) \ tr_printk(KERN_ERR, transport, fmt, ## args) #define tr_warn(transport, fmt, args...) \ tr_printk(KERN_WARNING, transport, fmt, ## args) #define tr_info(transport, fmt, args...) \ tr_printk(KERN_INFO, transport, fmt, ## args) #define TR_ASSERT(x, exp) \ do { \ if (!(exp)) \ tr_err(x, "ASSERTION %s FAILED in %s\n", \ #exp, __func__); \ } while (0) struct drbd_resource; struct drbd_connection; struct drbd_peer_device; enum drbd_stream { DATA_STREAM, CONTROL_STREAM }; enum drbd_tr_hints { CORK, UNCORK, NODELAY, NOSPACE, QUICKACK }; enum { /* bits in the flags word */ NET_CONGESTED, /* The data socket is congested */ RESOLVE_CONFLICTS, /* Set on one node, cleared on the peer! */ }; enum drbd_tr_free_op { CLOSE_CONNECTION, DESTROY_TRANSPORT }; /* A transport might wrap its own data structure around this. Having this base class as its first member. */ struct drbd_path { struct sockaddr_storage my_addr; struct sockaddr_storage peer_addr; struct kref kref; int my_addr_len; int peer_addr_len; bool established; /* updated by the transport */ struct list_head list; }; /* Each transport implementation should embed a struct drbd_transport into it's instance data structure. */ struct drbd_transport { struct drbd_transport_ops *ops; struct drbd_transport_class *class; struct list_head paths; const char *log_prefix; /* resource name */ struct net_conf *net_conf; /* content protected by rcu */ /* These members are intended to be updated by the transport: */ unsigned int ko_count; unsigned long flags; }; struct drbd_transport_stats { int unread_received; int unacked_send; int send_buffer_size; int send_buffer_used; }; /* argument to ->recv_pages() */ struct drbd_page_chain_head { struct page *head; unsigned int nr_pages; }; struct drbd_transport_ops { void (*free)(struct drbd_transport *, enum drbd_tr_free_op free_op); int (*connect)(struct drbd_transport *); /** * recv() - Receive data via the transport * @transport: The transport to use * @stream: The stream within the transport to use. Ether DATA_STREAM or CONTROL_STREAM * @buf: The function will place here the pointer to the data area * @size: Number of byte to receive * @msg_flags: Bitmask of CALLER_BUFFER, GROW_BUFFER and MSG_DONTWAIT * * recv() returns the requests data in a buffer (owned by the transport). * You may pass MSG_DONTWAIT as flags. Usually with the next call to recv() * or recv_pages() on the same stream, the buffer may no longer be accessed * by the caller. I.e. it is reclaimed by the transport. * * If the transport was not capable of fulfilling the complete "wish" of the * caller (that means it returned a smaller size that size), the caller may * call recv() again with the flag GROW_BUFFER, and *buf as returned by the * previous call. * Note1: This can happen if MSG_DONTWAIT was used, or if a receive timeout * was we with set_rcvtimeo(). * Note2: recv() is free to re-locate the buffer in such a call. I.e. to * modify *buf. Then it copies the content received so far to the new * memory location. * * Last not least the caller may also pass an arbitrary pointer in *buf with * the CALLER_BUFFER flag. This is expected to be used for small amounts * of data only * * Upon success the function returns the bytes read. Upon error the return * code is negative. A 0 indicates that the socket was closed by the remote * side. */ int (*recv)(struct drbd_transport *, enum drbd_stream, void **buf, size_t size, int flags); /** * recv_pages() - Receive bulk data via the transport's DATA_STREAM * @peer_device: Identify the transport and the device * @page_chain: Here recv_pages() will place the page chain head and length * @size: Number of bytes to receive * * recv_pages() will return the requested amount of data from DATA_STREAM, * and place it into pages allocated with drbd_alloc_pages(). * * Upon success the function returns 0. Upon error the function returns a * negative value */ int (*recv_pages)(struct drbd_transport *, struct drbd_page_chain_head *, size_t size); void (*stats)(struct drbd_transport *, struct drbd_transport_stats *stats); void (*set_rcvtimeo)(struct drbd_transport *, enum drbd_stream, long timeout); long (*get_rcvtimeo)(struct drbd_transport *, enum drbd_stream); int (*send_page)(struct drbd_transport *, enum drbd_stream, struct page *, int offset, size_t size, unsigned msg_flags); int (*send_zc_bio)(struct drbd_transport *, struct bio *bio); bool (*stream_ok)(struct drbd_transport *, enum drbd_stream); bool (*hint)(struct drbd_transport *, enum drbd_stream, enum drbd_tr_hints hint); void (*debugfs_show)(struct drbd_transport *, struct seq_file *m); int (*add_path)(struct drbd_transport *, struct drbd_path *path); int (*remove_path)(struct drbd_transport *, struct drbd_path *path); }; struct drbd_transport_class { const char *name; const int instance_size; const int path_instance_size; struct module *module; int (*init)(struct drbd_transport *); struct list_head list; }; /* An "abstract base class" for transport implementations. I.e. it should be embedded into a transport specific representation of a listening "socket" */ struct drbd_listener { struct kref kref; struct drbd_resource *resource; struct list_head list; /* link for resource->listeners */ struct list_head waiters; /* list head for waiter structs*/ spinlock_t waiters_lock; int pending_accepts; struct sockaddr_storage listen_addr; void (*destroy)(struct drbd_listener *); }; /* This represents a drbd receiver thread that is waiting for an incoming connection attempt. Again, should be embedded into a implementation object */ struct drbd_waiter { struct drbd_transport *transport; wait_queue_head_t wait; struct list_head list; struct drbd_listener *listener; }; /* drbd_main.c */ extern void drbd_destroy_path(struct kref *kref); /* drbd_transport.c */ extern int drbd_register_transport_class(struct drbd_transport_class *transport_class, int api_version, int drbd_transport_size); extern void drbd_unregister_transport_class(struct drbd_transport_class *transport_class); extern struct drbd_transport_class *drbd_get_transport_class(const char *transport_name); extern void drbd_put_transport_class(struct drbd_transport_class *); extern void drbd_print_transports_loaded(struct seq_file *seq); extern int drbd_get_listener(struct drbd_waiter *waiter, const struct sockaddr *addr, int (*create_fn)(struct drbd_transport *, const struct sockaddr *, struct drbd_listener **)); extern void drbd_put_listener(struct drbd_waiter *waiter); extern struct drbd_waiter *drbd_find_waiter_by_addr(struct drbd_listener *, struct sockaddr_storage *); extern bool drbd_stream_send_timed_out(struct drbd_transport *transport, enum drbd_stream stream); extern bool drbd_should_abort_listening(struct drbd_transport *transport); extern void drbd_path_event(struct drbd_transport *transport, struct drbd_path *path); /* drbd_receiver.c*/ extern struct page *drbd_alloc_pages(struct drbd_transport *, unsigned int, gfp_t); extern void drbd_free_pages(struct drbd_transport *transport, struct page *page, int is_net); static inline void drbd_alloc_page_chain(struct drbd_transport *t, struct drbd_page_chain_head *chain, unsigned int nr, gfp_t gfp_flags) { chain->head = drbd_alloc_pages(t, nr, gfp_flags); chain->nr_pages = chain->head ? nr : 0; } static inline void drbd_free_page_chain(struct drbd_transport *transport, struct drbd_page_chain_head *chain, int is_net) { drbd_free_pages(transport, chain->head, is_net); chain->head = NULL; chain->nr_pages = 0; } /* * Some helper functions to deal with our page chains. */ /* Our transports may sometimes need to only partially use a page. * We need to express that somehow. Use this struct, and "graft" it into * struct page at page->lru. * * According to include/linux/mm.h: * | A page may be used by anyone else who does a __get_free_page(). * | In this case, page_count still tracks the references, and should only * | be used through the normal accessor functions. The top bits of page->flags * | and page->virtual store page management information, but all other fields * | are unused and could be used privately, carefully. The management of this * | page is the responsibility of the one who allocated it, and those who have * | subsequently been given references to it. * (we do alloc_page(), that is equivalent). * * Red Hat struct page is different from upstream (layout and members) :( * So I am not too sure about the "all other fields", and it is not as easy to * find a place where sizeof(struct drbd_page_chain) would fit on all archs and * distribution-changed layouts. * * But (upstream) struct page also says: * | struct list_head lru; * ... * | * Can be used as a generic list * | * by the page owner. * * On 32bit, use unsigned short for offset and size, * to still fit in sizeof(page->lru). */ /* grafted over struct page.lru */ struct drbd_page_chain { struct page *next; /* next page in chain, if any */ #ifdef CONFIG_64BIT unsigned int offset; /* start offset of data within this page */ unsigned int size; /* number of data bytes within this page */ #else #if PAGE_SIZE > (1U<<16) #error "won't work." #endif unsigned short offset; /* start offset of data within this page */ unsigned short size; /* number of data bytes within this page */ #endif }; static inline void dummy_for_buildbug(void) { struct page *dummy; BUILD_BUG_ON(sizeof(struct drbd_page_chain) > sizeof(dummy->lru)); } #define page_chain_next(page) \ (((struct drbd_page_chain*)&(page)->lru)->next) #define page_chain_size(page) \ (((struct drbd_page_chain*)&(page)->lru)->size) #define page_chain_offset(page) \ (((struct drbd_page_chain*)&(page)->lru)->offset) #define set_page_chain_next(page, v) \ (((struct drbd_page_chain*)&(page)->lru)->next = (v)) #define set_page_chain_size(page, v) \ (((struct drbd_page_chain*)&(page)->lru)->size = (v)) #define set_page_chain_offset(page, v) \ (((struct drbd_page_chain*)&(page)->lru)->offset = (v)) #define set_page_chain_next_offset_size(page, n, o, s) \ *((struct drbd_page_chain*)&(page)->lru) = \ ((struct drbd_page_chain) { \ .next = (n), \ .offset = (o), \ .size = (s), \ }) #define page_chain_for_each(page) \ for (; page && ({ prefetch(page_chain_next(page)); 1; }); \ page = page_chain_next(page)) #define page_chain_for_each_safe(page, n) \ for (; page && ({ n = page_chain_next(page); 1; }); page = n) #ifndef SK_CAN_REUSE /* This constant was introduced by Pavel Emelyanov on Thu Apr 19 03:39:36 2012 +0000. Before the release of linux-3.5 commit 4a17fd52 sock: Introduce named constants for sk_reuse */ #define SK_CAN_REUSE 1 #endif #endif drbd-utils-8.9.6/drbd-headers/drbd_meta_data.h0000644000175000017500000000261312477341210021115 0ustar apoikosapoikos#ifndef DRBD_META_DATA_H #define DRBD_META_DATA_H #ifdef __KERNEL__ #define be_u64 u64 #define be_u32 u32 #define be_s32 s32 #define be_u16 u16 #else #define be_u64 struct { uint64_t be; } #define be_u32 struct { uint32_t be; } #define be_s32 struct { int32_t be; } #define be_u16 struct { uint16_t be; } #endif struct peer_dev_md_on_disk_9 { be_u64 bitmap_uuid; be_u64 bitmap_dagtag; be_u32 flags; be_s32 bitmap_index; be_u32 reserved_u32[2]; } __packed; struct meta_data_on_disk_9 { be_u64 effective_size; /* last agreed size */ be_u64 current_uuid; be_u64 reserved_u64[4]; /* to have the magic at the same position as in v07, and v08 */ be_u64 device_uuid; be_u32 flags; /* MDF */ be_u32 magic; be_u32 md_size_sect; be_u32 al_offset; /* offset to this block */ be_u32 al_nr_extents; /* important for restoring the AL */ be_u32 bm_offset; /* offset to the bitmap, from here */ be_u32 bm_bytes_per_bit; /* BM_BLOCK_SIZE */ be_u32 la_peer_max_bio_size; /* last peer max_bio_size */ be_u32 bm_max_peers; be_s32 node_id; /* see al_tr_number_to_on_disk_sector() */ be_u32 al_stripes; be_u32 al_stripe_size_4k; be_u32 reserved_u32[2]; struct peer_dev_md_on_disk_9 peers[DRBD_PEERS_MAX]; be_u64 history_uuids[HISTORY_UUIDS]; char padding[0] __attribute__((aligned(4096))); } __packed; #undef be_u64 #undef be_u32 #undef be_s32 #undef be_u16 #endif drbd-utils-8.9.6/drbd-headers/drbd_strings.h0000644000175000017500000000136112654447447020706 0ustar apoikosapoikos#ifndef __DRBD_STRINGS_H #define __DRBD_STRINGS_H struct state_names { const char * const *names; unsigned int size; }; extern struct state_names drbd_conn_state_names; extern struct state_names drbd_repl_state_names; extern struct state_names drbd_role_state_names; extern struct state_names drbd_disk_state_names; extern struct state_names drbd_error_messages; enum drbd_packet; extern const char *drbd_repl_str(enum drbd_repl_state); extern const char *drbd_conn_str(enum drbd_conn_state); extern const char *drbd_role_str(enum drbd_role); extern const char *drbd_disk_str(enum drbd_disk_state); extern const char *drbd_set_st_err_str(enum drbd_state_rv); extern const char *drbd_packet_name(enum drbd_packet); #endif /* __DRBD_STRINGS_H */ drbd-utils-8.9.6/configure.ac0000644000175000017500000003117312654447436016015 0ustar apoikosapoikosdnl dnl autoconf for DRBD dnl dnl License: GNU General Public License Version 2 (GPLv2) dnl Minimum autoconf version we require AC_PREREQ(2.53) dnl What we are, our version, who to bug in case of problems AC_INIT(DRBD, 8.9.6, [drbd-dev@lists.linbit.com]) dnl Sanitize $prefix. Autoconf does this by itself, but so late in the dnl generated configure script that the expansion does not occur until dnl after our eval magic below. if test "$prefix" = "NONE"; then prefix=$ac_default_prefix fi exec_prefix=$prefix dnl Expand autoconf variables so that we dont end up with '${prefix}' dnl in #defines dnl Autoconf deliberately leaves them unexpanded to allow make dnl exec_prefix=/foo install. DRBD supports only DESTDIR, KDIR and dnl KVER to be invoked with make. prefix="`eval echo ${prefix}`" exec_prefix="`eval echo ${exec_prefix}`" bindir="`eval echo ${bindir}`" sbindir="`eval echo ${sbindir}`" libexecdir="`eval echo ${libexecdir}`" datarootdir="`eval echo ${datarootdir}`" datadir="`eval echo ${datadir}`" sysconfdir="`eval echo ${sysconfdir}`" sharedstatedir="`eval echo ${sharedstatedir}`" localstatedir="`eval echo ${localstatedir}`" libdir="`eval echo ${libdir}`" includedir="`eval echo ${includedir}`" oldincludedir="`eval echo ${oldincludedir}`" infodir="`eval echo ${infodir}`" mandir="`eval echo ${mandir}`" docdir="`eval echo ${docdir}`" dnl "--with-" options (all except rgm enabled by default, pass --without- to disable) WITH_83_SUPPORT=yes WITH_84_SUPPORT=yes WITH_UDEV=yes WITH_XEN=yes WITH_PACEMAKER=yes WITH_HEARTBEAT=yes WITH_RGMANAGER=no WITH_BASHCOMPLETION=yes WITH_NOARCH_SUBPACKAGES=no WITH_MANUAL=yes AC_ARG_WITH([83support], [AS_HELP_STRING([--without-83support], [Do not include support for drbd driver/module <= 8.3])], [WITH_83_SUPPORT=$withval]) AC_ARG_WITH([84support], [AS_HELP_STRING([--without-84support], [Do not include support for drbd driver/module 8.4])], [WITH_84_SUPPORT=$withval]) AC_ARG_WITH([udev], [AS_HELP_STRING([--with-udev], [Enable udev integration])], [WITH_UDEV=$withval]) AC_ARG_WITH([xen], [AS_HELP_STRING([--with-xen], [Enable Xen integration])], [WITH_XEN=$withval]) AC_ARG_WITH([pacemaker], [AS_HELP_STRING([--with-pacemaker], [Enable Pacemaker integration])], [WITH_PACEMAKER=$withval]) AC_ARG_WITH([heartbeat], [AS_HELP_STRING([--with-heartbeat], [Enable Heartbeat v1 haresources integration scripts])], [WITH_HEARTBEAT=$withval]) AC_ARG_WITH([rgmanager], [AS_HELP_STRING([--with-rgmanager], [Enable Red Hat Cluster Suite integration])], [WITH_RGMANAGER=$withval]) AC_ARG_WITH([bashcompletion], [AS_HELP_STRING([--with-bashcompletion], [Enable programmable bash completion])], [WITH_BASHCOMPLETION=$withval]) AC_ARG_WITH([distro], [AS_HELP_STRING([--with-distro], [Configure for a specific distribution (supported values: generic, redhat, suse, debian, gentoo, slackware; default is to autodetect)])], [DISTRO=$withval]) AC_ARG_WITH([initdir], [AS_HELP_STRING([--with-initdir], [Override directory for init scripts (default is distribution-specific)])], [INITDIR=$withval]) AC_ARG_WITH([noarchsubpkg], [AS_HELP_STRING([--with-noarchsubpkg], [Build subpackages that support it for the "noarch" architecture (makes sense only with --enable-spec, supported by RPM from 4.6.0 forward)])], [WITH_NOARCH_SUBPACKAGES=$withval]) AC_ARG_ENABLE([spec], [AS_HELP_STRING([--enable-spec], [Rather than creating Makefiles, create an RPM spec file only])], [SPECMODE=$enableval], [SPECMODE=""]) AC_ARG_WITH([manual], [AS_HELP_STRING([--without-manual], [Do not include manual pages])], [WITH_MANUAL=$withval]) AC_SUBST(WITH_83_SUPPORT) AC_SUBST(WITH_84_SUPPORT) AC_SUBST(WITH_UDEV) AC_SUBST(WITH_XEN) AC_SUBST(WITH_PACEMAKER) AC_SUBST(WITH_HEARTBEAT) AC_SUBST(WITH_RGMANAGER) AC_SUBST(WITH_BASHCOMPLETION) AC_SUBST(WITH_MANUAL) dnl Do we know where systemd unit files go? PKG_PROG_PKG_CONFIG AC_ARG_WITH([systemdunitdir], [AC_HELP_STRING([--with-systemdunitdir=DIR], [Directory for systemd service files [Auto]])], [WITH_SYSTEMD_UNIT_DIR=$withval]) if test x"$with_systemdunitdir" = x || \ test x"$with_systemdunitdir" = xyes ; then if test x"$PKG_CONFIG" != x; then systemdunitdir=$($PKG_CONFIG --variable=systemdsystemunitdir systemd) fi if test x"$systemdunitdir" = x; then AC_MSG_NOTICE([Could not detect systemd unit directory]) fi else systemdunitdir=$with_systemdunitdir fi AC_SUBST(systemdunitdir) AC_MSG_RESULT([Using systemd unit directory: $systemdunitdir]) AC_ARG_WITH(tmpfilesdir, AC_HELP_STRING([--with-tmpfilesdir=DIR], [install configuration files for management of volatile files and directories in DIR [[PREFIX/lib/tmpfiles.d]]]), tmpfilesdir=$withval, tmpfilesdir='${prefix}/lib/tmpfiles.d') AC_SUBST(tmpfilesdir) # set default early default_udevdir=/lib/udev if test x"$with_udev" = x || \ test x"$with_udev" = xyes ; then if test x"$PKG_CONFIG" != x; then udevdir=$($PKG_CONFIG --variable=udevdir udev) fi if test x"$udevdir" = x; then AC_MSG_NOTICE([Could not detect udev rules directory, using default]) udevdir=$default_udevdir fi AC_MSG_RESULT([Using udev rules directory: $udevdir]) else udevdir=$default_udevdir fi dnl always replace, even if not used AC_SUBST(udevdir) udevrulesdir=$udevdir/rules.d AC_SUBST(udevrulesdir) AC_ARG_WITH([initscripttype], [AS_HELP_STRING([--with-initscripttype=INIT_SCRIPT_TYPE], [Type of init script to install (sysv|systemd|both). [auto]]) ]) case "$with_initscripttype" in "") if grep -ql systemd /sbin/init ; then initscripttype=systemd else initscripttype=sysv fi ;; sysv|systemd|both) initscripttype=$with_initscripttype ;; *) AC_MSG_ERROR([Illegal value -$with_initscripttype- for option --with-initscripttype]) ;; esac AC_SUBST(initscripttype) dnl Checks for programs AC_PROG_CC AC_PROG_LN_S AC_PATH_PROG(SED, sed) AC_PATH_PROG(GREP, grep) AC_PATH_PROG(FLEX, flex) AC_PATH_PROG(RPMBUILD, rpmbuild) AC_PATH_PROG(XSLTPROC, xsltproc) AC_PATH_PROG(TAR, tar) AC_PATH_PROG(GIT, git) AC_PATH_PROG(DPKG_BUILDPACKAGE, dpkg-buildpackage) AC_PATH_PROG(UDEVADM, udevadm, [false], [/sbin$PATH_SEPARATOR$PATH]) AC_PATH_PROG(UDEVINFO, udevinfo, [false], [/sbin$PATH_SEPARATOR$PATH]) if test -z "$CC"; then AC_MSG_ERROR([Cannot build utils without a C compiler.]) fi if test -z $FLEX; then AC_MSG_ERROR([Cannot build utils without flex.]) fi if test -z $RPMBUILD; then AC_MSG_WARN([No rpmbuild found, building RPM packages is disabled.]) fi if test -z $DPKG_BUILDPACKAGE; then AC_MSG_WARN([No dpkg-buildpackage found, building Debian packages is disabled.]) fi if test -z $XSLTPROC; then AC_MSG_WARN([Cannot build man pages without xsltproc. You may safely ignore this warning when building from a tarball.]) dnl default to some sane value at least, dnl so the error message about command not found makes sense dnl otherwise you get "--xinclude ... command not found" :-/ XSLTPROC=xsltproc fi if test -z $GIT; then AC_MSG_WARN(Cannot update buildtag without git. You may safely ignore this warning when building from a tarball.) fi if test $UDEVADM = false && test $UDEVINFO = false; then if test "$WITH_UDEV" = "yes"; then AC_MSG_WARN([udev support enabled, but neither udevadm nor udevinfo found on this system.]) fi fi dnl special header checks AC_LANG(C) AC_COMPILE_IFELSE([AC_LANG_SOURCE[ #include static unsigned int dummy = CTRL_CMD_DELMCAST_GRP; ]], [AC_DEFINE([HAVE_CTRL_CMD_DELMCAST_GRP],1,[Does genetlink provide CTRL_CMD_DELMCAST_GRP already])]) dnl Checks for system services BASH_COMPLETION_SUFFIX="" UDEV_RULE_SUFFIX="" RPM_DIST_TAG="" RPM_BUILDREQ_DEFAULT="gcc flex glibc-devel make" RPM_SUBPACKAGE_NOARCH="" RPM_REQ_PACEMAKER="" RPM_REQ_HEARTBEAT="" RPM_REQ_BASH_COMPLETION="" RPM_REQ_XEN="" RPM_REQ_CHKCONFIG_POST="" RPM_REQ_CHKCONFIG_PREUN="" dnl figure out the distribution we're running on, and set some variables accordingly if test -z $DISTRO; then AC_CHECK_FILE(/etc/gentoo-release, [DISTRO="gentoo"]) AC_CHECK_FILE(/etc/redhat-release, [DISTRO="redhat"]) AC_CHECK_FILE(/etc/slackware-version, [DISTRO="slackware"]) AC_CHECK_FILE(/etc/debian_version, [DISTRO="debian"]) AC_CHECK_FILE(/etc/SuSE-release, [DISTRO="suse"]) fi case "$DISTRO" in gentoo) AC_MSG_NOTICE([configured for Gentoo.]) ;; redhat) test -z $INITDIR && INITDIR="$sysconfdir/rc.d/init.d" RPM_DIST_TAG="%{?dist}" dnl Fedora/Red Hat packaging guidelines mandate that packages dnl belonging to the "minimal build system" should not be dnl listed in BuildRequires RPM_BUILDREQ_DEFAULT="flex" RPM_REQ_CHKCONFIG_POST="Requires(post): chkconfig" RPM_REQ_CHKCONFIG_PREUN="Requires(preun): chkconfig" AC_MSG_NOTICE([configured for Red Hat (includes Fedora, RHEL, CentOS).]) AC_CHECK_FILE(/etc/fedora-release, [SUB_DISTRO="fedora"], [SUB_DISTRO="RHEL"]) if test "$SUB_DISTRO" = "fedora"; then # pacemaker, heartbeat and bash-completion are not available in RHEL # Xen: Be relaxed on RHEL (hassle free update). Be strict on Fedora RPM_REQ_PACEMAKER="Requires: pacemaker" RPM_REQ_HEARTBEAT="Requires: heartbeat" RPM_REQ_BASH_COMPLETION="Requires: bash-completion" RPM_REQ_XEN="Requires: xen" fi ;; slackware) test -z $INITDIR && INITDIR="$sysconfdir/rc.d" AC_MSG_NOTICE([configured for Slackware.]) ;; debian) AC_MSG_NOTICE([configured for Debian (includes Ubuntu).]) ;; suse) BASH_COMPLETION_SUFFIX=".sh" # RPM_REQ_CHKCONFIG_POST="" chkconfig is part of aaa_base on suse # RPM_REQ_CHKCONFIG_PREUN="" chkconfig is part of aaa_base on suse AC_MSG_NOTICE([configured for SUSE (includes openSUSE, SLES).]) RPM_REQ_BASH_COMPLETION="Requires: bash" # The following are disabled for hassle free updates: # RPM_REQ_XEN="Requires: xen" # RPM_REQ_PACEMAKER="Requires: pacemaker" # RPM_REQ_HEARTBEAT="Requires: heartbeat" # Unfortunately gcc on SLES9 is broken with -O2. Works with -O1 if grep -q 'VERSION = 9' /etc/SuSE-release; then CFLAGS="-g -O1" fi ;; "") AC_MSG_WARN([Unable to determine what distribution we are running on. Distribution-specific features will be disabled.]) ;; esac dnl INITDIR may be set with --with-initdir, or set in the distro dnl detection magic above. If unset down to here, use a sensible dnl default. test -z $INITDIR && INITDIR="$sysconfdir/init.d" dnl Our udev rules file is known to work only with udev >= 85 if test "$WITH_UDEV" = "yes"; then udev_version=`$UDEVADM version 2>/dev/null` || udev_version=`$UDEVINFO -V | cut -d " " -f 3` if test -z $udev_version || test $udev_version -lt 85; then UDEV_RULE_SUFFIX=".disabled" AC_MSG_WARN([Obsolete or unknown udev version. Installing disabled udev rules.]) fi fi dnl Our sub-packages can be built for noarch, but RPM only supports dnl this from version 4.6.0 forward if test "$WITH_NOARCH_SUBPACKAGES" = "yes"; then RPM_SUBPACKAGE_NOARCH="BuildArch: noarch" fi AC_SUBST(DISTRO) AC_SUBST(INITDIR) AC_SUBST(BASH_COMPLETION_SUFFIX) AC_SUBST(UDEV_RULE_SUFFIX) AC_SUBST(RPM_DIST_TAG) AC_SUBST(RPM_BUILDREQ_DEFAULT) AC_SUBST(RPM_SUBPACKAGE_NOARCH) AC_SUBST(RPM_REQ_PACEMAKER) AC_SUBST(RPM_REQ_HEARTBEAT) AC_SUBST(RPM_REQ_BASH_COMPLETION) AC_SUBST(RPM_REQ_XEN) AC_SUBST(RPM_REQ_CHKCONFIG_POST) AC_SUBST(RPM_REQ_CHKCONFIG_PREUN) AH_TEMPLATE(DRBD_LIB_DIR, [Local state directory. Commonly /var/lib/drbd or /usr/local/var/lib/drbd]) AH_TEMPLATE(DRBD_RUN_DIR, [Runtime state directory. Commonly /var/run/drbd or /usr/local/var/run/drbd]) AH_TEMPLATE(DRBD_LOCK_DIR, [Local lock directory. Commonly /var/lock or /usr/local/var/lock]) AH_TEMPLATE(DRBD_CONFIG_DIR, [Local configuration directory. Commonly /etc or /usr/local/etc]) AH_TEMPLATE(DRBD_LEGACY_83, [Include support for drbd-8.3 kernel code]) AH_TEMPLATE(DRBD_LEGACY_84, [Include support for drbd-8.4 kernel code]) AC_SUBST(DRBD_LIB_DIR, [$localstatedir/lib/$PACKAGE_TARNAME]) AC_SUBST(DRBD_RUN_DIR, [$localstatedir/run/$PACKAGE_TARNAME]) AC_SUBST(DRBD_LOCK_DIR, [$localstatedir/lock]) AC_SUBST(DRBD_CONFIG_DIR, [$sysconfdir]) AC_DEFINE_UNQUOTED(DRBD_LIB_DIR, ["$DRBD_LIB_DIR"]) AC_DEFINE_UNQUOTED(DRBD_RUN_DIR, ["$DRBD_RUN_DIR"]) AC_DEFINE_UNQUOTED(DRBD_LOCK_DIR, ["$DRBD_LOCK_DIR"]) AC_DEFINE_UNQUOTED(DRBD_CONFIG_DIR, ["$DRBD_CONFIG_DIR"]) if test "$WITH_83_SUPPORT" = "yes"; then AC_DEFINE(DRBD_LEGACY_83, [1]) fi if test "$WITH_84_SUPPORT" = "yes"; then AC_DEFINE(DRBD_LEGACY_84, [1]) fi dnl The configuration files we create (from their .in template) if test -z $SPECMODE; then AC_CONFIG_FILES(Makefile user/shared/Makefile user/v9/Makefile user/v83/Makefile user/v84/Makefile scripts/Makefile documentation/v9/Makefile documentation/v83/Makefile documentation/v84/Makefile scripts/drbd.rules) AC_CONFIG_HEADERS(user/shared/config.h) else AC_CONFIG_FILES(drbd.spec) fi dnl output AC_OUTPUT drbd-utils-8.9.6/README0000644000175000017500000000065112466702073014374 0ustar apoikosapoikos DRBD ====== by Philipp Reisner and Lars Ellenberg LINBIT Information Technologies Reference documentation is included in the documentation directory. Please refer to the web pages at http://www.drbd.org/ http://www.drbd.org/docs/introduction/ to find maintained information. drbd-utils-8.9.6/drbd.spec.in0000644000175000017500000003163212654447436015723 0ustar apoikosapoikos# Define init script directory. %{_initddir} is available from Fedora # 9 forward; CentOS knows 5 only %{_initrddir}. Neither are known to # autoconf... %{!?_initddir: %{expand: %%global _initddir %{_initrddir}}} # Compatibility macro wrappers for legacy RPM versions that do not # support conditional builds %{!?bcond_without: %{expand: %%global bcond_without() %%{expand:%%%%{!?_without_%%{1}:%%%%global with_%%{1} 1}}}} %{!?bcond_with: %{expand: %%global bcond_with() %%{expand:%%%%{?_with_%%{1}:%%%%global with_%%{1} 1}}}} %{!?with: %{expand: %%global with() %%{expand:%%%%{?with_%%{1}:1}%%%%{!?with_%%{1}:0}}}} %{!?without: %{expand: %%global without() %%{expand:%%%%{?with_%%{1}:0}%%%%{!?with_%%{1}:1}}}} %if 0%{!?initscripttype:1} # initscripttype not explicitly defined in some macro file or on commandline # use presence of systemd_post macro to determine the initscripttype %if %{?systemd_post:1}%{!?systemd_post:0} %global initscripttype systemd %else %global initscripttype sysv %endif %endif # Conditionals # Invoke "rpmbuild --without " or "rpmbuild --with " # to disable or enable specific features %bcond_without manual %bcond_without udev %bcond_without pacemaker %bcond_with rgmanager %bcond_without heartbeat # conditionals may not contain "-" nor "_", hence "bashcompletion" %bcond_without bashcompletion %bcond_without sbinsymlinks # --with xen is ignored on any non-x86 architecture %bcond_without xen %bcond_without 83support %bcond_without 84support %ifnarch %{ix86} x86_64 %global _without_xen --without-xen %endif Name: drbd Summary: DRBD driver for Linux Version: @PACKAGE_VERSION@ Release: 1@RPM_DIST_TAG@ Source: http://oss.linbit.com/drbd/drbd-utils-%{version}.tar.gz License: GPLv2+ ExclusiveOS: linux Group: System Environment/Kernel URL: http://www.drbd.org/ BuildRoot: %(mktemp -ud %{_tmppath}/drbd-utils-%{version}-%{release}-XXXXXX) BuildRequires: @RPM_BUILDREQ_DEFAULT@ Requires: drbd-utils = %{version} %ifarch %{ix86} x86_64 %if %{with xen} Requires: drbd-xen = %{version} %endif %endif %if %{with udev} Requires: drbd-udev = %{version} BuildRequires: udev %endif %if %{with pacemaker} Requires: drbd-pacemaker = %{version} %endif ## %if %{with rgmanager} ## ## No. ## ## We don't want to annoy the majority of our userbase on pacemaker ## ## by pulling in the full rgmanager stack via drbd-rgmanager as well. ## Requires: drbd-rgmanager = %{version} ## %endif ## ## ## Neither do we want to force anyone to install heartbeat ## ## Usually they use corosync meanwhile. ## ## No need to pull in heartbeat via the drbd-heartbeat scripts ## ## meant for haresources mode ## %if %{with heartbeat} ## Requires: %{name}-heartbeat = %{version} ## %endif %if %{with bashcompletion} Requires: drbd-bash-completion = %{version} %endif %description DRBD mirrors a block device over the network to another machine. Think of it as networked raid 1. It is a building block for setting up high availability (HA) clusters. This is a virtual package, installing the full DRBD userland suite. # Just a few docs go into the "drbd" package. Everything else is part # of one of the drbd-* packages. %files %defattr(-,root,root,-) %doc COPYING %doc ChangeLog %doc README %package utils Summary: Management utilities for DRBD Group: System Environment/Kernel # Our kernel modules "require" specific drbd-utils versions, not ranges. # Which was natural as long as userland and module shared the same repo # and source tarball, and would be build together. # # Now we split the userland part, we "provide" a list of versions here, # to be able to use this package with existing module packages. # %if %{with 84support} # which 8.4 version equivalent this package provides Provides: drbd-utils = 8.4.5 Provides: drbd-utils = 8.4.4 Provides: drbd-utils = 8.4.3 Provides: drbd-utils = 8.4.2 Provides: drbd-utils = 8.4.1 Provides: drbd-utils = 8.4.0 %endif %if %{with 83support} # which 8.3 version equivalent this package provides Provides: drbd-utils = 8.3.16 %endif # We used to have one monolithic userland package. # Since all other packages require drbd-utils, # it should be sufficient to add the conflict here. Conflicts: drbd < 8.3.6 # These exist in centos extras: Conflicts: drbd82 drbd83 @RPM_REQ_CHKCONFIG_POST@ @RPM_REQ_CHKCONFIG_PREUN@ %description utils DRBD mirrors a block device over the network to another machine. Think of it as networked raid 1. It is a building block for setting up high availability (HA) clusters. This packages includes the DRBD administration tools. %files utils %defattr(755,root,root,-) %if %{with sbinsymlinks} /sbin/drbdsetup /sbin/drbdadm /sbin/drbdmeta %endif %{_sbindir}/drbdsetup %{_sbindir}/drbdadm %{_sbindir}/drbdmeta %if %{with 83support} %dir /lib/drbd/ /lib/drbd/drbdsetup-83 /lib/drbd/drbdadm-83 %endif %if %{with 84support} /lib/drbd/drbdsetup-84 /lib/drbd/drbdadm-84 %endif %if %{initscripttype} == "systemd" %{_unitdir}/drbd.service %{_tmpfilesdir}/drbd.conf /lib/drbd/drbd %else %{_initddir}/drbd %endif %{_sbindir}/drbd-overview %dir %{_prefix}/lib/drbd %{_prefix}/lib/drbd/outdate-peer.sh %{_prefix}/lib/drbd/snapshot-resync-target-lvm.sh %{_prefix}/lib/drbd/unsnapshot-resync-target-lvm.sh %{_prefix}/lib/drbd/notify-out-of-sync.sh %{_prefix}/lib/drbd/notify-split-brain.sh %{_prefix}/lib/drbd/notify-emergency-reboot.sh %{_prefix}/lib/drbd/notify-emergency-shutdown.sh %{_prefix}/lib/drbd/notify-io-error.sh %{_prefix}/lib/drbd/notify-pri-lost-after-sb.sh %{_prefix}/lib/drbd/notify-pri-lost.sh %{_prefix}/lib/drbd/notify-pri-on-incon-degr.sh %{_prefix}/lib/drbd/notify.sh %dir %{_var}/lib/drbd %ghost %dir %{_var}/run/drbd %defattr(-,root,root,-) %config(noreplace) %{_sysconfdir}/drbd.conf %dir %{_sysconfdir}/drbd.d %config(noreplace) %{_sysconfdir}/drbd.d/global_common.conf %if %{without manual} %else %{_mandir}/man8/drbd-* %{_mandir}/man8/drbdsetup-* %{_mandir}/man8/drbdadm-* %{_mandir}/man5/drbd.conf-* %{_mandir}/man8/drbdmeta-* %endif %doc scripts/drbd.conf.example %doc COPYING %doc ChangeLog %doc README %ifarch %{ix86} x86_64 %if %{with xen} %package xen Summary: Xen block device management script for DRBD Group: System Environment/Kernel Requires: drbd-utils = %{version}-%{release} @RPM_REQ_XEN@ @RPM_SUBPACKAGE_NOARCH@ %description xen This package contains a Xen block device helper script for DRBD, capable of promoting and demoting DRBD resources as necessary. %files xen %defattr(755,root,root,-) %{_sysconfdir}/xen/scripts/block-drbd %endif # with xen %endif # arch %{ix86} x86_64 %if %{with udev} %package udev Summary: udev integration scripts for DRBD Group: System Environment/Kernel Requires: drbd-utils = %{version}-%{release}, udev @RPM_SUBPACKAGE_NOARCH@ %description udev This package contains udev helper scripts for DRBD, managing symlinks to DRBD devices in /dev/drbd/by-res and /dev/drbd/by-disk. %files udev %defattr(-,root,root,-) %config @udevrulesdir@/65-drbd.rules* %endif # with udev %if %{with pacemaker} %package pacemaker Summary: Pacemaker resource agent for DRBD Group: System Environment/Base Requires: drbd-utils = %{version}-%{release} @RPM_REQ_PACEMAKER@ License: GPLv2 @RPM_SUBPACKAGE_NOARCH@ %description pacemaker This package contains the master/slave DRBD resource agent for the Pacemaker High Availability cluster manager. %files pacemaker %defattr(755,root,root,-) %{_prefix}/lib/drbd/crm-fence-peer.sh %{_prefix}/lib/drbd/crm-unfence-peer.sh %{_prefix}/lib/drbd/stonith_admin-fence-peer.sh %{_prefix}/lib/ocf/resource.d/linbit/drbd %endif # with pacemaker # Dependencies for drbd-rgmanager are particularly awful. On RHEL 5 # and prior (and corresponding Fedora releases), %{_datadir}/cluster # was owned by rgmanager version 2, so we have to depend on that. # # With Red Hat Cluster 3.0.1 (around Fedora 12), the DRBD resource # agent was merged in, and it became part of the resource-agents 3 # package (which of course is different from resource-agents on all # other platforms -- go figure). So for resource-agents >= 3, we must # generally conflict. # # Then for RHEL 6, Red Hat in all their glory decided to keep the # packaging scheme, but kicked DRBD out of the resource-agents # package. Thus, for RHEL 6 specifically, we must not conflict with # resource-agents >=3, but instead require it. # # The saga continues: # In RHEL 6.1 they have listed the drbd resource agent as valid agent, # but do not include it in their resource-agents package. -> So we # drop any dependency regarding rgmanager's version. # # All of this for exactly two (2) files. %if %{with rgmanager} %package rgmanager Summary: Red Hat Cluster Suite agent for DRBD Group: System Environment/Base Requires: drbd-utils = %{version}-%{release} @RPM_SUBPACKAGE_NOARCH@ %description rgmanager This package contains the DRBD resource agent for the Red Hat Cluster Suite resource manager. As of Red Hat Cluster Suite 3.0.1, the DRBD resource agent is included in the Cluster distribution. %files rgmanager %defattr(755,root,root,-) %{_datadir}/cluster/drbd.sh %{_prefix}/lib/drbd/rhcs_fence %defattr(-,root,root,-) %{_datadir}/cluster/drbd.metadata %endif # with rgmanager %if %{with heartbeat} %package heartbeat Summary: Heartbeat resource agent for DRBD Group: System Environment/Base Requires: %{name}-utils = %{version}-%{release} @RPM_REQ_HEARTBEAT@ License: GPLv2 @RPM_SUBPACKAGE_NOARCH@ %description heartbeat This package contains the DRBD resource agents for the Heartbeat cluster resource manager (in v1 compatibility mode). %files heartbeat %defattr(755,root,root,-) %{_sysconfdir}/ha.d/resource.d/drbddisk %{_sysconfdir}/ha.d/resource.d/drbdupper %defattr(-,root,root,-) %if %{without manual} %else %{_mandir}/man8/drbddisk-* %endif %endif # with heartbeat %if %{with bashcompletion} %package bash-completion Summary: Programmable bash completion support for drbdadm Group: System Environment/Base Requires: drbd-utils = %{version}-%{release} @RPM_REQ_BASH_COMPLETION@ @RPM_SUBPACKAGE_NOARCH@ %description bash-completion This package contains programmable bash completion support for the drbdadm management utility. %files bash-completion %defattr(-,root,root,-) %config %{_sysconfdir}/bash_completion.d/drbdadm* %endif # with bashcompletion %prep %setup -q -n drbd-utils-%{version} %build # rebuild configure... aclocal autoheader autoconf %configure \ %{?_without_udev} \ %{?_without_xen} \ %{?_without_pacemaker} \ %{?_without_heartbeat} \ %{?_with_rgmanager} \ %{?_without_bashcompletion} \ %{?_without_83support} \ %{?_without_84support} \ %{?_without_manual} \ --with-initdir=%{_initddir} \ %{?_tmpfilesdir:--with-tmpfilesdir=%{_tmpfilesdir}} \ --with-initscripttype=%{initscripttype} make %{?_smp_mflags} %install rm -rf %{buildroot} make install DESTDIR=%{buildroot} CREATE_MAN_LINK=no %if %{with sbinsymlinks} # Don't do this if you are already on a /sbin -=> /usr/sbin distro # compat: we used to live in /sbin/ # there may be many hardcoded /sbin/drbd* out there, # including variants of our own scripts. mkdir -p %{buildroot}/var/run/drbd mkdir %{buildroot}/sbin/ cd %{buildroot}/sbin/ ln -sv ..%{_sbindir}/drbdadm . ln -sv ..%{_sbindir}/drbdmeta . ln -sv ..%{_sbindir}/drbdsetup . %endif %clean rm -rf %{buildroot} %post utils %if %{initscripttype} == "systemd" %systemd_post drbd.service %else chkconfig --add drbd %endif %if %{without manual} %else for f in drbd drbdadm drbdmeta drbdsetup; do ln -sf $f-8.4.8.gz %{_mandir}/man8/$f.8.gz done ln -sf drbd.conf-8.4.5.gz %{_mandir}/man5/drbd.conf.5.gz %endif %if %{without udev} for i in `seq 0 15` ; do test -b /dev/drbd$i || mknod -m 0660 /dev/drbd$i b 147 $i; done %endif #without udev %preun utils for f in drbd drbdadm drbdmeta drbdsetup; do rm -f %{_mandir}/man8/$f.8.gz done rm -f %{_mandir}/man5/drbd.conf.5.gz %if %{initscripttype} == "systemd" %systemd_preun drbd.service %else if [ $1 -eq 0 ]; then %{_initrddir}/drbd stop >/dev/null 2>&1 /sbin/chkconfig --del drbd fi %endif %if %{initscripttype} == "systemd" %postun utils %systemd_postun %endif %changelog * Wed Feb 3 2016 Roland Kammerer - 8.9.6-1 - New upstream release. * Wed Dec 16 2015 Philipp Reisner - 8.9.5-1 - New upstream release. * Fri Sep 18 2015 Philipp Reisner - 8.9.4-1 - New upstream release. * Wed Jul 29 2015 Lars Ellenberg - 8.9.3-2 - fixes for regression of drbd-8.4 pacemaker integration * Tue Jun 16 2015 Philipp Reisner - 8.9.3-1 - New upstream release. * Fri Apr 03 2015 Philipp Reisner - 8.9.2-1 - New upstream release. * Fri Aug 08 2014 Lars Ellenberg - 8.9.1-3 - some more patches had been only merged into the "9" tools, but unfortunately not the 8.4 tool compat tools - place udev rules into $udevdir/*rules.d* - rebuild: fixed default in case pkg-config does not know about udevdir - fixed udev generated "by-disk" symlinks for drbd 8.4 * Tue Aug 05 2014 Lars Ellenberg - 8.9.1-1 - New upstream release. * Tue Jun 10 2014 Philipp Reisner - 8.9.0-1 - New upstream release. drbd-utils-8.9.6/scripts/0000755000175000017500000000000012654475367015215 5ustar apoikosapoikosdrbd-utils-8.9.6/scripts/drbd.sh.rhcs0000755000175000017500000000657612466702073017427 0ustar apoikosapoikos#!/bin/bash # # Copyright LINBIT, 2008 # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2, or (at your option) any # later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; see the file COPYING. If not, write to the # Free Software Foundation, Inc., 675 Mass Ave, Cambridge, # MA 02139, USA. # # # DRBD resource management using the drbdadm utility. # LC_ALL=C LANG=C PATH=/bin:/sbin:/usr/bin:/usr/sbin export LC_ALL LANG PATH . $(dirname $0)/ocf-shellfuncs drbd_verify_all() { # Do we have the drbdadm utility? if ! which drbdadm >/dev/null 2>&1 ; then ocf_log error "drbdadm not installed, not found in PATH ($PATH), or not executable." return $OCF_ERR_INSTALLED fi # Is drbd loaded? if ! grep drbd /proc/modules >/dev/null 2>&1; then ocf_log error "drbd not found in /proc/modules. Do you need to modprobe?" return $OCF_ERR_INSTALLED fi # Do we have the "resource" parameter? if [ -n "$OCF_RESKEY_resource" ]; then # Can drbdadm parse the resource name? if ! drbdadm sh-dev $OCF_RESKEY_resource >/dev/null 2>&1; then ocf_log error "DRBD resource \"$OCF_RESKEY_resource\" not found." return $OCF_ERR_CONFIGURED fi # Is the backing device a locally available block device? backing_dev=$(drbdadm sh-ll-dev $OCF_RESKEY_resource) for dev in $backing_dev ; do [ -b $dev ] && continue; ocf_log error "Backing device for DRBD resource \"$OCF_RESKEY_resource\" ($dev) not found or not a block device." return $OCF_ERR_INSTALLED done fi return 0 } drbd_status() { local all_primary=true for role in $(drbdadm role $OCF_RESKEY_resource); do case $role in Primary/*) ;; Secondary/*) all_primary=false ;; *) return $OCF_ERR_GENERIC ;; esac done $all_primary && return $OCF_SUCCESS return $OCF_NOT_RUNNING } drbd_promote() { drbdadm primary $OCF_RESKEY_resource || return $? } drbd_demote() { drbdadm secondary $OCF_RESKEY_resource || return $? } if [ -z "$OCF_CHECK_LEVEL" ]; then OCF_CHECK_LEVEL=0 fi # This one doesn't need to pass the verify check case $1 in meta-data) cat `echo $0 | sed 's/^\(.*\)\.sh$/\1.metadata/'` && exit 0 exit $OCF_ERR_GENERIC ;; esac # Everything else does drbd_verify_all || exit $? case $1 in start) if drbd_status; then ocf_log debug "DRBD resource ${OCF_RESKEY_resource} already configured" exit 0 fi drbd_promote if [ $? -ne 0 ]; then exit $OCF_ERR_GENERIC fi exit $? ;; stop) if drbd_status; then drbd_demote if [ $? -ne 0 ]; then exit $OCF_ERR_GENERIC fi else ocf_log debug "DRBD resource ${OCF_RESKEY_resource} is not configured" fi exit 0 ;; status|monitor) drbd_status exit $? ;; restart) $0 stop || exit $OCF_ERR_GENERIC $0 start || exit $OCF_ERR_GENERIC exit 0 ;; verify-all) exit 0 ;; *) echo "usage: $0 {start|stop|status|monitor|restart|meta-data|verify-all}" exit $OCF_ERR_GENERIC ;; esac drbd-utils-8.9.6/scripts/drbd-overview.pl0000755000175000017500000003073512634271674020335 0ustar apoikosapoikos#!/usr/bin/perl # vim: set sw=4 ts=4 et : use strict; use warnings; ## MAYBE set 'sane' PATH ?? $ENV{LANG} = 'C'; $ENV{LC_ALL} = 'C'; $ENV{LANGUAGE} = 'C'; #use Data::Dumper; # globals my $PROC_DRBD = "/proc/drbd"; my ($HOSTNAME) = (`uname -n` =~ /(\S+)/); my $stderr_to_dev_null = 1; my $watch = 0; my %drbd; my %minor_of_name; my $DRBD_VERSION; my @DRBD_VERSION; our $use_colors = (-t STDOUT) + 0; my %xen_info; my %virsh_info; # sets $drbd{minor}->{name} (and possibly ->{ll_dev}) sub map_minor_to_resource_names() { my @drbdadm_sh_status = `drbdadm sh-status`; my ($ll_res, $ll_dev, $ll_minor, $conf_res, $conf_vnr, $minor, $name, $vnr); for (@drbdadm_sh_status) { # volumes only present in >= 8.4 # some things generated by drbdadm /^_conf_res_name=(.*)\n/ and $conf_res = $1, $name = $conf_res; /^_conf_volume=(\d+)\n/ and $conf_vnr = $1; /^_stacked_on=(.*?)\n/ and $ll_res = $1; # not always present: /^_stacked_on_device=(.*)\n/ and $ll_dev = $1; /^_stacked_on_minor=(\d+)\n/ and $ll_minor = $1; # rest generated by drbdsetup /^_minor=(.*?)\n/ and $minor = $1; /^_res_name=(.+?)\n/ and $name = $1; /^_volume=(\d+)\n/ and $vnr = $1; /^_sh_status_process/ or next; $drbd{$minor}{name} = $name; if (defined $conf_vnr) { # >= 8.4, append /volume to resource name. # If both are present, they should be the same. But # just in case, prefer the kernel volume number, if it # is present and positive. Else, use the volume number # from the config. $drbd{$minor}{name} .= defined $vnr ? "/$vnr" : "/$conf_vnr"; } $minor_of_name{$name} = $minor; $drbd{$minor}{ll_dev} = defined($ll_dev) ? $ll_minor : $ll_res if $ll_res; } # fix up hack for git versions 8.3.1 > x > 8.3.0: # _stacked_on_minor information is missing, # _stacked_on is resource name # may be defined (and reported) out of order. for my $i (keys %drbd) { next unless exists $drbd{$i}->{ll_dev}; my $lower = $drbd{$i}->{ll_dev}; next if $lower =~ /^\d+$/; next unless exists $minor_of_name{$lower}; $drbd{$i}->{ll_dev} = $minor_of_name{$lower}; } # fix up to be able to report "lower dev of:" for my $i (keys %drbd) { next unless exists $drbd{$i}->{ll_dev}; my $lower = $drbd{$i}->{ll_dev}; $drbd{$lower}->{ll_dev_of} = $i; } } sub ll_dev_info { my $i = shift; ( "ll-dev of:", $i, $drbd{$i}{name} ) } # sets $drbd{minor}->{state} and (and possibly ->{sync}) sub slurp_proc_drbd_or_exit() { $_=; my ($DRBD_VERSION) = /version: ([\d\.]+)/; @DRBD_VERSION = split(/\./, $DRBD_VERSION); my $minor; while (defined($_ = )) { chomp; /^ *(\d+):/ and do { # skip unconfigured devices $minor = $1; if (/^ *(\d+): cs:Unconfigured/) { next unless exists $drbd{$minor} and exists $drbd{$minor}{name}; } my $uc = /Unconfigured/ ? "." : undef; ($drbd{$minor}{conn}) = $uc || m{\bcs:(\w+)\b}; ($drbd{$minor}{role}) = $uc || m{\bro:(\w+/\w+)\b}; ($drbd{$minor}{dstate}) = $uc || m{\bds:(\w+/\w+)\b}; }; /^\t\[.*sync.ed:/ and do { $drbd{$minor}{sync} = $_; }; /^\t[0-9 %]+oos:/ and do { $drbd{$minor}{sync} = $_; }; } close PD; for (values %drbd) { $_->{conn} ||= "Unconfigured"; $_->{role} ||= "."; $_->{dstate} ||= "."; } } our $ansi_color_re = qr{(\033\[[\d;]+?m)}; sub abbreviate { my($w, $max) = @_; $max ||= 15; my $col_pre = ($w =~ s/^$ansi_color_re//o ) ? $1 : ""; my $col_post = ($w =~ s/$ansi_color_re$//o) ? $1 : ""; # keep UPPERCase and a few lowercase characters. # Make "Connecting" to "C'ing", to get it distinct from "Connected" 1 while length($w) > $max && ( $w =~ s/^(C)(onnecting)$/"$1'" . substr($2, 2-$max)/eg || # needs to cut 2 characters, because one is inserted again. $w =~ s/([a-z]+)[a-z]/$1/g ); return $col_pre . substr($w, 0, $max) . $col_post; } # taking a sorted list of keys and a hash, produce a short output. # eg. Connected(*)/WFConnection(alice) sub shorten_list { my ($keys, $hash, $max) = @_; my %vals; my %vl; for my $k (@$keys) { $vals{ $hash->{$k} }{ $k }++; $vl{ $hash->{$k} }++; } # only a single value? Fine! # return abbreviate($hash->{$keys->[0]}, 6) . "(*)" return $hash->{$keys->[0]} . "(" . (values %vl)[0] . "*)" if 1 == (keys %vals); # only 1 or 2 keys, ie. 2 values? Fine, done. return join("/", map { abbreviate($hash->{$_}, 6); } @$keys) if (@$keys <= 2); # get sorted counts. my @v = sort { $b <=> $a; } values %vl; #print "=========", Dumper(\@v); # use a wildcard if one element is 3 or more times used, and more often than every other. my ($wc_data) = (($v[0] >= 3) && ($v[0] != $v[1])) ? grep($vl{$_} == $v[0], keys %vl) : (); my @stg; my %done; push(@stg, abbreviate($wc_data, 4) . "(" . $v[0] . "*)"), $done{$wc_data}++ if ($wc_data); for my $k2 (@$keys) { my $v = $hash->{$k2}; next if $done{$v}++; push @stg, abbreviate($v, 4) . "(" . join(",", keys %{$vals{$v}} ) . ")"; } return join("/", @stg); } sub slurp_drbdsetup() { unless (open(DS,"drbdsetup events2 --now --statistics " . ($use_colors ? "--color=always " : "") . " |")) { print "drbdsetup not started\n"; exit 0; } my(%later, $my_role); while () { chomp; next unless s/^exists //; last if /^-$/; # EOD s/^([\w.-]+) name:([\w.-]+) //; my $what = $1; my $res = $2; my %f = map { split(/:/, $_, 2); } split(/ +/, $_); if ($what eq "resource" && ($my_role = $f{'role'})) { $later{$res}{peers}{states}{$HOSTNAME} = $my_role; # local node is always connected $later{$res}{peers}{conns}{$HOSTNAME} = "Connected"; } elsif ($what eq "connection") { my $p = $f{'conn-name'}; my $cs= $f{'connection'}; my $r = $f{'role'}; # Increase difference between "Connecting" and "Connected" $cs =~ s/^Connecting/'ing/; $later{$res}{peers}{states}{$p} = $r; $later{$res}{peers}{conns}{$p} = $cs; $later{$res}{hosts}{$p}++; } elsif ($what eq "device") { my $minor = $f{minor}; my $vol = $f{volume}; $later{$res}{vol_minor}{$vol} = $minor; $later{$res}{peers}{dstates}{$HOSTNAME} = $f{disk}; } elsif ($what eq "peer-device") { my $n = $f{"conn-name"}; $later{$res}{peers}{dstates}{$n} = $f{"peer-disk"}; } else { warn("unknown key $what\n"); } } for my $res2 (keys %later) { my @h = sort keys %{$later{$res2}{hosts}}; my @h_incl = ($HOSTNAME, @h); my $vol_minor = $later{$res2}{vol_minor}; my $peers = $later{$res2}{peers}; for my $vol2 (keys %$vol_minor) { my $minor2 = $vol_minor->{$vol2}; my $name = length($vol2) ? "$res2/$vol2" : $res2; # create hash $drbd{$minor2}{name} = $name; my $v = $drbd{$minor2}; # role with local=first $v->{role} = join("/", $my_role, shorten_list(\@h, $peers->{states})); # role with all mixed together $v->{role} = shorten_list(\@h_incl, $peers->{states}); $v->{dstate} = shorten_list(\@h_incl, $peers->{dstates}); $v->{conn} = shorten_list(\@h_incl, $peers->{conns}); } } close DS; } # sets $drbd{minor}->{pv_info} sub get_pv_info() { for (`pvs --noheadings --units g -o pv_name,vg_name,pv_size,pv_used`) { m{^\s*/dev/drbd(\d+)\s+(\S+)\s+(\S+)\s+(\S+)\s*$} or next; # PV VG PSize Used $drbd{$1}{pv_info} = { vg => $2, size => $3, used => $4 }; } } sub pv_info { my $t = shift; "lvm-pv:", @{$t}{qw(vg size used)}; } # sets $drbd{minor}->{df_info} sub get_df_info() { for (`df -TPhl -x tmpfs --local`) { # Filesystem Type Size Used Avail Use% Mounted on m{^/dev/drbd(\d+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)} or next; $drbd{$1}{df_info} = { type => $2, size => $3, used => $4, avail => $5, use_percent => $6, mountpoint => $7 }; } } sub df_info { my $t = shift; @{$t}{qw(mountpoint type size used avail use_percent)}; } sub get_swap_info() { open(my $fd, "< /proc/swaps") or return; while (<$fd>) { # Filename Type Size Used Priority # /dev/drbd100 partition 262140 0 -1 m{^/dev/drbd(\d+)\s+(\S+)\s+(\d+)\s+(\d+)} or next; $drbd{$1}{df_info} = { type => 'swap', size => $3, used => $4, }; } } # sets $drbd{minor}->{xen_info} sub get_xen_info() { my $dom; my $running = 0; my %i; for (`xm list --long`) { /^\s+\(name ([^)\n]+)\)/ and $dom = $1; /drbd:([^)\n]+)/ and $i{$minor_of_name{$1}}++; m{phy:/dev/drbd(\d+)} and $i{$1}++; /^\s+\(state r/ and $running = 1; if (/^\)$/) { for (keys %i) { $drbd{$_}{xen_info} = $running ? "\*$dom" : "_$dom"; } $running = 0; %i = (); } } } # set $drbd{minor}->{virsh_info} sub get_virsh_info() { local $/ = undef; my $virsh_list = `virsh list --all`; # Id Name State # ---------------------------------- # 1 mail running # 2 support running # - debian-master shut off # - www shut off my %info; my $virsh_dumpxml; my $pid; $virsh_list =~ s/^\s+Id\s+Name\s+?State\s*-+\n//; while ($virsh_list =~ m{^\s*(\S+)\s+(\S+)\s+(\S.*?)\n}gm) { $info{$2} = { id => $1, name => $2, state => $3 }; # print STDERR "$1, $2, $3\n"; } for my $dom (keys %info) { # add error processing as above $pid = open(V, "-|"); return unless defined $pid; if ($pid == 0) { # child exec("virsh", "dumpxml", $dom) or die "can't exec program: $!"; # NOTREACHED } # parent $_ = ; close(V) or warn "virsh dumpxml exit code: $?\n"; for (m{]*>.*?}gs) { m{} or next; my $dev = $1; if ($dev !~ /^\d+$/) { my @stat = stat("/dev/drbd$dev") or next; $dev = $stat[6] & 0xff; } m{ $info{$dom}->{state} eq 'running' ? "\*$dom" : "_$dom", vdev => $1, bus => $2, }; } } } sub virsh_info { my $t = shift; @{$t}{qw(domname vdev bus)}; } # first, for debugging of this script and its regex'es, # allow reading from a prepared file instead of /proc/drbd # Getopt::Long is standard since quite some time, but in case it's not available somewhere we'll fail soft. eval { use Getopt::Long; GetOptions( "proc-drbd=s" => \$PROC_DRBD, "stderr-to-dev-null|d" => \$stderr_to_dev_null, "color|colors|c:s" => \$use_colors) or die "Unknown command line argument.\n"; $use_colors = 0 if $use_colors =~ m/^(never|no|off)$/; $use_colors = 1 if $use_colors =~ m/^(always|yes|on)$/; warn "unrecognized value for --color" unless $use_colors =~ /^[01]$/; }; open STDERR, "/dev/null" if $stderr_to_dev_null; unless (open(PD,$PROC_DRBD)) { print "drbd not loaded\n"; exit 0; } map_minor_to_resource_names; slurp_proc_drbd_or_exit; slurp_drbdsetup if $DRBD_VERSION[0] >= 9; get_pv_info; get_df_info; get_swap_info; get_xen_info; get_virsh_info; # generate output, adjust columns my @out = []; my @out_plain = []; my @maxw = (); my $line = 0; my @minors_sorted = sort { $a <=> $b } keys %drbd; my $max_minor = $minors_sorted[-1]; my $minor_width = $max_minor > 10 ? 1+int(log($max_minor)/log(10)) : 2; for my $m (@minors_sorted) { my $t = $drbd{$m}; my @used_by = exists $t->{xen_info} ? "xen-vbd: $t->{xen_info}" : exists $t->{pv_info} ? pv_info $t->{pv_info} : exists $t->{df_info} ? df_info $t->{df_info} : exists $t->{virsh_info} ? virsh_info $t->{virsh_info} : exists $t->{ll_dev_of} ? ll_dev_info $t->{ll_dev_of} : (); $out[$line] = [ sprintf("%*u:%s", $minor_width, $m, $t->{name} || "??not-found??"), defined($t->{ll_dev}) ? "^^$t->{ll_dev}" : "", $t->{conn}, $t->{role}, $t->{dstate}, @used_by ]; for (my $c = 0; $c < @{$out[$line]}; $c++) { # strip color codes for column width calculation my $w = $out[$line][$c]; $w =~ s/$ansi_color_re//og; my $l = length($w) + 1; $out_plain[$line][$c] = $w; $maxw[$c] = $l unless $maxw[$c] and $l < $maxw[$c]; } ++$line; if (defined $t->{sync}) { $out[$line++] = [ $t->{sync} ]; } } for my $l (0 .. $#out) { $_ = $out[$l]; for (my $c2 = 0; $c2 < @$_; $c2++) { # printf columns don't know about escape codes, need to pad manually. print $_->[$c2], ' ' x ($maxw[$c2] - length($out_plain[$l][$c2])); } print "\n"; } drbd-utils-8.9.6/scripts/drbd.service0000644000175000017500000000055612477305373017510 0ustar apoikosapoikos[Unit] Description=DRBD -- please disable. Unless you are NOT using a cluster manager. Wants=network.target sshd.service After=network.target sshd.service [Service] Type=oneshot RemainAfterExit=yes ExecStart=/lib/drbd/drbd start ExecStop=/lib/drbd/drbd stop # Re-adjust everything on reload ExecReload=/lib/drbd/drbd reload [Install] WantedBy=multi-user.target drbd-utils-8.9.6/scripts/global_common.conf0000644000175000017500000000401612477305373020665 0ustar apoikosapoikos# DRBD is the result of over a decade of development by LINBIT. # In case you need professional services for DRBD or have # feature requests visit http://www.linbit.com global { usage-count yes; # minor-count dialog-refresh disable-ip-verification # cmd-timeout-short 5; cmd-timeout-medium 121; cmd-timeout-long 600; } common { handlers { # These are EXAMPLE handlers only. # They may have severe implications, # like hard resetting the node under certain circumstances. # Be careful when chosing your poison. # pri-on-incon-degr "/usr/lib/drbd/notify-pri-on-incon-degr.sh; /usr/lib/drbd/notify-emergency-reboot.sh; echo b > /proc/sysrq-trigger ; reboot -f"; # pri-lost-after-sb "/usr/lib/drbd/notify-pri-lost-after-sb.sh; /usr/lib/drbd/notify-emergency-reboot.sh; echo b > /proc/sysrq-trigger ; reboot -f"; # local-io-error "/usr/lib/drbd/notify-io-error.sh; /usr/lib/drbd/notify-emergency-shutdown.sh; echo o > /proc/sysrq-trigger ; halt -f"; # fence-peer "/usr/lib/drbd/crm-fence-peer.sh"; # split-brain "/usr/lib/drbd/notify-split-brain.sh root"; # out-of-sync "/usr/lib/drbd/notify-out-of-sync.sh root"; # before-resync-target "/usr/lib/drbd/snapshot-resync-target-lvm.sh -p 15 -- -c 16k"; # after-resync-target /usr/lib/drbd/unsnapshot-resync-target-lvm.sh; } startup { # wfc-timeout degr-wfc-timeout outdated-wfc-timeout wait-after-sb } options { # cpu-mask on-no-data-accessible } disk { # size on-io-error fencing disk-barrier disk-flushes # disk-drain md-flushes resync-rate resync-after al-extents # c-plan-ahead c-delay-target c-fill-target c-max-rate # c-min-rate disk-timeout } net { # protocol timeout max-epoch-size max-buffers unplug-watermark # connect-int ping-int sndbuf-size rcvbuf-size ko-count # allow-two-primaries cram-hmac-alg shared-secret after-sb-0pri # after-sb-1pri after-sb-2pri always-asbp rr-conflict # ping-timeout data-integrity-alg tcp-cork on-congestion # congestion-fill congestion-extents csums-alg verify-alg # use-rle } } drbd-utils-8.9.6/scripts/crm-fence-peer.sh0000755000175000017500000010173512615625471020341 0ustar apoikosapoikos#!/bin/bash # sed_rsc_location_suitable_for_string_compare() { # expected input: exactly one tag per line: "^[[:space:]]*<.*/?>$" sed -ne ' # within the rsc_location constraint with that id, // { /<\/rsc_location>/q # done, if closing tag is found s/^[[:space:]]*// # trim spaces s/ *\bid="[^"]*"// # remove id tag # print each attribute on its own line, by : attr h # remember the current (tail of the) line # remove all but the first attribute, and print, s/^\([^[:space:]]*[[:space:]][^= ]*="[^"]*"\).*$/\1/p g # then restore the remembered line, # and remove the first attribute. s/^\([^[:space:]]*\)[[:space:]][^= ]*="[^"]*"\(.*\)$/\1\2/ # then repeat, until no more attributes are left t attr }' | sort } cibadmin_invocations=0 set_constraint() { cibadmin_invocations=$(( $cibadmin_invocations + 1 )) cibadmin -C -o constraints -X "$new_constraint" } remove_constraint() { cibadmin_invocations=$(( $cibadmin_invocations + 1 )) cibadmin -D -X "" } cib_xml="" get_cib_xml() { cibadmin_invocations=$(( $cibadmin_invocations + 1 )) cib_xml=$( set +x; cibadmin "$@" ) } # if not passed in, try to "guess" it from the cib # we only know the DRBD_RESOURCE. fence_peer_init() { # we know which instance we are: $OCF_RESOURCE_INSTANCE. # but we do not know the xml ID of the :( # cibadmin -Ql --xpath \ # '//master[primitive[@type="drbd" and instance_attributes/nvpair[@name = "drbd_resource" and @value="r0"]]]/@id' # but I'd have to pipe that through sed anyways, because @attribute # xpath queries are not supported. # and I'd be incompatible with older cibadmin not supporting --xpath. # be cool, sed it out: : ${master_id=$(set +x; echo "$cib_xml" | sed -ne '// { /= deadtime, dc-timeout > timeout # Intended use case: fencing resource-and-stonith, STONITH configured. # # Difference to a) # # If peer is still reachable according to the cib, # we first poll the cib/try to confirm with crmadmin, # until either crmadmin confirms reachability, timeout has elapsed, # or the peer becomes definitely unreachable. # # This gives STONITH the chance to kill us. # With "fencing resource-and-stontith;" this protects us against # completing transactions to userland which might otherwise be lost. # # We then place the constraint (if we are UpToDate), as explained below, # and return reachable/unreachable according to our last cib status poll # or crmadmin -S result. # # # replication link loss, current Primary calls this handler: # We are UpToDate, but we potentially need to wait for a DC election. # Once we have contacted the DC, we poll the cib until the peer is # confirmed unreachable, or crmadmin -S confirms it as reachable, # or timeout expired. # Then we place the constraint, and are done. # # If it is complete communications loss, one will stonith the other. # For two-node clusters with no-quorum-policy=ignore, we will have a # deathmatch shoot-out, which the former DC is likely to win. # # In dual-primary setups, if it is only replication link loss, both nodes # will call this handler, but only one will succeed to place the # constraint. The other will then typically need to "commit suicide". # With stonith enabled, and --suicide-on-failure-if-primary, # we will trigger a node level fencing, telling # pacemaker to "terminate" that node, # and scheduling a reboot -f just in case. # # Primary crash, promotion of former Secondary: # DC-election, if any, will have taken place already. # We are UpToDate, we place the constraint, done. # # node or cluster crash, promotion of Secondary with replication link down: # We are "Only" Consistent. Usually any "init-dead-time" or similar has # expired already, and the cib node states are already authoritative # without doing additional waiting. If the peer is still reachable, we # place the constraint - if the peer had better data, it should have a # higher master score, and we should not have been asked to become # primary. If the peer is not reachable, we don't do anything, and DRBD # will refuse to be promoted. This is necessary to avoid problems # With data diversion, in case this "crash" was due to a STONITH operation, # maybe the reboot did not fix our cluster communications! # # Note that typically, if STONITH is in use, it has been done on any # unreachable node _before_ we are promoted, so the cib should already # know that the peer is dead - if it is. # # slightly different logic than crm_is_true crm_is_not_false() { case $1 in no|n|false|0|off) false ;; *) true ;; esac } check_cluster_properties() { local x properties=$(set +x; echo "$cib_xml" | sed -n -e '/ $SECONDS )) || break sleep $(( net_hickup_time - SECONDS )) done set_states_from_proc_drbd : == DEBUG == DRBD_peer=${DRBD_peer[*]} === : == DEBUG == DRBD_pdsk=${DRBD_pdsk[*]} === if $DRBD_pdsk_all_uptodate ; then echo WARNING "All peer disks are UpToDate! Did not place the constraint." rc=0 return fi : == DEBUG == CTS_mode=$CTS_mode == : == DEBUG == DRBD_disk_all_consistent=$DRBD_disk_all_consistent == : == DEBUG == DRBD_disk_all_uptodate=$DRBD_disk_all_uptodate == : == DEBUG == $peer_state/${DRBD_disk[*]}/$unreachable_peer_is == if [[ ${#DRBD_disk[*]} = 0 ]]; then # Someone called this script, without the corresponding drbd # resource being configured. That's not very useful. echo WARNING "could not determine my disk state: did not place the constraint!" rc=0 # keep drbd_fence_peer_exit_code at "generic error", # which will cause a "script is broken" message in case it was # indeed called as handler from within drbd # No, NOT fenced/Consistent: # just because we have been able to shoot him # does not make our data any better. elif [[ $peer_state = reachable ]] && $DRBD_disk_all_consistent; then # = reachable ]] && $DRBD_disk_all_uptodate # is implicitly handled here as well. set_constraint && drbd_fence_peer_exit_code=4 rc=0 && echo INFO "peer is $peer_state, my disk is ${DRBD_disk[*]}: placed constraint '$id_prefix-$master_id'" elif [[ $peer_state = fenced ]] && $DRBD_disk_all_uptodate ; then set_constraint && drbd_fence_peer_exit_code=7 rc=0 && echo INFO "peer is $peer_state, my disk is $DRBD_disk: placed constraint '$id_prefix-$master_id'" # Peer is neither "reachable" nor "fenced" (above would have matched) # So we just hit some timeout. # As long as we are UpToDate, place the constraint and continue. # If you don't like that, use a ridiculously high timeout, # or patch this script. elif $DRBD_disk_all_uptodate ; then # We could differentiate between unreachable, # and DC-unreachable. In the latter case, placing the # constraint will fail anyways, and drbd_fence_peer_exit_code # will stay at "generic error". set_constraint && drbd_fence_peer_exit_code=5 rc=0 && echo INFO "peer is not reachable, my disk is UpToDate: placed constraint '$id_prefix-$master_id'" # This block is reachable by operator intervention only # (unless you are hacking this script and know what you are doing) elif [[ $peer_state != reachable ]] && [[ $unreachable_peer_is = outdated ]] && $DRBD_disk_all_consistent; then # If the peer is not reachable, but we are only Consistent, we # may need some way to still allow promotion. # Easy way out: --force primary with drbdsetup. # But that would not place the constraint, nor outdate the # peer. With this --unreachable-peer-is-outdated, we still try # to set the constraint. Next promotion attempt will find the # "correct" constraint, consider the peer as successfully # fenced, and continue. set_constraint && drbd_fence_peer_exit_code=5 rc=0 && echo WARNING "peer is unreachable, my disk is only Consistent: --unreachable-peer-is-outdated FORCED constraint '$id_prefix-$master_id'" && echo WARNING "This MAY RISK DATA INTEGRITY" # So I'm not UpToDate, and peer is not reachable. # Tell the module about "not reachable", and don't do anything else. else echo WARNING "peer is $peer_state, my disk is ${DRBD_disk[*]}: did not place the constraint!" drbd_fence_peer_exit_code=5 rc=0 # I'd like to return 6 here, otherwise pacemaker will retry # forever to promote, even though 6 is not strictly correct. fi return $rc } commit_suicide() { local reboot_timeout=20 local extra_msg if $stonith_enabled ; then # avoid double fence, tell pacemaker to kill me echo WARNING "trying to have pacemaker kill me now!" crm_attribute -t status -N $HOSTNAME -n terminate -v 1 echo WARNING "told pacemaker to kill me, but scheduling reboot -f in 300 seconds just in case" # ------------------------- echo WARNING $'\n'" told pacemaker to kill me,"\ $'\n'" but scheduling reboot -f in 300 seconds just in case."\ $'\n'" kill $$ # to cancel" | wall # ------------------------- reboot_timeout=300 extra_msg="Pacemaker terminate pending. If that fails, I'm " else # ------------------------- echo WARNING $'\n'" going to reboot -f in $reboot_timeout seconds"\ $'\n'" kill $$ # to cancel!" | wall # ------------------------- fi reboot_timeout=$(( reboot_timeout + SECONDS )) # pacemaker apparently cannot kill me. while (( $SECONDS < $reboot_timeout )); do echo WARNING "${extra_msg}going to reboot -f in $(( reboot_timeout - SECONDS )) seconds! To cancel: kill $$" sleep 2 done echo WARNING "going to reboot -f now!" reboot -f sleep 864000 } # drbd_peer_fencing fence|unfence drbd_peer_fencing() { local rc # input to fence_peer_init: # $DRBD_RESOURCE is set by command line of from environment. # $id_prefix is set by command line or default. # $master_id is set by command line or will be parsed from the cib. # output of fence_peer_init: local have_constraint new_constraint # if I cannot query the local cib, give up get_cib_xml -Ql || return fence_peer_init || return if [[ $1 = fence ]] || $unfence_only_if_owner_match ; then if [[ $fencing_attribute = "#uname" ]]; then fencing_value=$HOSTNAME elif ! fencing_value=$(crm_attribute -Q -t nodes -n $fencing_attribute 2>/dev/null); then fencing_attribute="#uname" fencing_value=$HOSTNAME fi # double negation: do not run but with my data. new_constraint="\ " fi case $1 in fence) local startup_fencing stonith_enabled check_cluster_properties if [[ -z $have_constraint ]] ; then # try to place it. try_place_constraint && return # maybe callback and operator raced for the same constraint? # before we potentially trigger node level fencing # or keep IO frozen, double check. # try_place_constraint has updated cib_xml from DC have_constraint=$(set +x; echo "$cib_xml" | sed_rsc_location_suitable_for_string_compare "$id_prefix-$master_id") fi if [[ "$have_constraint" = "$(set +x; echo "$new_constraint" | sed_rsc_location_suitable_for_string_compare "$id_prefix-$master_id")" ]]; then echo INFO "suitable constraint already placed: '$id_prefix-$master_id'" drbd_fence_peer_exit_code=4 rc=0 elif [[ -n "$have_constraint" ]] ; then # if this id already exists, but looks different, we may have lost a shootout echo WARNING "constraint "$have_constraint" already exists" # anything != 0 will do; # 21 happend to be "The object already exists" with my cibadmin rc=21 # maybe: drbd_fence_peer_exit_code=6 # as this is not the constraint we'd like to set, # it is likely the inverse, so we probably can assume # that the peer is active primary, or at least has # better data than us, and wants us outdated. fi if [[ $rc != 0 ]]; then # at least we tried. # maybe it was already in place? echo WARNING "DATA INTEGRITY at RISK: could not place the fencing constraint!" fi # XXX policy decision: if $suicide_on_failure_if_primary && [[ $drbd_fence_peer_exit_code != [3457] ]]; then set_states_from_proc_drbd [[ "${DRBD_role[*]}" = *Primary* ]] && commit_suicide fi return $rc ;; unfence) if [[ -n $have_constraint ]]; then set_states_from_proc_drbd if $DRBD_disk_all_uptodate && $DRBD_pdsk_all_uptodate; then if $unfence_only_if_owner_match && [[ "$have_constraint" != "$(set +x; echo "$new_constraint" | sed_rsc_location_suitable_for_string_compare "$id_prefix-$master_id")" ]] then echo WARNING "Constraint owner does not match, leaving constraint in place." else # try to remove it based on that xml-id remove_constraint && echo INFO "Removed constraint '$id_prefix-$master_id'" fi else local w="My" $DRBD_disk_all_uptodate && w="Peer's" echo WARNING "$w disk(s) are NOT all UpToDate, leaving constraint in place." return 1 fi else $quiet || echo "No constraint in place, nothing to do." return 0 fi esac } double_check_after_fencing() { set_states_from_proc_drbd : == DEBUG == DRBD_peer=${DRBD_peer[*]} === : == DEBUG == DRBD_pdsk=${DRBD_pdsk[*]} === if $DRBD_pdsk_all_uptodate ; then echo WARNING "All peer disks are UpToDate (again), trying to remove the constraint again." remove_constraint && drbd_fence_peer_exit_code=1 rc=0 return fi } guess_if_pacemaker_will_fence() { # try to guess whether it is useful to wait and poll again, # (node fencing in progress...), # or if pacemaker thinks the node is "clean" dead. local x # "return values:" crmd= in_ccm= expected= join= will_fence=false # Older pacemaker has an "ha" attribute, too. # For stonith-enabled=false, the "crmd" attribute may stay "online", # but once ha="dead", we can stop waiting for changes. ha_dead=false node_state=${node_state%>} node_state=${node_state%/} for x in ${node_state} ; do case $x in in_ccm=\"*\") x=${x#*=\"}; x=${x%\"}; in_ccm=$x ;; crmd=\"*\") x=${x#*=\"}; x=${x%\"}; crmd=$x ;; expected=\"*\") x=${x#*=\"}; x=${x%\"}; expected=$x ;; join=\"*\") x=${x#*=\"}; x=${x%\"}; join=$x ;; ha=\"dead\") ha_dead=true ;; esac done # if it is not enabled, no point in waiting for it. if ! $stonith_enabled ; then # "normalize" the rest of the logic # where this is called. # for stonith-enabled=false, and ha="dead", # reset crmd="offline". # Then we stop polling the cib for changes. $ha_dead && crmd="offline" return fi if [[ -z $node_state ]] ; then # if we don't know nothing about the peer, # and startup_fencing is explicitly disabled, # no fencing will take place. $startup_fencing || return fi # for further inspiration, see pacemaker:lib/pengine/unpack.c, determine_online_status_fencing() [[ -z $in_ccm ]] && will_fence=true [[ $crmd = "banned" ]] && will_fence=true if [[ ${expected-down} = "down" && $in_ccm = "false" && $crmd != "online" ]]; then : "pacemaker considers this as clean down" elif [[ $in_ccm = false ]] || [[ $crmd != "online" ]]; then will_fence=true fi } # return value in $peer_state: # DC-unreachable # We have not been able to contact the DC. # fenced # According to the node_state recorded in the cib, # the peer is offline and expected down # (which means successfully fenced, if stonith is enabled) # reachable # cib says it's online, and crmadmin -S says peer state is "ok" # unreachable # cib says it's offline (but does not yet say "expected" down) # and we reached the timeout # unknown # cib does not say it was offline (or we don't know who the peer is) # and we reached the timeout # check_peer_node_reachable() { # we are going to increase the cib timeout with every timeout (see below). # for the actual invocation, we use int(cibtimeout/10). # scaled by 5 / 4 with each iteration, # this results in a timeout sequence of 1 2 2 3 4 5 6 7 9 ... seconds local cibtimeout=18 local full_timeout local nr_other_nodes local other_node_uname_attrs # we have a cibadmin -Ql in cib_xml already # filter out $/\1/' | grep -v -F uname=\"$HOSTNAME\") set -- $other_node_uname_attrs nr_other_nodes=$# while :; do local state_lines= node_state= local crmd= in_ccm= expected= join= will_fence= ha_dead= while :; do local t=$SECONDS # # Update our view of the cib, ask the DC this time. # Timeout, in case no DC is available. # Caution, some cibadmin (pacemaker 0.6 and earlier) # apparently use -t use milliseconds, so will timeout # many times until a suitably long timeout is reached # by increasing below. # # Why not use the default timeout? # Because that would unecessarily wait for 30 seconds # or longer, even if the DC is re-elected right now, # and available within the next second. # get_cib_xml -Q -t $(( cibtimeout/10 )) && break # bash magic $SECONDS is seconds since shell invocation. if (( $SECONDS > $dc_timeout )) ; then # unreachable: cannot even reach the DC peer_state="DC-unreachable" return fi # avoid busy loop [[ $t = $SECONDS ]] && sleep 1 # try again, longer timeout. let "cibtimeout = cibtimeout * 5 / 4" done state_lines=$( set +x; echo "$cib_xml" | grep ' 2 cluster. # (yes, I've seen such beasts in the wild!) # As we don't know the peer, # we could only safely return here if *all* # potential peers are confirmed down. # Don't try to be smart, just wait for the full # timeout, which should allow STONITH to # complete. full_timeout=$(( $timeout - $SECONDS )) if (( $full_timeout > 0 )) ; then echo WARNING "don't know who my peer is; sleep $full_timeout seconds just in case" sleep $full_timeout fi # In the unlikely case that we don't know our DRBD peer, # there is no point in polling the cib again, # that won't teach us who our DRBD peer is. # # We waited $full_timeout seconds already, # to allow for node level fencing to shoot us. # # So if we are still alive, then obviously no-one has shot us. # peer_state="unknown" return fi # # we know the peer or/and are a two node cluster # node_state=$(set +x; echo "$state_lines" | grep -F uname=\"$DRBD_PEER\") # populates in_ccm, crmd, exxpected, join, will_fence=[false|true] guess_if_pacemaker_will_fence if ! $will_fence && [[ $crmd != "online" ]] ; then # "legacy" cman + pacemaker clusters older than 1.1.10 # may "forget" about startup fencing. # We can detect this because the "expected" attribute is missing. # Does not make much difference for our logic, though. [[ $expected/$in_ccm = "down/false" ]] && peer_state="fenced" || peer_state="unreachable" return fi # So the cib does still indicate the peer was reachable. # # try crmadmin; if we can sucessfully query the state of the remote crmd, # it is obviously reachable. # # Do this only after we have been able to reach a DC above. # Note: crmadmin timeout is in milli-seconds, and defaults to 30000 (30 seconds). # Our variable $cibtimeout should be in deci-seconds (see above) # (unless you use a very old version of pacemaker, so don't do that). # Convert deci-seconds to milli-seconds, and double it. if [[ $crmd = "online" ]] ; then local out if out=$( crmadmin -t $(( cibtimeout * 200 )) -S $DRBD_PEER ) \ && [[ $out = *"(ok)" ]]; then peer_state="reachable" return fi fi # We know our DRBD peer. # We are still not sure about its status, though. # # It is not (yet) "expected down" per the cib, but it is not # reliably reachable via crmadmin -S either. # # If we already polled for longer than timeout, give up. # # For a resource-and-stonith setup, or dual-primaries (which # you should only use with resource-and-stonith, anyways), # the recommended timeout is larger than the deadtime or # stonith timeout, and according to beekhof maybe should be # tuned up to the election-timeout (which, btw, defaults to 2 # minutes!). # if (( $SECONDS >= $timeout )) ; then [[ $crmd = offline ]] && peer_state="unreachable" || peer_state="unknown" return fi # wait a bit before we poll the DC again sleep 2 done # NOT REACHED } set_states_from_proc_drbd() { local IFS line lines i disk pdsk # DRBD_MINOR exported by drbdadm since 8.3.3 [[ $DRBD_MINOR ]] || DRBD_MINOR=$(drbdadm ${DRBD_CONF:+ -c "$DRBD_CONF"} sh-minor $DRBD_RESOURCE) || return # if we have more than one minor, do a word split, ... set -- $DRBD_MINOR # ... and convert into regex: IFS="|$IFS"; DRBD_MINOR="($*)"; IFS=${IFS#?} # We must not recurse into netlink, # this may be a callback triggered by "drbdsetup primary". # grep /proc/drbd instead DRBD_peer=() DRBD_role=() DRBD_disk=() DRBD_pdsk=() DRBD_disk_all_uptodate=true DRBD_disk_all_consistent=true DRBD_pdsk_all_uptodate=true IFS=$'\n' lines=($(sed -nre "/^ *$DRBD_MINOR: cs:/ { s/:/ /g; p; }" /proc/drbd)) IFS=$' \t\n' i=0 for line in "${lines[@]}"; do set -- $line DRBD_peer[i]=${5#*/} DRBD_role[i]=${5%/*} pdsk=${7#*/} disk=${7%/*} DRBD_disk[i]=${disk:-Unconfigured} DRBD_pdsk[i]=${pdsk:-DUnknown} case $disk in UpToDate) ;; Consistent) DRBD_disk_all_uptodate=false ;; *) DRBD_disk_all_uptodate=false DRBD_disk_all_consistent=false ;; esac [[ $pdsk != UpToDate ]] && DRBD_pdsk_all_uptodate=false let i++ done if (( i = 0 )) ; then DRBD_pdsk_all_uptodate=false DRBD_disk_all_uptodate=false DRBD_disk_all_consistent=false fi } ############################################################ # try to get possible output on stdout/err to syslog PROG=${0##*/} redirect_to_logger() { local lf=${1:-local5} case $lf in # do we want to exclude some? auth|authpriv|cron|daemon|ftp|kern|lpr|mail|news|syslog|user|uucp|local[0-7]) : OK ;; *) echo >&2 "invalid logfacility: $lf" return ;; esac # Funky redirection to avoid logger feeding its own output to itself accidentally. # Funky double exec to avoid an intermediate sub-shell. # Sometimes, the sub-shell lingers around, keeps file descriptors open, # and logger then won't notice the main script has finished, # forever waiting for further input. # The second exec replaces the subshell, and logger will notice directly # when its stdin is closed once the main script exits. # This avoids the spurious logger processes. exec > >( exec 1>&- 2>&- logger -t "$PROG[$$]" -p $lf.info ) 2>&1 } if [[ $- != *x* ]]; then # you may override with --logfacility below redirect_to_logger local5 fi # clean environment just in case. unset fencing_attribute id_prefix timeout dc_timeout unreachable_peer_is unset flock_timeout flock_required lock_dir lock_file quiet=false unfence_only_if_owner_match=false CTS_mode=false suicide_on_failure_if_primary=false # poor mans command line argument parsing, # allow for command line overrides set -- "$@" $OCF_RESKEY_unfence_extra_args while [[ $# != 0 ]]; do case $1 in --logfacility=*) redirect_to_logger ${1#*=} ;; --logfacility) redirect_to_logger $2 shift ;; --resource=*) DRBD_RESOURCE=${1#*=} ;; -r|--resource) DRBD_RESOURCE=$2 shift ;; --master-id=*) master_id=${1#*=} ;; -i|--master-id) master_id=$2 shift ;; --role=*) role=${1#*=} ;; -l|--role) role=${2} shift ;; --fencing-attribute=*) fencing_attribute=${1#*=} ;; -a|--fencing-attribute) fencing_attribute=$2 shift ;; --id-prefix=*) id_prefix=${1#*=} ;; -p|--id-prefix) id_prefix=$2 shift ;; --timeout=*) timeout=${1#*=} ;; -t|--timeout) timeout=$2 shift ;; --dc-timeout=*) dc_timeout=${1#*=} ;; -d|--dc-timeout) dc_timeout=$2 shift ;; --quiet) quiet=true ;; --unfence-only-if-owner-match) unfence_only_if_owner_match=true ;; --flock-required) flock_required=true ;; --flock-timeout=*) flock_timeout=${1#*=} ;; --flock-timeout) flock_timeout=$2 shift ;; --lock-dir=*) lock_dir=${1#*=} ;; --lock-dir) lock_dir=$2 shift ;; --lock-file=*) lock_file=${1#*=} ;; --lock-file) lock_file=$2 shift ;; --net-hickup=*|--network-hickup=*) net_hickup_time=${1#*=} ;; --net-hickup|--network-hickup) net_hickup_time=$2 shift ;; --CTS-mode) CTS_mode=true ;; --unreachable-peer-is-outdated) # This is NOT to be scripted. # Or people will put this into the handler definition in # drbd.conf, and all this nice work was useless. test -t 0 && unreachable_peer_is=outdated ;; --suicide-on-failure-if-primary) suicide_on_failure_if_primary=true ;; -*) echo >&2 "ignoring unknown option $1" ;; *) echo >&2 "ignoring unexpected argument $1" ;; esac shift done # # Sanitize lock_file and lock_dir # if [[ ${lock_dir:=/var/lock/drbd} != /* ]] ; then echo WARNING "lock_dir needs to be an absolute path, not [$lock_dir]; using default." lock_dir=/var/lock/drbd fi case $lock_file in "") lock_file=$lock_dir/fence.${DRBD_RESOURCE//\//_} ;; NONE) : ;; /*) : ;; *) lock_file=$lock_dir/$lock_file ;; esac if [[ $lock_file != NONE && $lock_file != $lock_dir/* ]]; then lock_dir=${lock_file%/*}; : ${lock_dir:=/} : == DEBUG == "override: lock_dir=$lock_dir to match lock_file=$lock_file" fi # DRBD_RESOURCE: from environment # master_id: parsed from cib : "== unreachable_peer_is == ${unreachable_peer_is:=unknown}" # apply defaults: : "== fencing_attribute == ${fencing_attribute:="#uname"}" : "== id_prefix == ${id_prefix:="drbd-fence-by-handler"}" : "== role == ${role:="Master"}" # defaults suitable for most cases : "== net_hickup_time == ${net_hickup_time:=0}" : "== timeout == ${timeout:=90}" : "== dc_timeout == ${dc_timeout:=20}" : "== flock_timeout == ${flock_timeout:=120}" : "== flock_required == ${flock_required:=false}" : "== lock_file == ${lock_file}" : "== lock_dir == ${lock_dir}" # check envars normally passed in by drbdadm # TODO DRBD_CONF is also passed in. we may need to use it in the # xpath query, in case someone is crazy enough to use different # conf files with the _same_ resource name. # for now: do not do that, or hardcode the cib id of the master # in the handler section of your drbd conf file. for var in DRBD_RESOURCE; do if [ -z "${!var}" ]; then echo "Environment variable \$$var not found (this is normally passed in by drbdadm)." >&2 exit 1 fi done # Fixup id-prefix to include the resource name # There may be multiple drbd instances part of the same M/S Group, pointing to # the same master-id. Still they need to all have their own constraint, to be # able to unfence independently when they finish their resync independently. # Be nice to people who already explicitly configure an id prefix containing # the resource name. if [[ $id_prefix != *"-$DRBD_RESOURCE" ]] ; then id_prefix="$id_prefix-$DRBD_RESOURCE" : "== id_prefix == ${id_prefix}" fi # make sure it contains what we expect HOSTNAME=$(uname -n) $quiet || echo "invoked for $DRBD_RESOURCE${master_id:+" (master-id: $master_id)"}" # to be set by drbd_peer_fencing() drbd_fence_peer_exit_code=1 got_flock=false if [[ $lock_file != NONE ]] ; then test -d "$lock_dir" || mkdir -p -m 0700 "$lock_dir" || echo WARNING "mkdir -p $lock_dir failed" if exec 9>"$lock_file" && flock --exclusive --timeout $flock_timeout 9 then got_flock=true else echo WARNING "Could not get flock on $lock_file" $flock_required && exit 1 # If I cannot get the lock file, I can at least still try to place the constraint fi : == DEBUG == $SECONDS seconds, got_flock=$got_flock == fi case $PROG in crm-fence-peer.sh) if drbd_peer_fencing fence; then : == DEBUG == $cibadmin_invocations cibadmin calls == : == DEBUG == $SECONDS seconds == [[ $drbd_fence_peer_exit_code = [347] ]] && double_check_after_fencing exit $drbd_fence_peer_exit_code fi ;; crm-unfence-peer.sh) if drbd_peer_fencing unfence; then : == DEBUG == $cibadmin_invocations cibadmin calls == : == DEBUG == $SECONDS seconds == exit 0 fi esac 9>&- # Don't want to "leak" the lock fd to child processes. # 1: unexpected error exit 1 drbd-utils-8.9.6/scripts/drbd.gentoo0000644000175000017500000000702512466702073017335 0ustar apoikosapoikos#!/sbin/runscript # Distributed under the terms of the GNU General Public License v2 # Copright 2001-2008 LINBIT Information Technologies # Philipp Reisner, Lars Ellenberg # Original script adapted to gentoo environment # I so do not see why gentoo would need it's own init script. # But if you think it does, well, you get to fix it. # See what we do in the generic one. echo "FIXME, contributers welcome. This is broken for 8.4" >&2 exit 255 depend() { use logger need net before heartbeat after sshd } opts="${opts} reload" DEFAULTFILE="/etc/conf.d/drbd" DRBDADM="/sbin/drbdadm" PROC_DRBD="/proc/drbd" MODPROBE="/sbin/modprobe" RMMOD="/sbin/rmmod" UDEV_TIMEOUT=10 ADD_MOD_PARAM="" if [ -f $DEFAULTFILE ]; then . $DEFAULTFILE fi # Just in case drbdadm want to display any errors in the configuration # file, or we need to ask the user about registering this installation # at http://usage.drbd.org, we call drbdadm here without any IO # redirection. $DRBDADM sh-nop function assure_module_is_loaded { [ -e "$PROC_DRBD" ] && return ebegin "Loading drbd module" ret=0 $MODPROBE -s drbd `$DRBDADM sh-mod-parms` $ADD_MOD_PARAM || ret=20 eend $ret return $ret } function adjust_with_progress { IFS_O=$IFS NEWLINE=' ' IFS=$NEWLINE local D=0 local S=0 local N=0 einfon "Setting drbd parameters " COMMANDS=`$DRBDADM -d adjust all` || { eend 20 "Error executing drbdadm" return 20 } echo -n "[ " for CMD in $COMMANDS; do if echo $CMD | grep -q disk; then echo -n "d$D "; D=$(( D+1 )); elif echo $CMD | grep -q syncer; then echo -n "s$S "; S=$(( S+1 )); elif echo $CMD | grep -q net; then echo -n "n$N "; N=$(( N+1 )); else echo echo -n ".. "; fi IFS=$IFS_O $CMD || { echo eend 20 "cmd $CMD failed!" return 20 } IFS=$NEWLINE done echo "]" eend 0 IFS=$IFS_O } start() { einfo "Starting DRBD resources:" eindent assure_module_is_loaded || return $? adjust_with_progress || return $? # make sure udev has time to create the device files ebegin "Waiting for udev device creation ..." for RESOURCE in `$DRBDADM sh-resources`; do for DEVICE in `$DRBDADM sh-dev $RESOURCE`; do UDEV_TIMEOUT_LOCAL=$UDEV_TIMEOUT while [ ! -e $DEVICE ] && [ $UDEV_TIMEOUT_LOCAL -gt 0 ] ; do sleep 1 UDEV_TIMEOUT_LOCAL=$(( $UDEV_TIMEOUT_LOCAL-1 )) done done done eend 0 einfon "Waiting for connection " $DRBDADM wait-con-int echo ret=$? eend $ret return $ret } stop() { ebegin "Stopping all DRBD resources" # Check for mounted drbd devices if ! grep -q '^/dev/drbd' /proc/mounts &>/dev/null; then if [ -e ${PROC_DRBD} ]; then ${DRBDADM} down all ${RMMOD} drbd fi ret=$? eend $ret return $ret else einfo "drbd devices mounted, please umount them before trying to stop drbd!" eend 1 return 1 fi } status() { # NEEDS to be heartbeat friendly... # so: put some "OK" in the output. if [ -e $PROC_DRBD ]; then ret=0 ebegin "drbd driver loaded OK; device status:" eend $ret cat $PROC_DRBD else ebegin "drbd not loaded" ret=3 eend $ret fi return $ret } reload() { ebegin "Reloading DRBD" ${DRBDADM} adjust all ret=$? eend $ret return $ret } drbd-utils-8.9.6/scripts/pretty-proc-drbd.sh0000644000175000017500000000742012466702073020741 0ustar apoikosapoikos#!/bin/bash PATH=/sbin:$PATH DEFAULTS=/etc/defaults/drbd-pretty-status # for highlighting see console_codes(4) colorize=false short=true # node role: Primary Secondary Unknown c_pri_1=$'\e[44m' c_pri_0=$'\e[49m' #c_sec_1=$'\e[7m' c_sec_0=$'\e[27m' c_sec_1="" c_sec_0="" c_unk_1=$'\e[43m' c_unk_0=$'\e[49m' # connection state: # Unconfigured # # StandAlone c_sta_1=$'\e[34m' c_sta_0=$'\e[39m' # Disconnecting Unconnected Timeout BrokenPipe NetworkFailure ProtocolError TearDown c_net_bad_1=$'\e[41m' c_net_bad_0=$'\e[49m' # WFConnection WFReportParams c_wfc_1=$'\e[36m' c_wfc_0=$'\e[39m' # Connected c_con_1=$'\e[32m' c_con_0=$'\e[39m' # StartingSyncS StartingSyncT WFBitMapS WFBitMapT WFSyncUUID c_ssy_1=$'\e[35m' c_ssy_0=$'\e[39m' # SyncSource PausedSyncS c_src_1=$'\e[46m' c_src_0=$'\e[49m' # SyncTarget PausedSyncT c_tgt_1=$'\e[41m' c_tgt_0=$'\e[49m' # disk state: # Attaching Negotiating DUnknown Consistent # uncolored for now # # Diskless Failed Inconsistent c_dsk_bad_1=$'\e[41m' c_dsk_bad_0=$'\e[49m' # Outdated c_out_1=$'\e[43m' c_out_0=$'\e[44m' # UpToDate c_u2d_1=$'\e[32m' c_u2d_0=$'\e[39m' while true; do case "$1" in -c) colorize=true; shift;; -v) short=false; shift;; *) break;; esac done drbd_pretty_status() { if ! $short || ! type column &> /dev/null || ! type paste &> /dev/null || ! type join &> /dev/null || ! type sed &> /dev/null || ! type tr &> /dev/null then cat /proc/drbd else sed -e '2q' < /proc/drbd sed_script=$( i=0; _sh_status_process() { let i++ ; stacked=${_stacked_on:+"^^${_stacked_on_minor:-${_stacked_on//[!a-zA-Z0-9_ -]/_}}"} printf "s|^ *%u:|%6u\t&%s%s|\n" \ $_minor $i \ "${_res_name//[!a-zA-Z0-9_ -]/_}" "$stacked" }; eval "$(drbdadm sh-status)" ) p() { sed -e "1,2d" \ -e "$sed_script" \ -e '/^ *[0-9]\+: cs:Unconfigured/d;' \ -e 's/^\(.* cs:.*[^ ]\) \([rs]...\)$/\1 - \2/g' \ -e 's/^\(.* \)cs:\([^ ]* \)st:\([^ ]* \)ds:\([^ ]*\)/\1\2\3\4/' \ -e 's/^\(.* \)cs:\([^ ]* \)ro:\([^ ]* \)ds:\([^ ]*\)/\1\2\3\4/' \ -e 's/^\(.* \)cs:\([^ ]*\)$/\1\2/' \ -e 's/^ *[0-9]\+:/ x &??not-found??/;' \ -e '/^$/d;/ns:.*nr:.*dw:/d;/resync:/d;/act_log:/d;' \ -e 's/^\(.\[.*\)\(sync.ed:\)/... ... \2/;/^.finish:/d;' \ -e 's/^\(.[0-9 %]*oos:\)/... ... \1/' \ < "/proc/drbd" | tr -s '\t ' ' ' } m() { join -1 2 -2 1 -o 1.1,2.2,2.3 \ <( ( drbdadm sh-dev all ; drbdadm -S sh-dev all ) | cat -n | sort -k2,2) \ <(sort < /proc/mounts ) | sort -n | tr -s '\t ' ' ' | sed -e 's/^ *//' } # echo "=== p ===" # p # echo "=== m ===" # m # echo "=========" # join -a1 <(p|sort) <(m|sort) # echo "=========" ( echo m:res cs ro ds p mounted fstype join -a1 <(p|sort) <(m|sort) | cut -d' ' -f2-6,8- | sort -k1,1n -k2,2 ) | column -t fi | if [[ $colorize != true ]]; then cat else c_bold=$'\e[1m' c_norm=$'\e[0m' sed -e " s/^??not-found??/$c_dsk_bad_1&$c_dsk_bad_0/g; s/^[^\t ]\+/$c_bold&$c_norm/; s/Primary/$c_pri_1&$c_pri_0/g; s/Secondary/$c_sec_1&$c_sec_0/g; s/\ >( exec 1>&- 2>&- logger -t "$PROG[$$]" -p local5.info) 2>&1 if [[ $DRBD_VOLUME ]]; then pretty_print="$DRBD_RESOURCE/$DRBD_VOLUME (drbd$DRBD_MINOR)" else pretty_print="$DRBD_RESOURCE" fi echo "invoked for $pretty_print" # Default to sending email to root, unless otherwise specified RECIPIENT=${1:-root} # check arguments specified on command line if [ -z "$RECIPIENT" ]; then echo "You must specify a notification recipient when using this handler." >&2 exit 1 fi # check envars normally passed in by drbdadm for var in DRBD_RESOURCE DRBD_PEER; do if [ -z "${!var}" ]; then echo "Environment variable \$$var not found (this is normally passed in by drbdadm)." >&2 exit 1 fi done : ${DRBD_CONF:="usually /etc/drbd.conf"} DRBD_LOCAL_HOST=$(hostname) case "$0" in *split-brain.sh) SUBJECT="DRBD split brain on resource $pretty_print" BODY=" DRBD has detected split brain on resource $pretty_print between $DRBD_LOCAL_HOST and $DRBD_PEER. Please rectify this immediately. Please see http://www.drbd.org/users-guide/s-resolve-split-brain.html for details on doing so." ;; *out-of-sync.sh) SUBJECT="DRBD resource $pretty_print has out-of-sync blocks" BODY=" DRBD has detected out-of-sync blocks on resource $pretty_print between $DRBD_LOCAL_HOST and $DRBD_PEER. Please see the system logs for details." ;; *io-error.sh) SUBJECT="DRBD resource $pretty_print detected a local I/O error" BODY=" DRBD has detected an I/O error on resource $pretty_print on $DRBD_LOCAL_HOST. Please see the system logs for details." ;; *pri-lost.sh) SUBJECT="DRBD resource $pretty_print is currently Primary, but is to become SyncTarget on $DRBD_LOCAL_HOST" BODY=" The DRBD resource $pretty_print is currently in the Primary role on host $DRBD_LOCAL_HOST, but lost the SyncSource election process." ;; *pri-lost-after-sb.sh) SUBJECT="DRBD resource $pretty_print is currently Primary, but lost split brain auto recovery on $DRBD_LOCAL_HOST" BODY=" The DRBD resource $pretty_print is currently in the Primary role on host $DRBD_LOCAL_HOST, but was selected as the split brain victim in a post split brain auto-recovery." ;; *pri-on-incon-degr.sh) SUBJECT="DRBD resource $pretty_print no longer has access to valid data on $DRBD_LOCAL_HOST" BODY=" DRBD has detected that the resource $pretty_print on $DRBD_LOCAL_HOST has lost access to its backing device, and has also lost connection to its peer, $DRBD_PEER. This resource now no longer has access to valid data." ;; *emergency-reboot.sh) SUBJECT="DRBD initiating emergency reboot of node $DRBD_LOCAL_HOST" BODY=" Due to an emergency condition, DRBD is about to issue a reboot of node $DRBD_LOCAL_HOST. If this is unintended, please check your DRBD configuration file ($DRBD_CONF)." ;; *emergency-shutdown.sh) SUBJECT="DRBD initiating emergency shutdown of node $DRBD_LOCAL_HOST" BODY=" Due to an emergency condition, DRBD is about to shut down node $DRBD_LOCAL_HOST. If this is unintended, please check your DRBD configuration file ($DRBD_CONF)." ;; *) SUBJECT="Unspecified DRBD notification" BODY=" DRBD on $DRBD_LOCAL_HOST was configured to launch a notification handler for resource $pretty_print, but no specific notification event was set. This is most likely due to DRBD misconfiguration. Please check your configuration file ($DRBD_CONF)." ;; esac echo "$BODY" | mail -s "$SUBJECT" $RECIPIENT drbd-utils-8.9.6/scripts/unsnapshot-resync-target-lvm.sh0000777000175000017500000000000012466702074031072 2snapshot-resync-target-lvm.shustar apoikosapoikosdrbd-utils-8.9.6/scripts/drbd.ocf0000755000175000017500000011262512615625471016621 0ustar apoikosapoikos#!/bin/bash # # # OCF Resource Agent compliant drbd resource script. # # Copyright (c) 2009 LINBIT HA-Solutions GmbH, # Copyright (c) 2009 Florian Haas, Lars Ellenberg # Based on the Heartbeat drbd OCF Resource Agent by Lars Marowsky-Bree # (though it turned out to be an almost complete rewrite) # # All Rights Reserved. # # This program is free software; you can redistribute it and/or modify # it under the terms of version 2 of the GNU General Public License as # published by the Free Software Foundation. # # This program is distributed in the hope that it would be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # # Further, this software is distributed without any warranty that it is # free of the rightful claim of any third person regarding infringement # or the like. Any license provided herein, whether implied or # otherwise, applies only to this software file. Patent licenses, if # any, provided herein do not apply to combinations of this program with # other software, or any other product whatsoever. # # You should have received a copy of the GNU General Public License # along with this program; if not, write the Free Software Foundation, # Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. # # # OCF instance parameters # OCF_RESKEY_drbd_resource # OCF_RESKEY_drbdconf # OCF_RESKEY_stop_outdates_secondary # OCF_RESKEY_adjust_master_score # # meta stuff this agent looks at: # OCF_RESKEY_CRM_meta_clone_max # OCF_RESKEY_CRM_meta_clone_node_max # OCF_RESKEY_CRM_meta_master_max # OCF_RESKEY_CRM_meta_master_node_max # # OCF_RESKEY_CRM_meta_interval # # OCF_RESKEY_CRM_meta_notify # OCF_RESKEY_CRM_meta_notify_active_uname # OCF_RESKEY_CRM_meta_notify_demote_uname # OCF_RESKEY_CRM_meta_notify_master_uname # OCF_RESKEY_CRM_meta_notify_operation # OCF_RESKEY_CRM_meta_notify_promote_uname # OCF_RESKEY_CRM_meta_notify_slave_uname # OCF_RESKEY_CRM_meta_notify_start_uname # OCF_RESKEY_CRM_meta_notify_stop_uname # OCF_RESKEY_CRM_meta_notify_type # ####################################################################### # Initialization: # Resource-agents have moved their ocf-shellfuncs file around. # There are supposed to be symlinks or wrapper files in the old location, # pointing to the new one, but people seem to get it wrong all the time. # Try several locations. if test -n "${OCF_FUNCTIONS_DIR}" ; then if test -e "${OCF_FUNCTIONS_DIR}/ocf-shellfuncs" ; then . "${OCF_FUNCTIONS_DIR}/ocf-shellfuncs" elif test -e "${OCF_FUNCTIONS_DIR}/.ocf-shellfuncs" ; then . "${OCF_FUNCTIONS_DIR}/.ocf-shellfuncs" fi else if test -e "${OCF_ROOT}/lib/heartbeat/ocf-shellfuncs" ; then . "${OCF_ROOT}/lib/heartbeat/ocf-shellfuncs" elif test -e "${OCF_ROOT}/resource.d/heartbeat/.ocf-shellfuncs"; then . "${OCF_ROOT}/resource.d/heartbeat/.ocf-shellfuncs" fi fi # Defaults OCF_RESKEY_drbdconf_default="/etc/drbd.conf" OCF_RESKEY_unfence_extra_args_default="--quiet --flock-required --flock-timeout 0 --unfence-only-if-owner-match" if ocf_is_true ${OCF_RESKEY_unfence_if_all_uptodate:=false}; then unfence_if_all_uptodate=true else unfence_if_all_uptodate=false fi # The passed in OCF_CRM_meta_notify_* environment # is not reliably with pacemaker up to at least # 1.0.10 and 1.1.4. It should be fixed later. # Until that is fixed, the "self-outdating feature" would base its actions on # wrong information, and possibly not outdate when it should, or, even worse, # outdate the last remaining valid copy. # Disable. OCF_RESKEY_stop_outdates_secondary_default="false" OCF_RESKEY_adjust_master_score_default="5 10 1000 10000" # ignored | Consistent | Unknown -' | | | # ignored | NOT UpToDate | UpToDate ---' | | # Secondary | UpToDate | unknown --------' | # ignored | UpToDate | known --------------+ # Primary | UpToDate | ignored --------------' : ${OCF_RESKEY_drbdconf:=${OCF_RESKEY_drbdconf_default}} : ${OCF_RESKEY_stop_outdates_secondary:=${OCF_RESKEY_stop_outdates_secondary_default}} : ${OCF_RESKEY_adjust_master_score:=${OCF_RESKEY_adjust_master_score_default}} # Defaults according to "Configuration 1.0 Explained", # "Multi-state resource configuration options" : ${OCF_RESKEY_CRM_meta_clone_node_max=1} : ${OCF_RESKEY_CRM_meta_master_max=1} : ${OCF_RESKEY_CRM_meta_master_node_max=1} ####################################################################### # for debugging this RA DEBUG_LOG_DIR=/tmp/drbd.ocf.ra.debug DEBUG_LOG=$DEBUG_LOG_DIR/log USE_DEBUG_LOG=false ls_stat_is_dir_0700_root() { set -- $(command ls -ldn "$1" 2>/dev/null); case "$1/$3" in drwx?-??-?/0|\ drwx?-??-?./0) true ;; *) false ;; esac } # try to avoid symlink vuln. if ls_stat_is_dir_0700_root $DEBUG_LOG_DIR && [[ -w "$DEBUG_LOG" && ! -L "$DEBUG_LOG" ]] then USE_DEBUG_LOG=true # PS4='+[`date +%F\ %T.%3N`] ' exec 9>>"$DEBUG_LOG" date >&9 echo "$*" >&9 env | grep OCF_ | sort >&9 else exec 9>/dev/null fi # end of debugging aid ####################################################################### meta_data() { cat < 1.3 This resource agent manages a DRBD resource as a master/slave resource. DRBD is a shared-nothing replicated storage device. Note that you should configure resource level fencing in DRBD, this cannot be done from this resource agent. See the DRBD User's Guide for more information. http://www.drbd.org/docs/applications/ Manages a DRBD device as a Master/Slave resource The name of the drbd resource from the drbd.conf file. drbd resource name Full path to the drbd.conf file. Path to drbd.conf Space separated list of four master score adjustments for different scenarios: - only access to 'consistent' data - only remote access to 'uptodate' data - currently Secondary, local access to 'uptodate' data, but remote is unknown - local access to 'uptodate' data, and currently Primary or remote is known Numeric values are expected to be non-decreasing. Default are the previously hardcoded values. Set the first value to 0 (and configure proper fencing methods) to prevent pacemaker from trying to promote while it is unclear whether the data is really the most recent copy. (DRBD knows it is "consistent", but is unsure about "uptodate"ness). Advanced use: Adjust the other values to better fit into complex dependency score calculations. master score adjustments Recommended setting: leave at default (disabled). Note that this feature depends on the passed in information in OCF_RESKEY_CRM_meta_notify_master_uname to be correct, which unfortunately is not reliable for pacemaker versions up to at least 1.0.10 / 1.1.4. If a Secondary is stopped (unconfigured), it may be marked as outdated in the drbd meta data, if we know there is still a Primary running in the cluster. Note that this does not affect fencing policies set in drbd config, but is an additional safety feature of this resource agent only. You can enable this behaviour by setting the parameter to true. If this feature seems to not do what you expect, make sure you have defined fencing policies in the drbd configuration as well. outdate a secondary on stop Some setups do not benefit from notifications. Allow to disable notifications without patching this resource agent. ignore missing notify=true If all volumes of this resource report to be UpToDate, call an unfence script hook, just in case some stale fencing constraint or similar is still around. = 8.9.5, this is dispatched to \$DRBDADM unfence-peer \$DRBD_RESOURCE In any case, the hook itself is responsible to fetch \$OCF_RESKEY_unfence_extra_args from its environment. ]]> call unfence hook once fully UpToDate This may be used to pass extra hints to the unfence hook. See description of unfence_if_all_uptodate. Extra arguments for the unfence hook. END } do_cmd() { # Run a command, return its exit code, capture any output, and log # everything if appropriate. local cmd="$*" cmd_out ret ocf_log debug "$DRBD_RESOURCE: Calling $cmd" cmd_out=$( "$@" ) ret=$? if [ $ret != 0 ]; then ocf_log err "$DRBD_RESOURCE: Called $cmd" ocf_log err "$DRBD_RESOURCE: Exit code $ret" ocf_log err "$DRBD_RESOURCE: Command output: $cmd_out" else ocf_log debug "$DRBD_RESOURCE: Exit code $ret" ocf_log debug "$DRBD_RESOURCE: Command output: $cmd_out" fi echo "$cmd_out" return $ret } do_drbdadm() { local ret # Run drbdadm with appropriate command line options, and capture # its output. # $DRBDADM is defined during drbd_validate as "drbdadm" plus # appropriate command line options do_cmd $DRBDADM "$@" ret=$? # having the version mismatch warning once per RA invokation # should be enough. export DRBD_DONT_WARN_ON_VERSION_MISMATCH= return $ret } set_master_score() { # Use quiet mode (-Q) to quench logging. Actual score updates # will get logged by attrd anyway if [[ $1 -le 0 ]]; then remove_master_score else do_cmd ${HA_SBIN_DIR}/crm_master -Q -l reboot -v $1 fi } remove_master_score() { do_cmd ${HA_SBIN_DIR}/crm_master -l reboot -D } _sh_status_process() { # _volume not present should not happen, # but may help make this agent work even if it talks to drbd 8.3. : ${_volume:=0} # not-yet-created volumes are reported as -1 (( _volume >= 0 )) || _volume=$[1 << 16] DRBD_ROLE_LOCAL[$_volume]=${_role:-Unconfigured} DRBD_ROLE_REMOTE[$_volume]=${_peer:-Unknown} DRBD_CSTATE[$_volume]=$_cstate DRBD_DSTATE_LOCAL[$_volume]=${_disk:-Unconfigured} DRBD_DSTATE_REMOTE[$_volume]=${_pdsk:-DUnknown} } drbd_set_status_variables() { # drbdsetup sh-status prints these values to stdout, # and then prints _sh_status_process. # # if we eval that, we do not need several drbdadm/drbdsetup commands # to figure out the various aspects of the state. local _minor _res_name _known _cstate _role _peer _disk _pdsk local _volume local _flags_susp _flags_aftr_isp _flags_peer_isp _flags_user_isp local _resynced_percent local out DRBD_ROLE_LOCAL=() DRBD_ROLE_REMOTE=() DRBD_CSTATE=() DRBD_DSTATE_LOCAL=() DRBD_DSTATE_REMOTE=() if $DRBD_HAS_MULTI_VOLUME ; then out="$($DRBDSETUP sh-status "$DRBD_RESOURCE")" && eval "$out" else # without "MULTI_VOLUME", the DRBD_DEVICES array # should contain exactly one value out="$($DRBDSETUP "$DRBD_DEVICES" sh-status)" && eval "$out" fi # if there was no output at all, or a weird output # make sure the status arrays won't be empty. [[ ${#DRBD_ROLE_LOCAL[@]} != 0 ]] || DRBD_ROLE_LOCAL=(Unconfigured) [[ ${#DRBD_ROLE_REMOTE[@]} != 0 ]] || DRBD_ROLE_REMOTE=(Unknown) [[ ${#DRBD_CSTATE[@]} != 0 ]] || DRBD_CSTATE=(Unconfigured) [[ ${#DRBD_DSTATE_LOCAL[@]} != 0 ]] || DRBD_DSTATE_LOCAL=(Unconfigured) [[ ${#DRBD_DSTATE_REMOTE[@]} != 0 ]] || DRBD_DSTATE_REMOTE=(DUnknown) : == DEBUG == DRBD_ROLE_LOCAL == ${DRBD_ROLE_LOCAL[@]} == : == DEBUG == DRBD_ROLE_REMOTE == ${DRBD_ROLE_REMOTE[@]} == : == DEBUG == DRBD_CSTATE == ${DRBD_CSTATE[@]} == : == DEBUG == DRBD_DSTATE_LOCAL == ${DRBD_DSTATE_LOCAL[@]} == : == DEBUG == DRBD_DSTATE_REMOTE == ${DRBD_DSTATE_REMOTE[@]} == } call_unfence() { # It is easier to just call the crm-unfence-peer script, without # duplicating part of its code here. Also adding cibadmin calls to # first check if such constraint does even exist would needlessly add # even more load on the cib. export OCF_RESKEY_unfence_extra_args : ${OCF_RESKEY_unfence_extra_args:=$OCF_RESKEY_unfence_extra_args_default} # The unfence-peer handler was introduced only in 8.9.5. if (( DRBDADM_VERSION_CODE >= 0x080905 )) ; then $DRBDADM unfence-peer $DRBD_RESOURCE else /usr/lib/drbd/crm-unfence-peer.sh -r $DRBD_RESOURCE fi : "unfence exit code: $?" } # This is not the only fencing mechanism. # But in addition to the drbd "fence-peer" handler, which should be configured, # and is expected to place some appropriate constraints, this is used to # actually store the Outdated information in DRBD on-disk meta data. # # called after stop, and from post notification events. maybe_outdate_self() { # if you claim your right to go online with stale data, # there you are. ocf_is_true $OCF_RESKEY_stop_outdates_secondary || return 1 local host stop_uname # We ignore $OCF_RESKEY_CRM_meta_notify_promote_uname here # because: if demote and promote for a _stacked_ resource # (or a "floating" one, where DRBD sits on top of some SAN) # happen in the same transition, demote will see the promote # hostname here, and voluntarily outdate itself. Which would # result in promote failure, as it is using the same meta # data, which would then be outdated. # If that is not sufficient for you, you probably need to # configure fencing policies in the drbd configuration. host=$(printf "%s\n" $OCF_RESKEY_CRM_meta_notify_master_uname | grep -vix -m1 -e "$HOSTNAME" ) if [[ -z $host ]] ; then # no current master host found, do not outdate myself return 1 fi for stop_uname in $OCF_RESKEY_CRM_meta_notify_stop_uname; do [[ $host == "$stop_uname" ]] || continue # post notification for stop on that host. # hrmpf. crm passed in stale master_uname :( # ignore return 1 done # e.g. post/promote of some other peer. # Should not happen, fencing constraints should take care of that. # But in case it does, scream out loud. case "${DRBD_ROLE_LOCAL[*]}" in *Primary*) # I am Primary. # The other one is Primary (according to OCF_RESKEY_CRM_meta_notify_master_uname). # But we cannot talk to each other :( (otherwise this function was not called) # One of us has to die. # Which one, however, is not ours to decide. ocf_log crit "resource internal SPLIT BRAIN: both $HOSTNAME and $host are Primary for $DRBD_RESOURCE, but the replication link is down!" return 1 esac # OK, I am not Primary, but there is an other node Primary # Outdate myself ocf_log notice "outdating $DRBD_RESOURCE: according to OCF_RESKEY_CRM_meta_notify_master_uname, '$host' is still master" do_drbdadm outdate $DRBD_RESOURCE # on some pacemaker versions, -INFINITY may cause resource instance stop/start. # But in this case that is ok, it may even clear the replication link # problem. set_master_score -INFINITY return 0 } drbd_update_master_score() { set -- $OCF_RESKEY_adjust_master_score local only_consistent=$1 only_remote=$2 local_ok=$3 as_good_as_it_gets=$4 # NOTE # there may be constraint scores from rules on role=Master, # that in some ways can add to the node attribute based master score we # specify below. If you think you want to add personal preferences, # in case the scores given by this RA do not suffice, this is the # value space you can work with: # -INFINITY: Do not promote. Really. Won't work anyways. # Too bad, at least with current (Oktober 2009) Pacemaker, # negative master scores cause instance stop; restart cycle :( # missing, zero: Do not promote. # I think my data is not good enough. # Though, of course, you may try, and it might even work. # 5: please, do not promote, unless this is your only option. # 10: promotion is probably a bad idea, our local data is no good, # you'd probably run into severe performance problems, and risk # application crashes or blocking IO in case you lose the # replication connection. # 1000: Ok to be promoted, we have good data locally (though we don't # know about the peer, so possibly it has even better data?). # You sould use the crm-fence-peer.sh handler or similar # mechanism to avoid data divergence. # 10000: Please promote me/keep me Primary. # I'm confident that my data is as good as it gets. # # For multi volume, we need to compare who is "better" a bit more sophisticated. # The ${XXX[*]//UpToDate}, without being in double quotes, results in a single space, # if all are UpToDate. : == DEBUG == ${DRBD_ROLE_LOCAL[*]}/${DRBD_DSTATE_LOCAL[*]//UpToDate/ }/${DRBD_DSTATE_REMOTE[*]//UpToDate/ }/ == case ${DRBD_ROLE_LOCAL[*]}/${DRBD_DSTATE_LOCAL[*]//UpToDate/ }/${DRBD_DSTATE_REMOTE[*]//UpToDate/ }/ in *Primary*/\ /\ /) # I am Primary, all local disks are UpToDate, # AND all peer disks are UpToDate set_master_score $as_good_as_it_gets : == DEBUG == unfence_if_all_uptodate=$unfence_if_all_uptodate $unfence_if_all_uptodate && call_unfence ;; *Primary*/\ /*/) # I am Primary, all local disks are UpToDate, # not so sure about the peer's disks set_master_score $as_good_as_it_gets ;; */\ /*DUnknown*/) # all local disks are UpToDate, # but I'm not Primary, # and I'm not sure about the peer's disk state(s). # We may need to outdate ourselves? # But if we outdate in a MONITOR, and are disconnected # secondary because of a hard primary crash, before CRM noticed # that there is no more master, we'd make us utterly useless! # Trust that the primary will also notice the disconnect, # and will place an appropriate fencing constraint via # its fence-peer handler callback. set_master_score $local_ok ;; */\ /*/) # We know something about our peer, which means that either the # replication link is established, or it was not even # consistent last time we talked to each other. # Also all our local disks are UpToDate, which means even if we are # currently synchronizing, we do so as SyncSource. set_master_score $as_good_as_it_gets ;; */*/\ /) # At least one of our local disks is not up to date. # But our peer is ALL OK. # We can expect to have access to useful # data, but must expect degraded performance. set_master_score $only_remote ;; */*Attaching*/*/|\ */*Negotiating*/*/) # some transitional state. # just don't do anything : ;; Unconfigured*|\ */*Diskless*/*/|\ */*Failed*/*/|\ */*Inconsistent*/*/|\ */*Outdated*/*/) # ALWAYS put the cluster in MAINTENANCE MODE # if you add a volume to a live replication group, # because the new volume will typically come up as Inconsistent # the first time, which would cause a monitor to revoke the # master score! # # At least some of our local disks are not really useable. # Our peer is not all good either (or some previous case block # would have matched). We have no access to useful data. # DRBD would refuse to be promoted, anyways. # # set_master_score -INFINITY # Too bad, at least with current (Oktober 2009) Pacemaker, # negative master scores cause instance stop; restart cycle :( # Hope that this will suffice. remove_master_score ;; *) # All local disks seem to be Consistent. # They _may_ be up to date, or not. # We hope that fencing mechanisms have put constraints in # place, so we won't be promoted with stale data. # But in case this was a cluster crash, # at least allow _someone_ to be promoted. set_master_score $only_consistent ;; esac : "$OCF_SUCCESS = OCF_SUCCESS" return $OCF_SUCCESS } is_drbd_enabled() { test -f /proc/drbd } ####################################################################### drbd_usage() { echo "\ usage: $0 {start|stop|monitor|validate-all|promote|demote|notify|meta-data} Expects to have a fully populated OCF RA-compliant environment set." } drbd_status() { local rc local dev rc=$OCF_NOT_RUNNING # NOT local! but "return values" # since 8.4 supports multi volumes per resource, # these are shell arrays. # # Initialize to "Unconfigured", in case this returns early. # They will be re-initialized and properly populated in drbd_set_status_variables. DRBD_ROLE_LOCAL=(Unconfigured) DRBD_ROLE_REMOTE=(Unknown) DRBD_CSTATE=(Unconfigured) DRBD_DSTATE_LOCAL=(Unconfigured) DRBD_DSTATE_REMOTE=(DUnknown) is_drbd_enabled || return $rc # Not running, if no block devices exist. # # FIXME what if some do, and some do not exist? # Adding/removing volumes to/from existing resources should only be # done with maintenance-mode enabled. # If someone does manually kill/remove only some of the volumes, # we tolerate that here. for dev in ${DRBD_DEVICES[@]} ""; do test -b $dev && break done [[ $dev ]] || return $rc # ok, module is loaded, block device nodes exist. # lets see the status drbd_set_status_variables case "${DRBD_ROLE_LOCAL[*]}" in *Primary*) rc=$OCF_RUNNING_MASTER ;; *Secondary*) rc=$OCF_SUCCESS ;; *Unconfigured*) rc=$OCF_NOT_RUNNING ;; *) ocf_log err "Unexpected role(s) >>${DRBD_ROLE_LOCAL[*]}<<" rc=$OCF_ERR_GENERIC esac return $rc } # I'm sorry, but there is no $OCF_DEGRADED_MASTER or similar yet. drbd_monitor() { local status drbd_status status=$? if [[ $status = $OCF_NOT_RUNNING ]] && ocf_is_probe ; then # see also linux-ha mailing list archives, # From: Andrew Beekhof # Subject: Re: pacemaker+drbd promotion delay # Date: 2012-04-13 01:47:37 GMT # e.g.: http://thread.gmane.org/gmane.linux.highavailability.user/37089/focus=37163 # --- : "do nothing" ; else drbd_update_master_score fi case $status in (0) : "OCF_SUCCESS" ;; (1) : "OCF_ERR_GENERIC" ;; (2) : "OCF_ERR_ARGS" ;; (3) : "OCF_ERR_UNIMPLEMENTED" ;; (4) : "OCF_ERR_PERM" ;; (5) : "OCF_ERR_INSTALLED" ;; (6) : "OCF_ERR_CONFIGURED" ;; (7) : "OCF_NOT_RUNNING" ;; (8) : "OCF_RUNNING_MASTER" ;; (9) : "OCF_FAILED_MASTER" ;; (*) : " WTF? $status " ;; esac return $status } figure_out_drbd_peer_uname() { # depending on whether or not the peer is currently # configured, slave, master, or about to be started, # it may be mentioned in various variables (or not at all) local x # intentionally not cared for stop_uname x=$(printf "%s\n" \ $OCF_RESKEY_CRM_meta_notify_start_uname \ $OCF_RESKEY_CRM_meta_notify_promote_uname \ $OCF_RESKEY_CRM_meta_notify_master_uname \ $OCF_RESKEY_CRM_meta_notify_slave_uname \ $OCF_RESKEY_CRM_meta_notify_demote_uname | grep -vix -m1 -e "$HOSTNAME" ) DRBD_TO_PEER=${x:+ --peer $x} } my_udevsettle() { for dev in ${DRBD_DEVICES[@]}; do while ! test -b $dev; do sleep 1; done done return 0 } create_device_udev_settle() { local dev if $DRBD_HAS_MULTI_VOLUME; then if do_drbdadm new-resource $DRBD_RESOURCE && do_drbdadm new-minor $DRBD_RESOURCE; then my_udevsettle else return 1 fi elif do_drbdadm syncer $DRBD_RESOURCE ; then my_udevsettle else return 1 fi } drbd_start() { local rc local status local first_try=true rc=$OCF_ERR_GENERIC if ! is_drbd_enabled; then do_cmd modprobe -s drbd `$DRBDADM sh-mod-parms` || { ocf_log err "Cannot load the drbd module."; : "$OCF_ERR_INSTALLED = OCF_ERR_INSTALLED" return $OCF_ERR_INSTALLED } ocf_log debug "$DRBD_RESOURCE start: Module loaded." fi # Keep trying to bring up the resource; # wait for the CRM to time us out if this fails while :; do drbd_status status=$? case "$status" in $OCF_SUCCESS) # Just in case we have to adjust something, this is a # good place to do it. Actually, we don't expect to be # called to "start" an already "running" resource, so # this is probably dead code. # Also, ignore the exit code of adjust, as we are # "running" already, anyways, right? figure_out_drbd_peer_uname do_drbdadm $DRBD_TO_PEER adjust $DRBD_RESOURCE rc=$OCF_SUCCESS break ;; $OCF_NOT_RUNNING) # Check for offline resize. If using internal meta data, # we may need to move it first to its expected location. $first_try && do_drbdadm check-resize $DRBD_RESOURCE figure_out_drbd_peer_uname if ! create_device_udev_settle; then # We cannot even create the objects exit $OCF_ERR_GENERIC fi if ! do_drbdadm $DRBD_TO_PEER attach $DRBD_RESOURCE ; then # If we cannot up it, even on the second try, # it is unlikely to get better. Don't wait for # this operation to timeout, but short circuit # exit with generic error. $first_try || exit $OCF_ERR_GENERIC sleep 1 fi ;; $OCF_RUNNING_MASTER) ocf_log warn "$DRBD_RESOURCE already Primary, demoting." do_drbdadm secondary $DRBD_RESOURCE esac $first_try || sleep 1 first_try=false done # in case someone does not configure monitor, # we must at least call it once after start. drbd_update_master_score return $rc } drbd_promote() { local rc local status local first_try=true rc=$OCF_ERR_GENERIC # Keep trying to promote the resource; # wait for the CRM to time us out if this fails while :; do drbd_status status=$? case "$status" in $OCF_SUCCESS) do_drbdadm primary $DRBD_RESOURCE if [[ $? = 17 ]]; then # All available disks are inconsistent, # or I am consistent, but failed to fence the peer. # Cannot become primary. # No need to retry indefinitely. ocf_log crit "Refusing to be promoted to Primary without UpToDate data" break fi ;; $OCF_NOT_RUNNING) ocf_log error "Trying to promote a resource that was not started" break ;; $OCF_RUNNING_MASTER) rc=$OCF_SUCCESS break esac $first_try || sleep 1 first_try=false done # avoid too tight pacemaker driven "recovery" loop, # if promotion keeps failing for some reason if [[ $rc != 0 ]] && (( $SECONDS < 15 )) ; then delay=$(( 15 - SECONDS )) ocf_log warn "promotion failed; sleep $delay # to prevent tight recovery loop" sleep $delay fi return $rc } drbd_demote() { local rc local status local first_try=true rc=$OCF_ERR_GENERIC # Keep trying to demote the resource; # wait for the CRM to time us out if this fails while :; do drbd_status status=$? case "$status" in $OCF_SUCCESS) rc=$OCF_SUCCESS break ;; $OCF_NOT_RUNNING) ocf_log error "Trying to promote a resource that was not started" break ;; $OCF_RUNNING_MASTER) do_drbdadm secondary $DRBD_RESOURCE esac $first_try || sleep 1 first_try=false done return $rc } drbd_stop() { local rc=$OCF_ERR_GENERIC local first_try=true # Keep trying to bring down the resource; # wait for the CRM to time us out if this fails while :; do drbd_status status=$? case "$status" in $OCF_SUCCESS) do_drbdadm down $DRBD_RESOURCE ;; $OCF_NOT_RUNNING) # Just in case, down it anyways, in case it has been # deconfigured but not yet removed. # Relevant for >= 8.4. do_drbdadm down $DRBD_RESOURCE # But ignore any return codes, # we are not running, so stop is successfull. rc=$OCF_SUCCESS break ;; $OCF_RUNNING_MASTER) ocf_log warn "$DRBD_RESOURCE still Primary, demoting." do_drbdadm secondary $DRBD_RESOURCE esac $first_try || sleep 1 first_try=false done # if there is some Master (Primary) still around, # outdate myself in drbd on-disk meta data. maybe_outdate_self # do not let old master scores laying around. # they may confuse crm if this node was set to standby. remove_master_score return $rc } drbd_notify() { local n_type=$OCF_RESKEY_CRM_meta_notify_type local n_op=$OCF_RESKEY_CRM_meta_notify_operation # active_* and *_resource not really interessting # : "== DEBUG == active = $OCF_RESKEY_CRM_meta_notify_active_uname" : "== DEBUG == slave = $OCF_RESKEY_CRM_meta_notify_slave_uname" : "== DEBUG == master = $OCF_RESKEY_CRM_meta_notify_master_uname" : "== DEBUG == start = $OCF_RESKEY_CRM_meta_notify_start_uname" : "== DEBUG == promote = $OCF_RESKEY_CRM_meta_notify_promote_uname" : "== DEBUG == stop = $OCF_RESKEY_CRM_meta_notify_stop_uname" : "== DEBUG == demote = $OCF_RESKEY_CRM_meta_notify_demote_uname" case $n_type/$n_op in */start) # We do not get a /pre/ start notification for ourself. # but we get a /pre/ start notification for the other side, unless both # are started from the same transition graph. If there are only two # peers (the "classic" two-node DRBD), this adjust is usually a no-op. # # In case of more than one _possible_ peer, we may still be StandAlone, # or configured for a meanwhile failed peer, and should now adjust our # network settings during pre-notification of start of the other node. # # We usually get /post/ notification for ourself and the peer. # In both cases adjust should be a no-op. drbd_set_status_variables figure_out_drbd_peer_uname do_drbdadm $DRBD_TO_PEER -v adjust $DRBD_RESOURCE ;; post/*) # After something has been done is a good time to # recheck our status: drbd_set_status_variables drbd_update_master_score : == DEBUG == ${DRBD_DSTATE_REMOTE[*]} == case ${DRBD_DSTATE_REMOTE[*]} in *DUnknown*) # Still not communicating. # Maybe someone else is primary (too)? maybe_outdate_self esac esac : "$OCF_SUCCESS = OCF_SUCCESS" return $OCF_SUCCESS } # "macro" to be able to give useful error messages # on clone resource configuration error. meta_expect() { local what=$1 whatvar=OCF_RESKEY_CRM_meta_${1//-/_} op=$2 expect=$3 local val=${!whatvar} if [[ -n $val ]]; then # [, not [[, or it won't work ;) [ $val $op $expect ] && return fi ocf_log err "meta parameter misconfigured, expected $what $op $expect, but found ${val:-unset}." exit $OCF_ERR_CONFIGURED } ls_stat_is_block_maj_147() { set -- $(command ls -L -l "$1" 2>/dev/null) [[ $1 = b* ]] && [[ $5 == 147,* ]] } check_crm_feature_set() { set -- ${OCF_RESKEY_crm_feature_set//[!0-9]/ } local a=${1:-0} b=${2:-0} c=${3:-0} (( a > 3 )) || (( a == 3 && b > 0 )) || (( a == 3 && b == 0 && c > 0 )) || ocf_log warn "You may be disappointed: This RA is intended for pacemaker 1.0 or better!" } drbd_validate_all () { DRBDADM="drbdadm" DRBDSETUP="drbdsetup" DRBD_HAS_MULTI_VOLUME=false # these will _exit_ if they don't find the binaries check_binary $DRBDADM check_binary $DRBDSETUP # XXX I really take cibadmin, sed, grep, etc. for granted. local VERSION DRBD_KERNEL_VERSION_CODE=0 DRBDADM_VERSION_CODE=0 if VERSION="$($DRBDADM --version 2>/dev/null)"; then eval $VERSION fi if (( $DRBD_KERNEL_VERSION_CODE == 0x0 )) ; then # Maybe the DRBD module was not loaded (yet). # I don't want to load the module here, # maybe this is just a probe or stop. # It will be loaded on "start", though. # Instead, look at modinfo output. # Newer drbdadm does this implicitly, but may reexec older # drbdadm versions for compatibility reasons. DRBD_KERNEL_VERSION_CODE=$(printf "0x%02x%02x%02x" $( modinfo -F version drbd | sed -ne 's/^\([0-9]\+\)\.\([0-9]\+\)\.\([0-9]\+\).*$/\1 \2 \3/p')) fi if (( $DRBD_KERNEL_VERSION_CODE >= 0x080400 )); then DRBD_HAS_MULTI_VOLUME=true elif (( $DRBD_KERNEL_VERSION_CODE >= 0x090000 )) ; then ocf_log err "This resource agent does (still) only support DRBD version 8.x" exit $OCF_ERR_INSTALLED fi check_crm_feature_set # Check clone and M/S options. meta_expect clone-max -le 2 meta_expect clone-node-max = 1 meta_expect master-node-max = 1 meta_expect master-max -le 2 # Rather than returning $OCF_ERR_CONFIGURED, we sometimes return # $OCF_ERR_INSTALLED here: the local config may be broken, but some # other node may have a valid config. # check drbdconf plausibility case "$OCF_RESKEY_drbdconf" in "") # this is actually ok. drbdadm has its own builtin defaults. # but as long as we assign an explicit default above, # this cannot happen anyways. : ;; *[!-%+./0-9:=@A-Z_a-z]*) # no, I do not trust the configurable cib parameters. ocf_log err "drbdconf name must only contain [-%+./0-9:=@A-Z_a-z]" : "$OCF_ERR_CONFIGURED = OCF_ERR_CONFIGURED" return $OCF_ERR_CONFIGURED ;; *) # Check if we can read the configuration file. if [ ! -r "${OCF_RESKEY_drbdconf}" ]; then ocf_log err "Configuration file ${OCF_RESKEY_drbdconf} does not exist or is not readable!" : "$OCF_ERR_INSTALLED = OCF_ERR_INSTALLED" return $OCF_ERR_INSTALLED fi DRBDADM="$DRBDADM -c $OCF_RESKEY_drbdconf" esac # check drbd_resource plausibility case "$OCF_RESKEY_drbd_resource" in "") ocf_log err "No resource name specified!" : "$OCF_ERR_CONFIGURED = OCF_ERR_CONFIGURED" return $OCF_ERR_CONFIGURED ;; *[!-%+./0-9:=@A-Z_a-z]*) # no, I do not trust the configurable cib parameters. ocf_log err "Resource name must only contain [-%+./0-9:=@A-Z_a-z]" : "$OCF_ERR_CONFIGURED = OCF_ERR_CONFIGURED" return $OCF_ERR_CONFIGURED esac # exporting this is useful for "drbdsetup show". # and it makes it all a little bit more readable. export DRBD_RESOURCE=$OCF_RESKEY_drbd_resource # The resource should appear in the config file, # otherwise something's fishy # NOTE # since 8.4 has multi volume support, # DRBD_DEVICES will be a shell array! # FIXME we should double check that we explicitly restrict the set of # valid characters in device names... if DRBD_DEVICES=($($DRBDADM --stacked sh-dev $DRBD_RESOURCE 2>/dev/null)); then # apparently a "stacked" resource. Remember for future DRBDADM calls. DRBDADM="$DRBDADM -S" elif DRBD_DEVICES=($($DRBDADM sh-dev $DRBD_RESOURCE 2>/dev/null)); then : # nothing to do. else if [[ $__OCF_ACTION = "monitor" && $OCF_RESKEY_CRM_meta_interval = 0 ]]; then # ok, this was a probe. That may happen on any node, # to enforce configuration. : "$OCF_NOT_RUNNING = OCF_NOT_RUNNING" return $OCF_NOT_RUNNING else # hm. probably misconfigured constraint somewhere. # sorry. don't retry anywhere. ocf_log err "DRBD resource ${DRBD_RESOURCE} not found in configuration file ${OCF_RESKEY_drbdconf}." remove_master_score : "$OCF_ERR_INSTALLED = OCF_ERR_INSTALLED" return $OCF_ERR_INSTALLED fi fi # check for master-max and allow-two-primaries on start|promote only, # so it could be stopped still, if someone re-configured while running. case $__OCF_ACTION:$OCF_RESKEY_CRM_meta_master_max in start:2|promote:2) if ! $DRBDADM -d -v dump $DRBD_RESOURCE 2>/dev/null | grep -q -Ee '^[[:space:]]*allow-two-primaries([[:space:]]+yes)?;$' then ocf_log err "master-max = 2, but DRBD resource $DRBD_RESOURCE does not allow-two-primaries." : "$OCF_ERR_CONFIGURED = OCF_ERR_CONFIGURED" return $OCF_ERR_CONFIGURED fi esac # detect whether notify is configured or not. # for probes, the meta_notify* namespace is not exported. case $__OCF_ACTION in monitor|validate-all) :;; *) # Test if the environment variables for either the notify # enabled, or one of its effects, are set. # If both are unset, we complain. if ocf_is_true ${OCF_RESKEY_ignore_missing_notifications:=false} ; then : "ignore" ; elif ! ocf_is_true ${OCF_RESKEY_CRM_meta_notify} && [[ ${OCF_RESKEY_CRM_meta_notify_start_uname- NOT SET } = " NOT SET " ]]; then ocf_log err "you really should enable notify when using this RA (or set ignore_missing_notifications=true)" : "$OCF_ERR_CONFIGURED = OCF_ERR_CONFIGURED" return $OCF_ERR_CONFIGURED fi esac local i j n=0 fallback=false for i in $OCF_RESKEY_adjust_master_score; do [[ $i = *[!0-9]* ]] && fallback=true && ocf_log err "BAD adjust_master_score value $i ; falling back to default" [[ $j && $i -lt $j ]] && fallback=true && ocf_log err "BAD adjust_master_score value $j > $i ; falling back to default" j=$i n=$(( n+1 )) done [[ $n != 4 ]] && fallback=true && ocf_log err "Not enough adjust_master_score values ($n != 4); falling back to default" $fallback && OCF_RESKEY_adjust_master_score=$OCF_RESKEY_adjust_master_score_default # we use it in various places, # just make sure it contains what we expect. HOSTNAME=`uname -n` : "$OCF_SUCCESS = OCF_SUCCESS" return $OCF_SUCCESS } ####################################################################### if [ $# != 1 ]; then drbd_usage exit $OCF_ERR_ARGS fi # if $__OCF_ACTION = monitor, but meta_interval not set, # this is a "probe". we could change behaviour. : ${OCF_RESKEY_CRM_meta_interval=0} case $__OCF_ACTION in meta-data) meta_data exit $OCF_SUCCESS ;; usage) drbd_usage exit $OCF_SUCCESS esac if $USE_DEBUG_LOG ; then exec 2>&9 set -x fi # Everything except usage and meta-data must pass the validate test drbd_validate_all || exit case $__OCF_ACTION in start) drbd_start ;; stop) drbd_stop ;; notify) drbd_notify ;; promote) drbd_promote ;; demote) drbd_demote ;; status) drbd_status ;; monitor) drbd_monitor ;; validate-all) ;; *) drbd_usage exit $OCF_ERR_UNIMPLEMENTED esac # exit code is the exit code (return code) of the last command (shell function) drbd-utils-8.9.6/scripts/drbd.lang0000644000175000017500000000514112466702073016760 0ustar apoikosapoikosDescription="DRBD configuration" -- Include IPv4 and IPv6 as "numbers" Digits=[[ [0-9.:]+[kmgtKMGTs]? ]] --Digits=[[ (? is inconsistent # 0 -> is outdated # 17 -> outdate failed because peer is primary. # Unfortunately 20 can have other reasons too.... if [ $EXIT_CODE -eq 5 ]; then RV=3; else if [ $EXIT_CODE -eq 17 ]; then RV=6; else if [ $EXIT_CODE -eq 0 ]; then RV=4; else echo "do not know about this exit code" fi fi fi fi done # We return to DRBD - kernel driver: # # 6 -> peer is primary (and UpToDate) # 5 -> peer is down / unreachable. # 4 -> peer is outdated # 3 -> peer is inconsistent exit $RV drbd-utils-8.9.6/scripts/drbd.conf.example0000644000175000017500000001207212572334335020417 0ustar apoikosapoikosresource example { options { on-no-data-accessible suspend-io; } net { cram-hmac-alg "sha1"; shared-secret "secret_string"; } # The disk section is possible on resource level and in each # volume section disk { # If you have a resonable RAID controller # with non volatile write cache (BBWC, flash) disk-flushes no; disk-barrier no; md-flushes no; } # volume sections on resource level, are inherited to all node # sections. Place it here if the backing devices have the same # device names on all your nodes. volume 1 { device minor 1; disk /dev/sdb1; meta-disk internal; disk { resync-after example/0; } } on wurzel { address 192.168.47.1:7780; volume 0 { device minor 0; disk /dev/vg_wurzel/lg_example; meta-disk /dev/vg_wurzel/lv_example_md; } } on sepp { address 192.168.47.2:7780; volume 0 { device minor 0; disk /dev/vg_sepp/lg_example; meta-disk /dev/vg_sepp/lv_example_md; } } } resource "ipv6_example_res" { net { cram-hmac-alg "sha1"; shared-secret "ieho4CiiUmaes6Ai"; } volume 2 { device "/dev/drbd_fancy_name" minor 0; disk /dev/vg0/example2; meta-disk internal; } on amd { # Here is an example of ipv6. # If you want to use ipv4 in ipv6 i.e. something like [::ffff:192.168.22.11] # you have to set disable-ip-verification in the global section. address ipv6 [fd0c:39f4:f135:305:230:48ff:fe63:5c9a]:7789; } on alf { address ipv6 [fd0c:39f4:f135:305:230:48ff:fe63:5ebe]:7789; } } # # A two volume setup with a node for disaster recovery in an off-site location. # resource alpha-bravo { net { cram-hmac-alg "sha1"; shared-secret "Gei6mahcui4Ai0Oh"; } on alpha { volume 0 { device minor 0; disk /dev/foo; meta-disk /dev/bar; } volume 1 { device minor 1; disk /dev/foo1; meta-disk /dev/bar1; } address 192.168.23.21:7780; } on bravo { volume 0 { device minor 0; disk /dev/foo; meta-disk /dev/bar; } volume 1 { device minor 1; disk /dev/foo1; meta-disk /dev/bar1; } address 192.168.23.22:7780; } } resource stacked_multi_volume { net { protocol A; on-congestion pull-ahead; congestion-fill 400M; congestion-extents 1000; } disk { c-fill-target 10M; } volume 0 { device minor 10; } volume 1 { device minor 11; } proxy { memlimit 500M; plugin { lzma contexts 4 level 9; } } stacked-on-top-of alpha-bravo { address 192.168.23.23:7780; proxy on charly { # In the regular production site, there is a dedicated host to run # DRBD-proxy inside 192.168.23.24:7780; # for connections to DRBD outside 172.16.17.18:7780; # for connections over the WAN or VPN options { memlimit 1G; # Additional proxy options are possible here } } } on delta { volume 0 { device minor 0; disk /dev/foo; meta-disk /dev/bar; } volume 1 { device minor 1; disk /dev/foo1; meta-disk /dev/bar1; } address 127.0.0.2:7780; proxy on delta { # In the DR-site the proxy runs on the machine that stores the data inside 127.0.0.1:7780; outside 172.16.17.19:7780; } } } resource drbd_9_two_connection { volume 0 { device minor 10; disk /dev/foo/bar; meta-disk internal; } on alpha { node-id 0; address 192.168.31.1:7800; } on bravo { node-id 1; address 192.168.31.2:7800; } on charlie { node-id 2; address 192.168.31.3:7800; } net { ko-count 3; } connection "optional name" { host alpha; host bravo; net { protocol C; } } connection { host alpha address 127.0.0.1:7800 via proxy on alpha { inside 127.0.0.2:7800; outside 192.168.31.1:7801; } host charlie address 127.0.0.1:7800 via proxy on charlie { inside 127.0.0.2:7800; outside 192.168.31.3:7800; } net { protocol A; } volume 0 { disk { resync-rate 10M; c-plan-ahead 20; c-delay-target 10; c-fill-target 100; c-min-rate 10; c-max-rate 100M; } } } connection { host bravo address 127.0.0.1:7800 via proxy on bravo { inside 127.0.0.2:7800; outside 192.168.31.2:7801; } host charlie address 127.0.0.1:7800 via proxy on charlie { inside 127.0.0.2:7800; outside 192.168.31.3:7800; } net { protocol A; } } } resource drbd_9_mesh { volume 0 { device minor 11; disk /dev/foo/bar2; meta-disk internal; } on alpha { node-id 0; address 192.168.31.1:7900; } on bravo { node-id 1; address 192.168.31.2:7900; } on charlie { node-id 2; address 192.168.31.3:7900; } connection-mesh { hosts alpha bravo charlie; net { protocol C; } } } resource drbd_9_multi_path { volume 0 { device minor 12; disk /dev/foo/bar3; meta-disk internal; } on alpha { node-id 0; } on bravo { node-id 1; } connection { path { host alpha address 192.168.41.1:7900; host bravo address 192.168.41.2:7900; } path { host alpha address 192.168.42.1:7900; host bravo address 192.168.42.2:7900; } net { transport rdma; sndbuf-size 10M; rcvbuf-size 10M; max-buffers 20000; protocol C; } } } drbd-utils-8.9.6/scripts/snapshot-resync-target-lvm.sh0000755000175000017500000000561412466702073022766 0ustar apoikosapoikos#!/bin/bash # # snapshot-resync-target-lvm.sh # This file is part of DRBD by Philipp Reisner and Lars Ellenberg. # # The caller (drbdadm) sets for us: # DRBD_RESOURCE, DRBD_VOLUME, DRBD_MINOR, DRBD_LL_DISK etc. # ########### # # There will be no resync if this script terminates with an # exit code != 0. So be carefull with the exit code! # export LC_ALL=C LANG=C if [[ -z "$DRBD_RESOURCE" || -z "$DRBD_LL_DISK" ]]; then echo "DRBD_RESOURCE/DRBD_LL_DISK is not set. This script is supposed to" echo "get called by drbdadm as a handler script" exit 0 fi PROG=$(basename $0) exec > >(exec 2>&- ; logger -t "$PROG[$$]" -p local5.info) 2>&1 echo "invoked for $DRBD_RESOURCE/$DRBD_VOLUME (drbd$DRBD_MINOR)" TEMP=$(getopt -o p:a:nv --long percent:,additional:,disconnect-on-error,verbose -- "$@") if [ $? != 0 ]; then echo "getopt failed" exit 0 fi if BACKING_BDEV=$(drbdadm sh-ll-dev "$DRBD_RESOURCE/$DRBD_VOLUME"); then is_stacked=false elif BACKING_BDEV=$(drbdadm sh-ll-dev "$(drbdadm -S sh-lr-of "$DRBD_RESOURCE")/$DRBD_VOLUME"); then is_stacked=true else echo "Cannot determine lower level device of resource $DRBD_RESOURCE/$DRBD_VOLUME, sorry." exit 0 fi set_vg_lv_size() { local X if ! X=$(lvs --noheadings --nosuffix --units s -o vg_name,lv_name,lv_size "$BACKING_BDEV") ; then # if lvs cannot tell me the info I need, # this is: echo "Cannot create snapshot of $BACKING_BDEV, apparently no LVM LV." return 1 fi set -- $X VG_NAME=$1 LV_NAME=$2 LV_SIZE_K=$[$3 / 2] return 0 } set_vg_lv_size || exit 0 # clean exit if not an lvm lv SNAP_PERC=10 SNAP_ADDITIONAL=10240 DISCONNECT_ON_ERROR=0 LVC_OPTIONS="" BE_VERBOSE=0 SNAP_NAME=$LV_NAME-before-resync $is_stacked && SNAP_NAME=$SNAP_NAME-stacked DEFAULTFILE="/etc/default/drbd-snapshot" if [ -f $DEFAULTFILE ]; then . $DEFAULTFILE fi ## command line parameters override default file eval set -- "$TEMP" while true; do case $1 in -p|--percent) SNAP_PERC="$2" shift ;; -a|--additional) SNAP_ADDITIONAL="$2" shift ;; -n|--disconnect-on-error) DISCONNECT_ON_ERROR=1 ;; -v|--verbose) BE_VERBOSE=1 ;; --) break ;; esac shift done shift # the -- LVC_OPTIONS="$@" if [[ $0 == *unsnapshot* ]]; then [ $BE_VERBOSE = 1 ] && set -x lvremove -f $VG_NAME/$SNAP_NAME exit 0 else ( set -e [ $BE_VERBOSE = 1 ] && set -x case $DRBD_MINOR in *[!0-9]*|"") if $is_stacked; then DRBD_MINOR=$(drbdadm -S sh-minor "$DRBD_RESOURCE") else DRBD_MINOR=$(drbdadm sh-minor "$DRBD_RESOURCE") fi ;; *) :;; # ok, already exported by drbdadm esac OUT_OF_SYNC=$(sed -ne "/^ *$DRBD_MINOR:/ "'{ n; s/^.* oos:\([0-9]*\).*$/\1/; s/^$/0/; # default if not found p; q; }' < /proc/drbd) # unit KiB SNAP_SIZE=$((OUT_OF_SYNC + SNAP_ADDITIONAL + LV_SIZE_K * SNAP_PERC / 100)) lvcreate -s -n $SNAP_NAME -L ${SNAP_SIZE}k $LVC_OPTIONS $VG_NAME/$LV_NAME ) RV=$? [ $DISCONNECT_ON_ERROR = 0 ] && exit 0 exit $RV fi drbd-utils-8.9.6/scripts/drbdupper0000644000175000017500000000221712466702073017115 0ustar apoikosapoikos#!/bin/bash # # This script is inteded to be used as resource script by heartbeat # # Dec 2005 by Philipp Reisner. # # In heartbeat's haresources you should have: # IPAddr::XXX drbdupper::resource Filesystem::XXX # in other words, you have to allocate the service IP before you # try to activate the upper DRBD resource. ### DEFAULTFILE="/etc/default/drbd" DRBDADM="/sbin/drbdadm" if [ -f $DEFAULTFILE ]; then . $DEFAULTFILE fi if [ "$#" -eq 2 ]; then RES="$1" CMD="$2" else echo "A resource name is required." exit 10 fi if [ "$RES" = "all" ]; then echo "A resource name is required." exit 10 fi case "$CMD" in start) set -e # exit if one of these fails $DRBDADM primary `$DRBDADM -S sh-lr-of $RES` $DRBDADM -S check-resize $RES || true # may fail $DRBDADM -S adjust $RES $DRBDADM -S wait-connect $RES || true # may fail $DRBDADM -S primary $RES ;; stop) $DRBDADM -S down $RES $DRBDADM secondary `$DRBDADM -S sh-lr-of $RES` ;; status) if $DRBDADM -S role $RES | grep -q "Primary/"; then echo "running" else echo "stopped" fi ;; *) echo "Usage: drbdupper {resource} {start|stop|status}" exit 1 ;; esac exit 0 drbd-utils-8.9.6/scripts/rhcs_fence0000644000175000017500000001305412466702073017226 0ustar apoikosapoikos#!/bin/bash Author="Lars Ellenberg " Date="2014-09-18" Version="1.0" License="GPL v2+" # # Inspired by the rhcs_fence perl version # by Digimer (digimer@alteeve.ca) # Alteeve's Niche! - https://alteeve.ca/w/ # As found at https://github.com/digimer/rhcs_fence/releases/tag/0.2.8 # # This program ties Linbit's DRBD into Red Hat's RHCS's fence daemon via the # 'fence_node' shell call. # from environment # if tools do not yet export the plural, # use the (deprecated) singular. : ${DRBD_PEERS:=$DRBD_PEER} PROG=${0##*/} : ${DEBUG:=1} LOG_PRIO=daemon.warning LOG_TAG="$PROG[$$] $DRBD_PEERS: $DRBD_RESOURCE(minor $DRBD_MINOR)" ############################################################################## # helper functions ############################################################################## die() { echo "$*"; exit 1; } all_minors_up_to_date() { set -- $DRBD_MINOR local n_minors=$# [[ $n_minors != 0 ]] || die "Resource minor numbers unknown! Unable to proceed." # build a "grep extended regex" local _OLDIFS=$IFS IFS="|" local minor_regex="^ *($*): cs:" IFS=$_OLDIFS # grep -c -Ee '^ *(m|i|n|o|r|s): cs:.* ds:UpToDate' /proc/drbd local proc_drbd=$( >( exec 1>&- logger -s -p ${LOG_PRIO%.*}.debug -t "$LOG_TAG: DEBUG" ) exec 1> >( exec 1>&- logger -s -p $LOG_PRIO -t "$LOG_TAG" ) else [[ $DEBUG != 0 ]] && exec 3> >( exec 1>&- 2>&- logger -p ${LOG_PRIO%.*}.debug -t "$LOG_TAG: DEBUG" ) exec 1> >( exec 1>&- 2>&- logger -p $LOG_PRIO -t "$LOG_TAG" ) fi # and now point stderr to logger, too exec 2>&1 if [[ $DEBUG = 0 ]]; then debug() { :; } else debug() { echo >&3 "$*" ; } if [[ $DEBUG -gt 1 ]]; then BASH_XTRACEFD=3 set -x fi fi ############################################################################## # "main" ############################################################################## [[ $DRBD_PEERS ]] || die "No target list specified. You need to pass DRBD_PEERS via environment." all_minors_up_to_date || die "some minor device is NOT 'UpToDate', will not fence peer" for peer in $DRBD_PEERS; do for name in $peer ${peer%%.*}; do set -- $(cman_tool -F id,type nodes -n $name) id=$1 state=$2 [[ $id ]] && break done if [[ -z $id ]] || [[ $id = *[!0-9]* ]] ; then die "could not resolve cman node id of $peer, giving up" fi echo "resolved $peer as cman node $name, id $id, state $state" # record fence domain state now set -- $(fence_tool ls) fence_tool_ls="$* " debug "fence_tool ls: $fence_tool_ls" if [[ $state = M ]] ; then eject_target && continue # with next peer, if any else # maybe cman noticed before the handler triggered, # and fencing is already active anyways. if [[ $fence_tool_ls = *"victim now $id "* ]]; then wait_for_id_to_drop_out_of_membership && continue # with next peer, if any fi fi # apparently it was not in the member list. # or we timed out waiting for fenced debug "trying direct fence of $name" dash_v=-v [[ $DEBUG -gt 1 ]] && dash_v=-vv echo "fence_node $dash_v $name" if fence_node $dash_v $name ; then echo "successfully fenced $name" continue # with next peer, if any else die "fencing $name failed, giving up" fi done # if we fenced more than one peer, # add an other log line [[ $peer != $DRBD_PEERS ]] && echo "SUCCESSFULLY FENCED $DRBD_PEERS" exit 7 drbd-utils-8.9.6/scripts/drbddisk0000755000175000017500000000613212466702073016717 0ustar apoikosapoikos#!/bin/bash # # This script is inteded to be used as resource script by heartbeat # # Copright 2003-2008 LINBIT Information Technologies # Philipp Reisner, Lars Ellenberg # ### DEFAULTFILE="/etc/default/drbd" DRBDADM="/sbin/drbdadm" if [ -f $DEFAULTFILE ]; then . $DEFAULTFILE fi if [ "$#" -eq 2 ]; then RES="$1" CMD="$2" else RES="all" CMD="$1" fi ## EXIT CODES # since this is a "legacy heartbeat R1 resource agent" script, # exit codes actually do not matter that much as long as we conform to # http://wiki.linux-ha.org/HeartbeatResourceAgent # but it does not hurt to conform to lsb init-script exit codes, # where we can. # http://refspecs.linux-foundation.org/LSB_3.1.0/ # LSB-Core-generic/LSB-Core-generic/iniscrptact.html #### drbd_set_role_from_proc_drbd() { local out if ! test -e /proc/drbd; then ROLE="Unconfigured" return fi dev=$( $DRBDADM sh-dev $RES ) minor=${dev#/dev/drbd} if [[ $minor = *[!0-9]* ]] ; then # sh-minor is only supported since drbd 8.3.1 minor=$( $DRBDADM sh-minor $RES ) fi if [[ -z $minor ]] || [[ $minor = *[!0-9]* ]] ; then ROLE=Unknown return fi if out=$(sed -ne "/^ *$minor: cs:/ { s/:/ /g; p; q; }" /proc/drbd); then set -- $out ROLE=${5%/*} : ${ROLE:=Unconfigured} # if it does not show up else ROLE=Unknown fi } case "$CMD" in start) # try several times, in case heartbeat deadtime # was smaller than drbd ping time try=6 while true; do $DRBDADM primary $RES && break let "--try" || exit 1 # LSB generic error sleep 1 done ;; stop) # heartbeat (haresources mode) will retry failed stop # for a number of times in addition to this internal retry. try=3 while true; do $DRBDADM secondary $RES && break # We used to lie here, and pretend success for anything != 11, # to avoid the reboot on failed stop recovery for "simple # config errors" and such. But that is incorrect. # Don't lie to your cluster manager. # And don't do config errors... let --try || exit 1 # LSB generic error sleep 1 done ;; status) if [ "$RES" = "all" ]; then echo "A resource name is required for status inquiries." exit 10 fi ST=$( $DRBDADM role $RES ) ROLE=${ST%/*} case $ROLE in Primary|Secondary|Unconfigured) # expected ;; *) # unexpected. whatever... # If we are unsure about the state of a resource, we need to # report it as possibly running, so heartbeat can, after failed # stop, do a recovery by reboot. # drbdsetup may fail for obscure reasons, e.g. if /var/lock/ is # suddenly readonly. So we retry by parsing /proc/drbd. drbd_set_role_from_proc_drbd esac case $ROLE in Primary) echo "running (Primary)" exit 0 # LSB status "service is OK" ;; Secondary|Unconfigured) echo "stopped ($ROLE)" exit 3 # LSB status "service is not running" ;; *) # NOTE the "running" in below message. # this is a "heartbeat" resource script, # the exit code is _ignored_. echo "cannot determine status, may be running ($ROLE)" exit 4 # LSB status "service status is unknown" ;; esac ;; *) echo "Usage: drbddisk [resource] {start|stop|status}" exit 1 ;; esac exit 0 drbd-utils-8.9.6/scripts/README0000644000175000017500000000136312466702073016064 0ustar apoikosapoikosdrbd drbd sys-v type init script drbd.gentoo gentoo specific variation of the same drbdadm.bash_completion bash completion for the drbdadm command drbddisk resource script for heartbeat (R1 style) block-drbd xen "drbd" vbd type implementation drbd.sh.rhcs resource script for Red Hat Cluster Suite rgmanager drbd.metadata.rhcs resource script metadata for Red Hat Cluster Suite rgmanager outdate-peer.sh example implementation of the fence-peer mechanism using ssh drbd.conf commented example configuration drbd-overview.pl consolidates /proc/drbd, /etc/drbd.conf, xm list, lvs, df pretty-proc-drbd.sh example how to pretty-print (optionally with color) /proc/drbd build helpers: get_uts_release.sh adjust_drbd_config_h.sh patch-kernel drbd-utils-8.9.6/scripts/README.rhcs_fence0000644000175000017500000000636712466702073020173 0ustar apoikosapoikosProgram: rhcs_fence Author: Madison Kelly (digimer@alteeve.com) Alteeve's Niche! - https://alteeve.com/w/ Date: 2013-03-13 Version: 0.2.6 License: GPL v2.0+ -=] Description: This script is designed to be used as DRBD's 'fence-peer' handler. It ties DRBD's fence call, using 'disk { fencing resource-and-stonith }' into Red Hat Cluster Service's fenced daemon. This allows you to configure fencing once in your cluster and use it for both the cluster and DRBD. This program was based heavily on Lon Hohberger "obliterate-peer.sh" script. This was created as a replacement fence handler designed to add some features and intelligence to his script, but became a new program in order to switch to perl. -=] Supported Environments This script supports two-node DRBD setups only, but the nodes themselves may be part of a larger cluster. This script should be used when 'fencing resource-and-stonith' is set only. The 'on { }' name *must* match the ' as well. -=] Limitations As this handler insists on seeing the local disk as 'UpToDate' before it will proceed with a fence. Thus, if you have a simultaneous and complete cluster crash followed by the recovery of only one node, the recovered node will be in a 'Consistent' state, which will abort the fence call. As such, this scenario will recover human intervention to recover from. -=] Notes: This program takes certain steps to avoid dual-fencing; - First, Timing: This program will use the cluster's 'Node ID' as a base value for a delay prior to fencing. If a node has 'Node ID: 1' (as seen with 'cman_tool status'), there will be no delay and the fence will occur immediately. All other nodes will sleep for ((node_id x 2) + 5) seconds, up to a maximum of 30 seconds. It is possible to override this behaviour by setting 'local_delay' in the head configuration section of the script. If this is a non-0 value, the script will pause for the defined number of seconds, ignoring the behaviour described above. - Second, 'UpToDate' check; When a fence call is made, this program checks the referenced resource minor number's disk state to ensure it is 'UpToDate' as resported by '/proc/drbd'. The fence call will abort if the disk state is 'Consistent' (or anything else). This helps prevent accidentally fencing the original survivng node when the cluster communication is up, but the storage network is not, avoiding a fence-loop. -=] Failure Modes: This program follows the "Fail Early, Fail Often" ethos. It will *only* fence the peer if several conditions are met. Please test the functionality of this script before going into production! Exit codes; 1 - Fence failed, see syslog 7 - Fence succeeded 255 - End of script hit, likely a program error If you run into any trouble, please enable 'debug' mode by setting the internal 'debug' value to '1'. If you need help, please send the output of the syslog of both nodes with debug enabled to the Linux Cluster mailing list or DRBD Users mailing list. -=] Getting Help: By email: digimer@alteeve.com / https://alteeve.com IRC: #linux-cluster and #drbd on freenode.net Mailing list: https://www.redhat.com/mailman/listinfo/linux-cluster http://lists.linbit.com/mailman/listinfo/drbd-user drbd-utils-8.9.6/scripts/drbdadm.bash_completion0000644000175000017500000001131612466702073021670 0ustar apoikosapoikos# # /etc/bash_completion.d/drbdadm # # Bash completion for the DRBD top-level management application, drbdadm. # # If you have bash completion enabled, this module will # # - provide tab completion for drbdadm sub-commands (up, down, primary, # secondary etc.); # # - try to detect your current resource state and provide appropriate # command completion for the sub-command you provided. For example, # when if you have entered the "primary" sub-command, it will list # only those resources that are currently in the Secondary role; # # - differentiate between stacked and unstacked resources. # # This module does NOT guarantee that the DRBD state engine will in # fact agree to do what you ask it to. For example, resources that are # currently Primary and not connected are not excluded from the # completion list for the "detach" sub-command. # # Finally, this module is only capable of parsing resources correctly # if you are using the default location for your DRBD configuration # file (/etc/drbd.conf). __drbdadm_all_resources() { # Detects all resources currently listed in drbd.conf local resources="$(${DRBDADM} sh-resources) all" COMPREPLY=( $(compgen -W "$resources" -- "$current") ) } __drbdadm_resources_by_status() { # Detects only those resources that match a particular status local status_type="$1" shift 1 local status_filter="$*" local resources="$(${DRBDADM} sh-resources)" local filtered_resources local res for res in $resources; do local resource_status="$(${DRBDADM} $status_type $res 2>/dev/null)" # In case of multiple volumes, consider only the first line set -- $resource_status resource_status=$1 local i for i in $status_filter; do if [ "${resource_status%%/*}" = $i ]; then filtered_resources="$filtered_resources $res" fi done done COMPREPLY=( $(compgen -W "$filtered_resources" -- "$current") ) } __drbdadm_commands() { # Lists drbdadm sub-commands COMPREPLY=( $(compgen -W "$drbdadm_command_list" -- "$current") ) } __drbdadm_options() { # Lists global drbdadm options local options='-d --dry-run -v --verbose -S --stacked -t --config-to-test' COMPREPLY=( $(compgen -W "$options" -- "$current") ) } __drbdadm_subcmd_options() { local subcmd="$1" local options=($(drbdadm help $subcmd | sed -e '1,/OPTIONS FOR/ d;/^$/,$ d;s/ \(--[a-z-]*\).*/\1/')) local filtered local o have for o in ${options[@]}; do for have in ${COMP_WORDS[@]}; do [[ $o = "$have" ]] && continue 2 done filtered="$filtered $o" done COMPREPLY=( $(compgen -W "$filtered" -- "$current") ) } _drbdadm() { local DRBDADM="env DRBD_DONT_WARN_ON_VERSION_MISMATCH=1 ${COMP_WORDS[0]}" local drbdadm_command_list=' attach disk-options detach connect net-options disconnect up resource-options down primary secondary invalidate invalidate-remote outdate verify pause-sync resume-sync resize adjust wait-connect role cstate dstate dump wait-connect wait-con-int create-md dump-md wipe-md get-gi show-gi help apply-al hidden-commands ' # Redefine the drbdadm we use in __drbdadm_all_resources and # __drbdadm_resources_by_status, if running in stacked mode case "$COMP_LINE " in *" -S "*|*" --stacked "*) DRBDADM="$DRBDADM --stacked" ;; esac local current previous # The word currently being evaluated for completion current=${COMP_WORDS[COMP_CWORD]} # The word that precedes the currently-evaluated one previous=${COMP_WORDS[COMP_CWORD-1]} case "$previous" in drbdadm) case "$current" in -*) __drbdadm_options ;; *) __drbdadm_commands ;; esac ;; primary) __drbdadm_resources_by_status "role" "Secondary" ;; secondary) __drbdadm_resources_by_status "role" "Primary" ;; detach|disk-options) __drbdadm_resources_by_status "dstate" "UpToDate" "Inconsistent" "Outdated" ;; outdate) __drbdadm_resources_by_status "dstate" "UpToDate" ;; attach|apply-al) __drbdadm_resources_by_status "dstate" "Diskless" "Unconfigured" ;; connect) __drbdadm_resources_by_status "cstate" "StandAlone" "Unconfigured" ;; invalidate-remote) __drbdadm_resources_by_status "cstate" "Connected" ;; disconnect|net-options) __drbdadm_resources_by_status "cstate" "Connected" "WFConnection" "VerifyT" "VerifyS" ;; verify) __drbdadm_resources_by_status "cstate" "Connected" ;; pause-sync) __drbdadm_resources_by_status "cstate" "SyncSource" "SyncTarget" ;; resume-sync) __drbdadm_resources_by_status "cstate" "PausedSyncS" "PausedSyncT" ;; *) if (( COMP_CWORD > 2 )); then local subcmd subcmd=${COMP_WORDS[1]} case "$drbdadm_command_list" in *" $subcmd "*) __drbdadm_subcmd_options $subcmd ;; esac else __drbdadm_all_resources fi ;; esac } complete -o default -F _drbdadm drbdadm drbd-utils-8.9.6/scripts/stonith_admin-fence-peer.sh0000755000175000017500000000346012466702074022413 0ustar apoikosapoikos#!/bin/sh # # DRBD fence-peer handler for Pacemaker 1.1 clusters # (via stonith-ng). # # Requires that the cluster is running with STONITH # enabled, and has configured and functional STONITH # agents. # # Also requires that the DRBD disk fencing policy # is at least "resource-only", but "resource-and-stonith" # is more likely to be useful as most people will # use this in dual-Primary configurations. # # Returns 7 on on success (DRBD fence-peer exit code # for "yes, I've managed to fence this node"). # Returns 1 on any error (undefined generic error code, # causes DRBD devices with the "resource-and-stonith" # fencing policy to remain suspended). log() { local msg msg="$1" logger -i -t "`basename $0`" -s "$msg" } die() { log "$*"; exit 1; } die_unless_all_minors_up_to_date() { set -- $DRBD_MINOR local n_minors=$# [ $n_minors != 0 ] || die "Resource minor numbers unknown! Unable to proceed." # and build a "grep extended regex" local _OLDIFS=$IFS IFS="|" local minor_regex="^ *($*): cs:" IFS=$_OLDIFS # grep -c -Ee '^ *(m|i|n|o|r|s): cs:.* ds:UpToDate' /proc/drbd local proc_drbd=$(cat /proc/drbd) local minors_of_resource=$(echo "$proc_drbd" | grep -E -e "$minor_regex") local n_up_to_date=$(echo "$minors_of_resource" | grep -c -e "ds:UpToDate") log "n_minors: $n_minors; n_up_to_date: $n_up_to_date" [ "$n_up_to_date" = "$n_minors" ] || die "$DRBD_RESOURCE(minor $DRBD_MINOR): some minor is not UpToDate, will not fence peer." } [ -n "$DRBD_PEERS" ] || die "DRBD_PEERS is empty or unset, cannot continue." die_unless_all_minors_up_to_date for p in $DRBD_PEERS; do stonith_admin --tolerance 5s --tag drbd --fence $p rc=$? if [ $rc -eq 0 ]; then log "stonith_admin successfully fenced peer $p." else die "Failed to fence peer $p. stonith_admin returned $rc." fi done exit 7 drbd-utils-8.9.6/scripts/drbd.tmpfiles.conf0000644000175000017500000000003512477305373020607 0ustar apoikosapoikosd /run/drbd 0700 root root - drbd-utils-8.9.6/scripts/Makefile.in0000644000175000017500000001414512634271674017260 0ustar apoikosapoikos# Makefile for scripts # # This file is part of DRBD by Philipp Reisner & Lars Ellenberg. # # Copright 2001-2008 LINBIT Information Technologies # Philipp Reisner, Lars Ellenberg # # drbd is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # drbd is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with drbd; see the file COPYING. If not, write to # the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. # # for Debian: # update-rc.d drbd defaults 70 08 # # variables set by configure DISTRO = @DISTRO@ prefix = @prefix@ exec_prefix = @exec_prefix@ datarootdir = @datarootdir@ datadir = @datadir@ sbindir = @sbindir@ sysconfdir = @sysconfdir@ systemdunitdir = @systemdunitdir@ tmpfilesdir = @tmpfilesdir@ udevrulesdir = @udevrulesdir@ initscripttype = @initscripttype@ BASH_COMPLETION_SUFFIX = @BASH_COMPLETION_SUFFIX@ UDEV_RULE_SUFFIX = @UDEV_RULE_SUFFIX@ INITDIR = @INITDIR@ LIBDIR = @prefix@/lib/@PACKAGE_TARNAME@ LN_S = @LN_S@ # features enabled or disabled by configure WITH_UDEV = @WITH_UDEV@ WITH_XEN = @WITH_XEN@ WITH_PACEMAKER = @WITH_PACEMAKER@ WITH_HEARTBEAT = @WITH_HEARTBEAT@ WITH_RGMANAGER = @WITH_RGMANAGER@ WITH_BASHCOMPLETION = @WITH_BASHCOMPLETION@ # variables meant to be overridden from the make command line DESTDIR ?= / all: install: install-utils install-udev install-xen install-heartbeat install-pacemaker install-rgmanager install-bashcompletion install-utils: install -d $(DESTDIR)$(LIBDIR) ifneq ($(initscripttype),systemd) # "sysv" or "both" install -d $(DESTDIR)$(INITDIR) install -m 755 drbd $(DESTDIR)$(INITDIR)/ endif # yes, debian apparently allows installing both types from the same package ifneq ($(initscripttype),sysv) # "systemd" or "both" install -d $(DESTDIR)$(systemdunitdir) install -m 755 drbd.service $(DESTDIR)$(systemdunitdir)/ install -d $(DESTDIR)/lib/drbd/ install -m 755 drbd $(DESTDIR)/lib/drbd/ install -d $(DESTDIR)$(tmpfilesdir)/ install -m 444 drbd.tmpfiles.conf $(DESTDIR)$(tmpfilesdir)/drbd.conf endif @ if [ ! -e $(DESTDIR)$(sysconfdir)/drbd.conf ]; then \ install -d $(DESTDIR)$(sysconfdir)/; \ install -m 644 drbd.conf $(DESTDIR)$(sysconfdir)/; \ install -d $(DESTDIR)$(sysconfdir)/drbd.d; \ install -m 644 global_common.conf $(DESTDIR)$(sysconfdir)/drbd.d; \ fi install -m 755 outdate-peer.sh $(DESTDIR)$(LIBDIR) install -m 755 snapshot-resync-target-lvm.sh $(DESTDIR)$(LIBDIR) install -m 755 notify.sh $(DESTDIR)$(LIBDIR) install -m 755 stonith_admin-fence-peer.sh $(DESTDIR)$(LIBDIR) ( set -e ; cd $(DESTDIR)$(LIBDIR) ;\ $(LN_S) -f snapshot-resync-target-lvm.sh unsnapshot-resync-target-lvm.sh ;\ $(LN_S) -f notify.sh notify-split-brain.sh ;\ $(LN_S) -f notify.sh notify-io-error.sh ;\ $(LN_S) -f notify.sh notify-pri-on-incon-degr.sh ;\ $(LN_S) -f notify.sh notify-pri-lost.sh ;\ $(LN_S) -f notify.sh notify-pri-lost-after-sb.sh ;\ $(LN_S) -f notify.sh notify-emergency-reboot.sh ;\ $(LN_S) -f notify.sh notify-emergency-shutdown.sh ;\ $(LN_S) -f notify.sh notify-out-of-sync.sh; ) install -d $(DESTDIR)$(sbindir) install -m 755 drbd-overview.pl $(DESTDIR)$(sbindir)/drbd-overview ifeq ($(DISTRO),debian) @ echo "Don't forget to run update-rc.d" else @ echo "Don't forget to run chkconfig" endif install-heartbeat: ifeq ($(WITH_HEARTBEAT),yes) mkdir -p $(DESTDIR)$(sysconfdir)/ha.d/resource.d install -m 755 drbddisk $(DESTDIR)$(sysconfdir)/ha.d/resource.d install -m 755 drbdupper $(DESTDIR)$(sysconfdir)/ha.d/resource.d endif # Do not use $(prefix) for the resource agent. The OCF standard # explicitly mandates where resource agents must live, # no matter what prefix is configured to. install-pacemaker: ifeq ($(WITH_PACEMAKER),yes) install -d $(DESTDIR)$(LIBDIR) install -m 755 crm-fence-peer.sh $(DESTDIR)$(LIBDIR) ( set -e ; cd $(DESTDIR)$(LIBDIR) ;\ $(LN_S) -f crm-fence-peer.sh crm-unfence-peer.sh ; ) mkdir -p $(DESTDIR)/usr/lib/ocf/resource.d/linbit install -m 755 drbd.ocf $(DESTDIR)/usr/lib/ocf/resource.d/linbit/drbd endif install-rgmanager: ifeq ($(WITH_RGMANAGER),yes) mkdir -p $(DESTDIR)$(datadir)/cluster install -m 755 drbd.sh.rhcs $(DESTDIR)$(datadir)/cluster/drbd.sh install -m 644 drbd.metadata.rhcs $(DESTDIR)$(datadir)/cluster/drbd.metadata install -d $(DESTDIR)$(LIBDIR) install -m 755 rhcs_fence $(DESTDIR)$(LIBDIR) endif install-xen: ifeq ($(WITH_XEN),yes) mkdir -p $(DESTDIR)$(sysconfdir)/xen/scripts install -m 755 block-drbd $(DESTDIR)$(sysconfdir)/xen/scripts endif install-udev: ifeq ($(WITH_UDEV),yes) mkdir -p $(DESTDIR)$(udevrulesdir) install -m 644 drbd.rules $(DESTDIR)$(udevrulesdir)/65-drbd.rules$(UDEV_RULE_SUFFIX) endif install-bashcompletion: ifeq ($(WITH_BASHCOMPLETION),yes) mkdir -p $(DESTDIR)$(sysconfdir)/bash_completion.d install -m 644 drbdadm.bash_completion $(DESTDIR)$(sysconfdir)/bash_completion.d/drbdadm$(BASH_COMPLETION_SUFFIX) endif clean: rm -f *~ rm -f datadisk distclean: clean uninstall: ifneq ($(initscripttype),systemd) # "sysv" or "both" rm -f $(DESTDIR)$(INITDIR)/drbd endif ifneq ($(initscripttype),sysv) # "systemd" or "both" rm -f $(DESTDIR)$(systemdunitdir)/drbd.service endif rm -f $(DESTDIR)$(sysconfdir)/ha.d/resource.d/drbddisk rm -f $(DESTDIR)$(sysconfdir)/ha.d/resource.d/drbdupper rm -f $(DESTDIR)$(sysconfdir)/xen/scripts/block-drbd rm -f $(DESTDIR)$(sysconfdir)/bash_completion.d/drbdadm$(BASH_COMPLETION_SUFFIX) rm -f $(DESTDIR)$(sbindir)/drbd-overview ! test -L $(DESTDIR)/sbin/rcdrbd || rm $(DESTDIR)/sbin/rcdrbd .PHONY: install uninstall clean distclean ../../configure: @echo "please (re-)run ./autogen.sh with appropriate arguments"; exit 1 ../../config.status: ../../configure @echo "please (re-)run ./configure with appropriate arguments"; exit 1 Makefile.in: ; Makefile: Makefile.in ../config.status cd .. && ./config.status scripts/Makefile drbd-utils-8.9.6/scripts/drbd.metadata.rhcs0000644000175000017500000000261412466702073020557 0ustar apoikosapoikos 1.0 This is a DRBD resource. The resource must be configured in the configuration file (/etc/drbd.conf), and the DRBD kernel module must be loaded. This is a DRBD resource. Symbolic name for this resource. Cluster resource name The DRBD resource name, as specified in /etc/drbd.conf. DRBD resource name drbd-utils-8.9.6/scripts/drbd.rules.in0000644000175000017500000000110612466702073017573 0ustar apoikosapoikos# This file contains the rules to create named DRBD devices. SUBSYSTEM!="block", GOTO="drbd_end" KERNEL!="drbd*", GOTO="drbd_end" IMPORT{program}="@sbindir@/drbdadm sh-udev minor-%m" # Use symlink from the environment if available ENV{SYMLINK}!="", SYMLINK="$env{SYMLINK}", GOTO="have_symlink" # Legacy rules for older DRBD 8.3 & 8.4 when drbdadm sh-udev did not yet export SYMLINK ENV{DISK}!="", SYMLINK+="drbd/by-disk/$env{DISK}" ENV{RESOURCE}!="", SYMLINK+="drbd/by-res/$env{RESOURCE}" LABEL="have_symlink" ENV{DEVICE}=="drbd_?*", SYMLINK+="$env{DEVICE}" LABEL="drbd_end" drbd-utils-8.9.6/scripts/block-drbd0000755000175000017500000001755712466702073017151 0ustar apoikosapoikos#!/bin/bash # # Copyright (c) 2007 LINBIT Information Technologies GmbH # Based on the original "block" VBD script by XenSource Inc. # # This script implements the "drbd" VBD type. To use a DRBD resource # as a virtual block device, include a line similar to this in your # domU configuration: # # disk = [ 'drbd:myresource,xvda1,w' ] # # This will direct Xen to put the DRBD resource named 'myresource' # into the Primary role, and configure it as device xvda1 in your # domU. You may use as many DRBD resources as you like. If you are # using DRBD in dual-Primary mode (available in DRBD versions 8.0 and # up), your DRBD-backed domU will be live migration capable. # # IMPORTANT: If you run DRBD in dual-Primary mode with Xen, you MUST # ensure that the only time the resource is accessed by # both nodes is during domain migration. If you fire up a # DRBD-backed domU simultaneously on two nodes, you WILL # wreck your VBD data. DO NOT attempt to set up a live # migration capable, DRBD-backed domU unless you # understand these implications. # # This script will not load the DRBD kernel module for you, nor will # it attach, detach, connect, or disconnect your resource. The init # script distributed with DRBD will do that for you. Make sure it is # started before attempting to start a DRBD-backed domU. # # Known limitations: # # - With 'file' and 'phy' VBD's, Xen will allow one block device to be # made available read-only to multiple domU's, or be mounted # read-only in the dom0 and be made available read-only to # domU's. This is not supported by the 'drbd' VBD type. # - Tested, thus far, only on Debian etch with Xen 3.0.3. # # For more information about DRBD, visit http://www.drbd.org/. # # # This library is free software; you can redistribute it and/or # modify it under the terms of version 2.1 of the GNU Lesser General Public # License as published by the Free Software Foundation. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # dir=$(dirname "$0") . "$dir/block-common.sh" PATH=/usr/sbin:/sbin:$PATH ## # canonicalise_mode mode # # Takes the given mode, which may be r, w, ro, rw, w!, or rw!, or variations # thereof, and canonicalises them to one of # # 'r': perform checks for a new read-only mount; # 'w': perform checks for a read-write mount; or # '!': perform no checks at all. # canonicalise_mode() { local mode="$1" if ! expr index "$mode" 'w' >/dev/null then echo 'r' elif ! expr index "$mode" '!' >/dev/null then echo 'w' else echo '!' fi } ## # check_sharing device mode # # Check whether the device requested is already in use. To use the device in # read-only mode, it may be in use in read-only mode, but may not be in use in # read-write anywhere at all. To use the device in read-write mode, it must # not be in use anywhere at all. # # Prints one of # # 'local': the device may not be used because it is mounted in the current # (i.e. the privileged domain) in a way incompatible with the # requested mode; # 'guest': the device may not be used because it already mounted by a guest # in a way incompatible with the requested mode; or # 'ok': the device may be used. # check_sharing() { local dev="$1" local mode="$2" local devmm=$(device_major_minor "$dev") local file # Here, different from the original 'block' script, we don't check # explicitly for read/write mounts. See "known limitations" above. toskip="^$" for file in $(cat /proc/mounts | grep -v "$toskip" | cut -f 1 -d ' ') do if [ -e "$file" ] then local d=$(device_major_minor "$file") if [ "$d" = "$devmm" ] then echo 'local' return fi fi done local base_path="$XENBUS_BASE_PATH/$XENBUS_TYPE" for dom in $(xenstore-list "$base_path") do for dev in $(xenstore-list "$base_path/$dom") do d=$(xenstore_read_default "$base_path/$dom/$dev/physical-device" "") if [ "$d" = "$devmm" ] then # Here, different from the original 'block' script, we don't # check explicitly for read/write mounts. See "known # limitations" above. if ! same_vm $dom then echo 'guest' return fi fi done done echo 'ok' } same_vm() { local otherdom="$1" # Note that othervm can be MISSING here, because Xend will be racing with # the hotplug scripts -- the entries in /local/domain can be removed by # Xend before the hotplug scripts have removed the entry in # /local/domain/0/backend/. In this case, we want to pretend that the # VM is the same as FRONTEND_UUID, because that way the 'sharing' will be # allowed. local othervm=$(xenstore_read_default "/local/domain/$otherdom/vm" \ "$FRONTEND_UUID") [ "$FRONTEND_UUID" = "$othervm" ] } ## # check_device_sharing dev mode # # Perform the sharing check for the given physical device and mode. # check_device_sharing() { local dev="$1" local mode=$(canonicalise_mode "$2") local result if [ "x$mode" = 'x!' ] then return 0 fi result=$(check_sharing "$dev" "$mode") if [ "$result" != 'ok' ] then do_ebusy "Device $dev is mounted " "$mode" "$result" fi } ## # do_ebusy prefix mode result # # Helper function for check_device_sharing check_file_sharing, calling ebusy # with an error message constructed from the given prefix, mode, and result # from a call to check_sharing. # do_ebusy() { local prefix="$1" local mode="$2" local result="$3" if [ "$result" = 'guest' ] then dom='a guest ' when='now' else dom='the privileged ' when='by a guest' fi if [ "$mode" = 'w' ] then m1='' m2='' else m1='read-write ' m2='read-only ' fi release_lock "block" ebusy \ "${prefix}${m1}in ${dom}domain, and so cannot be mounted ${m2}${when}." } t=$(xenstore_read_default "$XENBUS_PATH/type" 'MISSING') case "$command" in add) phys=$(xenstore_read_default "$XENBUS_PATH/physical-device" 'MISSING') if [ "$phys" != 'MISSING' ] then # Depending upon the hotplug configuration, it is possible for this # script to be called twice, so just bail. exit 0 fi if [ -n "$t" ] then p=$(xenstore_read "$XENBUS_PATH/params") mode=$(xenstore_read "$XENBUS_PATH/mode") fi case $t in drbd|phy) drbd_resource=$p drbd_role="$(drbdadm role $drbd_resource)" drbd_lrole="${drbd_role%%/*}" drbd_dev="$(drbdadm sh-dev $drbd_resource)" if [ "$drbd_lrole" != 'Primary' ]; then drbdadm primary $drbd_resource fi dev=$drbd_dev FRONTEND_ID=$(xenstore_read "$XENBUS_PATH/frontend-id") FRONTEND_UUID=$(xenstore_read_default \ "/local/domain/$FRONTEND_ID/vm" 'unknown') claim_lock "block" check_device_sharing "$dev" "$mode" write_dev "$dev" release_lock "block" exit 0 ;; "") claim_lock "block" success release_lock "block" ;; esac ;; remove) case $t in drbd|phy) p=$(xenstore_read "$XENBUS_PATH/params") drbd_resource=$p drbd_role="$(drbdadm role $drbd_resource)" drbd_lrole="${drbd_role%%/*}" drbd_dev="$(drbdadm sh-dev $drbd_resource)" if [ "$drbd_lrole" != 'Secondary' ]; then drbdadm secondary $drbd_resource fi exit 0 ;; "") exit 0 ;; esac ;; esac drbd-utils-8.9.6/scripts/get_uts_release.sh0000755000175000017500000000055512466702073020717 0ustar apoikosapoikos#!/bin/bash { for x in include/generated/utsrelease.h include/linux/{utsrelease,version}.h; do for d in $KDIR $O; do test -e "$d/$x" || continue; echo "#include \"$d/$x\""; done; done; echo "drbd_kernel_release UTS_RELEASE" } | gcc -nostdinc -E -P - | sed -ne 's/^drbd_kernel_release "\(.*\)".*/\1/p' drbd-utils-8.9.6/scripts/drbd0000755000175000017500000001702212523133457016042 0ustar apoikosapoikos#!/bin/bash # # chkconfig: - 70 08 # description: Loads and unloads the drbd module # # Copyright 2001-2013 LINBIT # # Philipp Reisner, Lars Ellenberg # ### BEGIN INIT INFO # Provides: drbd # Required-Start: $local_fs $network $syslog # Required-Stop: $local_fs $network $syslog # Should-Start: sshd multipathd # Should-Stop: sshd multipathd # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # X-Start-Before: heartbeat corosync # X-Stop-After: heartbeat corosync # X-Interactive: true # Short-Description: Control drbd resources. ### END INIT INFO DEFAULTFILE="/etc/default/drbd" DRBDADM="drbdadm" DRBDSETUP="drbdsetup" PROC_DRBD="/proc/drbd" MODPROBE="/sbin/modprobe" RMMOD="/sbin/rmmod" UDEV_TIMEOUT=10 ADD_MOD_PARAM="" PATH=/usr/sbin:/sbin:$PATH if [ -f $DEFAULTFILE ]; then . $DEFAULTFILE fi # we only use these two functions, define fallback versions of them ... log_daemon_msg() { echo -n "${1:-}: ${2:-}"; } log_end_msg() { echo "."; } # ... and let the lsb override them, if it thinks it knows better. if [ -f /lib/lsb/init-functions ]; then . /lib/lsb/init-functions fi assure_module_is_loaded() { [ -e "$PROC_DRBD" ] && return $MODPROBE -s drbd $ADD_MOD_PARAM || { echo "Can not load the drbd module."$'\n' exit 5 # LSB for "not installed" } # tell klogd to reload module symbol information ... [ -e /var/run/klogd.pid ] && [ -x /sbin/klogd ] && /sbin/klogd -i } drbd_pretty_status() { local proc_drbd=$1 # add resource names if ! type column &> /dev/null || ! type paste &> /dev/null || ! type join &> /dev/null || ! type sed &> /dev/null || ! type tr &> /dev/null then cat "$proc_drbd" return fi sed -e '2q' < "$proc_drbd" sed_script=$( i=0; _sh_status_process() { let i++ ; stacked=${_stacked_on:+"^^${_stacked_on_minor:-${_stacked_on//[!a-zA-Z0-9_ -]/_}}"} printf "s|^ *%u:|%6u\t&%s%s|\n" \ $_minor $i \ "${_res_name//[!a-zA-Z0-9_ -]/_}" "$stacked" }; eval "$(drbdadm sh-status)" ) p() { sed -e "1,2d" \ -e "$sed_script" \ -e '/^ *[0-9]\+: cs:Unconfigured/d;' \ -e 's/^\(.* cs:.*[^ ]\) \([rs]...\)$/\1 - \2/g' \ -e 's/^\(.* \)cs:\([^ ]* \)st:\([^ ]* \)ds:\([^ ]*\)/\1\2\3\4/' \ -e 's/^\(.* \)cs:\([^ ]* \)ro:\([^ ]* \)ds:\([^ ]*\)/\1\2\3\4/' \ -e 's/^\(.* \)cs:\([^ ]*\)$/\1\2/' \ -e 's/^ *[0-9]\+:/ x &??not-found??/;' \ -e '/^$/d;/ns:.*nr:.*dw:/d;/resync:/d;/act_log:/d;' \ -e 's/^\(.\[.*\)\(sync.ed:\)/... ... \2/;/^.finish:/d;' \ -e 's/^\(.[0-9 %]*oos:\)/... ... \1/' \ < "$proc_drbd" | tr -s '\t ' ' ' } m() { join -1 2 -2 1 -o 1.1,2.2,2.3 \ <( ( drbdadm sh-dev all ; drbdadm -S sh-dev all ) | cat -n | sort -k2,2) \ <(sort < /proc/mounts ) | sort -n | tr -s '\t ' ' ' | sed -e 's/^ *//' } # echo "=== p ===" # p # echo "=== m ===" # m # echo "=========" # join -a1 <(p|sort) <(m|sort) # echo "=========" ( echo m:res cs ro ds p mounted fstype join -a1 <(p|sort) <(m|sort) | cut -d' ' -f2-6,8- | sort -k1,1n -k2,2 ) | column -t } # Try to settle regardless of udev version or presence, # so "/etc/init.d/drbd stop" is able to rmmod, without interfering # temporary module references caused by udev scanning the devices. # But don't wait too long. _udev_settle() { if udevadm version ; then # ok, we have udevadm, use it. udevadm settle --timeout=5 else # if udevsettle is not there, # no matter. udevsettle --timeout=5 fi } run_hook() { n="hook_$1" if t=$(type -t "$n") && [[ "$t" == "function" ]] ; then shift "$n" "$@" fi } case "$1" in start) # no module, no DRBD. assure_module_is_loaded # Just in case drbdadm want to display any errors in the configuration # file, or we need to ask the user about registering this installation # at http://usage.drbd.org, we call drbdadm here without any IO # redirection. # If "no op" has a non-zero exit code, the config is unusable, # and every other command will fail. out=$($DRBDADM sh-nop 2>&1); ex=$? [[ $ex = 127 ]] && exit 5 # LSB for "not installed" log_daemon_msg "Starting DRBD resources" if [[ $ex != 0 ]] ; then printf "\n%s\n" "$out" >&2 log_end_msg 1 exit 6 # LSB for "not configured" fi $DRBDADM adjust-with-progress all [[ $? -gt 1 ]] && exit 20 # make sure udev has time to create the device files # FIXME this probably should, on platforms that have it, # use udevadm settle --timeout=X --exit-if-exists=$DEVICE for DEVICE in `$DRBDADM sh-dev all`; do UDEV_TIMEOUT_LOCAL=$UDEV_TIMEOUT while [ ! -e $DEVICE ] && [ $UDEV_TIMEOUT_LOCAL -gt 0 ] ; do sleep 1 UDEV_TIMEOUT_LOCAL=$(( $UDEV_TIMEOUT_LOCAL-1 )) done done [ -d /var/lock/subsys ] && touch /var/lock/subsys/drbd # for RedHat run_hook start_before-wait $DRBDADM wait-con-int # User interruptible version of wait-connect all run_hook start # Become primary if configured # Currently, this is necessary for drbd8 # drbd9 supports automatic promote and removes the "sh-b-pri" command. $DRBDADM sh-b-pri all || true log_end_msg 0 # Now handle stacked devices, if any STACKED_RESOURCES="" # no point trying stacking, if we don't have at least one primary. if grep -w Primary /proc/drbd &> /dev/null; then # heuristic: don't mess with dinosaurs # :-( if ! grep -Ee '\' /etc/ha.d/haresources &> /dev/null; then STACKED_RESOURCES=`$DRBDADM -S sh-resources` fi fi if [[ $STACKED_RESOURCES ]] ; then log_daemon_msg "Starting stacked DRBD resources" DEVICES=`$DRBDADM -S sh-dev all` $DRBDADM -S adjust-with-progress all if [[ $? -gt 1 ]] ; then log_end_msg 1 else for DEVICE in $DEVICES; do UDEV_TIMEOUT_LOCAL=$UDEV_TIMEOUT while [ ! -e $DEVICE ] && [ $UDEV_TIMEOUT_LOCAL -gt 0 ] ; do sleep 1 UDEV_TIMEOUT_LOCAL=$(( $UDEV_TIMEOUT_LOCAL-1 )) done done $DRBDADM -S wait-con-int # User interruptible version of wait-connect all $DRBDADM -S sh-b-pri all || true log_end_msg 0 fi fi ;; stop) $DRBDADM sh-nop [[ $? = 127 ]] && exit 5 # LSB for "not installed" log_daemon_msg "Stopping all DRBD resources" for try in 1 2; do if [ -e $PROC_DRBD ] ; then [[ $try = 2 ]] && echo "Retrying once..." # bypass drbdadm and drbd config file and everything, # to avoid leaving devices around that are not referenced by # the current config file, or in case the current config file # does not parse for some reason. for d in /dev/drbd* ; do [ -L "$d" ] && continue [ -b "$d" ] || continue M=$(umount "$d" 2>&1) case $M in *" not mounted") :;; *) echo "$M" >&2 ;; esac done for res in $($DRBDADM --stacked sh-resources) $($DRBDADM sh-resources); do $DRBDSETUP down "$res" done _udev_settle &> /dev/null if [ -d /sys/module/drbd/holders ]; then (cd /sys/module/drbd/holders; for tr in *; do [ -d ${tr} ] && ${RMMOD} ${tr}; done) fi $RMMOD drbd && break fi done run_hook stop [ -f /var/lock/subsys/drbd ] && rm /var/lock/subsys/drbd log_end_msg 0 ;; status) # NEEDS to be heartbeat friendly... # so: put some "OK" in the output. if [ -e $PROC_DRBD ]; then echo "drbd driver loaded OK; device status:" drbd_pretty_status $PROC_DRBD 2>/dev/null exit 0 else echo >&2 "drbd not loaded" exit 3 fi ;; reload) $DRBDADM sh-nop [[ $? = 127 ]] && exit 5 # LSB for "not installed" log_daemon_msg "Reloading DRBD configuration" $DRBDADM adjust all run_hook reload log_end_msg 0 ;; restart|force-reload) ( . $0 stop ) ( . $0 start ) ;; *) echo "Usage: /etc/init.d/drbd {start|stop|status|reload|restart|force-reload}" exit 1 ;; esac exit 0 drbd-utils-8.9.6/scripts/drbd.conf0000644000175000017500000000020512466702073016760 0ustar apoikosapoikos# You can find an example in /usr/share/doc/drbd.../drbd.conf.example include "drbd.d/global_common.conf"; include "drbd.d/*.res"; drbd-utils-8.9.6/user/0000755000175000017500000000000012654475367014504 5ustar apoikosapoikosdrbd-utils-8.9.6/user/linux/0000755000175000017500000000000012654475367015643 5ustar apoikosapoikosdrbd-utils-8.9.6/user/linux/drbd_config.h0000644000175000017500000000145612540016453020237 0ustar apoikosapoikos/* drbd_config.h DRBD's compile time configuration. drbd is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. drbd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with drbd; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef DRBD_CONFIG_H #define DRBD_CONFIG_H extern const char *drbd_buildtag(void); #endif drbd-utils-8.9.6/user/shared_prereqs.mk0000644000175000017500000000077312634271674020044 0ustar apoikosapoikos# to be included from user/v*/Makefiles ../shared/%: $(MAKE) -C $(@D) $(@F) drbd_buildtag.o: ../shared/drbd_buildtag.c # from make documentation, automatic prerequisites .%.d: %.c @set -e; rm -f $@; \ $(CC) -MM $(CFLAGS) $< > $@.$$$$; \ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ rm -f $@.$$$$ .drbdmeta_scanner.d: ../shared/drbdmeta_scanner.c all-dep = $($(filter-out drbd_buildtag.o,$(all-obj)):%.o=.%.d) ifneq (,$(filter-out clean distclean,$(MAKECMDGOALS))) include $(all-dep) endif drbd-utils-8.9.6/user/v84/0000755000175000017500000000000012654475367015125 5ustar apoikosapoikosdrbd-utils-8.9.6/user/v84/drbdtool_common.h0000644000175000017500000000146412466702074020451 0ustar apoikosapoikos#ifndef DRBDTOOL_COMMON_H #define DRBDTOOL_COMMON_H #include "drbd_endian.h" #include #include #include #include #include "shared_tool.h" #define LANANA_DRBD_MAJOR 147 /* we should get this into linux/major.h */ #ifndef DRBD_MAJOR #define DRBD_MAJOR LANANA_DRBD_MAJOR #elif (DRBD_MAJOR != LANANA_DRBD_MAJOR) # error "FIXME unexpected DRBD_MAJOR" #endif #ifndef __packed #define __packed __attribute__((packed)) #endif #ifndef ARRAY_SIZE #define ARRAY_SIZE(A) (sizeof(A)/sizeof(A[0])) #endif struct option; extern void dt_release_lockfile(int drbd_fd); extern void dt_print_uuids(const uint64_t* uuid, unsigned int flags); extern void dt_pretty_print_uuids(const uint64_t* uuid, unsigned int flags); extern int fget_token(char *s, int size, FILE* stream); #endif drbd-utils-8.9.6/user/v84/drbd_strings.c0000644000175000017500000001054512466702074017747 0ustar apoikosapoikos/* drbd.h This file is part of DRBD by Philipp Reisner and Lars Ellenberg. Copyright (C) 2003-2008, LINBIT Information Technologies GmbH. Copyright (C) 2003-2008, Philipp Reisner . Copyright (C) 2003-2008, Lars Ellenberg . drbd is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. drbd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with drbd; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include "drbd_strings.h" static const char *drbd_conn_s_names[] = { [C_STANDALONE] = "StandAlone", [C_DISCONNECTING] = "Disconnecting", [C_UNCONNECTED] = "Unconnected", [C_TIMEOUT] = "Timeout", [C_BROKEN_PIPE] = "BrokenPipe", [C_NETWORK_FAILURE] = "NetworkFailure", [C_PROTOCOL_ERROR] = "ProtocolError", [C_WF_CONNECTION] = "WFConnection", [C_WF_REPORT_PARAMS] = "WFReportParams", [C_TEAR_DOWN] = "TearDown", [C_CONNECTED] = "Connected", [C_STARTING_SYNC_S] = "StartingSyncS", [C_STARTING_SYNC_T] = "StartingSyncT", [C_WF_BITMAP_S] = "WFBitMapS", [C_WF_BITMAP_T] = "WFBitMapT", [C_WF_SYNC_UUID] = "WFSyncUUID", [C_SYNC_SOURCE] = "SyncSource", [C_SYNC_TARGET] = "SyncTarget", [C_PAUSED_SYNC_S] = "PausedSyncS", [C_PAUSED_SYNC_T] = "PausedSyncT", [C_VERIFY_S] = "VerifyS", [C_VERIFY_T] = "VerifyT", [C_AHEAD] = "Ahead", [C_BEHIND] = "Behind", }; static const char *drbd_role_s_names[] = { [R_PRIMARY] = "Primary", [R_SECONDARY] = "Secondary", [R_UNKNOWN] = "Unknown" }; static const char *drbd_disk_s_names[] = { [D_DISKLESS] = "Diskless", [D_ATTACHING] = "Attaching", [D_FAILED] = "Failed", [D_NEGOTIATING] = "Negotiating", [D_INCONSISTENT] = "Inconsistent", [D_OUTDATED] = "Outdated", [D_UNKNOWN] = "DUnknown", [D_CONSISTENT] = "Consistent", [D_UP_TO_DATE] = "UpToDate", }; static const char *drbd_state_sw_errors[] = { [-SS_TWO_PRIMARIES] = "Multiple primaries not allowed by config", [-SS_NO_UP_TO_DATE_DISK] = "Need access to UpToDate data", [-SS_NO_LOCAL_DISK] = "Can not resync without local disk", [-SS_NO_REMOTE_DISK] = "Can not resync without remote disk", [-SS_CONNECTED_OUTDATES] = "Refusing to be Outdated while Connected", [-SS_PRIMARY_NOP] = "Refusing to be Primary while peer is not outdated", [-SS_RESYNC_RUNNING] = "Can not start OV/resync since it is already active", [-SS_ALREADY_STANDALONE] = "Can not disconnect a StandAlone device", [-SS_CW_FAILED_BY_PEER] = "State change was refused by peer node", [-SS_IS_DISKLESS] = "Device is diskless, the requested operation requires a disk", [-SS_DEVICE_IN_USE] = "Device is held open by someone", [-SS_NO_NET_CONFIG] = "Have no net/connection configuration", [-SS_NO_VERIFY_ALG] = "Need a verify algorithm to start online verify", [-SS_NEED_CONNECTION] = "Need a connection to start verify or resync", [-SS_NOT_SUPPORTED] = "Peer does not support protocol", [-SS_LOWER_THAN_OUTDATED] = "Disk state is lower than outdated", [-SS_IN_TRANSIENT_STATE] = "In transient state, retry after next state change", [-SS_CONCURRENT_ST_CHG] = "Concurrent state changes detected and aborted", [-SS_OUTDATE_WO_CONN] = "Need a connection for a graceful disconnect/outdate peer", [-SS_O_VOL_PEER_PRI] = "Other vol primary on peer not allowed by config", }; const char *drbd_conn_str(enum drbd_conns s) { /* enums are unsigned... */ return s > C_BEHIND ? "TOO_LARGE" : drbd_conn_s_names[s]; } const char *drbd_role_str(enum drbd_role s) { return s > R_SECONDARY ? "TOO_LARGE" : drbd_role_s_names[s]; } const char *drbd_disk_str(enum drbd_disk_state s) { return s > D_UP_TO_DATE ? "TOO_LARGE" : drbd_disk_s_names[s]; } const char *drbd_set_st_err_str(enum drbd_state_rv err) { return err <= SS_AFTER_LAST_ERROR ? "TOO_SMALL" : err > SS_TWO_PRIMARIES ? "TOO_LARGE" : drbd_state_sw_errors[-err]; } drbd-utils-8.9.6/user/v84/drbdtool_common.c0000644000175000017500000000417712466702074020450 0ustar apoikosapoikos#define _GNU_SOURCE #define _XOPEN_SOURCE 600 #define _FILE_OFFSET_BITS 64 #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* for BLKGETSIZE64 */ #include #include "drbdtool_common.h" #include "config.h" void dt_pretty_print_uuids(const uint64_t* uuid, unsigned int flags) { printf( "\n" " +--< Current data generation UUID >-\n" " | +--< Bitmap's base data generation UUID >-\n" " | | +--< younger history UUID >-\n" " | | | +-< older history >-\n" " V V V V\n"); dt_print_uuids(uuid, flags); printf( " ^ ^ ^ ^ ^ ^ ^\n" " -< Data consistency flag >--+ | | | | | |\n" " -< Data was/is currently up-to-date >--+ | | | | |\n" " -< Node was/is currently primary >--+ | | | |\n" " -< Node was/is currently connected >--+ | | |\n" " -< Node was in the progress of setting all bits in the bitmap >--+ | |\n" " -< The peer's disk was out-dated or inconsistent >--+ |\n" " -< This node was a crashed primary, and has not seen its peer since >--+\n" "\n"); printf("flags:%s %s, %s, %s%s%s\n", (flags & MDF_CRASHED_PRIMARY) ? " crashed" : "", (flags & MDF_PRIMARY_IND) ? "Primary" : "Secondary", (flags & MDF_CONNECTED_IND) ? "Connected" : "StandAlone", (flags & MDF_CONSISTENT) ? ((flags & MDF_WAS_UP_TO_DATE) ? "UpToDate" : "Outdated") : "Inconsistent", (flags & MDF_FULL_SYNC) ? ", need full sync" : "", (flags & MDF_PEER_OUT_DATED) ? ", peer Outdated" : ""); printf("meta-data: %s\n", (flags & MDF_AL_CLEAN) ? "clean" : "need apply-al"); } drbd-utils-8.9.6/user/v84/drbd_nla.h0000644000175000017500000000044012466702074017026 0ustar apoikosapoikos#ifndef __DRBD_NLA_H #define __DRBD_NLA_H extern int drbd_nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla, const struct nla_policy *policy); extern struct nlattr *drbd_nla_find_nested(int maxtype, struct nlattr *nla, int attrtype); #endif /* __DRBD_NLA_H */ drbd-utils-8.9.6/user/v84/drbdsetup.c0000644000175000017500000030675012634271674017271 0ustar apoikosapoikos/* * DRBD setup via genetlink * * This file is part of DRBD by Philipp Reisner and Lars Ellenberg. * * Copyright (C) 2001-2008, LINBIT Information Technologies GmbH. * Copyright (C) 1999-2008, Philipp Reisner . * Copyright (C) 2002-2008, Lars Ellenberg . * * drbd is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * drbd is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with drbd; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #define _GNU_SOURCE #define _XOPEN_SOURCE 600 #define _FILE_OFFSET_BITS 64 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define EXIT_NOMEM 20 #define EXIT_NO_FAMILY 20 #define EXIT_SEND_ERR 20 #define EXIT_RECV_ERR 20 #define EXIT_TIMED_OUT 20 #define EXIT_NOSOCK 30 #define EXIT_THINKO 42 /* * We are not using libnl, * using its API for the few things we want to do * ends up being almost as much lines of code as * coding the necessary bits right here. */ #include "libgenl.h" #include "drbd_nla.h" #include #include #include #include #include "drbdtool_common.h" #include "registry.h" #include "config.h" #include "config_flags.h" #include "wrap_printf.h" #include "drbdsetup_colors.h" #include "drbd_strings.h" char *progname; /* for parsing of messages */ static struct nlattr *global_attrs[128]; /* there is an other table, nested_attr_tb, defined in genl_magic_func.h, * which can be used after _from_attrs, * to check for presence of struct fields. */ #define ntb(t) nested_attr_tb[__nla_type(t)] #ifdef PRINT_NLMSG_LEN /* I'm to lazy to check the maximum possible nlmsg length by hand */ int main(void) { static __u16 nla_attr_minlen[NLA_TYPE_MAX+1] __read_mostly = { [NLA_U8] = sizeof(__u8), [NLA_U16] = sizeof(__u16), [NLA_U32] = sizeof(__u32), [NLA_U64] = sizeof(__u64), [NLA_NESTED] = NLA_HDRLEN, }; int i; int sum_total = 0; #define LEN__(policy) do { \ int sum = 0; \ for (i = 0; i < ARRAY_SIZE(policy); i++) { \ sum += nla_total_size(policy[i].len ?: \ nla_attr_minlen[policy[i].type]); \ \ } \ sum += 4; \ sum_total += sum; \ printf("%-30s %4u [%4u]\n", \ #policy ":", sum, sum_total); \ } while (0) #define LEN_(p) LEN__(p ## _nl_policy) LEN_(disk_conf); LEN_(syncer_conf); LEN_(net_conf); LEN_(set_role_parms); LEN_(resize_parms); LEN_(state_info); LEN_(start_ov_parms); LEN_(new_c_uuid_parms); sum_total += sizeof(struct nlmsghdr) + sizeof(struct genlmsghdr) + sizeof(struct drbd_genlmsghdr); printf("sum total inclusive hdr overhead: %4u\n", sum_total); return 0; } #else #ifndef AF_INET_SDP #define AF_INET_SDP 27 #define PF_INET_SDP AF_INET_SDP #endif /* pretty print helpers */ static int indent = 0; #define INDENT_WIDTH 4 #define printI(fmt, args... ) printf("%*s" fmt,INDENT_WIDTH * indent,"" , ## args ) enum usage_type { BRIEF, FULL, XML, }; struct drbd_argument { const char* name; __u16 nla_type; int (*convert_function)(struct drbd_argument *, struct msg_buff *, struct drbd_genlmsghdr *dhdr, char *); }; /* Configuration requests typically need a context to operate on. * Possible keys are device minor/volume id (both fit in the drbd_genlmsghdr), * the replication link (aka connection) name, * and/or the replication group (aka resource) name */ enum cfg_ctx_key { /* Only one of these can be present in a command: */ CTX_MINOR = 1, CTX_RESOURCE = 2, CTX_ALL = 4, CTX_CONNECTION = 8, CTX_RESOURCE_AND_CONNECTION = 16, }; struct drbd_cmd { const char* cmd; const enum cfg_ctx_key ctx_key; const int cmd_id; const int tla_id; /* top level attribute id */ int (*function)(const struct drbd_cmd *, int, char **); struct drbd_argument *drbd_args; int (*show_function)(const struct drbd_cmd*, struct genl_info *, void *u_prt); struct option *options; bool missing_ok; bool warn_on_missing; bool continuous_poll; bool wait_for_connect_timeouts; bool set_defaults; bool lockless; struct context_def *ctx; }; // other functions static void print_command_usage(const struct drbd_cmd *cm, enum usage_type); // command functions static int generic_config_cmd(const struct drbd_cmd *cm, int argc, char **argv); static int down_cmd(const struct drbd_cmd *cm, int argc, char **argv); static int generic_get_cmd(const struct drbd_cmd *cm, int argc, char **argv); static int del_minor_cmd(const struct drbd_cmd *cm, int argc, char **argv); static int del_resource_cmd(const struct drbd_cmd *cm, int argc, char **argv); static int status_cmd(const struct drbd_cmd *cm, int argc, char **argv); // sub commands for generic_get_cmd static int print_notifications(const struct drbd_cmd *, struct genl_info *, void *u_ptr); static int show_scmd(const struct drbd_cmd *cm, struct genl_info *info, void *u_ptr); static int role_scmd(const struct drbd_cmd *cm, struct genl_info *info, void *u_ptr); static int sh_status_scmd(const struct drbd_cmd *cm, struct genl_info *info, void *u_ptr); static int cstate_scmd(const struct drbd_cmd *cm, struct genl_info *info, void *u_ptr); static int dstate_scmd(const struct drbd_cmd *cm, struct genl_info *info, void *u_ptr); static int uuids_scmd(const struct drbd_cmd *cm, struct genl_info *info, void *u_ptr); static int lk_bdev_scmd(const struct drbd_cmd *cm, struct genl_info *info, void *u_ptr); static int print_broadcast_events(const struct drbd_cmd *, struct genl_info *, void *u_ptr); static int w_connected_state(const struct drbd_cmd *, struct genl_info *, void *u_ptr); static int w_synced_state(const struct drbd_cmd *, struct genl_info *, void *u_ptr); // convert functions for arguments static int conv_block_dev(struct drbd_argument *ad, struct msg_buff *msg, struct drbd_genlmsghdr *dhdr, char* arg); static int conv_md_idx(struct drbd_argument *ad, struct msg_buff *msg, struct drbd_genlmsghdr *dhdr, char* arg); static int conv_resource_name(struct drbd_argument *ad, struct msg_buff *msg, struct drbd_genlmsghdr *dhdr, char* arg); static int conv_volume(struct drbd_argument *ad, struct msg_buff *msg, struct drbd_genlmsghdr *dhdr, char* arg); static int conv_minor(struct drbd_argument *ad, struct msg_buff *msg, struct drbd_genlmsghdr *dhdr, char* arg); struct resources_list { struct resources_list *next; char *name; struct nlattr *res_opts; struct resource_info info; struct resource_statistics statistics; }; static struct resources_list *list_resources(void); static struct resources_list *sort_resources(struct resources_list *); static void free_resources(struct resources_list *); struct devices_list { struct devices_list *next; unsigned minor; struct drbd_cfg_context ctx; struct disk_conf disk_conf; struct device_info info; struct device_statistics statistics; }; static struct devices_list *list_devices(char *); static void free_devices(struct devices_list *); struct connections_list { struct connections_list *next; struct drbd_cfg_context ctx; struct nlattr *net_conf; struct connection_info info; struct connection_statistics statistics; }; static struct connections_list *sort_connections(struct connections_list *); static struct connections_list *list_connections(char *); static void free_connections(struct connections_list *); struct peer_devices_list { struct peer_devices_list *next; struct drbd_cfg_context ctx; struct peer_device_info info; struct peer_device_statistics statistics; struct devices_list *device; int timeout_ms; /* used only by wait_for_family() */ }; static struct peer_devices_list *list_peer_devices(char *); static void free_peer_devices(struct peer_devices_list *); struct option wait_cmds_options[] = { { "wfc-timeout",required_argument, 0, 't' }, { "degr-wfc-timeout",required_argument,0,'d'}, { "outdated-wfc-timeout",required_argument,0,'o'}, { "wait-after-sb",optional_argument,0,'w'}, { 0, 0, 0, 0 } }; struct option events_cmd_options[] = { { "timestamps", no_argument, 0, 'T' }, { "statistics", no_argument, 0, 's' }, { "now", no_argument, 0, 'n' }, { } }; struct option show_cmd_options[] = { { "show-defaults", no_argument, 0, 'D' }, { } }; static struct option status_cmd_options[] = { { "verbose", no_argument, 0, 'v' }, { "statistics", no_argument, 0, 's' }, { "color", optional_argument, 0, 'c' }, { } }; #define F_CONFIG_CMD generic_config_cmd #define NO_PAYLOAD 0 #define F_GET_CMD(scmd) DRBD_ADM_GET_STATUS, NO_PAYLOAD, generic_get_cmd, \ .show_function = scmd #define F_NEW_EVENTS_CMD(scmd) DRBD_ADM_GET_INITIAL_STATE, NO_PAYLOAD, generic_get_cmd, \ .show_function = scmd const struct drbd_cmd commands[] = { {"primary", CTX_MINOR, DRBD_ADM_PRIMARY, DRBD_NLA_SET_ROLE_PARMS, F_CONFIG_CMD, .ctx = &primary_cmd_ctx }, {"secondary", CTX_MINOR, DRBD_ADM_SECONDARY, NO_PAYLOAD, F_CONFIG_CMD }, {"attach", CTX_MINOR, DRBD_ADM_ATTACH, DRBD_NLA_DISK_CONF, F_CONFIG_CMD, .drbd_args = (struct drbd_argument[]) { { "lower_dev", T_backing_dev, conv_block_dev }, { "meta_data_dev", T_meta_dev, conv_block_dev }, { "meta_data_index", T_meta_dev_idx, conv_md_idx }, { } }, .ctx = &attach_cmd_ctx }, {"disk-options", CTX_MINOR, DRBD_ADM_CHG_DISK_OPTS, DRBD_NLA_DISK_CONF, F_CONFIG_CMD, .set_defaults = true, .ctx = &disk_options_ctx }, {"detach", CTX_MINOR, DRBD_ADM_DETACH, DRBD_NLA_DETACH_PARMS, F_CONFIG_CMD, .ctx = &detach_cmd_ctx }, {"connect", CTX_RESOURCE_AND_CONNECTION, DRBD_ADM_CONNECT, DRBD_NLA_NET_CONF, F_CONFIG_CMD, .ctx = &connect_cmd_ctx }, {"net-options", CTX_CONNECTION, DRBD_ADM_CHG_NET_OPTS, DRBD_NLA_NET_CONF, F_CONFIG_CMD, .set_defaults = true, .ctx = &net_options_ctx }, {"disconnect", CTX_CONNECTION, DRBD_ADM_DISCONNECT, DRBD_NLA_DISCONNECT_PARMS, F_CONFIG_CMD, .ctx = &disconnect_cmd_ctx }, {"resize", CTX_MINOR, DRBD_ADM_RESIZE, DRBD_NLA_RESIZE_PARMS, F_CONFIG_CMD, .ctx = &resize_cmd_ctx }, {"resource-options", CTX_RESOURCE, DRBD_ADM_RESOURCE_OPTS, DRBD_NLA_RESOURCE_OPTS, F_CONFIG_CMD, .set_defaults = true, .ctx = &resource_options_cmd_ctx }, {"new-current-uuid", CTX_MINOR, DRBD_ADM_NEW_C_UUID, DRBD_NLA_NEW_C_UUID_PARMS, F_CONFIG_CMD, .ctx = &new_current_uuid_cmd_ctx }, {"invalidate", CTX_MINOR, DRBD_ADM_INVALIDATE, NO_PAYLOAD, F_CONFIG_CMD, }, {"invalidate-remote", CTX_MINOR, DRBD_ADM_INVAL_PEER, NO_PAYLOAD, F_CONFIG_CMD, }, {"pause-sync", CTX_MINOR, DRBD_ADM_PAUSE_SYNC, NO_PAYLOAD, F_CONFIG_CMD, }, {"resume-sync", CTX_MINOR, DRBD_ADM_RESUME_SYNC, NO_PAYLOAD, F_CONFIG_CMD, }, {"suspend-io", CTX_MINOR, DRBD_ADM_SUSPEND_IO, NO_PAYLOAD, F_CONFIG_CMD, }, {"resume-io", CTX_MINOR, DRBD_ADM_RESUME_IO, NO_PAYLOAD, F_CONFIG_CMD, }, {"outdate", CTX_MINOR, DRBD_ADM_OUTDATE, NO_PAYLOAD, F_CONFIG_CMD, }, {"verify", CTX_MINOR, DRBD_ADM_START_OV, DRBD_NLA_START_OV_PARMS, F_CONFIG_CMD, .ctx = &verify_cmd_ctx }, {"down", CTX_RESOURCE, DRBD_ADM_DOWN, NO_PAYLOAD, down_cmd, .missing_ok = true, .warn_on_missing = true, }, {"state", CTX_MINOR, F_GET_CMD(role_scmd) }, {"role", CTX_MINOR, F_GET_CMD(role_scmd), .lockless = true, }, {"sh-status", CTX_MINOR | CTX_RESOURCE | CTX_ALL, F_GET_CMD(sh_status_scmd), .missing_ok = true, .lockless = true, }, {"cstate", CTX_MINOR, F_GET_CMD(cstate_scmd), .lockless = true, }, {"dstate", CTX_MINOR, F_GET_CMD(dstate_scmd), .lockless = true, }, {"show-gi", CTX_MINOR, F_GET_CMD(uuids_scmd), .lockless = true, }, {"get-gi", CTX_MINOR, F_GET_CMD(uuids_scmd), .lockless = true, }, {"show", CTX_MINOR | CTX_RESOURCE | CTX_ALL, F_GET_CMD(show_scmd), .options = show_cmd_options, .lockless = true, }, {"status", CTX_RESOURCE | CTX_ALL, 0, 0, status_cmd, .options = status_cmd_options, .lockless = true, }, {"check-resize", CTX_MINOR, F_GET_CMD(lk_bdev_scmd), .lockless = true, }, {"events", CTX_MINOR | CTX_RESOURCE | CTX_ALL, F_GET_CMD(print_broadcast_events), .missing_ok = true, .continuous_poll = true, .lockless = true, }, {"events2", CTX_RESOURCE | CTX_ALL, F_NEW_EVENTS_CMD(print_notifications), .options = events_cmd_options, .missing_ok = true, .continuous_poll = true, .lockless = true }, {"wait-connect", CTX_MINOR, F_GET_CMD(w_connected_state), .options = wait_cmds_options, .continuous_poll = true, .wait_for_connect_timeouts = true, .lockless = true, }, {"wait-sync", CTX_MINOR, F_GET_CMD(w_synced_state), .options = wait_cmds_options, .continuous_poll = true, .wait_for_connect_timeouts = true, .lockless = true, }, {"new-resource", CTX_RESOURCE, DRBD_ADM_NEW_RESOURCE, DRBD_NLA_RESOURCE_OPTS, F_CONFIG_CMD, .ctx = &resource_options_cmd_ctx }, /* only payload is resource name and volume number */ {"new-minor", 0, DRBD_ADM_NEW_MINOR, DRBD_NLA_CFG_CONTEXT, F_CONFIG_CMD, .drbd_args = (struct drbd_argument[]) { { "resource", T_ctx_resource_name, conv_resource_name }, { "minor", 0, conv_minor }, { "volume", T_ctx_volume, conv_volume }, { } }, .ctx = &new_minor_cmd_ctx }, {"del-minor", CTX_MINOR, DRBD_ADM_DEL_MINOR, NO_PAYLOAD, del_minor_cmd, }, {"del-resource", CTX_RESOURCE, DRBD_ADM_DEL_RESOURCE, NO_PAYLOAD, del_resource_cmd, } }; bool show_defaults; bool wait_after_split_brain; #define OTHER_ERROR 900 #define EM(C) [ C - ERR_CODE_BASE ] /* The EM(123) are used for old error messages. */ static const char *error_messages[] = { EM(NO_ERROR) = "No further Information available.", EM(ERR_LOCAL_ADDR) = "Local address(port) already in use.", EM(ERR_PEER_ADDR) = "Remote address(port) already in use.", EM(ERR_OPEN_DISK) = "Can not open backing device.", EM(ERR_OPEN_MD_DISK) = "Can not open meta device.", EM(106) = "Lower device already in use.", EM(ERR_DISK_NOT_BDEV) = "Lower device is not a block device.", EM(ERR_MD_NOT_BDEV) = "Meta device is not a block device.", EM(109) = "Open of lower device failed.", EM(110) = "Open of meta device failed.", EM(ERR_DISK_TOO_SMALL) = "Low.dev. smaller than requested DRBD-dev. size.", EM(ERR_MD_DISK_TOO_SMALL) = "Meta device too small.", EM(113) = "You have to use the disk command first.", EM(ERR_BDCLAIM_DISK) = "Lower device is already claimed. This usually means it is mounted.", EM(ERR_BDCLAIM_MD_DISK) = "Meta device is already claimed. This usually means it is mounted.", EM(ERR_MD_IDX_INVALID) = "Lower device / meta device / index combination invalid.", EM(117) = "Currently we only support devices up to 3.998TB.\n" "(up to 2TB in case you do not have CONFIG_LBD set)\n" "Contact office@linbit.com, if you need more.", EM(ERR_IO_MD_DISK) = "IO error(s) occurred during initial access to meta-data.\n", EM(ERR_MD_UNCLEAN) = "Unclean meta-data found.\nYou need to 'drbdadm apply-al res'\n", EM(ERR_MD_INVALID) = "No valid meta-data signature found.\n\n" "\t==> Use 'drbdadm create-md res' to initialize meta-data area. <==\n", EM(ERR_AUTH_ALG) = "The 'cram-hmac-alg' you specified is not known in " "the kernel. (Maybe you need to modprobe it, or modprobe hmac?)", EM(ERR_AUTH_ALG_ND) = "The 'cram-hmac-alg' you specified is not a digest.", EM(ERR_NOMEM) = "kmalloc() failed. Out of memory?", EM(ERR_DISCARD_IMPOSSIBLE) = "--discard-my-data not allowed when primary.", EM(ERR_DISK_CONFIGURED) = "Device is attached to a disk (use detach first)", EM(ERR_NET_CONFIGURED) = "Device has a net-config (use disconnect first)", EM(ERR_MANDATORY_TAG) = "UnknownMandatoryTag", EM(ERR_MINOR_INVALID) = "Device minor not allocated", EM(128) = "Resulting device state would be invalid", EM(ERR_INTR) = "Interrupted by Signal", EM(ERR_RESIZE_RESYNC) = "Resize not allowed during resync.", EM(ERR_NO_PRIMARY) = "Need one Primary node to resize.", EM(ERR_RESYNC_AFTER) = "The resync-after minor number is invalid", EM(ERR_RESYNC_AFTER_CYCLE) = "This would cause a resync-after dependency cycle", EM(ERR_PAUSE_IS_SET) = "Sync-pause flag is already set", EM(ERR_PAUSE_IS_CLEAR) = "Sync-pause flag is already cleared", EM(136) = "Disk state is lower than outdated", EM(ERR_PACKET_NR) = "Kernel does not know how to handle your request.\n" "Maybe API_VERSION mismatch?", EM(ERR_NO_DISK) = "Device does not have a disk-config", EM(ERR_NOT_PROTO_C) = "Protocol C required", EM(ERR_NOMEM_BITMAP) = "vmalloc() failed. Out of memory?", EM(ERR_INTEGRITY_ALG) = "The 'data-integrity-alg' you specified is not known in " "the kernel. (Maybe you need to modprobe it, or modprobe hmac?)", EM(ERR_INTEGRITY_ALG_ND) = "The 'data-integrity-alg' you specified is not a digest.", EM(ERR_CPU_MASK_PARSE) = "Invalid cpu-mask.", EM(ERR_VERIFY_ALG) = "VERIFYAlgNotAvail", EM(ERR_VERIFY_ALG_ND) = "VERIFYAlgNotDigest", EM(ERR_VERIFY_RUNNING) = "Can not change verify-alg while online verify runs", EM(ERR_DATA_NOT_CURRENT) = "Can only attach to the data we lost last (see kernel log).", EM(ERR_CONNECTED) = "Need to be StandAlone", EM(ERR_CSUMS_ALG) = "CSUMSAlgNotAvail", EM(ERR_CSUMS_ALG_ND) = "CSUMSAlgNotDigest", EM(ERR_CSUMS_RESYNC_RUNNING) = "Can not change csums-alg while resync is in progress", EM(ERR_PERM) = "Permission denied. CAP_SYS_ADMIN necessary", EM(ERR_NEED_APV_93) = "Protocol version 93 required to use --assume-clean", EM(ERR_STONITH_AND_PROT_A) = "Fencing policy resource-and-stonith only with prot B or C allowed", EM(ERR_CONG_NOT_PROTO_A) = "on-congestion policy pull-ahead only with prot A allowed", EM(ERR_PIC_AFTER_DEP) = "Sync-pause flag is already cleared.\n" "Note: Resync pause caused by a local resync-after dependency.", EM(ERR_PIC_PEER_DEP) = "Sync-pause flag is already cleared.\n" "Note: Resync pause caused by the peer node.", EM(ERR_RES_NOT_KNOWN) = "Unknown resource", EM(ERR_RES_IN_USE) = "Resource still in use (delete all minors first)", EM(ERR_MINOR_CONFIGURED) = "Minor still configured (down it first)", EM(ERR_MINOR_OR_VOLUME_EXISTS) = "Minor or volume exists already (delete it first)", EM(ERR_INVALID_REQUEST) = "Invalid configuration request", EM(ERR_NEED_APV_100) = "Prot version 100 required in order to change\n" "these network options while connected", EM(ERR_NEED_ALLOW_TWO_PRI) = "Can not clear allow_two_primaries as long as\n" "there a primaries on both sides", EM(ERR_MD_LAYOUT_CONNECTED) = "DRBD need to be connected for online MD layout change\n", EM(ERR_MD_LAYOUT_TOO_BIG) = "Resulting AL area too big\n", EM(ERR_MD_LAYOUT_TOO_SMALL) = "Resulting AL are too small\n", EM(ERR_MD_LAYOUT_NO_FIT) = "Resulting AL does not fit into available meta data space\n", EM(ERR_IMPLICIT_SHRINK) = "Implicit device shrinking not allowed. See kernel log.\n", }; #define MAX_ERROR (sizeof(error_messages)/sizeof(*error_messages)) const char * error_to_string(int err_no) { const unsigned int idx = err_no - ERR_CODE_BASE; if (idx >= MAX_ERROR) return "Unknown... maybe API_VERSION mismatch?"; return error_messages[idx]; } #undef MAX_ERROR char *cmdname = NULL; /* "drbdsetup" for reporting in usage etc. */ /* * In CTX_MINOR, CTX_RESOURCE, CTX_ALL, objname and minor refer to the object * the command operates on. */ char *objname; unsigned minor = -1U; enum cfg_ctx_key context; char *opt_local_addr, *opt_peer_addr; int lock_fd; struct genl_sock *drbd_sock = NULL; int try_genl = 1; struct genl_family drbd_genl_family = { .name = "drbd", .version = GENL_MAGIC_VERSION, .hdrsize = GENL_MAGIC_FAMILY_HDRSZ, }; static bool endpoints_equal(struct drbd_cfg_context *a, struct drbd_cfg_context *b) { return a->ctx_my_addr_len == b->ctx_my_addr_len && a->ctx_peer_addr_len == b->ctx_peer_addr_len && !memcmp(a->ctx_my_addr, b->ctx_my_addr, a->ctx_my_addr_len) && !memcmp(a->ctx_peer_addr, b->ctx_peer_addr, a->ctx_peer_addr_len); } static int conv_block_dev(struct drbd_argument *ad, struct msg_buff *msg, struct drbd_genlmsghdr *dhdr, char* arg) { struct stat sb; int device_fd; if ((device_fd = open(arg,O_RDWR))==-1) { PERROR("Can not open device '%s'", arg); return OTHER_ERROR; } if (fstat(device_fd, &sb)) { PERROR("fstat(%s) failed", arg); return OTHER_ERROR; } if(!S_ISBLK(sb.st_mode)) { fprintf(stderr, "%s is not a block device!\n", arg); return OTHER_ERROR; } close(device_fd); nla_put_string(msg, ad->nla_type, arg); return NO_ERROR; } static int conv_md_idx(struct drbd_argument *ad, struct msg_buff *msg, struct drbd_genlmsghdr *dhdr, char* arg) { int idx; if(!strcmp(arg,"internal")) idx = DRBD_MD_INDEX_FLEX_INT; else if(!strcmp(arg,"flexible")) idx = DRBD_MD_INDEX_FLEX_EXT; else idx = m_strtoll(arg,1); nla_put_u32(msg, ad->nla_type, idx); return NO_ERROR; } static int conv_resource_name(struct drbd_argument *ad, struct msg_buff *msg, struct drbd_genlmsghdr *dhdr, char* arg) { /* additional sanity checks? */ nla_put_string(msg, T_ctx_resource_name, arg); return NO_ERROR; } static int conv_volume(struct drbd_argument *ad, struct msg_buff *msg, struct drbd_genlmsghdr *dhdr, char* arg) { unsigned vol = m_strtoll(arg,1); /* sanity check on vol < 256? */ nla_put_u32(msg, T_ctx_volume, vol); return NO_ERROR; } static int conv_minor(struct drbd_argument *ad, struct msg_buff *msg, struct drbd_genlmsghdr *dhdr, char* arg) { unsigned minor = dt_minor_of_dev(arg); if (minor == -1U) { fprintf(stderr, "Cannot determine minor device number of " "device '%s'\n", arg); return OTHER_ERROR; } dhdr->minor = minor; return NO_ERROR; } static struct option *make_longoptions(const struct drbd_cmd *cm) { static struct option buffer[47]; int i = 0; int primary_force_index = -1; int connect_tentative_index = -1; if (cm->ctx) { struct field_def *field; /* * Make sure to keep cm->ctx->fields first: we use the index * returned by getopt_long() to access cm->ctx->fields. */ for (field = cm->ctx->fields; field->name; field++) { assert(i < ARRAY_SIZE(buffer)); buffer[i].name = field->name; buffer[i].has_arg = field->argument_is_optional ? optional_argument : required_argument; buffer[i].flag = NULL; buffer[i].val = 0; if (!strcmp(cm->cmd, "primary") && !strcmp(field->name, "force")) primary_force_index = i; if (!strcmp(cm->cmd, "connect") && !strcmp(field->name, "tentative")) connect_tentative_index = i; i++; } assert(field - cm->ctx->fields == i); } if (cm->options) { struct option *option; for (option = cm->options; option->name; option++) { assert(i < ARRAY_SIZE(buffer)); buffer[i] = *option; i++; } } if (primary_force_index != -1) { /* * For backward compatibility, add --overwrite-data-of-peer as * an alias to --force. */ assert(i < ARRAY_SIZE(buffer)); buffer[i] = buffer[primary_force_index]; buffer[i].name = "overwrite-data-of-peer"; buffer[i].val = 1000 + primary_force_index; i++; } if (connect_tentative_index != -1) { /* * For backward compatibility, add --dry-run as an alias to * --tentative. */ assert(i < ARRAY_SIZE(buffer)); buffer[i] = buffer[connect_tentative_index]; buffer[i].name = "dry-run"; buffer[i].val = 1000 + connect_tentative_index; i++; } if (cm->set_defaults) { assert(i < ARRAY_SIZE(buffer)); buffer[i].name = "set-defaults"; buffer[i].has_arg = 0; buffer[i].flag = NULL; buffer[i].val = '('; i++; } assert(i < ARRAY_SIZE(buffer)); buffer[i].name = NULL; buffer[i].has_arg = 0; buffer[i].flag = NULL; buffer[i].val = 0; return buffer; } /* prepends global objname to output (if any) */ static int print_config_error(int err_no, char *desc) { int rv=0; if (err_no == NO_ERROR || err_no == SS_SUCCESS) return 0; if (err_no == OTHER_ERROR) { if (desc) fprintf(stderr,"%s: %s\n", objname, desc); return 20; } if ( ( err_no >= AFTER_LAST_ERR_CODE || err_no <= ERR_CODE_BASE ) && ( err_no > SS_CW_NO_NEED || err_no <= SS_AFTER_LAST_ERROR) ) { fprintf(stderr,"%s: Error code %d unknown.\n" "You should update the drbd userland tools.\n", objname, err_no); rv = 20; } else { if(err_no > ERR_CODE_BASE ) { fprintf(stderr,"%s: Failure: (%d) %s\n", objname, err_no, desc ?: error_to_string(err_no)); rv = 10; } else if (err_no == SS_UNKNOWN_ERROR) { fprintf(stderr,"%s: State change failed: (%d)" "unknown error.\n", objname, err_no); rv = 11; } else if (err_no > SS_TWO_PRIMARIES) { // Ignore SS_SUCCESS, SS_NOTHING_TO_DO, SS_CW_Success... } else { fprintf(stderr,"%s: State change failed: (%d) %s\n", objname, err_no, drbd_set_st_err_str(err_no)); if (err_no == SS_NO_UP_TO_DATE_DISK) { /* all available disks are inconsistent, * or I am consistent, but cannot outdate the peer. */ rv = 17; } else if (err_no == SS_LOWER_THAN_OUTDATED) { /* was inconsistent anyways */ rv = 5; } else if (err_no == SS_NO_LOCAL_DISK) { /* Can not start resync, no local disks, try with drbdmeta */ rv = 16; } else { rv = 11; } } } if (global_attrs[DRBD_NLA_CFG_REPLY] && global_attrs[DRBD_NLA_CFG_REPLY]->nla_len) { struct nlattr *nla; int rem; fprintf(stderr, "additional info from kernel:\n"); nla_for_each_nested(nla, global_attrs[DRBD_NLA_CFG_REPLY], rem) { if (nla_type(nla) == __nla_type(T_info_text)) fprintf(stderr, "%s\n", (char*)nla_data(nla)); } } return rv; } static void warn_print_excess_args(int argc, char **argv, int i) { fprintf(stderr, "Excess arguments:"); for (; i < argc; i++) fprintf(stderr, " %s", argv[i]); printf("\n"); } int drbd_tla_parse(struct nlmsghdr *nlh) { return nla_parse(global_attrs, ARRAY_SIZE(drbd_tla_nl_policy)-1, nlmsg_attrdata(nlh, GENL_HDRLEN + drbd_genl_family.hdrsize), nlmsg_attrlen(nlh, GENL_HDRLEN + drbd_genl_family.hdrsize), drbd_tla_nl_policy); } #define ASSERT(exp) if (!(exp)) \ fprintf(stderr,"ASSERT( " #exp " ) in %s:%d\n", __FILE__,__LINE__); static int _generic_config_cmd(const struct drbd_cmd *cm, int argc, char **argv, int quiet) { struct drbd_argument *ad = cm->drbd_args; struct nlattr *nla; struct option *options; int c, i; int rv = NO_ERROR; char *desc = NULL; /* error description from kernel reply message */ struct drbd_genlmsghdr *dhdr; struct msg_buff *smsg; struct iovec iov; /* pre allocate request message and reply buffer */ iov.iov_len = DEFAULT_MSG_SIZE; iov.iov_base = malloc(iov.iov_len); smsg = msg_new(DEFAULT_MSG_SIZE); if (!smsg || !iov.iov_base) { desc = "could not allocate netlink messages"; rv = OTHER_ERROR; goto error; } dhdr = genlmsg_put(smsg, &drbd_genl_family, 0, cm->cmd_id); dhdr->minor = -1; dhdr->flags = 0; i = 1; if (context & (CTX_RESOURCE | CTX_CONNECTION)) { nla = nla_nest_start(smsg, DRBD_NLA_CFG_CONTEXT); if (context & CTX_RESOURCE) nla_put_string(smsg, T_ctx_resource_name, objname); if (context & CTX_CONNECTION) { nla_put_address(smsg, T_ctx_my_addr, opt_local_addr); nla_put_address(smsg, T_ctx_peer_addr, opt_peer_addr); } nla_nest_end(smsg, nla); } else if (context & CTX_MINOR) { dhdr->minor = minor; i++; } nla = NULL; options = make_longoptions(cm); optind = 0; /* reset getopt_long() */ for (;;) { int idx; c = getopt_long(argc, argv, "(", options, &idx); if (c == -1) break; if (c >= 1000) { /* This is a field alias. */ idx = c - 1000; c = 0; } if (c == 0) { struct field_def *field = &cm->ctx->fields[idx]; assert (field->name == options[idx].name); if (!nla) { assert (cm->tla_id != NO_PAYLOAD); nla = nla_nest_start(smsg, cm->tla_id); } if (!field->put(cm->ctx, field, smsg, optarg)) { fprintf(stderr, "Option --%s: invalid " "argument '%s'\n", field->name, optarg); rv = OTHER_ERROR; goto error; } } else if (c == '(') dhdr->flags |= DRBD_GENL_F_SET_DEFAULTS; else { rv = OTHER_ERROR; goto error; } } for (i = optind, ad = cm->drbd_args; ad && ad->name; i++) { if (argc < i + 1) { fprintf(stderr, "Missing argument '%s'\n", ad->name); print_command_usage(cm, FULL); rv = OTHER_ERROR; goto error; } if (!nla) { assert (cm->tla_id != NO_PAYLOAD); nla = nla_nest_start(smsg, cm->tla_id); } rv = ad->convert_function(ad, smsg, dhdr, argv[i]); if (rv != NO_ERROR) goto error; ad++; } /* dhdr->minor may have been set by one of the convert functions. */ minor = dhdr->minor; /* argc should be cmd + n options + n args; * if it is more, we did not understand some */ if (i < argc) { warn_print_excess_args(argc, argv, i); rv = OTHER_ERROR; goto error; } if (rv == NO_ERROR) { int received; if (nla) nla_nest_end(smsg, nla); if (genl_send(drbd_sock, smsg)) { desc = "error sending config command"; rv = OTHER_ERROR; goto error; } retry_recv: /* reduce timeout! limit retries */ received = genl_recv_msgs(drbd_sock, &iov, &desc, 120000); if (received > 0) { struct nlmsghdr *nlh = (struct nlmsghdr*)iov.iov_base; struct drbd_genlmsghdr *dh = genlmsg_data(nlmsg_data(nlh)); ASSERT(dh->minor == minor); rv = dh->ret_code; if (rv == ERR_RES_NOT_KNOWN) { if (cm->warn_on_missing && isatty(STDERR_FILENO)) fprintf(stderr, "Resource unknown\n"); if (cm->missing_ok) rv = NO_ERROR; } drbd_tla_parse(nlh); } else { if (received == -E_RCV_ERROR_REPLY && !errno) goto retry_recv; if (!desc) desc = "error receiving config reply"; rv = OTHER_ERROR; } } error: msg_free(smsg); if (!quiet) rv = print_config_error(rv, desc); free(iov.iov_base); return rv; } static int generic_config_cmd(const struct drbd_cmd *cm, int argc, char **argv) { return _generic_config_cmd(cm, argc, argv, 0); } static int del_minor_cmd(const struct drbd_cmd *cm, int argc, char **argv) { int rv; rv = generic_config_cmd(cm, argc, argv); if (!rv) unregister_minor(minor); return rv; } static int del_resource_cmd(const struct drbd_cmd *cm, int argc, char **argv) { int rv; rv = generic_config_cmd(cm, argc, argv); if (!rv) unregister_resource(objname); return rv; } static const struct drbd_cmd *find_cmd_by_name(const char *name) { unsigned int i; for (i = 0; i < ARRAY_SIZE(commands); i++) { if (!strcmp(name, commands[i].cmd)) { return commands + i; } } return NULL; } static void print_options(const char *cmd_name, const char *sect_name) { const struct drbd_cmd *cmd; struct field_def *field; int opened = 0; cmd = find_cmd_by_name(cmd_name); if (!cmd) { fprintf(stderr, "%s internal error, no such cmd %s\n", cmdname, cmd_name); abort(); } if (!global_attrs[cmd->tla_id]) return; if (drbd_nla_parse_nested(nested_attr_tb, cmd->ctx->nla_policy_size - 1, global_attrs[cmd->tla_id], cmd->ctx->nla_policy)) { fprintf(stderr, "nla_policy violation for %s payload!\n", sect_name); /* still, print those that validated ok */ } if (!cmd->ctx) return; for (field = cmd->ctx->fields; field->name; field++) { struct nlattr *nlattr; const char *str; bool is_default; nlattr = ntb(field->nla_type); if (!nlattr) continue; if (!opened) { opened=1; printI("%s {\n",sect_name); ++indent; } str = field->get(cmd->ctx, field, nlattr); is_default = field->is_default(field, str); if (is_default && !show_defaults) continue; if (field->needs_double_quoting) str = double_quote_string(str); printI("%-16s\t%s;",field->name, str); if (field->unit || is_default) { printf(" # "); if (field->unit) printf("%s", field->unit); if (field->unit && is_default) printf(", "); if (is_default) printf("default"); } printf("\n"); } if(opened) { --indent; printI("}\n"); } } struct choose_timo_ctx { unsigned minor; struct msg_buff *smsg; struct iovec *iov; int timeout; int wfc_timeout; int degr_wfc_timeout; int outdated_wfc_timeout; }; int choose_timeout(struct choose_timo_ctx *ctx) { char *desc = NULL; struct drbd_genlmsghdr *dhdr; int rr; if (0 < ctx->wfc_timeout && (ctx->wfc_timeout < ctx->degr_wfc_timeout || ctx->degr_wfc_timeout == 0)) { ctx->degr_wfc_timeout = ctx->wfc_timeout; fprintf(stderr, "degr-wfc-timeout has to be shorter than wfc-timeout\n" "degr-wfc-timeout implicitly set to wfc-timeout (%ds)\n", ctx->degr_wfc_timeout); } if (0 < ctx->degr_wfc_timeout && (ctx->degr_wfc_timeout < ctx->outdated_wfc_timeout || ctx->outdated_wfc_timeout == 0)) { ctx->outdated_wfc_timeout = ctx->wfc_timeout; fprintf(stderr, "outdated-wfc-timeout has to be shorter than degr-wfc-timeout\n" "outdated-wfc-timeout implicitly set to degr-wfc-timeout (%ds)\n", ctx->degr_wfc_timeout); } dhdr = genlmsg_put(ctx->smsg, &drbd_genl_family, 0, DRBD_ADM_GET_TIMEOUT_TYPE); dhdr->minor = ctx->minor; dhdr->flags = 0; if (genl_send(drbd_sock, ctx->smsg)) { desc = "error sending config command"; goto error; } rr = genl_recv_msgs(drbd_sock, ctx->iov, &desc, 120000); if (rr > 0) { struct nlmsghdr *nlh = (struct nlmsghdr*)ctx->iov->iov_base; struct genl_info info = { .seq = nlh->nlmsg_seq, .nlhdr = nlh, .genlhdr = nlmsg_data(nlh), .userhdr = genlmsg_data(nlmsg_data(nlh)), .attrs = global_attrs, }; struct drbd_genlmsghdr *dh = info.userhdr; struct timeout_parms parms; ASSERT(dh->minor == ctx->minor); rr = dh->ret_code; if (rr == ERR_MINOR_INVALID) { desc = "minor not available"; goto error; } if (rr != NO_ERROR) goto error; if (drbd_tla_parse(nlh) || timeout_parms_from_attrs(&parms, &info)) { desc = "reply did not validate - " "do you need to upgrade your userland tools?"; goto error; } rr = parms.timeout_type; ctx->timeout = (rr == UT_DEGRADED) ? ctx->degr_wfc_timeout : (rr == UT_PEER_OUTDATED) ? ctx->outdated_wfc_timeout : ctx->wfc_timeout; return 0; } error: if (!desc) desc = "error receiving netlink reply"; fprintf(stderr, "error determining which timeout to use: %s\n", desc); return 20; } #include static bool kernel_older_than(int version, int patchlevel, int sublevel) { struct utsname utsname; char *rel; int l; if (uname(&utsname) != 0) return false; rel = utsname.release; l = strtol(rel, &rel, 10); if (l > version) return false; else if (l < version || *rel == 0) return true; l = strtol(rel + 1, &rel, 10); if (l > patchlevel) return false; else if (l < patchlevel || *rel == 0) return true; l = strtol(rel + 1, &rel, 10); if (l >= sublevel) return false; return true; } static bool opt_now; static bool opt_verbose; static bool opt_statistics; static bool opt_timestamps; static int generic_get(const struct drbd_cmd *cm, int timeout_arg, void *u_ptr) { char *desc = NULL; struct drbd_genlmsghdr *dhdr; struct msg_buff *smsg; struct iovec iov; int timeout_ms, flags; int rv = NO_ERROR; int err = 0; /* pre allocate request message and reply buffer */ iov.iov_len = DEFAULT_MSG_SIZE; iov.iov_base = malloc(iov.iov_len); smsg = msg_new(DEFAULT_MSG_SIZE); if (!smsg || !iov.iov_base) { desc = "could not allocate netlink messages"; rv = OTHER_ERROR; goto out; } if (cm->continuous_poll) { if (genl_join_mc_group(drbd_sock, "events") && !kernel_older_than(2, 6, 23)) { desc = "unable to join drbd events multicast group"; rv = OTHER_ERROR; goto out2; } } flags = 0; if (minor == -1U) flags |= NLM_F_DUMP; dhdr = genlmsg_put(smsg, &drbd_genl_family, flags, cm->cmd_id); dhdr->minor = minor; dhdr->flags = 0; if (minor == -1U && strcmp(objname, "all")) { /* Restrict the dump to a single resource. */ struct nlattr *nla; nla = nla_nest_start(smsg, DRBD_NLA_CFG_CONTEXT); nla_put_string(smsg, T_ctx_resource_name, objname); nla_nest_end(smsg, nla); } if (genl_send(drbd_sock, smsg)) { desc = "error sending config command"; rv = OTHER_ERROR; goto out2; } /* disable sequence number check in genl_recv_msgs */ drbd_sock->s_seq_expect = 0; for (;;) { int received, rem, ret; struct nlmsghdr *nlh = (struct nlmsghdr *)iov.iov_base; struct timeval before; struct pollfd pollfds[2] = { [0] = { .fd = 1, .events = POLLHUP, }, [1] = { .fd = drbd_sock->s_fd, .events = POLLIN, }, }; gettimeofday(&before, NULL); timeout_ms = timeout_arg; ret = poll(pollfds, 2, timeout_arg); if (ret == 0) { err = 5; goto out2; } if (pollfds[0].revents == POLLERR || pollfds[0].revents == POLLHUP) goto out2; received = genl_recv_msgs(drbd_sock, &iov, &desc, -1); if (received < 0) { switch(received) { case E_RCV_TIMEDOUT: err = 5; goto out2; case -E_RCV_FAILED: err = 20; goto out2; case -E_RCV_NO_SOURCE_ADDR: continue; /* ignore invalid message */ case -E_RCV_SEQ_MISMATCH: /* we disabled it, so it should not happen */ err = 20; goto out2; case -E_RCV_MSG_TRUNC: continue; case -E_RCV_UNEXPECTED_TYPE: continue; case -E_RCV_NLMSG_DONE: if (cm->continuous_poll) continue; err = cm->show_function(cm, NULL, u_ptr); if (err) goto out2; err = -*(int*)nlmsg_data(nlh); if (err && (err != ENODEV || !cm->missing_ok)) { fprintf(stderr, "received netlink error reply: %s\n", strerror(err)); err = 20; } goto out2; case -E_RCV_ERROR_REPLY: if (!errno) /* positive ACK message */ continue; if (!desc) desc = strerror(errno); fprintf(stderr, "received netlink error reply: %s\n", desc); err = 20; goto out2; default: if (!desc) desc = "error receiving config reply"; err = 20; goto out2; } } if (timeout_ms != -1) { struct timeval after; int elapsed_ms; bool exit; gettimeofday(&after, NULL); elapsed_ms = (after.tv_sec - before.tv_sec) * 1000 + (after.tv_usec - before.tv_usec) / 1000; timeout_ms -= elapsed_ms; exit = timeout_ms <= 0; if (exit) { err = 5; goto out2; } } /* There may be multiple messages in one datagram (for dump replies). */ nlmsg_for_each_msg(nlh, nlh, received, rem) { struct drbd_genlmsghdr *dh = genlmsg_data(nlmsg_data(nlh)); struct genl_info info = (struct genl_info){ .seq = nlh->nlmsg_seq, .nlhdr = nlh, .genlhdr = nlmsg_data(nlh), .userhdr = genlmsg_data(nlmsg_data(nlh)), .attrs = global_attrs, }; if (nlh->nlmsg_type < NLMSG_MIN_TYPE) { /* Ignore netlink control messages. */ continue; } if (nlh->nlmsg_type == GENL_ID_CTRL) { #ifdef HAVE_CTRL_CMD_DELMCAST_GRP if (info.genlhdr->cmd == CTRL_CMD_DELMCAST_GRP) { struct nlattr *nla = nlmsg_find_attr(nlh, GENL_HDRLEN, CTRL_ATTR_FAMILY_ID); if (nla && nla_get_u16(nla) == drbd_genl_family.id) { /* FIXME: We could wait for the multicast group to be recreated ... */ goto out2; } } #endif /* Ignore other generic netlink control messages. */ continue; } if (nlh->nlmsg_type != drbd_genl_family.id) { /* Ignore messages for all other netlink families. */ continue; } /* parse early, otherwise drbd_cfg_context_from_attrs * can not work */ if (drbd_tla_parse(nlh)) { /* FIXME * should continuous_poll continue? */ desc = "reply did not validate - " "do you need to upgrade your userland tools?"; rv = OTHER_ERROR; goto out2; } if (cm->continuous_poll) { struct drbd_cfg_context ctx; /* * We will receive all events and have to * filter for what we want ourself. */ /* FIXME * Do we want to ignore broadcasts until the * initial get/dump requests is done? */ if (!drbd_cfg_context_from_attrs(&ctx, &info)) { switch (context) { case CTX_MINOR: /* Assert that, for an unicast reply, * reply minor matches request minor. * "unsolicited" kernel broadcasts are "pid=0" (netlink "port id") * (and expected to be genlmsghdr.cmd == DRBD_EVENT) */ if (minor != dh->minor) { if (info.nlhdr->nlmsg_pid != 0) dbg(1, "received netlink packet for minor %u, while expecting %u\n", dh->minor, minor); continue; } break; case CTX_ALL: break; case CTX_RESOURCE: if (strcmp(objname, ctx.ctx_resource_name)) continue; break; #if 0 case CTX_CONNECTION: case CTX_CONNECTION | CTX_RESOURCE: if (!endpoints_equal(&ctx, &global_ctx)) continue; break; #endif #if 0 case CTX_PEER_DEVICE: if (!endpoints_equal(&ctx, &global_ctx) || ctx.ctx_volume != global_ctx.ctx_volume) continue; break; #endif default: assert(0); } } } rv = dh->ret_code; if (rv == ERR_MINOR_INVALID) { if (cm->warn_on_missing) fprintf(stderr, "Minor invalid"); if (cm->missing_ok) rv = NO_ERROR; } if (rv != NO_ERROR) goto out2; err = cm->show_function(cm, &info, u_ptr); if (err) { if (err < 0) err = 0; goto out2; } } if (!cm->continuous_poll && !(flags & NLM_F_DUMP)) { /* There will be no more reply packets. */ err = cm->show_function(cm, NULL, u_ptr); goto out2; } } out2: msg_free(smsg); out: if (!err) err = print_config_error(rv, desc); free(iov.iov_base); return err; } static int generic_get_cmd(const struct drbd_cmd *cm, int argc, char **argv) { static struct option no_options[] = { { } }; struct choose_timo_ctx timeo_ctx = { .wfc_timeout = DRBD_WFC_TIMEOUT_DEF, .degr_wfc_timeout = DRBD_DEGR_WFC_TIMEOUT_DEF, .outdated_wfc_timeout = DRBD_OUTDATED_WFC_TIMEOUT_DEF, }; int timeout_ms = -1; /* "infinite" */ struct option *options = cm->options ? cm->options : no_options; const char *opts = make_optstring(options); optind = 0; /* reset getopt_long() */ for(;;) { int c = getopt_long(argc, argv, opts, options, 0); if (c == -1) break; switch(c) { default: case '?': return 20; case 't': timeo_ctx.wfc_timeout = m_strtoll(optarg, 1); if(DRBD_WFC_TIMEOUT_MIN > timeo_ctx.wfc_timeout || timeo_ctx.wfc_timeout > DRBD_WFC_TIMEOUT_MAX) { fprintf(stderr, "wfc_timeout => %d" " out of range [%d..%d]\n", timeo_ctx.wfc_timeout, DRBD_WFC_TIMEOUT_MIN, DRBD_WFC_TIMEOUT_MAX); return 20; } break; case 'd': timeo_ctx.degr_wfc_timeout = m_strtoll(optarg, 1); if(DRBD_DEGR_WFC_TIMEOUT_MIN > timeo_ctx.degr_wfc_timeout || timeo_ctx.degr_wfc_timeout > DRBD_DEGR_WFC_TIMEOUT_MAX) { fprintf(stderr, "degr_wfc_timeout => %d" " out of range [%d..%d]\n", timeo_ctx.degr_wfc_timeout, DRBD_DEGR_WFC_TIMEOUT_MIN, DRBD_DEGR_WFC_TIMEOUT_MAX); return 20; } break; case 'o': timeo_ctx.outdated_wfc_timeout = m_strtoll(optarg, 1); if(DRBD_OUTDATED_WFC_TIMEOUT_MIN > timeo_ctx.outdated_wfc_timeout || timeo_ctx.outdated_wfc_timeout > DRBD_OUTDATED_WFC_TIMEOUT_MAX) { fprintf(stderr, "outdated_wfc_timeout => %d" " out of range [%d..%d]\n", timeo_ctx.outdated_wfc_timeout, DRBD_OUTDATED_WFC_TIMEOUT_MIN, DRBD_OUTDATED_WFC_TIMEOUT_MAX); return 20; } break; case 'n': opt_now = true; break; case 's': opt_verbose = true; opt_statistics = true; break; case 'w': if (!optarg || !strcmp(optarg, "yes")) wait_after_split_brain = true; break; case 'D': show_defaults = true; break; case 'T': opt_timestamps = true; break; } } if (optind < argc) { warn_print_excess_args(argc, argv, optind); return 20; } if (cm->wait_for_connect_timeouts) { /* wait-connect, wait-sync */ struct msg_buff *smsg; struct iovec iov; int rr; iov.iov_len = 8192; iov.iov_base = malloc(iov.iov_len); smsg = msg_new(DEFAULT_MSG_SIZE); if (!smsg || !iov.iov_base) { fprintf(stderr, "could not allocate netlink messages\n"); return 20; } timeo_ctx.minor = minor; timeo_ctx.smsg = smsg; timeo_ctx.iov = &iov; rr = choose_timeout(&timeo_ctx); if (rr) return rr; if (timeo_ctx.timeout) timeout_ms = timeo_ctx.timeout * 1000; msg_free(smsg); free(iov.iov_base); } else if (!cm->continuous_poll) /* normal "get" request, or "show" */ timeout_ms = 120000; /* else: events command, defaults to "infinity" */ return generic_get(cm, timeout_ms, NULL); } static void show_address(void* address, int addr_len) { char buffer[ADDRESS_STR_MAX]; sprint_address(buffer, address, addr_len); printI("address\t\t\t%s;\n", buffer); } struct minors_list { struct minors_list *next; unsigned minor; }; struct minors_list *__remembered_minors; static int remember_minor(const struct drbd_cmd *cmd, struct genl_info *info, void *u_ptr) { struct drbd_cfg_context cfg = { .ctx_volume = -1U }; if (!info) return 0; drbd_cfg_context_from_attrs(&cfg, info); if (cfg.ctx_volume != -1U) { unsigned minor = ((struct drbd_genlmsghdr*)(info->userhdr))->minor; struct minors_list *m = malloc(sizeof(*m)); m->next = __remembered_minors; m->minor = minor; __remembered_minors = m; } return 0; } static void free_minors(struct minors_list *minors) { while (minors) { struct minors_list *m = minors; minors = minors->next; free(m); } } /* * Expects objname to be set to the resource name or "all". */ static struct minors_list *enumerate_minors(void) { struct drbd_cmd cmd = { .cmd_id = DRBD_ADM_GET_STATUS, .show_function = remember_minor, .missing_ok = true, }; struct minors_list *m; int err; err = generic_get_cmd(&cmd, 0, NULL); m = __remembered_minors; __remembered_minors = NULL; if (err) { free_minors(m); m = NULL; } return m; } static int remember_resource(const struct drbd_cmd *cmd, struct genl_info *info, void *u_ptr) { struct resources_list ***tail = u_ptr; struct drbd_cfg_context cfg = { .ctx_volume = -1U }; if (!info) return 0; drbd_cfg_context_from_attrs(&cfg, info); if (cfg.ctx_resource_name) { struct resources_list *r = calloc(1, sizeof(*r)); struct nlattr *res_opts = global_attrs[DRBD_NLA_RESOURCE_OPTS]; r->name = strdup(cfg.ctx_resource_name); if (res_opts) { int size = nla_total_size(nla_len(res_opts)); r->res_opts = malloc(size); memcpy(r->res_opts, res_opts, size); } resource_info_from_attrs(&r->info, info); memset(&r->statistics, -1, sizeof(r->statistics)); resource_statistics_from_attrs(&r->statistics, info); **tail = r; *tail = &r->next; } return 0; } static void free_resources(struct resources_list *resources) { while (resources) { struct resources_list *r = resources; resources = resources->next; free(r->name); free(r->res_opts); free(r); } } static int resource_name_cmp(const struct resources_list * const *a, const struct resources_list * const *b) { return strcmp((*a)->name, (*b)->name); } static struct resources_list *sort_resources(struct resources_list *resources) { struct resources_list *r; int n; for (r = resources, n = 0; r; r = r->next) n++; if (n > 1) { struct resources_list **array; array = malloc(sizeof(*array) * n); for (r = resources, n = 0; r; r = r->next) array[n++] = r; qsort(array, n, sizeof(*array), (int (*)(const void *, const void *)) resource_name_cmp); n--; array[n]->next = NULL; for (; n > 0; n--) array[n - 1]->next = array[n]; resources = array[0]; free(array); } return resources; } /* * Expects objname to be set to the resource name or "all". */ static struct resources_list *list_resources(void) { struct drbd_cmd cmd = { .cmd_id = DRBD_ADM_GET_RESOURCES, .show_function = remember_resource, .missing_ok = false, }; struct resources_list *list = NULL, **tail = &list; char *old_objname = objname; unsigned old_minor = minor; int err; objname = "all"; minor = -1; err = generic_get(&cmd, 120000, &tail); objname = old_objname; minor = old_minor; if (err) { free_resources(list); list = NULL; } return list; } static int remember_device(const struct drbd_cmd *cm, struct genl_info *info, void *u_ptr) { struct devices_list ***tail = u_ptr; struct drbd_cfg_context ctx = { .ctx_volume = -1U }; if (!info) return 0; drbd_cfg_context_from_attrs(&ctx, info); if (ctx.ctx_volume != -1U) { struct devices_list *d = calloc(1, sizeof(*d)); d->minor = ((struct drbd_genlmsghdr*)(info->userhdr))->minor; d->ctx = ctx; disk_conf_from_attrs(&d->disk_conf, info); d->info.dev_disk_state = D_DISKLESS; device_info_from_attrs(&d->info, info); memset(&d->statistics, -1, sizeof(d->statistics)); device_statistics_from_attrs(&d->statistics, info); **tail = d; *tail = &d->next; } return 0; } /* * Expects objname to be set to the resource name or "all". */ static struct devices_list *list_devices(char *resource_name) { struct drbd_cmd cmd = { .cmd_id = DRBD_ADM_GET_DEVICES, .show_function = remember_device, .missing_ok = false, }; struct devices_list *list = NULL, **tail = &list; char *old_objname = objname; unsigned old_minor = minor; int err; objname = resource_name ? resource_name : "all"; minor = -1; err = generic_get(&cmd, 120000, &tail); objname = old_objname; minor = old_minor; if (err) { free_devices(list); list = NULL; } return list; } static void free_devices(struct devices_list *devices) { while (devices) { struct devices_list *d = devices; devices = devices->next; free(d); } } static int remember_connection(const struct drbd_cmd *cmd, struct genl_info *info, void *u_ptr) { struct connections_list ***tail = u_ptr; struct drbd_cfg_context ctx = { .ctx_volume = -1U }; if (!info) return 0; drbd_cfg_context_from_attrs(&ctx, info); if (ctx.ctx_resource_name) { struct connections_list *c = calloc(1, sizeof(*c)); struct nlattr *net_conf = global_attrs[DRBD_NLA_NET_CONF]; c->ctx = ctx; if (net_conf) { int size = nla_total_size(nla_len(net_conf)); c->net_conf = malloc(size); memcpy(c->net_conf, net_conf, size); } connection_info_from_attrs(&c->info, info); memset(&c->statistics, -1, sizeof(c->statistics)); connection_statistics_from_attrs(&c->statistics, info); **tail = c; *tail = &c->next; } return 0; } #if 0 static int connection_name_cmp(const struct connections_list * const *a, const struct connections_list * const *b) { if (!(*a)->ctx.ctx_conn_name_len != !(*b)->ctx.ctx_conn_name_len) return !(*b)->ctx.ctx_conn_name_len; return strcmp((*a)->ctx.ctx_conn_name, (*b)->ctx.ctx_conn_name); } #endif static struct connections_list *sort_connections(struct connections_list *connections) { struct connections_list *c; int n; for (c = connections, n = 0; c; c = c->next) n++; if (n > 1) { struct connections_list **array; array = malloc(sizeof(*array) * n); for (c = connections, n = 0; c; c = c->next) array[n++] = c; #if 0 qsort(array, n, sizeof(*array), (int (*)(const void *, const void *)) connection_name_cmp); #endif n--; array[n]->next = NULL; for (; n > 0; n--) array[n - 1]->next = array[n]; connections = array[0]; free(array); } return connections; } /* * Expects objname to be set to the resource name or "all". */ static struct connections_list *list_connections(char *resource_name) { struct drbd_cmd cmd = { .cmd_id = DRBD_ADM_GET_CONNECTIONS, .show_function = remember_connection, .missing_ok = true, }; struct connections_list *list = NULL, **tail = &list; char *old_objname = objname; unsigned old_minor = minor; int err; objname = resource_name ? resource_name : "all"; minor = -1; err = generic_get(&cmd, 120000, &tail); objname = old_objname; minor = old_minor; if (err) { free_connections(list); list = NULL; } return list; } static void free_connections(struct connections_list *connections) { while (connections) { struct connections_list *l = connections; connections = connections->next; free(l); } } static int remember_peer_device(const struct drbd_cmd *cmd, struct genl_info *info, void *u_ptr) { struct peer_devices_list ***tail = u_ptr; struct drbd_cfg_context ctx = { .ctx_volume = -1U }; if (!info) return 0; drbd_cfg_context_from_attrs(&ctx, info); if (ctx.ctx_resource_name) { struct peer_devices_list *p = calloc(1, sizeof(*p)); if (!p) exit(20); p->ctx = ctx; peer_device_info_from_attrs(&p->info, info); memset(&p->statistics, -1, sizeof(p->statistics)); peer_device_statistics_from_attrs(&p->statistics, info); **tail = p; *tail = &p->next; } return 0; } /* * Expects objname to be set to the resource name or "all". */ static struct peer_devices_list *list_peer_devices(char *resource_name) { struct drbd_cmd cmd = { .cmd_id = DRBD_ADM_GET_PEER_DEVICES, .show_function = remember_peer_device, .missing_ok = false, }; struct peer_devices_list *list = NULL, **tail = &list; char *old_objname = objname; unsigned old_minor = minor; int err; objname = resource_name ? resource_name : "all"; minor = -1; err = generic_get(&cmd, 120000, &tail); objname = old_objname; minor = old_minor; if (err) { free_peer_devices(list); list = NULL; } return list; } static void free_peer_devices(struct peer_devices_list *peer_devices) { while (peer_devices) { struct peer_devices_list *p = peer_devices; peer_devices = peer_devices->next; free(p); } } /* may be called for a "show" of a single minor device. * prints all available configuration information in that case. * * may also be called iteratively for a "show-all", which should try to not * print redundant configuration information for the same resource (tconn). */ static int show_scmd(const struct drbd_cmd *cm, struct genl_info *info, void *u_ptr) { /* FIXME need some define for max len here */ static char last_ctx_resource_name[128]; static int call_count; struct drbd_cfg_context cfg = { .ctx_volume = -1U }; struct disk_conf dc = { .disk_size = 0, }; struct net_conf nc = { .timeout = 0, };; if (!info) { if (call_count) { --indent; printI("}\n"); /* close _this_host */ --indent; printI("}\n"); /* close resource */ } fflush(stdout); return 0; } call_count++; /* FIXME: Is the folowing check needed? */ if (!global_attrs[DRBD_NLA_CFG_CONTEXT]) dbg(1, "unexpected packet, configuration context missing!\n"); drbd_cfg_context_from_attrs(&cfg, info); disk_conf_from_attrs(&dc, info); net_conf_from_attrs(&nc, info); if (strncmp(last_ctx_resource_name, cfg.ctx_resource_name, sizeof(last_ctx_resource_name))) { if (strncmp(last_ctx_resource_name, "", sizeof(last_ctx_resource_name))) { --indent; printI("}\n"); /* close _this_host */ --indent; printI("}\n\n"); } strncpy(last_ctx_resource_name, cfg.ctx_resource_name, sizeof(last_ctx_resource_name)); printI("resource %s {\n", cfg.ctx_resource_name); ++indent; print_options("resource-options", "options"); print_options("net-options", "net"); if (cfg.ctx_peer_addr_len) { printI("_remote_host {\n"); ++indent; show_address(cfg.ctx_peer_addr, cfg.ctx_peer_addr_len); --indent; printI("}\n"); } printI("_this_host {\n"); ++indent; if (cfg.ctx_my_addr_len) show_address(cfg.ctx_my_addr, cfg.ctx_my_addr_len); } if (cfg.ctx_volume != -1U) { unsigned minor = ((struct drbd_genlmsghdr*)(info->userhdr))->minor; printI("volume %d {\n", cfg.ctx_volume); ++indent; printI("device\t\t\tminor %d;\n", minor); if (global_attrs[DRBD_NLA_DISK_CONF]) { if (dc.backing_dev[0]) { printI("disk\t\t\t\"%s\";\n", dc.backing_dev); printI("meta-disk\t\t\t"); switch(dc.meta_dev_idx) { case DRBD_MD_INDEX_INTERNAL: case DRBD_MD_INDEX_FLEX_INT: printf("internal;\n"); break; case DRBD_MD_INDEX_FLEX_EXT: printf("%s;\n", double_quote_string(dc.meta_dev)); break; default: printf("%s [ %d ];\n", double_quote_string(dc.meta_dev), dc.meta_dev_idx); } } } print_options("attach", "disk"); --indent; printI("}\n"); /* close volume */ } return 0; } static int lk_bdev_scmd(const struct drbd_cmd *cm, struct genl_info *info, void *u_ptr) { unsigned minor; struct disk_conf dc = { .disk_size = 0, }; struct bdev_info bd = { 0, }; uint64_t bd_size; int fd; if (!info) return 0; minor = ((struct drbd_genlmsghdr*)(info->userhdr))->minor; disk_conf_from_attrs(&dc, info); if (!dc.backing_dev) { fprintf(stderr, "Has no disk config, try with drbdmeta.\n"); return 1; } if (dc.meta_dev_idx >= 0 || dc.meta_dev_idx == DRBD_MD_INDEX_FLEX_EXT) { lk_bdev_delete(minor); return 0; } fd = open(dc.backing_dev, O_RDONLY); if (fd == -1) { fprintf(stderr, "Could not open %s: %m.\n", dc.backing_dev); return 1; } bd_size = bdev_size(fd); close(fd); if (lk_bdev_load(minor, &bd) == 0 && bd.bd_size == bd_size && bd.bd_name && !strcmp(bd.bd_name, dc.backing_dev)) return 0; /* nothing changed. */ bd.bd_size = bd_size; bd.bd_name = dc.backing_dev; lk_bdev_save(minor, &bd); return 0; } static int sh_status_scmd(const struct drbd_cmd *cm __attribute((unused)), struct genl_info *info, void *u_ptr) { unsigned minor; struct drbd_cfg_context cfg = { .ctx_volume = -1U }; struct state_info si = { .current_state = 0, }; union drbd_state state; int available = 0; if (!info) return 0; minor = ((struct drbd_genlmsghdr*)(info->userhdr))->minor; /* variable prefix; maybe rather make that a command line parameter? * or use "drbd_sh_status"? */ #define _P "" printf("%s_minor=%u\n", _P, minor); drbd_cfg_context_from_attrs(&cfg, info); if (cfg.ctx_resource_name) printf("%s_res_name=%s\n", _P, shell_escape(cfg.ctx_resource_name)); printf("%s_volume=%d\n", _P, cfg.ctx_volume); if (state_info_from_attrs(&si, info) == 0) available = 1; state.i = si.current_state; if (state.conn == C_STANDALONE && state.disk == D_DISKLESS && state.role != R_PRIMARY) { printf("%s_known=%s\n\n", _P, available ? "Unconfigured" : "NA # not available or not yet created"); printf("%s_cstate=Unconfigured\n", _P); printf("%s_role=\n", _P); printf("%s_peer=\n", _P); printf("%s_disk=\n", _P); printf("%s_pdsk=\n", _P); printf("%s_flags_susp=\n", _P); printf("%s_flags_aftr_isp=\n", _P); printf("%s_flags_peer_isp=\n", _P); printf("%s_flags_user_isp=\n", _P); printf("%s_resynced_percent=\n", _P); } else { printf( "%s_known=Configured\n\n" /* connection state */ "%s_cstate=%s\n" /* role */ "%s_role=%s\n" "%s_peer=%s\n" /* disk state */ "%s_disk=%s\n" "%s_pdsk=%s\n\n", _P, _P, drbd_conn_str(state.conn), _P, drbd_role_str(state.role), _P, drbd_role_str(state.peer), _P, drbd_disk_str(state.disk), _P, drbd_disk_str(state.pdsk)); /* io suspended ? */ printf("%s_flags_susp=%s\n", _P, state.susp ? "1" : ""); /* reason why sync is paused */ printf("%s_flags_aftr_isp=%s\n", _P, state.aftr_isp ? "1" : ""); printf("%s_flags_peer_isp=%s\n", _P, state.peer_isp ? "1" : ""); printf("%s_flags_user_isp=%s\n\n", _P, state.user_isp ? "1" : ""); printf("%s_resynced_percent=", _P); if (ntb(T_bits_rs_total)) { uint32_t shift = si.bits_rs_total >= (1ULL << 32) ? 16 : 10; uint64_t left = (si.bits_oos - si.bits_rs_failed) >> shift; uint64_t total = 1UL + (si.bits_rs_total >> shift); uint64_t tmp = 1000UL - left * 1000UL/total; unsigned synced = tmp; printf("%i.%i\n", synced / 10, synced % 10); /* what else? everything available! */ } else printf("\n"); } printf("\n%s_sh_status_process\n\n\n", _P); fflush(stdout); return 0; #undef _P } static int role_scmd(const struct drbd_cmd *cm __attribute((unused)), struct genl_info *info, void *u_ptr) { union drbd_state state = { .i = 0 }; if (!strcmp(cm->cmd, "state")) { fprintf(stderr, "'%s ... state' is deprecated, use '%s ... role' instead.\n", cmdname, cmdname); } if (!info) return 0; if (global_attrs[DRBD_NLA_STATE_INFO]) { drbd_nla_parse_nested(nested_attr_tb, ARRAY_SIZE(state_info_nl_policy) - 1, global_attrs[DRBD_NLA_STATE_INFO], state_info_nl_policy); if (ntb(T_current_state)) state.i = nla_get_u32(ntb(T_current_state)); } if (state.conn == C_STANDALONE && state.disk == D_DISKLESS) { printf("Unconfigured\n"); } else { printf("%s/%s\n",drbd_role_str(state.role),drbd_role_str(state.peer)); } return 0; } static int cstate_scmd(const struct drbd_cmd *cm __attribute((unused)), struct genl_info *info, void *u_ptr) { union drbd_state state = { .i = 0 }; if (!info) return 0; if (global_attrs[DRBD_NLA_STATE_INFO]) { drbd_nla_parse_nested(nested_attr_tb, ARRAY_SIZE(state_info_nl_policy) - 1, global_attrs[DRBD_NLA_STATE_INFO], state_info_nl_policy); if (ntb(T_current_state)) state.i = nla_get_u32(ntb(T_current_state)); } if (state.conn == C_STANDALONE && state.disk == D_DISKLESS) { printf("Unconfigured\n"); } else { printf("%s\n",drbd_conn_str(state.conn)); } return 0; } static int dstate_scmd(const struct drbd_cmd *cm __attribute((unused)), struct genl_info *info, void *u_ptr) { union drbd_state state = { .i = 0 }; if (!info) return 0; if (global_attrs[DRBD_NLA_STATE_INFO]) { drbd_nla_parse_nested(nested_attr_tb, ARRAY_SIZE(state_info_nl_policy)-1, global_attrs[DRBD_NLA_STATE_INFO], state_info_nl_policy); if (ntb(T_current_state)) state.i = nla_get_u32(ntb(T_current_state)); } if ( state.conn == C_STANDALONE && state.disk == D_DISKLESS) { printf("Unconfigured\n"); } else { printf("%s/%s\n",drbd_disk_str(state.disk),drbd_disk_str(state.pdsk)); } return 0; } static int uuids_scmd(const struct drbd_cmd *cm, struct genl_info *info, void *u_ptr) { union drbd_state state = { .i = 0 }; uint64_t ed_uuid; uint64_t *uuids = NULL; int flags = flags; if (!info) return 0; if (global_attrs[DRBD_NLA_STATE_INFO]) { drbd_nla_parse_nested(nested_attr_tb, ARRAY_SIZE(state_info_nl_policy)-1, global_attrs[DRBD_NLA_STATE_INFO], state_info_nl_policy); if (ntb(T_current_state)) state.i = nla_get_u32(ntb(T_current_state)); if (ntb(T_uuids)) uuids = nla_data(ntb(T_uuids)); if (ntb(T_disk_flags)) flags = nla_get_u32(ntb(T_disk_flags)); if (ntb(T_ed_uuid)) ed_uuid = nla_get_u64(ntb(T_ed_uuid)); } if (state.conn == C_STANDALONE && state.disk == D_DISKLESS) { fprintf(stderr, "Device is unconfigured\n"); return 1; } if (state.disk == D_DISKLESS) { /* XXX we could print the ed_uuid anyways: */ if (0) printf(X64(016)"\n", ed_uuid); fprintf(stderr, "Device has no disk\n"); return 1; } if (uuids) { if(!strcmp(cm->cmd,"show-gi")) { dt_pretty_print_uuids(uuids,flags); } else if(!strcmp(cm->cmd,"get-gi")) { dt_print_uuids(uuids,flags); } else { ASSERT( 0 ); } } else { fprintf(stderr, "No uuids found in reply!\n" "Maybe you need to upgrade your userland tools?\n"); } return 0; } static int down_cmd(const struct drbd_cmd *cm, int argc, char **argv) { struct minors_list *minors, *m; int rv; int success; if(argc > 2) { warn_print_excess_args(argc, argv, 2); return OTHER_ERROR; } minors = enumerate_minors(); rv = _generic_config_cmd(cm, argc, argv, 1); success = (rv >= SS_SUCCESS && rv < ERR_CODE_BASE) || rv == NO_ERROR; if (success) { for (m = minors; m; m = m->next) unregister_minor(m->minor); free_minors(minors); unregister_resource(objname); } else { free_minors(minors); return print_config_error(rv, NULL); } return 0; } static const char *susp_str(struct resource_info *info) { static char buffer[32]; *buffer = 0; if (info->res_susp) strcat(buffer, ",user" + (*buffer == 0)); if (info->res_susp_nod) strcat(buffer, ",no-data" + (*buffer == 0)); if (info->res_susp_fen) strcat(buffer, ",fencing" + (*buffer == 0)); if (*buffer == 0) strcat(buffer, "no"); return buffer; } int nowrap_printf(int indent, const char *format, ...) { va_list ap; int ret; va_start(ap, format); ret = vprintf(format, ap); va_end(ap); return ret; } void print_resource_statistics(int indent, struct resource_statistics *old, struct resource_statistics *new, int (*wrap_printf)(int, const char *, ...)) { static const char *write_ordering_str[] = { [WO_NONE] = "none", [WO_DRAIN_IO] = "drain", [WO_BDEV_FLUSH] = "flush", [WO_BIO_BARRIER] = "barrier", }; uint32_t wo = new->res_stat_write_ordering; if ((!old || old->res_stat_write_ordering != wo) && wo < ARRAY_SIZE(write_ordering_str) && write_ordering_str[wo]) { wrap_printf(indent, " write-ordering:%s", write_ordering_str[wo]); } } void print_device_statistics(int indent, struct device_statistics *old, struct device_statistics *new, int (*wrap_printf)(int, const char *, ...)) { if (opt_statistics) { if (opt_verbose) wrap_printf(indent, " size:" U64, (uint64_t)new->dev_size / 2); wrap_printf(indent, " read:" U64, (uint64_t)new->dev_read / 2); wrap_printf(indent, " written:" U64, (uint64_t)new->dev_write / 2); if (opt_verbose) { wrap_printf(indent, " al-writes:" U64, (uint64_t)new->dev_al_writes); wrap_printf(indent, " bm-writes:" U64, (uint64_t)new->dev_bm_writes); wrap_printf(indent, " upper-pending:" U32, new->dev_upper_pending); wrap_printf(indent, " lower-pending:" U32, new->dev_lower_pending); if (!old || old->dev_al_suspended != new->dev_al_suspended) wrap_printf(indent, " al-suspended:%s", new->dev_al_suspended ? "yes" : "no"); } } if ((!old || old->dev_upper_blocked != new->dev_upper_blocked || old->dev_lower_blocked != new->dev_lower_blocked) && new->dev_size != -1 && (opt_verbose || new->dev_upper_blocked || new->dev_lower_blocked)) { const char *x1 = "", *x2 = ""; bool first = true; if (new->dev_upper_blocked) { x1 = ",upper" + first; first = false; } if (new->dev_lower_blocked) { x2 = ",lower" + first; first = false; } if (first) x1 = "no"; wrap_printf(indent, " blocked:%s%s", x1, x2); } } void print_connection_statistics(int indent, struct connection_statistics *old, struct connection_statistics *new, int (*wrap_printf)(int, const char *, ...)) { if (!old || old->conn_congested != new->conn_congested) wrap_printf(indent, " congested:%s", new->conn_congested ? "yes" : "no"); } void print_peer_device_statistics(int indent, struct peer_device_statistics *old, struct peer_device_statistics *new, int (*wrap_printf)(int, const char *, ...)) { wrap_printf(indent, " received:" U64, (uint64_t)new->peer_dev_received / 2); wrap_printf(indent, " sent:" U64, (uint64_t)new->peer_dev_sent / 2); if (opt_verbose || new->peer_dev_out_of_sync) wrap_printf(indent, " out-of-sync:" U64, (uint64_t)new->peer_dev_out_of_sync / 2); if (opt_verbose) { wrap_printf(indent, " pending:" U32, new->peer_dev_pending); wrap_printf(indent, " unacked:" U32, new->peer_dev_unacked); } } void resource_status(struct resources_list *resource) { enum drbd_role role = resource->info.res_role; wrap_printf(0, "%s", resource->name); #if 0 if (opt_verbose) { struct nlattr *nla; nla = nla_find_nested(resource->res_opts, __nla_type(T_node_id)); if (nla) wrap_printf(4, " node-id:%d", *(uint32_t *)nla_data(nla)); } #endif wrap_printf(4, " role:%s%s%s", role_color_start(role, true), drbd_role_str(role), role_color_stop(role, true)); if (opt_verbose || resource->info.res_susp || resource->info.res_susp_nod || resource->info.res_susp_fen) wrap_printf(4, " suspended:%s", susp_str(&resource->info)); #if 0 if (opt_verbose || resource->info.res_weak) wrap_printf(4, " weak:%s", resource->info.res_weak ? "yes" : "no"); #endif if (opt_statistics && opt_verbose) { wrap_printf(4, "\n"); print_resource_statistics(4, NULL, &resource->statistics, wrap_printf); } wrap_printf(0, "\n"); } static void device_status(struct devices_list *device, bool single_device) { enum drbd_disk_state disk_state = device->info.dev_disk_state; int indent = 2; if (opt_verbose || !(single_device && device->ctx.ctx_volume == 0)) { wrap_printf(indent, "volume:%u", device->ctx.ctx_volume); indent = 6; if (opt_verbose) wrap_printf(indent, " minor:%u", device->minor); } wrap_printf(indent, " disk:%s%s%s", disk_state_color_start(disk_state, true), drbd_disk_str(disk_state), disk_state_color_stop(disk_state, true)); indent = 6; if (device->statistics.dev_size != -1) { if (opt_statistics) wrap_printf(indent, "\n"); print_device_statistics(indent, NULL, &device->statistics, wrap_printf); } wrap_printf(indent, "\n"); } static const char *resync_susp_str(struct peer_device_info *info) { static char buffer[64]; *buffer = 0; if (info->peer_resync_susp_user) strcat(buffer, ",user" + (*buffer == 0)); if (info->peer_resync_susp_peer) strcat(buffer, ",peer" + (*buffer == 0)); if (info->peer_resync_susp_dependency) strcat(buffer, ",dependency" + (*buffer == 0)); if (*buffer == 0) strcat(buffer, "no"); return buffer; } const char *drbd_repl_str9(enum drbd_conns s) { static const char *n[] = { [C_WF_REPORT_PARAMS] = "Off", [C_CONNECTED] = "Established", }; return (s == C_WF_REPORT_PARAMS || s == C_CONNECTED) ? n[s] : drbd_conn_str(s); } const char *drbd_conn_str9(enum drbd_conns s) { static const char *n[] = { [C_WF_CONNECTION] = "Connecting", [C_WF_REPORT_PARAMS] = "Connected", }; return (s == C_WF_CONNECTION || s == C_WF_REPORT_PARAMS) ? n[s] : drbd_conn_str(s); } static void peer_device_status(struct peer_devices_list *peer_device, bool single_device) { int indent = 4; if (opt_verbose || !(single_device && peer_device->ctx.ctx_volume == 0)) { wrap_printf(indent, "volume:%d", peer_device->ctx.ctx_volume); indent = 8; } /* this > C_WF_REPORT_PARAMS is > L_ESTABLISHED in DRBD 9 */ if (opt_verbose || peer_device->info.peer_repl_state > C_WF_REPORT_PARAMS) { enum drbd_conns repl_state = peer_device->info.peer_repl_state; wrap_printf(indent, " replication:%s%s%s", repl_state_color_start(repl_state), drbd_repl_str9(repl_state), repl_state_color_stop(repl_state)); indent = 8; } /* this C_WF_REPORT_PARAMS is C_CONNECTED resp. L_OFF in DRBD 9 */ if (opt_verbose || opt_statistics || peer_device->info.peer_repl_state != C_WF_REPORT_PARAMS || peer_device->info.peer_disk_state != D_UNKNOWN) { enum drbd_disk_state disk_state = peer_device->info.peer_disk_state; wrap_printf(indent, " peer-disk:%s%s%s", disk_state_color_start(disk_state, false), drbd_disk_str(disk_state), disk_state_color_stop(disk_state, false)); indent = 8; if (peer_device->info.peer_repl_state >= C_SYNC_SOURCE && peer_device->info.peer_repl_state <= C_PAUSED_SYNC_T) { wrap_printf(indent, " done:%.2f", 100 * (1 - (double)peer_device->statistics.peer_dev_out_of_sync / (double)peer_device->device->statistics.dev_size)); } if (opt_verbose || peer_device->info.peer_resync_susp_user || peer_device->info.peer_resync_susp_peer || peer_device->info.peer_resync_susp_dependency) wrap_printf(indent, " resync-suspended:%s", resync_susp_str(&peer_device->info)); if (opt_statistics && peer_device->statistics.peer_dev_received != -1) { wrap_printf(indent, "\n"); print_peer_device_statistics(indent, NULL, &peer_device->statistics, wrap_printf); } } wrap_printf(0, "\n"); } static void peer_devices_status(struct drbd_cfg_context *ctx, struct peer_devices_list *peer_devices, bool single_device) { struct peer_devices_list *peer_device; for (peer_device = peer_devices; peer_device; peer_device = peer_device->next) { if (!endpoints_equal(ctx, &peer_device->ctx)) continue; peer_device_status(peer_device, single_device); } } static void connection_status(struct connections_list *connection, struct peer_devices_list *peer_devices, bool single_device) { wrap_printf(2, "%s", "peer" /* connection->ctx.ctx_conn_name */); /* We do not want the IP-pair information */ /* We do not have any node-id information */ /* this C_WF_REPORT_PARAMS is C_CONNECTED in DRBD 9 */ if (opt_verbose || connection->info.conn_connection_state < C_WF_REPORT_PARAMS) { enum drbd_conns cstate = connection->info.conn_connection_state; wrap_printf(6, " connection:%s%s%s", cstate_color_start(cstate), drbd_conn_str9(cstate), cstate_color_stop(cstate)); } if (opt_verbose || connection->info.conn_connection_state == C_WF_REPORT_PARAMS) { enum drbd_role role = connection->info.conn_role; wrap_printf(6, " role:%s%s%s", role_color_start(role, false), drbd_role_str(role), role_color_stop(role, false)); } if (opt_verbose || connection->statistics.conn_congested > 0) print_connection_statistics(6, NULL, &connection->statistics, wrap_printf); wrap_printf(0, "\n"); if (opt_verbose || opt_statistics || connection->info.conn_connection_state == C_WF_REPORT_PARAMS) peer_devices_status(&connection->ctx, peer_devices, single_device); } static void stop_colors(int sig) { printf("%s", stop_color_code()); signal(sig, SIG_DFL); raise(sig); } static void link_peer_devices_to_devices(struct peer_devices_list *peer_devices, struct devices_list *devices) { struct peer_devices_list *peer_device; struct devices_list *device; for (peer_device = peer_devices; peer_device; peer_device = peer_device->next) { for (device = devices; device; device = device->next) { if (peer_device->ctx.ctx_volume == device->ctx.ctx_volume) { peer_device->device = device; break; } } } } static void print_usage_and_exit(const char* addinfo); static int status_cmd(const struct drbd_cmd *cm, int argc, char **argv) { struct resources_list *resources, *resource; struct sigaction sa = { .sa_handler = stop_colors, .sa_flags = SA_RESETHAND, }; bool found = false; int c; optind = 0; /* reset getopt_long() */ for (;;) { c = getopt_long(argc, argv, make_optstring(cm->options), cm->options, 0); if (c == -1) break; switch(c) { default: case '?': return 20; case 'v': opt_verbose = true; break; case 's': opt_statistics = true; break; case 'c': if (!optarg || !strcmp(optarg, "always")) opt_color = ALWAYS_COLOR; else if (!strcmp(optarg, "never")) opt_color = NEVER_COLOR; else if (!strcmp(optarg, "auto")) opt_color = AUTO_COLOR; else print_usage_and_exit("unknown --color argument"); break; } } resources = sort_resources(list_resources()); sigaction(SIGHUP, &sa, NULL); sigaction(SIGINT, &sa, NULL); sigaction(SIGPIPE, &sa, NULL); sigaction(SIGTERM, &sa, NULL); for (resource = resources; resource; resource = resource->next) { struct devices_list *devices, *device; struct connections_list *connections, *connection; struct peer_devices_list *peer_devices = NULL; bool single_device; if (strcmp(objname, "all") && strcmp(objname, resource->name)) continue; devices = list_devices(resource->name); connections = sort_connections(list_connections(resource->name)); if (devices && connections) peer_devices = list_peer_devices(resource->name); link_peer_devices_to_devices(peer_devices, devices); resource_status(resource); single_device = devices && !devices->next; for (device = devices; device; device = device->next) device_status(device, single_device); for (connection = connections; connection; connection = connection->next) connection_status(connection, peer_devices, single_device); wrap_printf(0, "\n"); free_connections(connections); free_devices(devices); free_peer_devices(peer_devices); found = true; } free_resources(resources); if (!found && strcmp(objname, "all")) { fprintf(stderr, "%s: No such resource\n", objname); return 10; } return 0; } static int event_key(char *key, int size, const char *name, unsigned minor, struct drbd_cfg_context *ctx) { int ret, pos = 0; ret = snprintf(key + pos, size, "%s", name); if (ret < 0) return ret; pos += ret; if (size) size -= ret; if (ctx->ctx_resource_name) { ret = snprintf(key + pos, size, " name:%s", ctx->ctx_resource_name); if (ret < 0) return ret; pos += ret; if (size) size -= ret; } /* Always use "peer" as connection name, * and print it if ctx has peer address set. * Do not show IP address pairs */ if (ctx->ctx_peer_addr_len) { ret = snprintf(key + pos, size, " conn-name:%s", "peer"); if (ret < 0) return ret; pos += ret; if (size) size -= ret; } if (ctx->ctx_volume != -1U) { ret = snprintf(key + pos, size, " volume:%u", ctx->ctx_volume); if (ret < 0) return ret; pos += ret; if (size) size -= ret; } if (minor != -1U) { ret = snprintf(key + pos, size, " minor:%u", minor); if (ret < 0) return ret; pos += ret; /* if (size) */ /* size -= ret; */ } return pos; } static int known_objects_cmp(const void *a, const void *b) { return strcmp(((const struct entry *)a)->key, ((const struct entry *)b)->key); } static void *update_info(char **key, void *value, size_t size) { static void *known_objects; struct entry entry = { .key = *key }, **found; if (value) { void *old_value = NULL; found = tsearch(&entry, &known_objects, known_objects_cmp); if (*found != &entry) old_value = (*found)->data; else { *found = malloc(sizeof(**found)); if (!*found) goto fail; (*found)->key = *key; *key = NULL; } (*found)->data = malloc(size); if (!(*found)->data) goto fail; memcpy((*found)->data, value, size); return old_value; } else { found = tfind(&entry, &known_objects, known_objects_cmp); if (found) { struct entry *entry = *found; tdelete(entry, &known_objects, known_objects_cmp); free(entry->data); free(entry->key); free(entry); } return NULL; } fail: perror(progname); exit(20); } static int print_notifications(const struct drbd_cmd *cm, struct genl_info *info, void *u_ptr) { static const char *action_name[] = { [NOTIFY_EXISTS] = "exists", [NOTIFY_CREATE] = "create", [NOTIFY_CHANGE] = "change", [NOTIFY_DESTROY] = "destroy", [NOTIFY_CALL] = "call", [NOTIFY_RESPONSE] = "response", }; static char *object_name[] = { [DRBD_RESOURCE_STATE] = "resource", [DRBD_DEVICE_STATE] = "device", [DRBD_CONNECTION_STATE] = "connection", [DRBD_PEER_DEVICE_STATE] = "peer-device", [DRBD_HELPER] = "helper", }; static uint32_t last_seq; static bool last_seq_known; static struct timeval tv; static bool keep_tv; struct drbd_cfg_context ctx = { .ctx_volume = -1U }; struct drbd_notification_header nh = { .nh_type = -1U }; enum drbd_notification_type action; struct drbd_genlmsghdr *dh; char *key = NULL; if (!info) { keep_tv = false; return 0; } dh = info->userhdr; if (dh->ret_code == ERR_MINOR_INVALID && cm->missing_ok) return 0; if (dh->ret_code != NO_ERROR) return dh->ret_code; if (drbd_notification_header_from_attrs(&nh, info)) return 0; action = nh.nh_type & ~NOTIFY_FLAGS; if (action >= ARRAY_SIZE(action_name) || !action_name[action]) { dbg(1, "unknown notification type\n"); goto out; } if (opt_now && action != NOTIFY_EXISTS) return 0; if (info->genlhdr->cmd != DRBD_INITIAL_STATE_DONE) { if (drbd_cfg_context_from_attrs(&ctx, info)) return 0; if (info->genlhdr->cmd >= ARRAY_SIZE(object_name) || !object_name[info->genlhdr->cmd]) { dbg(1, "unknown notification\n"); goto out; } } if (action != NOTIFY_EXISTS) { if (last_seq_known) { int skipped = info->nlhdr->nlmsg_seq - (last_seq + 1); if (skipped) printf("- skipped %d\n", skipped); } last_seq = info->nlhdr->nlmsg_seq; last_seq_known = true; } if (opt_timestamps) { struct tm *tm; if (!keep_tv) gettimeofday(&tv, NULL); keep_tv = !!(nh.nh_type & NOTIFY_CONTINUES); tm = localtime(&tv.tv_sec); printf("%04u-%02u-%02uT%02u:%02u:%02u.%06u%+03d:%02u ", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)tv.tv_usec, (int)(tm->tm_gmtoff / 3600), (int)((abs(tm->tm_gmtoff) / 60) % 60)); } if (info->genlhdr->cmd != DRBD_INITIAL_STATE_DONE) { const char *name = object_name[info->genlhdr->cmd]; int size; size = event_key(NULL, 0, name, dh->minor, &ctx); if (size < 0) goto fail; key = malloc(size + 1); if (!key) goto fail; event_key(key, size + 1, name, dh->minor, &ctx); } printf("%s %s", action_name[action], key ? key : "-"); switch(info->genlhdr->cmd) { case DRBD_RESOURCE_STATE: if (action != NOTIFY_DESTROY) { struct { struct resource_info i; struct resource_statistics s; } *old, new; if (resource_info_from_attrs(&new.i, info)) { dbg(1, "resource info missing\n"); goto nl_out; } old = update_info(&key, &new, sizeof(new)); if (!old || new.i.res_role != old->i.res_role) printf(" role:%s", drbd_role_str(new.i.res_role)); if (!old || new.i.res_susp != old->i.res_susp || new.i.res_susp_nod != old->i.res_susp_nod || new.i.res_susp_fen != old->i.res_susp_fen) printf(" suspended:%s", susp_str(&new.i)); if (opt_statistics) { if (resource_statistics_from_attrs(&new.s, info)) { dbg(1, "resource statistics missing\n"); if (old) new.s = old->s; } else print_resource_statistics(0, old ? &old->s : NULL, &new.s, nowrap_printf); } free(old); } else update_info(&key, NULL, 0); break; case DRBD_DEVICE_STATE: if (action != NOTIFY_DESTROY) { struct { struct device_info i; struct device_statistics s; } *old, new; if (device_info_from_attrs(&new.i, info)) { dbg(1, "device info missing\n"); goto nl_out; } old = update_info(&key, &new, sizeof(new)); if (!old || new.i.dev_disk_state != old->i.dev_disk_state) printf(" disk:%s", drbd_disk_str(new.i.dev_disk_state)); if (opt_statistics) { if (device_statistics_from_attrs(&new.s, info)) { dbg(1, "device statistics missing\n"); if (old) new.s = old->s; } else print_device_statistics(0, old ? &old->s : NULL, &new.s, nowrap_printf); } free(old); } else update_info(&key, NULL, 0); break; case DRBD_CONNECTION_STATE: if (action != NOTIFY_DESTROY) { struct { struct connection_info i; struct connection_statistics s; } *old, new; if (connection_info_from_attrs(&new.i, info)) { dbg(1, "connection info missing\n"); goto nl_out; } old = update_info(&key, &new, sizeof(new)); if (!old || new.i.conn_connection_state != old->i.conn_connection_state) printf(" connection:%s", drbd_conn_str9(new.i.conn_connection_state)); if (!old || new.i.conn_role != old->i.conn_role) printf(" role:%s", drbd_role_str(new.i.conn_role)); if (opt_statistics) { if (connection_statistics_from_attrs(&new.s, info)) { dbg(1, "connection statistics missing\n"); if (old) new.s = old->s; } else print_connection_statistics(0, old ? &old->s : NULL, &new.s, nowrap_printf); } free(old); } else update_info(&key, NULL, 0); break; case DRBD_PEER_DEVICE_STATE: if (action != NOTIFY_DESTROY) { struct { struct peer_device_info i; struct peer_device_statistics s; } *old, new; if (peer_device_info_from_attrs(&new.i, info)) { dbg(1, "peer device info missing\n"); goto nl_out; } old = update_info(&key, &new, sizeof(new)); if (!old || new.i.peer_repl_state != old->i.peer_repl_state) printf(" replication:%s", drbd_repl_str9(new.i.peer_repl_state)); if (!old || new.i.peer_disk_state != old->i.peer_disk_state) printf(" peer-disk:%s", drbd_disk_str(new.i.peer_disk_state)); if (!old || new.i.peer_resync_susp_user != old->i.peer_resync_susp_user || new.i.peer_resync_susp_peer != old->i.peer_resync_susp_peer || new.i.peer_resync_susp_dependency != old->i.peer_resync_susp_dependency) printf(" resync-suspended:%s", resync_susp_str(&new.i)); if (opt_statistics) { if (peer_device_statistics_from_attrs(&new.s, info)) { dbg(1, "peer device statistics missing\n"); if (old) new.s = old->s; } else print_peer_device_statistics(0, old ? &old->s : NULL, &new.s, nowrap_printf); } free(old); } else update_info(&key, NULL, 0); break; case DRBD_HELPER: { struct drbd_helper_info helper_info; if (!drbd_helper_info_from_attrs(&helper_info, info)) { printf(" helper:%s", helper_info.helper_name); if (action == NOTIFY_RESPONSE) printf(" status:%u", helper_info.helper_status); } else { dbg(1, "helper info missing\n"); goto nl_out; } } break; case DRBD_INITIAL_STATE_DONE: break; } nl_out: printf("\n"); out: free(key); fflush(stdout); if (opt_now && info->genlhdr->cmd == DRBD_INITIAL_STATE_DONE) return -1; return 0; fail: perror(progname); exit(20); } /* printf format for minor, resource name, volume */ #define MNV_FMT "%d,%s[%d]" static void print_state(char *tag, unsigned seq, unsigned minor, const char *resource_name, unsigned vnr, __u32 state_i) { union drbd_state s = { .i = state_i }; printf("%u %s " MNV_FMT " { cs:%s ro:%s/%s ds:%s/%s %c%c%c%c }\n", seq, tag, minor, resource_name, vnr, drbd_conn_str(s.conn), drbd_role_str(s.role), drbd_role_str(s.peer), drbd_disk_str(s.disk), drbd_disk_str(s.pdsk), s.susp ? 's' : 'r', s.aftr_isp ? 'a' : '-', s.peer_isp ? 'p' : '-', s.user_isp ? 'u' : '-' ); } static int print_broadcast_events(const struct drbd_cmd *cm, struct genl_info *info, void *u_ptr) { struct drbd_cfg_context cfg = { .ctx_volume = -1U }; struct state_info si = { .current_state = 0 }; struct disk_conf dc = { .disk_size = 0, }; struct net_conf nc = { .timeout = 0, }; struct drbd_genlmsghdr *dh; /* End of initial dump. Ignore. Maybe: print some marker? */ if (!info) return 0; dh = info->userhdr; if (dh->ret_code == ERR_MINOR_INVALID && cm->missing_ok) return 0; if (drbd_cfg_context_from_attrs(&cfg, info)) { dbg(1, "unexpected packet, configuration context missing!\n"); /* keep running anyways. */ struct nlattr *nla = NULL; if (info->attrs[DRBD_NLA_CFG_REPLY]) nla = drbd_nla_find_nested(ARRAY_SIZE(drbd_cfg_reply_nl_policy) - 1, info->attrs[DRBD_NLA_CFG_REPLY], T_info_text); if (nla) { char *txt = nla_data(nla); char *c; for (c = txt; *c; c++) if (*c == '\n') *c = '_'; printf("%u # %s\n", info->seq, txt); } goto out; } if (state_info_from_attrs(&si, info)) { /* this is a DRBD_ADM_GET_STATUS reply * with information about a resource without any volumes */ printf("%u R - %s\n", info->seq, cfg.ctx_resource_name); goto out; } disk_conf_from_attrs(&dc, info); net_conf_from_attrs(&nc, info); switch (si.sib_reason) { case SIB_STATE_CHANGE: print_state("ST-prev", info->seq, dh->minor, cfg.ctx_resource_name, cfg.ctx_volume, si.prev_state); print_state("ST-new", info->seq, dh->minor, cfg.ctx_resource_name, cfg.ctx_volume, si.new_state); /* fall through */ case SIB_GET_STATUS_REPLY: print_state("ST", info->seq, dh->minor, cfg.ctx_resource_name, cfg.ctx_volume, si.current_state); break; case SIB_HELPER_PRE: printf("%u UH " MNV_FMT " %s\n", info->seq, dh->minor, cfg.ctx_resource_name, cfg.ctx_volume, si.helper); break; case SIB_HELPER_POST: printf("%u UH-post " MNV_FMT " %s 0x%04x\n", info->seq, dh->minor, cfg.ctx_resource_name, cfg.ctx_volume, si.helper, si.helper_exit_code); break; case SIB_SYNC_PROGRESS: { uint32_t shift = si.bits_rs_total >= (1ULL << 32) ? 16 : 10; uint64_t left = (si.bits_oos - si.bits_rs_failed) >> shift; uint64_t total = 1UL + (si.bits_rs_total >> shift); uint64_t tmp = 1000UL - left * 1000UL/total; unsigned synced = tmp; printf("%u SP " MNV_FMT " %i.%i\n", info->seq, dh->minor, cfg.ctx_resource_name, cfg.ctx_volume, synced / 10, synced % 10); } break; default: /* we could add the si.reason */ printf("%u ?? " MNV_FMT " \n", info->seq, dh->minor, cfg.ctx_resource_name, cfg.ctx_volume, si.sib_reason); break; } out: fflush(stdout); return 0; } static int w_connected_state(const struct drbd_cmd *cm, struct genl_info *info, void *u_ptr) { struct state_info si = { .current_state = 0 }; union drbd_state state; if (!info) return 0; if (!global_attrs[DRBD_NLA_STATE_INFO]) return 0; if (state_info_from_attrs(&si, info)) { fprintf(stderr,"nla_policy violation!?\n"); return 0; } if (si.sib_reason != SIB_STATE_CHANGE && si.sib_reason != SIB_GET_STATUS_REPLY) return 0; state.i = si.current_state; if (state.conn >= C_CONNECTED) return -1; /* done waiting */ if (state.conn < C_UNCONNECTED) { struct drbd_genlmsghdr *dhdr = info->userhdr; struct drbd_cfg_context cfg = { .ctx_volume = -1U }; if (!wait_after_split_brain) return -1; /* done waiting */ drbd_cfg_context_from_attrs(&cfg, info); fprintf(stderr, "\ndrbd%u (%s[%u]) is %s, " "but I'm configured to wait anways (--wait-after-sb)\n", dhdr->minor, cfg.ctx_resource_name, cfg.ctx_volume, drbd_conn_str(state.conn)); } return 0; } static int w_synced_state(const struct drbd_cmd *cm, struct genl_info *info, void *u_ptr) { struct state_info si = { .current_state = 0 }; union drbd_state state; if (!info) return 0; if (!global_attrs[DRBD_NLA_STATE_INFO]) return 0; if (state_info_from_attrs(&si, info)) { fprintf(stderr,"nla_policy violation!?\n"); return 0; } if (si.sib_reason != SIB_STATE_CHANGE && si.sib_reason != SIB_GET_STATUS_REPLY) return 0; state.i = si.current_state; if (state.conn == C_CONNECTED) return -1; /* done waiting */ if (!wait_after_split_brain && state.conn < C_UNCONNECTED) return -1; /* done waiting */ return 0; } /* * Check if an integer is a power of two. */ static bool power_of_two(int i) { return i && !(i & (i - 1)); } static void print_command_usage(const struct drbd_cmd *cm, enum usage_type ut) { struct drbd_argument *args; if(ut == XML) { enum cfg_ctx_key ctx = cm->ctx_key; printf("\n", cm->cmd); if (ctx & CTX_RESOURCE_AND_CONNECTION) ctx = CTX_RESOURCE | CTX_CONNECTION; if (ctx & (CTX_RESOURCE | CTX_MINOR | CTX_ALL)) { bool more_than_one_choice = !power_of_two(ctx & (CTX_RESOURCE | CTX_MINOR | CTX_ALL)); const char *indent = "\t\t" + !more_than_one_choice; if (more_than_one_choice) printf("\t\n"); if (ctx & CTX_RESOURCE) printf("%sresource\n", indent); if (ctx & CTX_MINOR) printf("%sminor\n", indent); if (ctx & CTX_ALL) printf("%sall\n", indent); if (more_than_one_choice) printf("\t\n"); } if (ctx & CTX_CONNECTION) { printf("\tlocal_addr\n"); printf("\tremote_addr\n"); } if(cm->drbd_args) { for (args = cm->drbd_args; args->name; args++) { printf("\t%s\n", args->name); } } if (cm->options) { struct option *option; for (option = cm->options; option->name; option++) { /* * The "string" options here really are * timeouts, but we can't describe them * in a resonable way here. */ printf("\t\n", option->name, option->has_arg == no_argument ? "flag" : "string"); } } if (cm->set_defaults) printf("\t\n"); if (cm->ctx) { struct field_def *field; for (field = cm->ctx->fields; field->name; field++) field->describe_xml(field); } printf("\n"); return; } if (ut == BRIEF) wrap_printf(4, "%-18s ", cm->cmd); else { wrap_printf(0, "USAGE:\n"); wrap_printf(1, "%s %s", progname, cm->cmd); if (cm->ctx_key && ut != BRIEF) { enum cfg_ctx_key ctx = cm->ctx_key; if (ctx & CTX_RESOURCE_AND_CONNECTION) ctx = CTX_RESOURCE | CTX_CONNECTION; if (ctx & (CTX_RESOURCE | CTX_MINOR | CTX_ALL)) { bool first = true; wrap_printf(4, " {"); if (ctx & CTX_RESOURCE) { wrap_printf(4, "%s", "|resource" + first); first = false; } if (ctx & CTX_MINOR) { wrap_printf(4, "%s", "|minor" + first); first = false; } if (ctx & CTX_ALL) { wrap_printf(4, "%s", "|all" + first); first = false; } wrap_printf(4, "}"); } if (ctx & CTX_CONNECTION) { wrap_printf(4, " [{af}:]{local_addr}[:{port}]"); wrap_printf(4, " [{af}:]{remote_addr}[:{port}]"); } } if (cm->drbd_args) { for (args = cm->drbd_args; args->name; args++) wrap_printf(4, " {%s}", args->name); } if (cm->options) { struct option *option; for (option = cm->options; option->name; option++) wrap_printf(4, " [--%s%s]", option->name, option->has_arg == no_argument ? "" : "=..."); } if (cm->set_defaults) wrap_printf(4, " [--set-defaults]"); if (cm->ctx) { struct field_def *field; for (field = cm->ctx->fields; field->name; field++) { char buffer[300]; int n; n = field->usage(field, buffer, sizeof(buffer)); assert(n < sizeof(buffer)); wrap_printf(4, " %s", buffer); } } wrap_printf(4, "\n"); } } static void print_usage_and_exit(const char* addinfo) { size_t i; printf("\nUSAGE: %s command device arguments options\n\n" "Device is usually /dev/drbdX or /dev/drbd/X.\n" "\nCommands are:\n",cmdname); for (i = 0; i < ARRAY_SIZE(commands); i++) print_command_usage(&commands[i], BRIEF); printf("\n\n" "To get more details about a command issue " "'drbdsetup help cmd'.\n" "\n"); /* printf("\n\nVersion: "PACKAGE_VERSION" (api:%d)\n%s\n", API_VERSION, drbd_buildtag()); */ if (addinfo) printf("\n%s\n",addinfo); exit(20); } static int modprobe_drbd(void) { struct stat sb; int ret, retries = 10; ret = stat("/proc/drbd", &sb); if (ret && errno == ENOENT && 0 == system("/sbin/modprobe drbd")) { for(;;) { struct timespec ts = { .tv_nsec = 1000000, }; ret = stat("/proc/drbd", &sb); if (!ret || retries-- == 0) break; nanosleep(&ts, NULL); } } if (ret) { fprintf(stderr, "Could not stat /proc/drbd: %m\n"); fprintf(stderr, "Make sure that the DRBD kernel module is installed " "and can be loaded!\n"); } return ret == 0; } void exec_legacy_drbdsetup(char **argv) { #ifdef DRBD_LEGACY_83 static const char * const legacy_drbdsetup = "drbdsetup-83"; char *progname, *drbdsetup; /* in case drbdsetup is called with an absolute or relative pathname * look for the v83 drbdsetup binary in the same location, * otherwise, just let execvp sort it out... */ if ((progname = strrchr(argv[0], '/')) == 0) { drbdsetup = strdup(legacy_drbdsetup); } else { size_t len_dir, l; ++progname; len_dir = progname - argv[0]; l = len_dir + strlen(legacy_drbdsetup) + 1; drbdsetup = malloc(l); if (!drbdsetup) { fprintf(stderr, "Malloc() failed\n"); exit(20); } strncpy(drbdsetup, argv[0], len_dir); strcpy(drbdsetup + len_dir, legacy_drbdsetup); } execvp(drbdsetup, argv); #else fprintf(stderr, "This drbdsetup was not built with support for drbd-8.3\n" "Consider to rebuild with ./configure --with-83-support\n"); #endif } int main(int argc, char **argv) { const struct drbd_cmd *cmd; struct option *options; int c, rv = 0; int longindex, first_optind; progname = basename(argv[0]); if (chdir("/")) { /* highly unlikely, but gcc is picky */ perror("cannot chdir /"); return -111; } cmdname = strrchr(argv[0],'/'); if (cmdname) argv[0] = ++cmdname; else cmdname = argv[0]; if (argc > 2 && (!strcmp(argv[2], "--help") || !strcmp(argv[2], "-h"))) { char *swap = argv[1]; argv[1] = argv[2]; argv[2] = swap; } if (argc > 1 && (!strcmp(argv[1], "help") || !strcmp(argv[1], "xml-help") || !strcmp(argv[1], "--help") || !strcmp(argv[1], "-h"))) { enum usage_type usage_type = !strcmp(argv[1], "xml-help") ? XML : FULL; if(argc > 2) { cmd = find_cmd_by_name(argv[2]); if(cmd) { print_command_usage(cmd, usage_type); exit(0); } else print_usage_and_exit("unknown command"); } else print_usage_and_exit(0); } /* * drbdsetup previously took the object to operate on as its first argument, * followed by the command. For backwards compatibility, still support his. */ if (argc >= 3 && !find_cmd_by_name(argv[1]) && find_cmd_by_name(argv[2])) { char *swap = argv[1]; argv[1] = argv[2]; argv[2] = swap; } if (argc < 2) print_usage_and_exit(0); cmd = find_cmd_by_name(argv[1]); if (!cmd) print_usage_and_exit("invalid command"); if (!modprobe_drbd()) { if (!strcmp(argv[0], "down") || !strcmp(argv[0], "secondary") || !strcmp(argv[0], "disconnect") || !strcmp(argv[0], "detach")) return 0; /* "down" succeeds even if drbd is missing */ return 20; } if (try_genl) { if (cmd->continuous_poll && kernel_older_than(2, 6, 23)) drbd_genl_family.nl_groups = -1; drbd_sock = genl_connect_to_family(&drbd_genl_family); if (!drbd_sock) { try_genl = 0; exec_legacy_drbdsetup(argv); /* Only reached in case exec() failed... */ fprintf(stderr, "Could not connect to 'drbd' generic netlink family\n"); return 20; } if (drbd_genl_family.version != API_VERSION || drbd_genl_family.hdrsize != sizeof(struct drbd_genlmsghdr)) { fprintf(stderr, "API mismatch!\n\t" "API version drbdsetup: %u kernel: %u\n\t" "header size drbdsetup: %u kernel: %u\n", API_VERSION, drbd_genl_family.version, (unsigned)sizeof(struct drbd_genlmsghdr), drbd_genl_family.hdrsize); return 20; } } /* Make argv[0] the command name so that getopt_long() will leave it in * the first position. */ argv++; argc--; options = make_longoptions(cmd); for (;;) { c = getopt_long(argc, argv, "(", options, &longindex); if (c == -1) break; if (c == '?' || c == ':') print_usage_and_exit(0); } /* All non-option arguments now are in argv[optind .. argc - 1]. */ first_optind = optind; context = 0; if (cmd->ctx_key & (CTX_MINOR | CTX_RESOURCE | CTX_ALL | CTX_RESOURCE_AND_CONNECTION)) { if (argc == optind && !(cmd->ctx_key & (CTX_RESOURCE_AND_CONNECTION | CTX_CONNECTION)) && (cmd->ctx_key & CTX_ALL)) { context |= CTX_ALL; /* assume "all" if no argument is given */ objname = "all"; } else { if (argc <= optind) { fprintf(stderr, "Missing first argument\n"); print_command_usage(cmd, FULL); exit(20); } objname = argv[optind++]; ensure_sanity_of_res_name(objname); if (!strcmp(objname, "all")) { if (!(cmd->ctx_key & CTX_ALL)) print_usage_and_exit("command does not accept argument 'all'"); context = CTX_ALL; } else if (cmd->ctx_key & CTX_MINOR) { minor = dt_minor_of_dev(objname); if (minor != -1U) context = CTX_MINOR; else if (!(cmd->ctx_key & (CTX_RESOURCE | CTX_RESOURCE_AND_CONNECTION))) { fprintf(stderr, "Cannot determine minor device number of " "device '%s'\n", objname); exit(20); } } /* It could have been "all", but was not. * It could have been a minor number (or device node name), but was not. * So it has to be a resource, * or a resource and possibly connection specification. * (CTX_CONNECTION alone will not enter this branch). */ if (!context) context = CTX_RESOURCE; } } if (cmd->ctx_key & (CTX_CONNECTION | CTX_RESOURCE_AND_CONNECTION)) { if (argc <= optind + 1) { fprintf(stderr, "Missing connection endpoint argument\n"); print_command_usage(cmd, FULL); exit(20); } opt_local_addr = argv[optind++]; opt_peer_addr = argv[optind++]; context |= CTX_CONNECTION; } /* Remove the options we have already processed from argv */ if (first_optind != optind) { int n; for (n = 0; n < argc - optind; n++) argv[first_optind + n] = argv[optind + n]; argc -= optind - first_optind; } if (objname == NULL) objname = "??"; if ((context & CTX_MINOR) && !cmd->lockless) lock_fd = dt_lock_drbd(minor); rv = cmd->function(cmd, argc, argv); if ((context & CTX_MINOR) && !cmd->lockless) dt_unlock_drbd(lock_fd); return rv; } #endif drbd-utils-8.9.6/user/v84/linux/0000755000175000017500000000000012654475367016264 5ustar apoikosapoikosdrbd-utils-8.9.6/user/v84/linux/genl_magic_func.h0000644000175000017500000003027012466702074021524 0ustar apoikosapoikos#ifndef GENL_MAGIC_FUNC_H #define GENL_MAGIC_FUNC_H #include /* * Magic: declare tla policy {{{1 * Magic: declare nested policies * {{{2 */ #undef GENL_mc_group #define GENL_mc_group(group) #undef GENL_notification #define GENL_notification(op_name, op_num, mcast_group, tla_list) #undef GENL_op #define GENL_op(op_name, op_num, handler, tla_list) #undef GENL_struct #define GENL_struct(tag_name, tag_number, s_name, s_fields) \ [tag_name] = { .type = NLA_NESTED }, static struct nla_policy CONCAT_(GENL_MAGIC_FAMILY, _tla_nl_policy)[] \ __attribute__((unused)) = { #include GENL_MAGIC_INCLUDE_FILE }; #undef GENL_struct #define GENL_struct(tag_name, tag_number, s_name, s_fields) \ static struct nla_policy s_name ## _nl_policy[] __read_mostly = \ { s_fields }; #undef __field #define __field(attr_nr, attr_flag, name, nla_type, _type, __get, \ __put, __is_signed) \ [attr_nr] = { .type = nla_type }, #undef __array #define __array(attr_nr, attr_flag, name, nla_type, _type, maxlen, \ __get, __put, __is_signed) \ [attr_nr] = { .type = nla_type, \ .len = maxlen - (nla_type == NLA_NUL_STRING) }, #include GENL_MAGIC_INCLUDE_FILE #ifndef __KERNEL__ #ifndef pr_info #define pr_info(args...) fprintf(stderr, args); #endif #endif #ifdef GENL_MAGIC_DEBUG static void dprint_field(const char *dir, int nla_type, const char *name, void *valp) { __u64 val = valp ? *(__u32 *)valp : 1; switch (nla_type) { case NLA_U8: val = (__u8)val; case NLA_U16: val = (__u16)val; case NLA_U32: val = (__u32)val; pr_info("%s attr %s: %d 0x%08x\n", dir, name, (int)val, (unsigned)val); break; case NLA_U64: val = *(__u64*)valp; pr_info("%s attr %s: %lld 0x%08llx\n", dir, name, (long long)val, (unsigned long long)val); break; case NLA_FLAG: if (val) pr_info("%s attr %s: set\n", dir, name); break; } } static void dprint_array(const char *dir, int nla_type, const char *name, const char *val, unsigned len) { switch (nla_type) { case NLA_NUL_STRING: if (len && val[len-1] == '\0') len--; pr_info("%s attr %s: [len:%u] '%s'\n", dir, name, len, val); break; default: /* we can always show 4 byte, * thats what nlattr are aligned to. */ pr_info("%s attr %s: [len:%u] %02x%02x%02x%02x ...\n", dir, name, len, val[0], val[1], val[2], val[3]); } } #define DPRINT_TLA(a, op, b) pr_info("%s %s %s\n", a, op, b); /* Name is a member field name of the struct s. * If s is NULL (only parsing, no copy requested in *_from_attrs()), * nla is supposed to point to the attribute containing the information * corresponding to that struct member. */ #define DPRINT_FIELD(dir, nla_type, name, s, nla) \ do { \ if (s) \ dprint_field(dir, nla_type, #name, &s->name); \ else if (nla) \ dprint_field(dir, nla_type, #name, \ (nla_type == NLA_FLAG) ? NULL \ : nla_data(nla)); \ } while (0) #define DPRINT_ARRAY(dir, nla_type, name, s, nla) \ do { \ if (s) \ dprint_array(dir, nla_type, #name, \ s->name, s->name ## _len); \ else if (nla) \ dprint_array(dir, nla_type, #name, \ nla_data(nla), nla_len(nla)); \ } while (0) #else #define DPRINT_TLA(a, op, b) do {} while (0) #define DPRINT_FIELD(dir, nla_type, name, s, nla) do {} while (0) #define DPRINT_ARRAY(dir, nla_type, name, s, nla) do {} while (0) #endif /* * Magic: provide conversion functions {{{1 * populate struct from attribute table: * {{{2 */ /* processing of generic netlink messages is serialized. * use one static buffer for parsing of nested attributes */ static struct nlattr *nested_attr_tb[128]; #ifndef BUILD_BUG_ON /* Force a compilation error if condition is true */ #define BUILD_BUG_ON(condition) ((void)BUILD_BUG_ON_ZERO(condition)) /* Force a compilation error if condition is true, but also produce a result (of value 0 and type size_t), so the expression can be used e.g. in a structure initializer (or where-ever else comma expressions aren't permitted). */ #define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); })) #define BUILD_BUG_ON_NULL(e) ((void *)sizeof(struct { int:-!!(e); })) #endif #undef GENL_struct #define GENL_struct(tag_name, tag_number, s_name, s_fields) \ static int __ ## s_name ## _from_attrs(struct s_name *s, \ struct genl_info *info, bool exclude_invariants) \ { \ const int maxtype = ARRAY_SIZE(s_name ## _nl_policy)-1; \ struct nlattr *tla = info->attrs[tag_number]; \ struct nlattr **ntb = nested_attr_tb; \ struct nlattr *nla; \ int err; \ BUILD_BUG_ON(ARRAY_SIZE(s_name ## _nl_policy) > ARRAY_SIZE(nested_attr_tb)); \ if (!tla) \ return -ENOMSG; \ DPRINT_TLA(#s_name, "<=-", #tag_name); \ err = drbd_nla_parse_nested(ntb, maxtype, tla, s_name ## _nl_policy); \ if (err) \ return err; \ \ s_fields \ return 0; \ } __attribute__((unused)) \ static int s_name ## _from_attrs(struct s_name *s, \ struct genl_info *info) \ { \ return __ ## s_name ## _from_attrs(s, info, false); \ } __attribute__((unused)) \ static int s_name ## _from_attrs_for_change(struct s_name *s, \ struct genl_info *info) \ { \ return __ ## s_name ## _from_attrs(s, info, true); \ } __attribute__((unused)) \ #define __assign(attr_nr, attr_flag, name, nla_type, type, assignment...) \ nla = ntb[attr_nr]; \ if (nla) { \ if (exclude_invariants && ((attr_flag) & DRBD_F_INVARIANT)) { \ pr_info("<< must not change invariant attr: %s\n", #name); \ return -EEXIST; \ } \ assignment; \ } else if (exclude_invariants && ((attr_flag) & DRBD_F_INVARIANT)) { \ /* attribute missing from payload, */ \ /* which was expected */ \ } else if ((attr_flag) & DRBD_F_REQUIRED) { \ pr_info("<< missing attr: %s\n", #name); \ return -ENOMSG; \ } #undef __field #define __field(attr_nr, attr_flag, name, nla_type, type, __get, __put, \ __is_signed) \ __assign(attr_nr, attr_flag, name, nla_type, type, \ if (s) \ s->name = __get(nla); \ DPRINT_FIELD("<<", nla_type, name, s, nla)) /* validate_nla() already checked nla_len <= maxlen appropriately. */ #undef __array #define __array(attr_nr, attr_flag, name, nla_type, type, maxlen, \ __get, __put, __is_signed) \ __assign(attr_nr, attr_flag, name, nla_type, type, \ if (s) \ s->name ## _len = \ __get(s->name, nla, maxlen); \ DPRINT_ARRAY("<<", nla_type, name, s, nla)) #include GENL_MAGIC_INCLUDE_FILE #undef GENL_struct #define GENL_struct(tag_name, tag_number, s_name, s_fields) /* * Magic: define op number to op name mapping {{{1 * {{{2 */ static const char *CONCAT_(GENL_MAGIC_FAMILY, _genl_cmd_to_str)(__u8 cmd) __attribute__ ((unused)); static const char *CONCAT_(GENL_MAGIC_FAMILY, _genl_cmd_to_str)(__u8 cmd) { switch (cmd) { #undef GENL_op #define GENL_op(op_name, op_num, handler, tla_list) \ case op_num: return #op_name; #include GENL_MAGIC_INCLUDE_FILE default: return "unknown"; } } #ifdef __KERNEL__ #include /* * Magic: define genl_ops {{{1 * {{{2 */ #undef GENL_op #define GENL_op(op_name, op_num, handler, tla_list) \ { \ handler \ .cmd = op_name, \ .policy = CONCAT_(GENL_MAGIC_FAMILY, _tla_nl_policy), \ }, #define ZZZ_genl_ops CONCAT_(GENL_MAGIC_FAMILY, _genl_ops) static struct genl_ops ZZZ_genl_ops[] __read_mostly = { #include GENL_MAGIC_INCLUDE_FILE }; #undef GENL_op #define GENL_op(op_name, op_num, handler, tla_list) /* * Define the genl_family, multicast groups, {{{1 * and provide register/unregister functions. * {{{2 */ #define ZZZ_genl_family CONCAT_(GENL_MAGIC_FAMILY, _genl_family) static struct genl_family ZZZ_genl_family __read_mostly = { .id = GENL_ID_GENERATE, .name = __stringify(GENL_MAGIC_FAMILY), .version = GENL_MAGIC_VERSION, #ifdef GENL_MAGIC_FAMILY_HDRSZ .hdrsize = NLA_ALIGN(GENL_MAGIC_FAMILY_HDRSZ), #endif .maxattr = ARRAY_SIZE(drbd_tla_nl_policy)-1, }; /* * Magic: define multicast groups * Magic: define multicast group registration helper */ #undef GENL_mc_group #define GENL_mc_group(group) \ static struct genl_multicast_group \ CONCAT_(GENL_MAGIC_FAMILY, _mcg_ ## group) __read_mostly = { \ .name = #group, \ }; \ static int CONCAT_(GENL_MAGIC_FAMILY, _genl_multicast_ ## group)( \ struct sk_buff *skb, gfp_t flags) \ { \ unsigned int group_id = \ CONCAT_(GENL_MAGIC_FAMILY, _mcg_ ## group).id; \ if (!group_id) \ return -EINVAL; \ return genlmsg_multicast(skb, 0, group_id, flags); \ } #include GENL_MAGIC_INCLUDE_FILE int CONCAT_(GENL_MAGIC_FAMILY, _genl_register)(void) { int err = genl_register_family_with_ops(&ZZZ_genl_family, ZZZ_genl_ops, ARRAY_SIZE(ZZZ_genl_ops)); if (err) return err; #undef GENL_mc_group #define GENL_mc_group(group) \ err = genl_register_mc_group(&ZZZ_genl_family, \ &CONCAT_(GENL_MAGIC_FAMILY, _mcg_ ## group)); \ if (err) \ goto fail; \ else \ pr_info("%s: mcg %s: %u\n", #group, \ __stringify(GENL_MAGIC_FAMILY), \ CONCAT_(GENL_MAGIC_FAMILY, _mcg_ ## group).id); #include GENL_MAGIC_INCLUDE_FILE #undef GENL_mc_group #define GENL_mc_group(group) return 0; fail: genl_unregister_family(&ZZZ_genl_family); return err; } void CONCAT_(GENL_MAGIC_FAMILY, _genl_unregister)(void) { genl_unregister_family(&ZZZ_genl_family); } /* * Magic: provide conversion functions {{{1 * populate skb from struct. * {{{2 */ #undef GENL_op #define GENL_op(op_name, op_num, handler, tla_list) #undef GENL_struct #define GENL_struct(tag_name, tag_number, s_name, s_fields) \ static int s_name ## _to_skb(struct sk_buff *skb, struct s_name *s, \ const bool exclude_sensitive) \ { \ struct nlattr *tla = nla_nest_start(skb, tag_number); \ if (!tla) \ goto nla_put_failure; \ DPRINT_TLA(#s_name, "-=>", #tag_name); \ s_fields \ nla_nest_end(skb, tla); \ return 0; \ \ nla_put_failure: \ if (tla) \ nla_nest_cancel(skb, tla); \ return -EMSGSIZE; \ } \ static inline int s_name ## _to_priv_skb(struct sk_buff *skb, \ struct s_name *s) \ { \ return s_name ## _to_skb(skb, s, 0); \ } \ static inline int s_name ## _to_unpriv_skb(struct sk_buff *skb, \ struct s_name *s) \ { \ return s_name ## _to_skb(skb, s, 1); \ } #undef __field #define __field(attr_nr, attr_flag, name, nla_type, type, __get, __put, \ __is_signed) \ if (!exclude_sensitive || !((attr_flag) & DRBD_F_SENSITIVE)) { \ DPRINT_FIELD(">>", nla_type, name, s, NULL); \ if (__put(skb, attr_nr, s->name)) \ goto nla_put_failure; \ } #undef __array #define __array(attr_nr, attr_flag, name, nla_type, type, maxlen, \ __get, __put, __is_signed) \ if (!exclude_sensitive || !((attr_flag) & DRBD_F_SENSITIVE)) { \ DPRINT_ARRAY(">>",nla_type, name, s, NULL); \ if (__put(skb, attr_nr, min_t(int, maxlen, \ s->name ## _len + (nla_type == NLA_NUL_STRING)),\ s->name)) \ goto nla_put_failure; \ } #include GENL_MAGIC_INCLUDE_FILE /* Functions for initializing structs to default values. */ #undef __field #define __field(attr_nr, attr_flag, name, nla_type, type, __get, __put, \ __is_signed) #undef __array #define __array(attr_nr, attr_flag, name, nla_type, type, maxlen, \ __get, __put, __is_signed) #undef __u32_field_def #define __u32_field_def(attr_nr, attr_flag, name, default) \ x->name = default; #undef __s32_field_def #define __s32_field_def(attr_nr, attr_flag, name, default) \ x->name = default; #undef __flg_field_def #define __flg_field_def(attr_nr, attr_flag, name, default) \ x->name = default; #undef __str_field_def #define __str_field_def(attr_nr, attr_flag, name, maxlen) \ memset(x->name, 0, sizeof(x->name)); \ x->name ## _len = 0; #undef GENL_struct #define GENL_struct(tag_name, tag_number, s_name, s_fields) \ static void set_ ## s_name ## _defaults(struct s_name *x) __attribute__((unused)); \ static void set_ ## s_name ## _defaults(struct s_name *x) { \ s_fields \ } #include GENL_MAGIC_INCLUDE_FILE #endif /* __KERNEL__ */ /* }}}1 */ #endif /* GENL_MAGIC_FUNC_H */ /* vim: set foldmethod=marker foldlevel=1 nofoldenable : */ drbd-utils-8.9.6/user/v84/linux/drbd_genl.h0000644000175000017500000005264712634301641020350 0ustar apoikosapoikos/* * General overview: * full generic netlink message: * |nlmsghdr|genlmsghdr| * * payload: * |optional fixed size family header| * * sequence of netlink attributes: * I chose to have all "top level" attributes NLA_NESTED, * corresponding to some real struct. * So we have a sequence of |tla, len| * * nested nla sequence: * may be empty, or contain a sequence of netlink attributes * representing the struct fields. * * The tag number of any field (regardless of containing struct) * will be available as T_ ## field_name, * so you cannot have the same field name in two differnt structs. * * The tag numbers themselves are per struct, though, * so should always begin at 1 (not 0, that is the special "NLA_UNSPEC" type, * which we won't use here). * The tag numbers are used as index in the respective nla_policy array. * * GENL_struct(tag_name, tag_number, struct name, struct fields) - struct and policy * genl_magic_struct.h * generates the struct declaration, * generates an entry in the tla enum, * genl_magic_func.h * generates an entry in the static tla policy * with .type = NLA_NESTED * generates the static _nl_policy definition, * and static conversion functions * * genl_magic_func.h * * GENL_mc_group(group) * genl_magic_struct.h * does nothing * genl_magic_func.h * defines and registers the mcast group, * and provides a send helper * * GENL_notification(op_name, op_num, mcast_group, tla list) * These are notifications to userspace. * * genl_magic_struct.h * generates an entry in the genl_ops enum, * genl_magic_func.h * does nothing * * mcast group: the name of the mcast group this notification should be * expected on * tla list: the list of expected top level attributes, * for documentation and sanity checking. * * GENL_op(op_name, op_num, flags and handler, tla list) - "genl operations" * These are requests from userspace. * * _op and _notification share the same "number space", * op_nr will be assigned to "genlmsghdr->cmd" * * genl_magic_struct.h * generates an entry in the genl_ops enum, * genl_magic_func.h * generates an entry in the static genl_ops array, * and static register/unregister functions to * genl_register_family_with_ops(). * * flags and handler: * GENL_op_init( .doit = x, .dumpit = y, .flags = something) * GENL_doit(x) => .dumpit = NULL, .flags = GENL_ADMIN_PERM * tla list: the list of expected top level attributes, * for documentation and sanity checking. */ /* * STRUCTS */ /* this is sent kernel -> userland on various error conditions, and contains * informational textual info, which is supposedly human readable. * The computer relevant return code is in the drbd_genlmsghdr. */ GENL_struct(DRBD_NLA_CFG_REPLY, 1, drbd_cfg_reply, /* "arbitrary" size strings, nla_policy.len = 0 */ __str_field(1, DRBD_GENLA_F_MANDATORY, info_text, 0) ) /* Configuration requests typically need a context to operate on. * Possible keys are device minor (fits in the drbd_genlmsghdr), * the replication link (aka connection) name, * and/or the replication group (aka resource) name, * and the volume id within the resource. */ GENL_struct(DRBD_NLA_CFG_CONTEXT, 2, drbd_cfg_context, __u32_field(1, DRBD_GENLA_F_MANDATORY, ctx_volume) __str_field(2, DRBD_GENLA_F_MANDATORY, ctx_resource_name, 128) __bin_field(3, DRBD_GENLA_F_MANDATORY, ctx_my_addr, 128) __bin_field(4, DRBD_GENLA_F_MANDATORY, ctx_peer_addr, 128) ) GENL_struct(DRBD_NLA_DISK_CONF, 3, disk_conf, __str_field(1, DRBD_F_REQUIRED | DRBD_F_INVARIANT, backing_dev, 128) __str_field(2, DRBD_F_REQUIRED | DRBD_F_INVARIANT, meta_dev, 128) __s32_field(3, DRBD_F_REQUIRED | DRBD_F_INVARIANT, meta_dev_idx) /* use the resize command to try and change the disk_size */ __u64_field(4, DRBD_GENLA_F_MANDATORY | DRBD_F_INVARIANT, disk_size) /* we could change the max_bio_bvecs, * but it won't propagate through the stack */ __u32_field(5, DRBD_GENLA_F_MANDATORY | DRBD_F_INVARIANT, max_bio_bvecs) __u32_field_def(6, DRBD_GENLA_F_MANDATORY, on_io_error, DRBD_ON_IO_ERROR_DEF) __u32_field_def(7, DRBD_GENLA_F_MANDATORY, fencing, DRBD_FENCING_DEF) __u32_field_def(8, DRBD_GENLA_F_MANDATORY, resync_rate, DRBD_RESYNC_RATE_DEF) __s32_field_def(9, DRBD_GENLA_F_MANDATORY, resync_after, DRBD_MINOR_NUMBER_DEF) __u32_field_def(10, DRBD_GENLA_F_MANDATORY, al_extents, DRBD_AL_EXTENTS_DEF) __u32_field_def(11, DRBD_GENLA_F_MANDATORY, c_plan_ahead, DRBD_C_PLAN_AHEAD_DEF) __u32_field_def(12, DRBD_GENLA_F_MANDATORY, c_delay_target, DRBD_C_DELAY_TARGET_DEF) __u32_field_def(13, DRBD_GENLA_F_MANDATORY, c_fill_target, DRBD_C_FILL_TARGET_DEF) __u32_field_def(14, DRBD_GENLA_F_MANDATORY, c_max_rate, DRBD_C_MAX_RATE_DEF) __u32_field_def(15, DRBD_GENLA_F_MANDATORY, c_min_rate, DRBD_C_MIN_RATE_DEF) __u32_field_def(20, DRBD_GENLA_F_MANDATORY, disk_timeout, DRBD_DISK_TIMEOUT_DEF) __u32_field_def(21, 0 /* OPTIONAL */, read_balancing, DRBD_READ_BALANCING_DEF) __u32_field_def(25, 0 /* OPTIONAL */, rs_discard_granularity, DRBD_RS_DISCARD_GRANULARITY_DEF) __flg_field_def(16, DRBD_GENLA_F_MANDATORY, disk_barrier, DRBD_DISK_BARRIER_DEF) __flg_field_def(17, DRBD_GENLA_F_MANDATORY, disk_flushes, DRBD_DISK_FLUSHES_DEF) __flg_field_def(18, DRBD_GENLA_F_MANDATORY, disk_drain, DRBD_DISK_DRAIN_DEF) __flg_field_def(19, DRBD_GENLA_F_MANDATORY, md_flushes, DRBD_MD_FLUSHES_DEF) __flg_field_def(23, 0 /* OPTIONAL */, al_updates, DRBD_AL_UPDATES_DEF) __flg_field_def(24, 0 /* OPTIONAL */, discard_zeroes_if_aligned, DRBD_DISCARD_ZEROES_IF_ALIGNED) ) GENL_struct(DRBD_NLA_RESOURCE_OPTS, 4, res_opts, __str_field_def(1, DRBD_GENLA_F_MANDATORY, cpu_mask, 32) __u32_field_def(2, DRBD_GENLA_F_MANDATORY, on_no_data, DRBD_ON_NO_DATA_DEF) ) GENL_struct(DRBD_NLA_NET_CONF, 5, net_conf, __str_field_def(1, DRBD_GENLA_F_MANDATORY | DRBD_F_SENSITIVE, shared_secret, SHARED_SECRET_MAX) __str_field_def(2, DRBD_GENLA_F_MANDATORY, cram_hmac_alg, SHARED_SECRET_MAX) __str_field_def(3, DRBD_GENLA_F_MANDATORY, integrity_alg, SHARED_SECRET_MAX) __str_field_def(4, DRBD_GENLA_F_MANDATORY, verify_alg, SHARED_SECRET_MAX) __str_field_def(5, DRBD_GENLA_F_MANDATORY, csums_alg, SHARED_SECRET_MAX) __u32_field_def(6, DRBD_GENLA_F_MANDATORY, wire_protocol, DRBD_PROTOCOL_DEF) __u32_field_def(7, DRBD_GENLA_F_MANDATORY, connect_int, DRBD_CONNECT_INT_DEF) __u32_field_def(8, DRBD_GENLA_F_MANDATORY, timeout, DRBD_TIMEOUT_DEF) __u32_field_def(9, DRBD_GENLA_F_MANDATORY, ping_int, DRBD_PING_INT_DEF) __u32_field_def(10, DRBD_GENLA_F_MANDATORY, ping_timeo, DRBD_PING_TIMEO_DEF) __u32_field_def(11, DRBD_GENLA_F_MANDATORY, sndbuf_size, DRBD_SNDBUF_SIZE_DEF) __u32_field_def(12, DRBD_GENLA_F_MANDATORY, rcvbuf_size, DRBD_RCVBUF_SIZE_DEF) __u32_field_def(13, DRBD_GENLA_F_MANDATORY, ko_count, DRBD_KO_COUNT_DEF) __u32_field_def(14, DRBD_GENLA_F_MANDATORY, max_buffers, DRBD_MAX_BUFFERS_DEF) __u32_field_def(15, DRBD_GENLA_F_MANDATORY, max_epoch_size, DRBD_MAX_EPOCH_SIZE_DEF) __u32_field_def(16, DRBD_GENLA_F_MANDATORY, unplug_watermark, DRBD_UNPLUG_WATERMARK_DEF) __u32_field_def(17, DRBD_GENLA_F_MANDATORY, after_sb_0p, DRBD_AFTER_SB_0P_DEF) __u32_field_def(18, DRBD_GENLA_F_MANDATORY, after_sb_1p, DRBD_AFTER_SB_1P_DEF) __u32_field_def(19, DRBD_GENLA_F_MANDATORY, after_sb_2p, DRBD_AFTER_SB_2P_DEF) __u32_field_def(20, DRBD_GENLA_F_MANDATORY, rr_conflict, DRBD_RR_CONFLICT_DEF) __u32_field_def(21, DRBD_GENLA_F_MANDATORY, on_congestion, DRBD_ON_CONGESTION_DEF) __u32_field_def(22, DRBD_GENLA_F_MANDATORY, cong_fill, DRBD_CONG_FILL_DEF) __u32_field_def(23, DRBD_GENLA_F_MANDATORY, cong_extents, DRBD_CONG_EXTENTS_DEF) __flg_field_def(24, DRBD_GENLA_F_MANDATORY, two_primaries, DRBD_ALLOW_TWO_PRIMARIES_DEF) __flg_field(25, DRBD_GENLA_F_MANDATORY | DRBD_F_INVARIANT, discard_my_data) __flg_field_def(26, DRBD_GENLA_F_MANDATORY, tcp_cork, DRBD_TCP_CORK_DEF) __flg_field_def(27, DRBD_GENLA_F_MANDATORY, always_asbp, DRBD_ALWAYS_ASBP_DEF) __flg_field(28, DRBD_GENLA_F_MANDATORY | DRBD_F_INVARIANT, tentative) __flg_field_def(29, DRBD_GENLA_F_MANDATORY, use_rle, DRBD_USE_RLE_DEF) /* 9: __u32_field_def(30, DRBD_GENLA_F_MANDATORY, fencing_policy, DRBD_FENCING_DEF) */ /* 9: __str_field_def(31, DRBD_GENLA_F_MANDATORY, name, SHARED_SECRET_MAX) */ /* 9: __u32_field(32, DRBD_F_REQUIRED | DRBD_F_INVARIANT, peer_node_id) */ __flg_field_def(33, 0 /* OPTIONAL */, csums_after_crash_only, DRBD_CSUMS_AFTER_CRASH_ONLY_DEF) __u32_field_def(34, 0 /* OPTIONAL */, sock_check_timeo, DRBD_SOCKET_CHECK_TIMEO_DEF) __bin_field(35, 0 /* OPTIONAL */, my_addr2, 128) __bin_field(36, 0 /* OPTIONAL */, peer_addr2, 128) ) GENL_struct(DRBD_NLA_SET_ROLE_PARMS, 6, set_role_parms, __flg_field(1, DRBD_GENLA_F_MANDATORY, assume_uptodate) ) GENL_struct(DRBD_NLA_RESIZE_PARMS, 7, resize_parms, __u64_field(1, DRBD_GENLA_F_MANDATORY, resize_size) __flg_field(2, DRBD_GENLA_F_MANDATORY, resize_force) __flg_field(3, DRBD_GENLA_F_MANDATORY, no_resync) __u32_field_def(4, 0 /* OPTIONAL */, al_stripes, DRBD_AL_STRIPES_DEF) __u32_field_def(5, 0 /* OPTIONAL */, al_stripe_size, DRBD_AL_STRIPE_SIZE_DEF) ) GENL_struct(DRBD_NLA_STATE_INFO, 8, state_info, /* the reason of the broadcast, * if this is an event triggered broadcast. */ __u32_field(1, DRBD_GENLA_F_MANDATORY, sib_reason) __u32_field(2, DRBD_F_REQUIRED, current_state) __u64_field(3, DRBD_GENLA_F_MANDATORY, capacity) __u64_field(4, DRBD_GENLA_F_MANDATORY, ed_uuid) /* These are for broadcast from after state change work. * prev_state and new_state are from the moment the state change took * place, new_state is not neccessarily the same as current_state, * there may have been more state changes since. Which will be * broadcasted soon, in their respective after state change work. */ __u32_field(5, DRBD_GENLA_F_MANDATORY, prev_state) __u32_field(6, DRBD_GENLA_F_MANDATORY, new_state) /* if we have a local disk: */ __bin_field(7, DRBD_GENLA_F_MANDATORY, uuids, (UI_SIZE*sizeof(__u64))) __u32_field(8, DRBD_GENLA_F_MANDATORY, disk_flags) __u64_field(9, DRBD_GENLA_F_MANDATORY, bits_total) __u64_field(10, DRBD_GENLA_F_MANDATORY, bits_oos) /* and in case resync or online verify is active */ __u64_field(11, DRBD_GENLA_F_MANDATORY, bits_rs_total) __u64_field(12, DRBD_GENLA_F_MANDATORY, bits_rs_failed) /* for pre and post notifications of helper execution */ __str_field(13, DRBD_GENLA_F_MANDATORY, helper, 32) __u32_field(14, DRBD_GENLA_F_MANDATORY, helper_exit_code) __u64_field(15, 0, send_cnt) __u64_field(16, 0, recv_cnt) __u64_field(17, 0, read_cnt) __u64_field(18, 0, writ_cnt) __u64_field(19, 0, al_writ_cnt) __u64_field(20, 0, bm_writ_cnt) __u32_field(21, 0, ap_bio_cnt) __u32_field(22, 0, ap_pending_cnt) __u32_field(23, 0, rs_pending_cnt) ) GENL_struct(DRBD_NLA_START_OV_PARMS, 9, start_ov_parms, __u64_field(1, DRBD_GENLA_F_MANDATORY, ov_start_sector) __u64_field(2, DRBD_GENLA_F_MANDATORY, ov_stop_sector) ) GENL_struct(DRBD_NLA_NEW_C_UUID_PARMS, 10, new_c_uuid_parms, __flg_field(1, DRBD_GENLA_F_MANDATORY, clear_bm) ) GENL_struct(DRBD_NLA_TIMEOUT_PARMS, 11, timeout_parms, __u32_field(1, DRBD_F_REQUIRED, timeout_type) ) GENL_struct(DRBD_NLA_DISCONNECT_PARMS, 12, disconnect_parms, __flg_field(1, DRBD_GENLA_F_MANDATORY, force_disconnect) ) GENL_struct(DRBD_NLA_DETACH_PARMS, 13, detach_parms, __flg_field(1, DRBD_GENLA_F_MANDATORY, force_detach) ) GENL_struct(DRBD_NLA_RESOURCE_INFO, 15, resource_info, __u32_field(1, 0, res_role) __flg_field(2, 0, res_susp) __flg_field(3, 0, res_susp_nod) __flg_field(4, 0, res_susp_fen) /* __flg_field(5, 0, res_weak) */ ) GENL_struct(DRBD_NLA_DEVICE_INFO, 16, device_info, __u32_field(1, 0, dev_disk_state) ) GENL_struct(DRBD_NLA_CONNECTION_INFO, 17, connection_info, __u32_field(1, 0, conn_connection_state) __u32_field(2, 0, conn_role) ) GENL_struct(DRBD_NLA_PEER_DEVICE_INFO, 18, peer_device_info, __u32_field(1, 0, peer_repl_state) __u32_field(2, 0, peer_disk_state) __u32_field(3, 0, peer_resync_susp_user) __u32_field(4, 0, peer_resync_susp_peer) __u32_field(5, 0, peer_resync_susp_dependency) ) GENL_struct(DRBD_NLA_RESOURCE_STATISTICS, 19, resource_statistics, __u32_field(1, 0, res_stat_write_ordering) ) GENL_struct(DRBD_NLA_DEVICE_STATISTICS, 20, device_statistics, __u64_field(1, 0, dev_size) /* (sectors) */ __u64_field(2, 0, dev_read) /* (sectors) */ __u64_field(3, 0, dev_write) /* (sectors) */ __u64_field(4, 0, dev_al_writes) /* activity log writes (count) */ __u64_field(5, 0, dev_bm_writes) /* bitmap writes (count) */ __u32_field(6, 0, dev_upper_pending) /* application requests in progress */ __u32_field(7, 0, dev_lower_pending) /* backing device requests in progress */ __flg_field(8, 0, dev_upper_blocked) __flg_field(9, 0, dev_lower_blocked) __flg_field(10, 0, dev_al_suspended) /* activity log suspended */ __u64_field(11, 0, dev_exposed_data_uuid) __u64_field(12, 0, dev_current_uuid) __u32_field(13, 0, dev_disk_flags) __bin_field(14, 0, history_uuids, HISTORY_UUIDS * sizeof(__u64)) ) GENL_struct(DRBD_NLA_CONNECTION_STATISTICS, 21, connection_statistics, __flg_field(1, 0, conn_congested) ) GENL_struct(DRBD_NLA_PEER_DEVICE_STATISTICS, 22, peer_device_statistics, __u64_field(1, 0, peer_dev_received) /* sectors */ __u64_field(2, 0, peer_dev_sent) /* sectors */ __u32_field(3, 0, peer_dev_pending) /* number of requests */ __u32_field(4, 0, peer_dev_unacked) /* number of requests */ __u64_field(5, 0, peer_dev_out_of_sync) /* sectors */ __u64_field(6, 0, peer_dev_resync_failed) /* sectors */ __u64_field(7, 0, peer_dev_bitmap_uuid) __u32_field(9, 0, peer_dev_flags) ) GENL_struct(DRBD_NLA_NOTIFICATION_HEADER, 23, drbd_notification_header, __u32_field(1, DRBD_GENLA_F_MANDATORY, nh_type) ) GENL_struct(DRBD_NLA_HELPER, 24, drbd_helper_info, __str_field(1, DRBD_GENLA_F_MANDATORY, helper_name, 32) __u32_field(2, DRBD_GENLA_F_MANDATORY, helper_status) ) /* * Notifications and commands (genlmsghdr->cmd) */ GENL_mc_group(events) /* kernel -> userspace announcement of changes */ GENL_notification( DRBD_EVENT, 1, events, GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_STATE_INFO, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_NET_CONF, DRBD_GENLA_F_MANDATORY) GENL_tla_expected(DRBD_NLA_DISK_CONF, DRBD_GENLA_F_MANDATORY) GENL_tla_expected(DRBD_NLA_SYNCER_CONF, DRBD_GENLA_F_MANDATORY) ) /* query kernel for specific or all info */ GENL_op( DRBD_ADM_GET_STATUS, 2, GENL_op_init( .doit = drbd_adm_get_status, .dumpit = drbd_adm_get_status_all, /* anyone may ask for the status, * it is broadcasted anyways */ ), /* To select the object .doit. * Or a subset of objects in .dumpit. */ GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_GENLA_F_MANDATORY) ) /* add DRBD minor devices as volumes to resources */ GENL_op(DRBD_ADM_NEW_MINOR, 5, GENL_doit(drbd_adm_add_minor), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED)) GENL_op(DRBD_ADM_DEL_MINOR, 6, GENL_doit(drbd_adm_delete_minor), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED)) /* add or delete resources */ GENL_op(DRBD_ADM_NEW_RESOURCE, 7, GENL_doit(drbd_adm_new_resource), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED)) GENL_op(DRBD_ADM_DEL_RESOURCE, 8, GENL_doit(drbd_adm_del_resource), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED)) GENL_op(DRBD_ADM_RESOURCE_OPTS, 9, GENL_doit(drbd_adm_resource_opts), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_RESOURCE_OPTS, DRBD_GENLA_F_MANDATORY) ) GENL_op( DRBD_ADM_CONNECT, 10, GENL_doit(drbd_adm_connect), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_NET_CONF, DRBD_F_REQUIRED) ) GENL_op( DRBD_ADM_CHG_NET_OPTS, 29, GENL_doit(drbd_adm_net_opts), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_NET_CONF, DRBD_F_REQUIRED) ) GENL_op(DRBD_ADM_DISCONNECT, 11, GENL_doit(drbd_adm_disconnect), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED)) GENL_op(DRBD_ADM_ATTACH, 12, GENL_doit(drbd_adm_attach), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_DISK_CONF, DRBD_F_REQUIRED) ) GENL_op(DRBD_ADM_CHG_DISK_OPTS, 28, GENL_doit(drbd_adm_disk_opts), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_DISK_OPTS, DRBD_F_REQUIRED) ) GENL_op( DRBD_ADM_RESIZE, 13, GENL_doit(drbd_adm_resize), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_RESIZE_PARMS, DRBD_GENLA_F_MANDATORY) ) GENL_op( DRBD_ADM_PRIMARY, 14, GENL_doit(drbd_adm_set_role), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_SET_ROLE_PARMS, DRBD_F_REQUIRED) ) GENL_op( DRBD_ADM_SECONDARY, 15, GENL_doit(drbd_adm_set_role), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_SET_ROLE_PARMS, DRBD_F_REQUIRED) ) GENL_op( DRBD_ADM_NEW_C_UUID, 16, GENL_doit(drbd_adm_new_c_uuid), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_NEW_C_UUID_PARMS, DRBD_GENLA_F_MANDATORY) ) GENL_op( DRBD_ADM_START_OV, 17, GENL_doit(drbd_adm_start_ov), GENL_tla_expected(DRBD_NLA_START_OV_PARMS, DRBD_GENLA_F_MANDATORY) ) GENL_op(DRBD_ADM_DETACH, 18, GENL_doit(drbd_adm_detach), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_DETACH_PARMS, DRBD_GENLA_F_MANDATORY)) GENL_op(DRBD_ADM_INVALIDATE, 19, GENL_doit(drbd_adm_invalidate), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED)) GENL_op(DRBD_ADM_INVAL_PEER, 20, GENL_doit(drbd_adm_invalidate_peer), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED)) GENL_op(DRBD_ADM_PAUSE_SYNC, 21, GENL_doit(drbd_adm_pause_sync), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED)) GENL_op(DRBD_ADM_RESUME_SYNC, 22, GENL_doit(drbd_adm_resume_sync), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED)) GENL_op(DRBD_ADM_SUSPEND_IO, 23, GENL_doit(drbd_adm_suspend_io), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED)) GENL_op(DRBD_ADM_RESUME_IO, 24, GENL_doit(drbd_adm_resume_io), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED)) GENL_op(DRBD_ADM_OUTDATE, 25, GENL_doit(drbd_adm_outdate), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED)) GENL_op(DRBD_ADM_GET_TIMEOUT_TYPE, 26, GENL_doit(drbd_adm_get_timeout_type), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED)) GENL_op(DRBD_ADM_DOWN, 27, GENL_doit(drbd_adm_down), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED)) GENL_op(DRBD_ADM_GET_RESOURCES, 30, GENL_op_init( .dumpit = drbd_adm_dump_resources, ), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_GENLA_F_MANDATORY) GENL_tla_expected(DRBD_NLA_RESOURCE_INFO, DRBD_GENLA_F_MANDATORY) GENL_tla_expected(DRBD_NLA_RESOURCE_STATISTICS, DRBD_GENLA_F_MANDATORY)) GENL_op(DRBD_ADM_GET_DEVICES, 31, GENL_op_init( .dumpit = drbd_adm_dump_devices, .done = drbd_adm_dump_devices_done, ), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_GENLA_F_MANDATORY) GENL_tla_expected(DRBD_NLA_DEVICE_INFO, DRBD_GENLA_F_MANDATORY) GENL_tla_expected(DRBD_NLA_DEVICE_STATISTICS, DRBD_GENLA_F_MANDATORY)) GENL_op(DRBD_ADM_GET_CONNECTIONS, 32, GENL_op_init( .dumpit = drbd_adm_dump_connections, .done = drbd_adm_dump_connections_done, ), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_GENLA_F_MANDATORY) GENL_tla_expected(DRBD_NLA_CONNECTION_INFO, DRBD_GENLA_F_MANDATORY) GENL_tla_expected(DRBD_NLA_CONNECTION_STATISTICS, DRBD_GENLA_F_MANDATORY)) GENL_op(DRBD_ADM_GET_PEER_DEVICES, 33, GENL_op_init( .dumpit = drbd_adm_dump_peer_devices, .done = drbd_adm_dump_peer_devices_done, ), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_GENLA_F_MANDATORY) GENL_tla_expected(DRBD_NLA_PEER_DEVICE_INFO, DRBD_GENLA_F_MANDATORY) GENL_tla_expected(DRBD_NLA_PEER_DEVICE_STATISTICS, DRBD_GENLA_F_MANDATORY)) GENL_notification( DRBD_RESOURCE_STATE, 34, events, GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_NOTIFICATION_HEADER, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_RESOURCE_INFO, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_RESOURCE_STATISTICS, DRBD_F_REQUIRED)) GENL_notification( DRBD_DEVICE_STATE, 35, events, GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_NOTIFICATION_HEADER, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_DEVICE_INFO, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_DEVICE_STATISTICS, DRBD_F_REQUIRED)) GENL_notification( DRBD_CONNECTION_STATE, 36, events, GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_NOTIFICATION_HEADER, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_CONNECTION_INFO, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_CONNECTION_STATISTICS, DRBD_F_REQUIRED)) GENL_notification( DRBD_PEER_DEVICE_STATE, 37, events, GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_NOTIFICATION_HEADER, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_PEER_DEVICE_INFO, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_PEER_DEVICE_STATISTICS, DRBD_F_REQUIRED)) GENL_op( DRBD_ADM_GET_INITIAL_STATE, 38, GENL_op_init( .dumpit = drbd_adm_get_initial_state, ), GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_GENLA_F_MANDATORY)) GENL_notification( DRBD_HELPER, 40, events, GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) GENL_tla_expected(DRBD_NLA_HELPER, DRBD_F_REQUIRED)) GENL_notification( DRBD_INITIAL_STATE_DONE, 41, events, GENL_tla_expected(DRBD_NLA_NOTIFICATION_HEADER, DRBD_F_REQUIRED)) drbd-utils-8.9.6/user/v84/linux/genl_magic_struct.h0000644000175000017500000001673012466702074022122 0ustar apoikosapoikos#ifndef GENL_MAGIC_STRUCT_H #define GENL_MAGIC_STRUCT_H #ifndef GENL_MAGIC_FAMILY # error "you need to define GENL_MAGIC_FAMILY before inclusion" #endif #ifndef GENL_MAGIC_VERSION # error "you need to define GENL_MAGIC_VERSION before inclusion" #endif #ifndef GENL_MAGIC_INCLUDE_FILE # error "you need to define GENL_MAGIC_INCLUDE_FILE before inclusion" #endif #include #include #include #define CONCAT__(a,b) a ## b #define CONCAT_(a,b) CONCAT__(a,b) extern int CONCAT_(GENL_MAGIC_FAMILY, _genl_register)(void); extern void CONCAT_(GENL_MAGIC_FAMILY, _genl_unregister)(void); /* * Extension of genl attribute validation policies {{{2 */ /* * @DRBD_GENLA_F_MANDATORY: By default, netlink ignores attributes it does not * know about. This flag can be set in nlattr->nla_type to indicate that this * attribute must not be ignored. * * We check and remove this flag in drbd_nla_check_mandatory() before * validating the attribute types and lengths via nla_parse_nested(). */ #define DRBD_GENLA_F_MANDATORY (1 << 14) /* * Flags specific to drbd and not visible at the netlink layer, used in * _from_attrs and _to_skb: * * @DRBD_F_REQUIRED: Attribute is required; a request without this attribute is * invalid. * * @DRBD_F_SENSITIVE: Attribute includes sensitive information and must not be * included in unpriviledged get requests or broadcasts. * * @DRBD_F_INVARIANT: Attribute is set when an object is initially created, but * cannot subsequently be changed. */ #define DRBD_F_REQUIRED (1 << 0) #define DRBD_F_SENSITIVE (1 << 1) #define DRBD_F_INVARIANT (1 << 2) #define __nla_type(x) ((__u16)((x) & NLA_TYPE_MASK & ~DRBD_GENLA_F_MANDATORY)) /* }}}1 * MAGIC * multi-include macro expansion magic starts here */ /* MAGIC helpers {{{2 */ /* possible field types */ #define __flg_field(attr_nr, attr_flag, name) \ __field(attr_nr, attr_flag, name, NLA_U8, char, \ nla_get_u8, nla_put_u8, false) #define __u8_field(attr_nr, attr_flag, name) \ __field(attr_nr, attr_flag, name, NLA_U8, unsigned char, \ nla_get_u8, nla_put_u8, false) #define __u16_field(attr_nr, attr_flag, name) \ __field(attr_nr, attr_flag, name, NLA_U16, __u16, \ nla_get_u16, nla_put_u16, false) #define __u32_field(attr_nr, attr_flag, name) \ __field(attr_nr, attr_flag, name, NLA_U32, __u32, \ nla_get_u32, nla_put_u32, false) #define __s32_field(attr_nr, attr_flag, name) \ __field(attr_nr, attr_flag, name, NLA_U32, __s32, \ nla_get_u32, nla_put_u32, true) #define __u64_field(attr_nr, attr_flag, name) \ __field(attr_nr, attr_flag, name, NLA_U64, __u64, \ nla_get_u64, nla_put_u64, false) #define __str_field(attr_nr, attr_flag, name, maxlen) \ __array(attr_nr, attr_flag, name, NLA_NUL_STRING, char, maxlen, \ nla_strlcpy, nla_put, false) #define __bin_field(attr_nr, attr_flag, name, maxlen) \ __array(attr_nr, attr_flag, name, NLA_BINARY, char, maxlen, \ nla_memcpy, nla_put, false) /* fields with default values */ #define __flg_field_def(attr_nr, attr_flag, name, default) \ __flg_field(attr_nr, attr_flag, name) #define __u32_field_def(attr_nr, attr_flag, name, default) \ __u32_field(attr_nr, attr_flag, name) #define __s32_field_def(attr_nr, attr_flag, name, default) \ __s32_field(attr_nr, attr_flag, name) #define __str_field_def(attr_nr, attr_flag, name, maxlen) \ __str_field(attr_nr, attr_flag, name, maxlen) #define GENL_op_init(args...) args #define GENL_doit(handler) \ .doit = handler, \ .flags = GENL_ADMIN_PERM, #define GENL_dumpit(handler) \ .dumpit = handler, \ .flags = GENL_ADMIN_PERM, /* }}}1 * Magic: define the enum symbols for genl_ops * Magic: define the enum symbols for top level attributes * Magic: define the enum symbols for nested attributes * {{{2 */ #undef GENL_struct #define GENL_struct(tag_name, tag_number, s_name, s_fields) #undef GENL_mc_group #define GENL_mc_group(group) #undef GENL_notification #define GENL_notification(op_name, op_num, mcast_group, tla_list) \ op_name = op_num, #undef GENL_op #define GENL_op(op_name, op_num, handler, tla_list) \ op_name = op_num, enum { #include GENL_MAGIC_INCLUDE_FILE }; #undef GENL_notification #define GENL_notification(op_name, op_num, mcast_group, tla_list) #undef GENL_op #define GENL_op(op_name, op_num, handler, attr_list) #undef GENL_struct #define GENL_struct(tag_name, tag_number, s_name, s_fields) \ tag_name = tag_number, enum { #include GENL_MAGIC_INCLUDE_FILE }; #undef GENL_struct #define GENL_struct(tag_name, tag_number, s_name, s_fields) \ enum { \ s_fields \ }; #undef __field #define __field(attr_nr, attr_flag, name, nla_type, type, \ __get, __put, __is_signed) \ T_ ## name = (__u16)(attr_nr | ((attr_flag) & DRBD_GENLA_F_MANDATORY)), #undef __array #define __array(attr_nr, attr_flag, name, nla_type, type, \ maxlen, __get, __put, __is_signed) \ T_ ## name = (__u16)(attr_nr | ((attr_flag) & DRBD_GENLA_F_MANDATORY)), #include GENL_MAGIC_INCLUDE_FILE /* }}}1 * Magic: compile time assert unique numbers for operations * Magic: -"- unique numbers for top level attributes * Magic: -"- unique numbers for nested attributes * {{{2 */ #undef GENL_struct #define GENL_struct(tag_name, tag_number, s_name, s_fields) #undef GENL_op #define GENL_op(op_name, op_num, handler, attr_list) \ case op_name: #undef GENL_notification #define GENL_notification(op_name, op_num, mcast_group, tla_list) \ case op_name: static inline void ct_assert_unique_operations(void) { switch (0) { #include GENL_MAGIC_INCLUDE_FILE ; } } #undef GENL_op #define GENL_op(op_name, op_num, handler, attr_list) #undef GENL_notification #define GENL_notification(op_name, op_num, mcast_group, tla_list) #undef GENL_struct #define GENL_struct(tag_name, tag_number, s_name, s_fields) \ case tag_number: static inline void ct_assert_unique_top_level_attributes(void) { switch (0) { #include GENL_MAGIC_INCLUDE_FILE ; } } #undef GENL_struct #define GENL_struct(tag_name, tag_number, s_name, s_fields) \ static inline void ct_assert_unique_ ## s_name ## _attributes(void) \ { \ switch (0) { \ s_fields \ ; \ } \ } #undef __field #define __field(attr_nr, attr_flag, name, nla_type, type, __get, __put, \ __is_signed) \ case attr_nr: #undef __array #define __array(attr_nr, attr_flag, name, nla_type, type, maxlen, \ __get, __put, __is_signed) \ case attr_nr: #include GENL_MAGIC_INCLUDE_FILE /* }}}1 * Magic: declare structs * struct { * fields * }; * {{{2 */ #undef GENL_struct #define GENL_struct(tag_name, tag_number, s_name, s_fields) \ struct s_name { s_fields }; #undef __field #define __field(attr_nr, attr_flag, name, nla_type, type, __get, __put, \ __is_signed) \ type name; #undef __array #define __array(attr_nr, attr_flag, name, nla_type, type, maxlen, \ __get, __put, __is_signed) \ type name[maxlen]; \ __u32 name ## _len; #include GENL_MAGIC_INCLUDE_FILE #undef GENL_struct #define GENL_struct(tag_name, tag_number, s_name, s_fields) \ enum { \ s_fields \ }; #undef __field #define __field(attr_nr, attr_flag, name, nla_type, type, __get, __put, \ is_signed) \ F_ ## name ## _IS_SIGNED = is_signed, #undef __array #define __array(attr_nr, attr_flag, name, nla_type, type, maxlen, \ __get, __put, is_signed) \ F_ ## name ## _IS_SIGNED = is_signed, #include GENL_MAGIC_INCLUDE_FILE /* }}}1 */ #endif /* GENL_MAGIC_STRUCT_H */ /* vim: set foldmethod=marker nofoldenable : */ drbd-utils-8.9.6/user/v84/linux/drbd.h0000644000175000017500000002470712466702074017347 0ustar apoikosapoikos/* drbd.h Kernel module for 2.6.x Kernels This file is part of DRBD by Philipp Reisner and Lars Ellenberg. Copyright (C) 2001-2008, LINBIT Information Technologies GmbH. Copyright (C) 2001-2008, Philipp Reisner . Copyright (C) 2001-2008, Lars Ellenberg . drbd is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. drbd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with drbd; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef DRBD_H #define DRBD_H #include #include #ifdef __KERNEL__ #include #include #else #include #include #include /* Although the Linux source code makes a difference between generic endianness and the bitfields' endianness, there is no architecture as of Linux-2.6.24-rc4 where the bitfields' endianness does not match the generic endianness. */ #if __BYTE_ORDER == __LITTLE_ENDIAN #define __LITTLE_ENDIAN_BITFIELD #elif __BYTE_ORDER == __BIG_ENDIAN #define __BIG_ENDIAN_BITFIELD #else # error "sorry, weird endianness on this box" #endif #endif enum drbd_io_error_p { EP_PASS_ON, /* FIXME should the better be named "Ignore"? */ EP_CALL_HELPER, EP_DETACH }; enum drbd_fencing_p { FP_NOT_AVAIL = -1, /* Not a policy */ FP_DONT_CARE = 0, FP_RESOURCE, FP_STONITH }; enum drbd_disconnect_p { DP_RECONNECT, DP_DROP_NET_CONF, DP_FREEZE_IO }; enum drbd_after_sb_p { ASB_DISCONNECT, ASB_DISCARD_YOUNGER_PRI, ASB_DISCARD_OLDER_PRI, ASB_DISCARD_ZERO_CHG, ASB_DISCARD_LEAST_CHG, ASB_DISCARD_LOCAL, ASB_DISCARD_REMOTE, ASB_CONSENSUS, ASB_DISCARD_SECONDARY, ASB_CALL_HELPER, ASB_VIOLENTLY }; enum drbd_on_no_data { OND_IO_ERROR, OND_SUSPEND_IO }; enum drbd_on_congestion { OC_BLOCK, OC_PULL_AHEAD, OC_DISCONNECT, }; enum drbd_read_balancing { RB_PREFER_LOCAL, RB_PREFER_REMOTE, RB_ROUND_ROBIN, RB_LEAST_PENDING, RB_CONGESTED_REMOTE, RB_32K_STRIPING, RB_64K_STRIPING, RB_128K_STRIPING, RB_256K_STRIPING, RB_512K_STRIPING, RB_1M_STRIPING, }; /* KEEP the order, do not delete or insert. Only append. */ enum drbd_ret_code { ERR_CODE_BASE = 100, NO_ERROR = 101, ERR_LOCAL_ADDR = 102, ERR_PEER_ADDR = 103, ERR_OPEN_DISK = 104, ERR_OPEN_MD_DISK = 105, ERR_DISK_NOT_BDEV = 107, ERR_MD_NOT_BDEV = 108, ERR_DISK_TOO_SMALL = 111, ERR_MD_DISK_TOO_SMALL = 112, ERR_BDCLAIM_DISK = 114, ERR_BDCLAIM_MD_DISK = 115, ERR_MD_IDX_INVALID = 116, ERR_IO_MD_DISK = 118, ERR_MD_INVALID = 119, ERR_AUTH_ALG = 120, ERR_AUTH_ALG_ND = 121, ERR_NOMEM = 122, ERR_DISCARD_IMPOSSIBLE = 123, ERR_DISK_CONFIGURED = 124, ERR_NET_CONFIGURED = 125, ERR_MANDATORY_TAG = 126, ERR_MINOR_INVALID = 127, ERR_INTR = 129, /* EINTR */ ERR_RESIZE_RESYNC = 130, ERR_NO_PRIMARY = 131, ERR_RESYNC_AFTER = 132, ERR_RESYNC_AFTER_CYCLE = 133, ERR_PAUSE_IS_SET = 134, ERR_PAUSE_IS_CLEAR = 135, ERR_PACKET_NR = 137, ERR_NO_DISK = 138, ERR_NOT_PROTO_C = 139, ERR_NOMEM_BITMAP = 140, ERR_INTEGRITY_ALG = 141, /* DRBD 8.2 only */ ERR_INTEGRITY_ALG_ND = 142, /* DRBD 8.2 only */ ERR_CPU_MASK_PARSE = 143, /* DRBD 8.2 only */ ERR_CSUMS_ALG = 144, /* DRBD 8.2 only */ ERR_CSUMS_ALG_ND = 145, /* DRBD 8.2 only */ ERR_VERIFY_ALG = 146, /* DRBD 8.2 only */ ERR_VERIFY_ALG_ND = 147, /* DRBD 8.2 only */ ERR_CSUMS_RESYNC_RUNNING= 148, /* DRBD 8.2 only */ ERR_VERIFY_RUNNING = 149, /* DRBD 8.2 only */ ERR_DATA_NOT_CURRENT = 150, ERR_CONNECTED = 151, /* DRBD 8.3 only */ ERR_PERM = 152, ERR_NEED_APV_93 = 153, ERR_STONITH_AND_PROT_A = 154, ERR_CONG_NOT_PROTO_A = 155, ERR_PIC_AFTER_DEP = 156, ERR_PIC_PEER_DEP = 157, ERR_RES_NOT_KNOWN = 158, ERR_RES_IN_USE = 159, ERR_MINOR_CONFIGURED = 160, ERR_MINOR_OR_VOLUME_EXISTS = 161, ERR_INVALID_REQUEST = 162, ERR_NEED_APV_100 = 163, ERR_NEED_ALLOW_TWO_PRI = 164, ERR_MD_UNCLEAN = 165, ERR_MD_LAYOUT_CONNECTED = 166, ERR_MD_LAYOUT_TOO_BIG = 167, ERR_MD_LAYOUT_TOO_SMALL = 168, ERR_MD_LAYOUT_NO_FIT = 169, ERR_IMPLICIT_SHRINK = 170, /* insert new ones above this line */ AFTER_LAST_ERR_CODE }; #define DRBD_PROT_A 1 #define DRBD_PROT_B 2 #define DRBD_PROT_C 3 enum drbd_role { R_UNKNOWN = 0, R_PRIMARY = 1, /* role */ R_SECONDARY = 2, /* role */ R_MASK = 3, }; /* The order of these constants is important. * The lower ones (=C_WF_REPORT_PARAMS ==> There is a socket */ enum drbd_conns { C_STANDALONE, C_DISCONNECTING, /* Temporal state on the way to StandAlone. */ C_UNCONNECTED, /* >= C_UNCONNECTED -> inc_net() succeeds */ /* These temporal states are all used on the way * from >= C_CONNECTED to Unconnected. * The 'disconnect reason' states * I do not allow to change between them. */ C_TIMEOUT, C_BROKEN_PIPE, C_NETWORK_FAILURE, C_PROTOCOL_ERROR, C_TEAR_DOWN, C_WF_CONNECTION, C_WF_REPORT_PARAMS, /* we have a socket */ C_CONNECTED, /* we have introduced each other */ C_STARTING_SYNC_S, /* starting full sync by admin request. */ C_STARTING_SYNC_T, /* starting full sync by admin request. */ C_WF_BITMAP_S, C_WF_BITMAP_T, C_WF_SYNC_UUID, /* All SyncStates are tested with this comparison * xx >= C_SYNC_SOURCE && xx <= C_PAUSED_SYNC_T */ C_SYNC_SOURCE, C_SYNC_TARGET, C_VERIFY_S, C_VERIFY_T, C_PAUSED_SYNC_S, C_PAUSED_SYNC_T, C_AHEAD, C_BEHIND, C_MASK = 31 }; enum drbd_disk_state { D_DISKLESS, D_ATTACHING, /* In the process of reading the meta-data */ D_FAILED, /* Becomes D_DISKLESS as soon as we told it the peer */ /* when >= D_FAILED it is legal to access mdev->ldev */ D_NEGOTIATING, /* Late attaching state, we need to talk to the peer */ D_INCONSISTENT, D_OUTDATED, D_UNKNOWN, /* Only used for the peer, never for myself */ D_CONSISTENT, /* Might be D_OUTDATED, might be D_UP_TO_DATE ... */ D_UP_TO_DATE, /* Only this disk state allows applications' IO ! */ D_MASK = 15 }; union drbd_state { /* According to gcc's docs is the ... * The order of allocation of bit-fields within a unit (C90 6.5.2.1, C99 6.7.2.1). * Determined by ABI. * pointed out by Maxim Uvarov q * even though we transmit as "cpu_to_be32(state)", * the offsets of the bitfields still need to be swapped * on different endianness. */ struct { #if defined(__LITTLE_ENDIAN_BITFIELD) unsigned role:2 ; /* 3/4 primary/secondary/unknown */ unsigned peer:2 ; /* 3/4 primary/secondary/unknown */ unsigned conn:5 ; /* 17/32 cstates */ unsigned disk:4 ; /* 8/16 from D_DISKLESS to D_UP_TO_DATE */ unsigned pdsk:4 ; /* 8/16 from D_DISKLESS to D_UP_TO_DATE */ unsigned susp:1 ; /* 2/2 IO suspended no/yes (by user) */ unsigned aftr_isp:1 ; /* isp .. imposed sync pause */ unsigned peer_isp:1 ; unsigned user_isp:1 ; unsigned susp_nod:1 ; /* IO suspended because no data */ unsigned susp_fen:1 ; /* IO suspended because fence peer handler runs*/ unsigned _pad:9; /* 0 unused */ #elif defined(__BIG_ENDIAN_BITFIELD) unsigned _pad:9; unsigned susp_fen:1 ; unsigned susp_nod:1 ; unsigned user_isp:1 ; unsigned peer_isp:1 ; unsigned aftr_isp:1 ; /* isp .. imposed sync pause */ unsigned susp:1 ; /* 2/2 IO suspended no/yes */ unsigned pdsk:4 ; /* 8/16 from D_DISKLESS to D_UP_TO_DATE */ unsigned disk:4 ; /* 8/16 from D_DISKLESS to D_UP_TO_DATE */ unsigned conn:5 ; /* 17/32 cstates */ unsigned peer:2 ; /* 3/4 primary/secondary/unknown */ unsigned role:2 ; /* 3/4 primary/secondary/unknown */ #else # error "this endianness is not supported" #endif }; unsigned int i; }; enum drbd_state_rv { SS_CW_NO_NEED = 4, SS_CW_SUCCESS = 3, SS_NOTHING_TO_DO = 2, SS_SUCCESS = 1, SS_UNKNOWN_ERROR = 0, /* Used to sleep longer in _drbd_request_state */ SS_TWO_PRIMARIES = -1, SS_NO_UP_TO_DATE_DISK = -2, SS_NO_LOCAL_DISK = -4, SS_NO_REMOTE_DISK = -5, SS_CONNECTED_OUTDATES = -6, SS_PRIMARY_NOP = -7, SS_RESYNC_RUNNING = -8, SS_ALREADY_STANDALONE = -9, SS_CW_FAILED_BY_PEER = -10, SS_IS_DISKLESS = -11, SS_DEVICE_IN_USE = -12, SS_NO_NET_CONFIG = -13, SS_NO_VERIFY_ALG = -14, /* drbd-8.2 only */ SS_NEED_CONNECTION = -15, /* drbd-8.2 only */ SS_LOWER_THAN_OUTDATED = -16, SS_NOT_SUPPORTED = -17, /* drbd-8.2 only */ SS_IN_TRANSIENT_STATE = -18, /* Retry after the next state change */ SS_CONCURRENT_ST_CHG = -19, /* Concurrent cluster side state change! */ SS_O_VOL_PEER_PRI = -20, SS_OUTDATE_WO_CONN = -21, SS_AFTER_LAST_ERROR = -22, /* Keep this at bottom */ }; #define SHARED_SECRET_MAX 64 #define MDF_CONSISTENT (1 << 0) #define MDF_PRIMARY_IND (1 << 1) #define MDF_CONNECTED_IND (1 << 2) #define MDF_FULL_SYNC (1 << 3) #define MDF_WAS_UP_TO_DATE (1 << 4) #define MDF_PEER_OUT_DATED (1 << 5) #define MDF_CRASHED_PRIMARY (1 << 6) #define MDF_AL_CLEAN (1 << 7) #define MDF_AL_DISABLED (1 << 8) #define MAX_PEERS 32 enum drbd_uuid_index { UI_CURRENT, UI_BITMAP, UI_HISTORY_START, UI_HISTORY_END, UI_SIZE, /* nl-packet: number of dirty bits */ UI_FLAGS, /* nl-packet: flags */ UI_EXTENDED_SIZE /* Everything. */ }; #define HISTORY_UUIDS MAX_PEERS enum drbd_timeout_flag { UT_DEFAULT = 0, UT_DEGRADED = 1, UT_PEER_OUTDATED = 2, }; #define UUID_JUST_CREATED ((__u64)4) enum write_ordering_e { WO_NONE, WO_DRAIN_IO, WO_BDEV_FLUSH, WO_BIO_BARRIER }; enum drbd_notification_type { NOTIFY_EXISTS, NOTIFY_CREATE, NOTIFY_CHANGE, NOTIFY_DESTROY, NOTIFY_CALL, NOTIFY_RESPONSE, NOTIFY_CONTINUES = 0x8000, NOTIFY_FLAGS = NOTIFY_CONTINUES, }; /* magic numbers used in meta data and network packets */ #define DRBD_MAGIC 0x83740267 #define DRBD_MAGIC_BIG 0x835a #define DRBD_MAGIC_100 0x8620ec20 #define DRBD_MD_MAGIC_07 (DRBD_MAGIC+3) #define DRBD_MD_MAGIC_08 (DRBD_MAGIC+4) #define DRBD_MD_MAGIC_84_UNCLEAN (DRBD_MAGIC+5) /* how I came up with this magic? * base64 decode "actlog==" ;) */ #define DRBD_AL_MAGIC 0x69cb65a2 /* these are of type "int" */ #define DRBD_MD_INDEX_INTERNAL -1 #define DRBD_MD_INDEX_FLEX_EXT -2 #define DRBD_MD_INDEX_FLEX_INT -3 #define DRBD_CPU_MASK_SIZE 32 #endif drbd-utils-8.9.6/user/v84/linux/drbd_limits.h0000644000175000017500000001713712632556027020727 0ustar apoikosapoikos/* drbd_limits.h This file is part of DRBD by Philipp Reisner and Lars Ellenberg. */ /* * Our current limitations. * Some of them are hard limits, * some of them are arbitrary range limits, that make it easier to provide * feedback about nonsense settings for certain configurable values. */ #ifndef DRBD_LIMITS_H #define DRBD_LIMITS_H 1 #define DEBUG_RANGE_CHECK 0 #define DRBD_MINOR_COUNT_MIN 1 #define DRBD_MINOR_COUNT_MAX 255 #define DRBD_MINOR_COUNT_DEF 32 #define DRBD_MINOR_COUNT_SCALE '1' #define DRBD_VOLUME_MAX 65535 #define DRBD_DIALOG_REFRESH_MIN 0 #define DRBD_DIALOG_REFRESH_MAX 600 #define DRBD_DIALOG_REFRESH_SCALE '1' /* valid port number */ #define DRBD_PORT_MIN 1 #define DRBD_PORT_MAX 0xffff #define DRBD_PORT_SCALE '1' /* startup { */ /* if you want more than 3.4 days, disable */ #define DRBD_WFC_TIMEOUT_MIN 0 #define DRBD_WFC_TIMEOUT_MAX 300000 #define DRBD_WFC_TIMEOUT_DEF 0 #define DRBD_WFC_TIMEOUT_SCALE '1' #define DRBD_DEGR_WFC_TIMEOUT_MIN 0 #define DRBD_DEGR_WFC_TIMEOUT_MAX 300000 #define DRBD_DEGR_WFC_TIMEOUT_DEF 0 #define DRBD_DEGR_WFC_TIMEOUT_SCALE '1' #define DRBD_OUTDATED_WFC_TIMEOUT_MIN 0 #define DRBD_OUTDATED_WFC_TIMEOUT_MAX 300000 #define DRBD_OUTDATED_WFC_TIMEOUT_DEF 0 #define DRBD_OUTDATED_WFC_TIMEOUT_SCALE '1' /* }*/ /* net { */ /* timeout, unit centi seconds * more than one minute timeout is not useful */ #define DRBD_TIMEOUT_MIN 1 #define DRBD_TIMEOUT_MAX 600 #define DRBD_TIMEOUT_DEF 60 /* 6 seconds */ #define DRBD_TIMEOUT_SCALE '1' /* If backing disk takes longer than disk_timeout, mark the disk as failed */ #define DRBD_DISK_TIMEOUT_MIN 0 /* 0 = disabled */ #define DRBD_DISK_TIMEOUT_MAX 6000 /* 10 Minutes */ #define DRBD_DISK_TIMEOUT_DEF 0 /* disabled */ #define DRBD_DISK_TIMEOUT_SCALE '1' /* active connection retries when C_WF_CONNECTION */ #define DRBD_CONNECT_INT_MIN 1 #define DRBD_CONNECT_INT_MAX 120 #define DRBD_CONNECT_INT_DEF 10 /* seconds */ #define DRBD_CONNECT_INT_SCALE '1' /* keep-alive probes when idle */ #define DRBD_PING_INT_MIN 1 #define DRBD_PING_INT_MAX 120 #define DRBD_PING_INT_DEF 10 #define DRBD_PING_INT_SCALE '1' /* timeout for the ping packets.*/ #define DRBD_PING_TIMEO_MIN 1 #define DRBD_PING_TIMEO_MAX 300 #define DRBD_PING_TIMEO_DEF 5 #define DRBD_PING_TIMEO_SCALE '1' /* max number of write requests between write barriers */ #define DRBD_MAX_EPOCH_SIZE_MIN 1 #define DRBD_MAX_EPOCH_SIZE_MAX 20000 #define DRBD_MAX_EPOCH_SIZE_DEF 2048 #define DRBD_MAX_EPOCH_SIZE_SCALE '1' /* I don't think that a tcp send buffer of more than 10M is useful */ #define DRBD_SNDBUF_SIZE_MIN 0 #define DRBD_SNDBUF_SIZE_MAX (10<<20) #define DRBD_SNDBUF_SIZE_DEF 0 #define DRBD_SNDBUF_SIZE_SCALE '1' #define DRBD_RCVBUF_SIZE_MIN 0 #define DRBD_RCVBUF_SIZE_MAX (10<<20) #define DRBD_RCVBUF_SIZE_DEF 0 #define DRBD_RCVBUF_SIZE_SCALE '1' /* @4k PageSize -> 128kB - 512MB */ #define DRBD_MAX_BUFFERS_MIN 32 #define DRBD_MAX_BUFFERS_MAX 131072 #define DRBD_MAX_BUFFERS_DEF 2048 #define DRBD_MAX_BUFFERS_SCALE '1' /* @4k PageSize -> 4kB - 512MB */ #define DRBD_UNPLUG_WATERMARK_MIN 1 #define DRBD_UNPLUG_WATERMARK_MAX 131072 #define DRBD_UNPLUG_WATERMARK_DEF (DRBD_MAX_BUFFERS_DEF/16) #define DRBD_UNPLUG_WATERMARK_SCALE '1' /* 0 is disabled. * 200 should be more than enough even for very short timeouts */ #define DRBD_KO_COUNT_MIN 0 #define DRBD_KO_COUNT_MAX 200 #define DRBD_KO_COUNT_DEF 7 #define DRBD_KO_COUNT_SCALE '1' /* } */ /* syncer { */ /* FIXME allow rate to be zero? */ #define DRBD_RESYNC_RATE_MIN 1 /* channel bonding 10 GbE, or other hardware */ #define DRBD_RESYNC_RATE_MAX (4 << 20) #define DRBD_RESYNC_RATE_DEF 250 #define DRBD_RESYNC_RATE_SCALE 'k' /* kilobytes */ #define DRBD_AL_EXTENTS_MIN 67 /* we use u16 as "slot number", (u16)~0 is "FREE". * If you use >= 292 kB on-disk ring buffer, * this is the maximum you can use: */ #define DRBD_AL_EXTENTS_MAX 0xfffe #define DRBD_AL_EXTENTS_DEF 1237 #define DRBD_AL_EXTENTS_SCALE '1' #define DRBD_MINOR_NUMBER_MIN -1 #define DRBD_MINOR_NUMBER_MAX ((1 << 20) - 1) #define DRBD_MINOR_NUMBER_DEF -1 #define DRBD_MINOR_NUMBER_SCALE '1' /* } */ /* drbdsetup XY resize -d Z * you are free to reduce the device size to nothing, if you want to. * the upper limit with 64bit kernel, enough ram and flexible meta data * is 1 PiB, currently. */ /* DRBD_MAX_SECTORS */ #define DRBD_DISK_SIZE_MIN 0 #define DRBD_DISK_SIZE_MAX (1 * (2LLU << 40)) #define DRBD_DISK_SIZE_DEF 0 /* = disabled = no user size... */ #define DRBD_DISK_SIZE_SCALE 's' /* sectors */ #define DRBD_ON_IO_ERROR_DEF EP_DETACH #define DRBD_FENCING_DEF FP_DONT_CARE #define DRBD_AFTER_SB_0P_DEF ASB_DISCONNECT #define DRBD_AFTER_SB_1P_DEF ASB_DISCONNECT #define DRBD_AFTER_SB_2P_DEF ASB_DISCONNECT #define DRBD_RR_CONFLICT_DEF ASB_DISCONNECT #define DRBD_ON_NO_DATA_DEF OND_IO_ERROR #define DRBD_ON_CONGESTION_DEF OC_BLOCK #define DRBD_READ_BALANCING_DEF RB_PREFER_LOCAL #define DRBD_MAX_BIO_BVECS_MIN 0 #define DRBD_MAX_BIO_BVECS_MAX 128 #define DRBD_MAX_BIO_BVECS_DEF 0 #define DRBD_MAX_BIO_BVECS_SCALE '1' #define DRBD_C_PLAN_AHEAD_MIN 0 #define DRBD_C_PLAN_AHEAD_MAX 300 #define DRBD_C_PLAN_AHEAD_DEF 20 #define DRBD_C_PLAN_AHEAD_SCALE '1' #define DRBD_C_DELAY_TARGET_MIN 1 #define DRBD_C_DELAY_TARGET_MAX 100 #define DRBD_C_DELAY_TARGET_DEF 10 #define DRBD_C_DELAY_TARGET_SCALE '1' #define DRBD_C_FILL_TARGET_MIN 0 #define DRBD_C_FILL_TARGET_MAX (1<<20) /* 500MByte in sec */ #define DRBD_C_FILL_TARGET_DEF 100 /* Try to place 50KiB in socket send buffer during resync */ #define DRBD_C_FILL_TARGET_SCALE 's' /* sectors */ #define DRBD_C_MAX_RATE_MIN 250 #define DRBD_C_MAX_RATE_MAX (4 << 20) #define DRBD_C_MAX_RATE_DEF 102400 #define DRBD_C_MAX_RATE_SCALE 'k' /* kilobytes */ #define DRBD_C_MIN_RATE_MIN 0 #define DRBD_C_MIN_RATE_MAX (4 << 20) #define DRBD_C_MIN_RATE_DEF 250 #define DRBD_C_MIN_RATE_SCALE 'k' /* kilobytes */ #define DRBD_CONG_FILL_MIN 0 #define DRBD_CONG_FILL_MAX (10<<21) /* 10GByte in sectors */ #define DRBD_CONG_FILL_DEF 0 #define DRBD_CONG_FILL_SCALE 's' /* sectors */ #define DRBD_CONG_EXTENTS_MIN DRBD_AL_EXTENTS_MIN #define DRBD_CONG_EXTENTS_MAX DRBD_AL_EXTENTS_MAX #define DRBD_CONG_EXTENTS_DEF DRBD_AL_EXTENTS_DEF #define DRBD_CONG_EXTENTS_SCALE DRBD_AL_EXTENTS_SCALE #define DRBD_PROTOCOL_DEF DRBD_PROT_C #define DRBD_DISK_BARRIER_DEF 0 #define DRBD_DISK_FLUSHES_DEF 1 #define DRBD_DISK_DRAIN_DEF 1 #define DRBD_MD_FLUSHES_DEF 1 #define DRBD_TCP_CORK_DEF 1 #define DRBD_AL_UPDATES_DEF 1 /* We used to ignore the discard_zeroes_data setting. * To not change established (and expected) behaviour, * by default assume that, for discard_zeroes_data=0, * we can make that an effective discard_zeroes_data=1, * if we only explicitly zero-out unaligned partial chunks. */ #define DRBD_DISCARD_ZEROES_IF_ALIGNED_DEF 1 #define DRBD_ALLOW_TWO_PRIMARIES_DEF 0 #define DRBD_ALWAYS_ASBP_DEF 0 #define DRBD_USE_RLE_DEF 1 #define DRBD_CSUMS_AFTER_CRASH_ONLY_DEF 0 #define DRBD_AL_STRIPES_MIN 1 #define DRBD_AL_STRIPES_MAX 1024 #define DRBD_AL_STRIPES_DEF 1 #define DRBD_AL_STRIPES_SCALE '1' #define DRBD_AL_STRIPE_SIZE_MIN 4 #define DRBD_AL_STRIPE_SIZE_MAX 16777216 #define DRBD_AL_STRIPE_SIZE_DEF 32 #define DRBD_AL_STRIPE_SIZE_SCALE 'k' /* kilobytes */ #define DRBD_SOCKET_CHECK_TIMEO_MIN 0 #define DRBD_SOCKET_CHECK_TIMEO_MAX DRBD_PING_TIMEO_MAX #define DRBD_SOCKET_CHECK_TIMEO_DEF 0 #define DRBD_SOCKET_CHECK_TIMEO_SCALE '1' #define DRBD_RS_DISCARD_GRANULARITY_MIN 0 #define DRBD_RS_DISCARD_GRANULARITY_MAX (1<<20) /* 1MiByte */ #define DRBD_RS_DISCARD_GRANULARITY_DEF 0 /* disabled by default */ #define DRBD_RS_DISCARD_GRANULARITY_SCALE '1' /* sectors */ #endif drbd-utils-8.9.6/user/v84/linux/drbd_config.h0000644000175000017500000000153112466702074020662 0ustar apoikosapoikos/* drbd_config.h DRBD's compile time configuration. drbd is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. drbd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with drbd; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef DRBD_LEGACY_84_CONFIG_H #define DRBD_LEGACY_84_CONFIG_H extern const char *drbd_buildtag(void); #define API_VERSION 1 #endif drbd-utils-8.9.6/user/v84/linux/drbd_genl_api.h0000644000175000017500000000335112466702074021175 0ustar apoikosapoikos#ifndef DRBD_GENL_STRUCT_H #define DRBD_GENL_STRUCT_H /** * struct drbd_genlmsghdr - DRBD specific header used in NETLINK_GENERIC requests * @minor: * For admin requests (user -> kernel): which minor device to operate on. * For (unicast) replies or informational (broadcast) messages * (kernel -> user): which minor device the information is about. * If we do not operate on minors, but on connections or resources, * the minor value shall be (~0), and the attribute DRBD_NLA_CFG_CONTEXT * is used instead. * @flags: possible operation modifiers (relevant only for user->kernel): * DRBD_GENL_F_SET_DEFAULTS * @volume: * When creating a new minor (adding it to a resource), the resource needs * to know which volume number within the resource this is supposed to be. * The volume number corresponds to the same volume number on the remote side, * whereas the minor number on the remote side may be different * (union with flags). * @ret_code: kernel->userland unicast cfg reply return code (union with flags); */ struct drbd_genlmsghdr { __u32 minor; union { __u32 flags; __s32 ret_code; }; }; /* To be used in drbd_genlmsghdr.flags */ enum { DRBD_GENL_F_SET_DEFAULTS = 1, }; enum drbd_state_info_bcast_reason { SIB_GET_STATUS_REPLY = 1, SIB_STATE_CHANGE = 2, SIB_HELPER_PRE = 3, SIB_HELPER_POST = 4, SIB_SYNC_PROGRESS = 5, }; /* hack around predefined gcc/cpp "linux=1", * we cannot possibly include <1/drbd_genl.h> */ #undef linux #include #define GENL_MAGIC_VERSION API_VERSION #define GENL_MAGIC_FAMILY drbd #define GENL_MAGIC_FAMILY_HDRSZ sizeof(struct drbd_genlmsghdr) #define GENL_MAGIC_INCLUDE_FILE #include #endif drbd-utils-8.9.6/user/v84/config_flags.h0000644000175000017500000000371612634271674017717 0ustar apoikosapoikos#ifndef __DRBD_CONFIG_FLAGS_H #define __DRBD_CONFIG_FLAGS_H struct msg_buff; struct nlattr; struct context_def; struct field_def { const char *name; unsigned short nla_type; bool (*is_default)(struct field_def *, const char *); bool (*is_equal)(struct field_def *, const char *, const char *); const char *(*get)(struct context_def *, struct field_def *, struct nlattr *); bool (*put)(struct context_def *, struct field_def *, struct msg_buff *, const char *); int (*usage)(struct field_def *, char *, int); void (*describe_xml)(struct field_def *); union { struct { const char **map; int size; int def; } e; /* ENUM, ENUM_NOCASE */ struct { long long min; long long max; long long def; bool is_signed; char scale; } n; /* NUMERIC */ struct { bool def; } b; /* BOOLEAN */ } u; bool needs_double_quoting; bool argument_is_optional; const char *unit; }; struct context_def { struct nla_policy *nla_policy; int nla_policy_size; struct field_def fields[]; }; extern struct context_def disk_options_ctx; extern struct context_def net_options_ctx; extern struct context_def primary_cmd_ctx; extern struct context_def attach_cmd_ctx; extern struct context_def detach_cmd_ctx; extern struct context_def connect_cmd_ctx; extern struct context_def disconnect_cmd_ctx; extern struct context_def resize_cmd_ctx; extern struct context_def resource_options_cmd_ctx; extern struct context_def new_current_uuid_cmd_ctx; extern struct context_def verify_cmd_ctx; extern struct context_def new_minor_cmd_ctx; extern const char *double_quote_string(const char *str); /* Also used by argument processing in drbdsetup */ extern int nla_put_address(struct msg_buff *msg, int attrtype, const char *arg); /* INET6_ADDRSTRLEN + 'ipv6 []:54321 + possible scope + some */ #define ADDRESS_STR_MAX 256 extern void sprint_address(char *buffer, void *address, int addr_len); extern int get_af_ssocks(int warn_and_use_default); #endif /* __DRBD_CONFIG_FLAGS_H */ drbd-utils-8.9.6/user/v84/drbd_nla.c0000644000175000017500000000232512466702074017025 0ustar apoikosapoikos#include #include "libgenl.h" #include #include "drbd_nla.h" static int drbd_nla_check_mandatory(int maxtype, struct nlattr *nla) { struct nlattr *head = nla_data(nla); int len = nla_len(nla); int rem; /* * validate_nla (called from nla_parse_nested) ignores attributes * beyond maxtype, and does not understand the DRBD_GENLA_F_MANDATORY flag. * In order to have it validate attributes with the DRBD_GENLA_F_MANDATORY * flag set also, check and remove that flag before calling * nla_parse_nested. */ nla_for_each_attr(nla, head, len, rem) { if (nla->nla_type & DRBD_GENLA_F_MANDATORY) { nla->nla_type &= ~DRBD_GENLA_F_MANDATORY; if (nla_type(nla) > maxtype) return -EOPNOTSUPP; } } return 0; } int drbd_nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla, const struct nla_policy *policy) { int err; err = drbd_nla_check_mandatory(maxtype, nla); if (!err) err = nla_parse_nested(tb, maxtype, nla, policy); return err; } struct nlattr *drbd_nla_find_nested(int maxtype, struct nlattr *nla, int attrtype) { int err; err = drbd_nla_check_mandatory(maxtype, nla); if (err) /* ignore */; return nla_find_nested(nla, attrtype); } drbd-utils-8.9.6/user/v84/drbdadm_parser.h0000644000175000017500000000645712477305373020253 0ustar apoikosapoikos/* drbdadm_parser.h a hand crafted parser This file is part of DRBD by Philipp Reisner and Lars Ellenberg. Copyright (C) 2006-2008, LINBIT Information Technologies GmbH Copyright (C) 2006-2008, Philipp Reisner Copyright (C) 2006-2008, Lars Ellenberg drbd is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. drbd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with drbd; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ enum range_checks { R_NO_CHECK, R_MINOR_COUNT, R_DIALOG_REFRESH, R_DISK_SIZE, R_TIMEOUT, R_CONNECT_INT, R_PING_INT, R_MAX_BUFFERS, R_MAX_EPOCH_SIZE, R_SNDBUF_SIZE, R_RCVBUF_SIZE, R_KO_COUNT, R_RATE, R_GROUP, R_AL_EXTENTS, R_PORT, R_META_IDX, R_WFC_TIMEOUT, R_DEGR_WFC_TIMEOUT, R_OUTDATED_WFC_TIMEOUT, R_C_PLAN_AHEAD, R_C_DELAY_TARGET, R_C_FILL_TARGET, R_C_MAX_RATE, R_C_MIN_RATE, R_CONG_FILL, R_CONG_EXTENTS, R_PROTOCOL, }; enum yytokentype { TK_GLOBAL = 258, TK_RESOURCE, TK_ON, TK_STACKED, TK_IGNORE, TK_NET, TK_DISK, TK_SKIP, TK_SYNCER, /* depricated after 8.3 */ TK_STARTUP, TK_DISABLE_IP_VERIFICATION, TK_DIALOG_REFRESH, TK_PROTOCOL, TK_HANDLER, TK_COMMON, TK_ADDRESS, TK_ALT_ADDRESS, TK_DEVICE, TK_MINOR, TK_META_DISK, TK_FLEX_META_DISK, TK_MINOR_COUNT, TK_IPADDR, TK_INTEGER, TK_STRING, TK_ELSE, TK_DISK_FLAG, TK_DISK_NO_FLAG, TK_DISK_OPTION, TK_NET_FLAG, TK_NET_NO_FLAG, TK_NET_OPTION, TK_SYNCER_FLAG, TK_SYNCER_OPTION, TK_STARTUP_FLAG, TK_STARTUP_OPTION, TK_STARTUP_DELEGATE, TK_HANDLER_OPTION, TK_USAGE_COUNT, TK_ASK, TK_YES, TK_NO, TK__THIS_HOST, TK__REMOTE_HOST, TK_PROXY, TK_INSIDE, TK_OUTSIDE, TK_MEMLIMIT, TK_PROXY_OPTION, TK_PROXY_DELEGATE, TK_ERR_STRING_TOO_LONG, TK_ERR_DQSTRING_TOO_LONG, TK_ERR_DQSTRING, TK_SCI, TK_SDP, TK_SSOCKS, TK_IPV4, TK_IPV6, TK_IPADDR6, TK_NET_DELEGATE, TK_INCLUDE, TK_BWLIMIT, TK_FLOATING, TK_DEPRECATED_OPTION, TK_VOLUME, TK_CMD_TIMEOUT_SHORT, TK_CMD_TIMEOUT_MEDIUM, TK_CMD_TIMEOUT_LONG, TK_RES_OPTION, TK_OPTIONS, TK__GROUPING_BASE = 0x1000, TK_SYNCER_OLD_OPT = 0x2000, /* Might be or'ed to TK_[NET|DISK]_[OPTION|SWITCH] */ TK_PROXY_GROUP = 0x3000, /* Gets or'ed to some options */ }; /* The higher bits define one or more token groups. */ #define GET_TOKEN_GROUP(__x) ((__x) & ~(TK__GROUPING_BASE - 1)) #define REMOVE_GROUP_FROM_TOKEN(__x) ((__x) & (TK__GROUPING_BASE - 1)) typedef struct YYSTYPE { char* txt; enum range_checks rc; } YYSTYPE; #define yystype YYSTYPE /* obsolescent; will be withdrawn */ #define YYSTYPE_IS_DECLARED 1 #define YYSTYPE_IS_TRIVIAL 1 extern yystype yylval; extern char* yytext; extern FILE* yyin; /* avoid compiler warnings about implicit declaration */ int yylex(void); void my_yypush_buffer_state(FILE *f); void yypop_buffer_state (void ); void yyrestart(FILE *input_file); drbd-utils-8.9.6/user/v84/drbdadm_scanner.fl0000644000175000017500000002307412632556027020551 0ustar apoikosapoikos%{ #include #include #include #include "drbdadm_parser.h" #include "drbdadm.h" #include "drbdtool_common.h" void long_string(char* text); void long_dqstring(char* text); void err_dqstring(char* text); #if 0 #define DP printf("'%s' ",yytext) #else #define DP #endif #define CP yylval.txt = strdup(yytext); yylval.rc = R_NO_CHECK #define RC(N) yylval.rc = R_ ## N #define YY_NO_INPUT 1 #define YY_NO_UNPUT 1 static void yyunput (int c, register char * yy_bp ) __attribute((unused)); #ifndef YY_FLEX_SUBMINOR_VERSION #define MAX_INCLUDE_DEPTH 10 YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH]; int include_stack_ptr = 0; #endif %} %option noyywrap NUM [0-9]{1,8}[MKGs]? SNUMB [0-9]{1,3} IPV4ADDR ({SNUMB}"."){3}{SNUMB} HEX4 [0-9a-fA-F]{1,4} IPV6ADDR ((({HEX4}":"){0,5}{HEX4})?":"{HEX4}?":"({HEX4}(":"{HEX4}){0,5})?("%"{STRING})?)|("::"[fF]{4}":"{IPV4ADDR}) WS [ \t\r] OPCHAR [{};\[\]:] DQSTRING \"([^\"\\\n]|\\[^\n]){0,255}\" LONG_DQSTRING \"([^\"\\\n]|\\[^\n]){255}. ERR_DQSTRING \"([^\"\\\n]|\\[^\n]){0,255}[\\\n] STRING [a-zA-Z0-9/._-]{1,128} LONG_STRING [a-zA-Z0-9/._-]{129} %% \n { line++; } \#.* /* ignore comments */ {WS} /* ignore whitespaces */ {OPCHAR} { DP; return yytext[0]; } on { DP; return TK_ON; } ignore-on { DP; return TK_IGNORE; } stacked-on-top-of { DP; return TK_STACKED; } floating { DP; return TK_FLOATING; } no { DP; return TK_NO; } net { DP; return TK_NET; } yes { DP; return TK_YES; } ask { DP; return TK_ASK; } skip { DP; return TK_SKIP; } disk { DP; return TK_DISK; } proxy { DP; return TK_PROXY; } minor { DP; return TK_MINOR; } inside { DP; return TK_INSIDE; } volume { DP; return TK_VOLUME; } cmd-timeout-short { DP; return TK_CMD_TIMEOUT_SHORT; } cmd-timeout-medium { DP; return TK_CMD_TIMEOUT_MEDIUM; } cmd-timeout-long { DP; return TK_CMD_TIMEOUT_LONG; } syncer { DP; return TK_SYNCER; } device { DP; return TK_DEVICE; } global { DP; return TK_GLOBAL; } common { DP; return TK_COMMON; } options { DP; return TK_OPTIONS; } outside { DP; return TK_OUTSIDE; } address { DP; return TK_ADDRESS; } alternate-link-address { DP; return TK_ALT_ADDRESS; } startup { DP; return TK_STARTUP; } include { DP; return TK_INCLUDE; } handlers { DP; return TK_HANDLER; } minor-count { DP; return TK_MINOR_COUNT; } disable-ip-verification { DP; return TK_DISABLE_IP_VERIFICATION;} dialog-refresh { DP; return TK_DIALOG_REFRESH; } resource { DP; return TK_RESOURCE; } meta-disk { DP; return TK_META_DISK; } flexible-meta-disk { DP; return TK_FLEX_META_DISK; } usage-count { DP; return TK_USAGE_COUNT; } _this_host { DP; return TK__THIS_HOST; } _remote_host { DP; return TK__REMOTE_HOST; } sci { DP; CP; return TK_SCI; } ssocks { DP; CP; return TK_SSOCKS; } sdp { DP; CP; return TK_SDP; } ipv4 { DP; CP; return TK_IPV4; } ipv6 { DP; CP; return TK_IPV6; } size { DP; CP; RC(DISK_SIZE); return TK_DISK_OPTION; } on-io-error { DP; CP; return TK_DISK_OPTION; } fencing { DP; CP; return TK_DISK_OPTION; } max-bio-bvecs { DP; CP; return TK_DISK_OPTION; } disk-timeout { DP; CP; return TK_DISK_OPTION; } read-balancing { DP; CP; return TK_DISK_OPTION; } rs-discard-granularity { DP; CP; return TK_DISK_OPTION; } use-bmbv { DP; CP; return TK_DISK_FLAG; } disk-barrier { DP; CP; return TK_DISK_FLAG; } disk-flushes { DP; CP; return TK_DISK_FLAG; } disk-drain { DP; CP; return TK_DISK_FLAG; } md-flushes { DP; CP; return TK_DISK_FLAG; } no-disk-barrier { DP; CP; return TK_DISK_NO_FLAG; } no-disk-flushes { DP; CP; return TK_DISK_NO_FLAG; } no-disk-drain { DP; CP; return TK_DISK_NO_FLAG; } no-md-flushes { DP; CP; return TK_DISK_NO_FLAG; } timeout { DP; CP; RC(TIMEOUT); return TK_NET_OPTION; } protocol { DP; CP; RC(PROTOCOL); return TK_NET_OPTION; } ko-count { DP; CP; RC(KO_COUNT); return TK_NET_OPTION; } ping-int { DP; CP; RC(PING_INT); return TK_NET_OPTION; } max-buffers { DP; CP; RC(MAX_BUFFERS); return TK_NET_OPTION;} sndbuf-size { DP; CP; RC(SNDBUF_SIZE); return TK_NET_OPTION | TK_PROXY_GROUP;} rcvbuf-size { DP; CP; RC(RCVBUF_SIZE); return TK_NET_OPTION | TK_PROXY_GROUP;} connect-int { DP; CP; RC(CONNECT_INT); return TK_NET_OPTION;} cram-hmac-alg { DP; CP; return TK_NET_OPTION; } shared-secret { DP; CP; return TK_NET_OPTION; } max-epoch-size { DP; CP; RC(MAX_EPOCH_SIZE); return TK_NET_OPTION;} after-sb-[012]pri { DP; CP; return TK_NET_OPTION; } rr-conflict { DP; CP; return TK_NET_OPTION; } ping-timeout { DP; CP; return TK_NET_OPTION | TK_PROXY_GROUP;} unplug-watermark { DP; CP; return TK_NET_OPTION; } data-integrity-alg { DP; CP; return TK_NET_OPTION; } on-congestion { DP; CP; return TK_NET_OPTION; } socket-check-timeout { DP; CP; return TK_NET_OPTION; } congestion-fill { DP; CP; RC(CONG_FILL); return TK_NET_OPTION; } congestion-extents { DP; CP; RC(CONG_EXTENTS); return TK_NET_OPTION;} allow-two-primaries { DP; CP; return TK_NET_FLAG; } always-asbp { DP; CP; return TK_NET_FLAG; } no-tcp-cork { DP; CP; return TK_NET_NO_FLAG; } tcp-cork { DP; CP; return TK_NET_FLAG; } discard-my-data { DP; CP; return TK_NET_DELEGATE; } rate { DP; CP; RC(RATE); return TK_SYNCER_OLD_OPT | TK_DISK_OPTION; } resync-rate { DP; CP; RC(RATE); return TK_DISK_OPTION; } after { DP; CP; return TK_SYNCER_OLD_OPT | TK_DISK_OPTION; } resync-after { DP; CP; return TK_DISK_OPTION; } verify-alg { DP; CP; return TK_SYNCER_OLD_OPT | TK_NET_OPTION; } csums-alg { DP; CP; return TK_SYNCER_OLD_OPT | TK_NET_OPTION; } csums-after-crash-only { DP; CP; return TK_NET_FLAG; } al-extents { DP; CP; RC(AL_EXTENTS); return TK_SYNCER_OLD_OPT | TK_DISK_OPTION;} al-updates { DP; CP; return TK_DISK_FLAG; } discard-zeroes-if-aligned { DP; CP; return TK_DISK_FLAG; } cpu-mask { DP; CP; return TK_SYNCER_OLD_OPT | TK_RES_OPTION; } use-rle { DP; CP; return TK_SYNCER_OLD_OPT | TK_NET_FLAG; } delay-probe-volume { DP; CP; return TK_DEPRECATED_OPTION; } delay-probe-interval { DP; CP; return TK_DEPRECATED_OPTION; } c-plan-ahead { DP; CP; RC(C_PLAN_AHEAD); return TK_SYNCER_OLD_OPT | TK_DISK_OPTION; } c-delay-target { DP; CP; RC(C_DELAY_TARGET); return TK_SYNCER_OLD_OPT | TK_DISK_OPTION; } c-fill-target { DP; CP; RC(C_FILL_TARGET); return TK_SYNCER_OLD_OPT | TK_DISK_OPTION; } c-max-rate { DP; CP; RC(C_MAX_RATE); return TK_SYNCER_OLD_OPT | TK_DISK_OPTION; } c-min-rate { DP; CP; RC(C_MIN_RATE); return TK_SYNCER_OLD_OPT | TK_DISK_OPTION; } throttle-threshold { DP; CP; return TK_DEPRECATED_OPTION; } hold-off-threshold { DP; CP; return TK_DEPRECATED_OPTION; } on-no-data-accessible { DP; CP; return TK_SYNCER_OLD_OPT | TK_RES_OPTION; } wfc-timeout { DP; CP; RC(WFC_TIMEOUT); return TK_STARTUP_OPTION;} degr-wfc-timeout { DP; CP; RC(DEGR_WFC_TIMEOUT); return TK_STARTUP_OPTION;} outdated-wfc-timeout { DP; CP; RC(OUTDATED_WFC_TIMEOUT); return TK_STARTUP_OPTION;} stacked-timeouts { DP; return TK_STARTUP_DELEGATE; } become-primary-on { DP; return TK_STARTUP_DELEGATE; } wait-after-sb { DP; CP; return TK_STARTUP_FLAG; } pri-on-incon-degr { DP; CP; return TK_HANDLER_OPTION; } pri-lost-after-sb { DP; CP; return TK_HANDLER_OPTION; } pri-lost { DP; CP; return TK_HANDLER_OPTION; } initial-split-brain { DP; CP; return TK_HANDLER_OPTION; } split-brain { DP; CP; return TK_HANDLER_OPTION; } outdate-peer { DP; CP; return TK_HANDLER_OPTION; } fence-peer { DP; CP; return TK_HANDLER_OPTION; } unfence-peer { DP; CP; return TK_HANDLER_OPTION; } local-io-error { DP; CP; return TK_HANDLER_OPTION; } before-resync-target { DP; CP; return TK_HANDLER_OPTION; } after-resync-target { DP; CP; return TK_HANDLER_OPTION; } before-resync-source { DP; CP; return TK_HANDLER_OPTION; } memlimit { DP; CP; return TK_PROXY_OPTION | TK_PROXY_GROUP; } read-loops { DP; CP; return TK_PROXY_OPTION | TK_PROXY_GROUP; } compression { DP; CP; return TK_PROXY_OPTION | TK_PROXY_GROUP; } bwlimit { DP; CP; return TK_PROXY_OPTION | TK_PROXY_GROUP; } plugin { DP; CP; return TK_PROXY_DELEGATE; } out-of-sync { DP; CP; return TK_HANDLER_OPTION; } {IPV4ADDR} { DP; CP; return TK_IPADDR; } {IPV6ADDR} { DP; CP; return TK_IPADDR6; } {NUM} { DP; CP; return TK_INTEGER; } {DQSTRING} { unescape(yytext); DP; CP; return TK_STRING; } {STRING} { DP; CP; return TK_STRING; } {LONG_STRING} { return TK_ERR_STRING_TOO_LONG; } {LONG_DQSTRING} { return TK_ERR_DQSTRING_TOO_LONG; } {ERR_DQSTRING} { return TK_ERR_DQSTRING; } . { DP; return TK_ELSE; } %% /* Compatibility cruft for flex version 2.5.4a */ #ifndef YY_FLEX_SUBMINOR_VERSION /** Pushes the new state onto the stack. The new state becomes * the current state. This function will allocate the stack * if necessary. * @param new_buffer The new state. * */ void yypush_buffer_state (YY_BUFFER_STATE new_buffer ) { if (new_buffer == NULL) return; if ( include_stack_ptr >= MAX_INCLUDE_DEPTH ) { fprintf( stderr, "Includes nested too deeply" ); exit( 1 ); } include_stack[include_stack_ptr++] = YY_CURRENT_BUFFER; yy_switch_to_buffer(new_buffer); BEGIN(INITIAL); } /** Removes and deletes the top of the stack, if present. * The next element becomes the new top. * */ void yypop_buffer_state (void) { if (!YY_CURRENT_BUFFER) return; if ( --include_stack_ptr < 0 ) { fprintf( stderr, "error in flex compat code\n" ); exit( 1 ); } yy_delete_buffer(YY_CURRENT_BUFFER ); yy_switch_to_buffer(include_stack[include_stack_ptr]); } #endif void my_yypush_buffer_state(FILE *f) { /* Since we do not have YY_BUF_SIZE outside of the flex generated file.*/ yypush_buffer_state(yy_create_buffer(f, YY_BUF_SIZE)); } drbd-utils-8.9.6/user/v84/drbdadm_adjust.c0000644000175000017500000005005512523133457020227 0ustar apoikosapoikos/* drbdadm_adjust.c This file is part of DRBD by Philipp Reisner and Lars Ellenberg. Copyright (C) 2003-2008, LINBIT Information Technologies GmbH. Copyright (C) 2003-2008, Philipp Reisner . Copyright (C) 2003-2008, Lars Ellenberg . drbd is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. drbd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with drbd; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #define _GNU_SOURCE #define _XOPEN_SOURCE 600 #define _FILE_OFFSET_BITS 64 #include #include #include #include #include #include #include #include #include #include #include #include #include "drbdadm.h" #include "drbdtool_common.h" #include "drbdadm_parser.h" #include "config_flags.h" /* drbdsetup show might complain that the device minor does not exist at all. Redirect stderr to /dev/null therefore. */ static FILE *m_popen(int *pid,char** argv) { int mpid; int pipes[2]; int dev_null; if(pipe(pipes)) { err("Creation of pipes failed: %m\n"); exit(E_EXEC_ERROR); } dev_null = open("/dev/null", O_WRONLY); if (dev_null == -1) { err("Opening /dev/null failed: %m\n"); exit(E_EXEC_ERROR); } mpid = fork(); if(mpid == -1) { err("Can not fork"); exit(E_EXEC_ERROR); } if(mpid == 0) { close(pipes[0]); // close reading end dup2(pipes[1], fileno(stdout)); close(pipes[1]); dup2(dev_null, fileno(stderr)); close(dev_null); execvp(argv[0],argv); err("Can not exec"); exit(E_EXEC_ERROR); } close(pipes[1]); // close writing end close(dev_null); *pid=mpid; return fdopen(pipes[0],"r"); } static int is_equal(struct context_def *ctx, struct d_option *a, struct d_option *b) { struct field_def *field; for (field = ctx->fields; field->name; field++) { if (!strcmp(field->name, a->name)) return field->is_equal(field, a->value, b->value); } err("Internal error: option '%s' not known in this context\n", a->name); abort(); } static bool is_default(struct context_def *ctx, struct d_option *opt) { struct field_def *field; for (field = ctx->fields; field->name; field++) { if (strcmp(field->name, opt->name)) continue; return field->is_default(field, opt->value); } return false; } static int opts_equal(struct context_def *ctx, struct d_option* conf, struct d_option* running) { struct d_option* opt; while(running) { if((opt=find_opt(conf,running->name))) { if(!is_equal(ctx, running, opt)) { if (verbose > 2) err("Value of '%s' differs: r=%s c=%s\n", opt->name,running->value,opt->value); return 0; } if (verbose > 3) err("Value of '%s' equal: r=%s c=%s\n", opt->name,running->value,opt->value); opt->mentioned=1; } else { if(!is_default(ctx, running)) { if (verbose > 2) err("Only in running config %s: %s\n", running->name,running->value); return 0; } if (verbose > 3) err("Is default: '%s' equal: r=%s\n", running->name,running->value); } running=running->next; } while(conf) { if(conf->mentioned==0 && !is_default(ctx, conf)) { if (verbose > 2) err("Only in config file %s: %s\n", conf->name,conf->value); return 0; } conf=conf->next; } return 1; } static int addr_equal(struct d_resource* conf, struct d_resource* running) { int equal; char *peer_addr, *peer_af, *peer_port; if (conf->peer == NULL && running->peer == NULL) return 1; if (running->peer == NULL) return 0; equal = !strcmp(conf->me->address, running->me->address) && !strcmp(conf->me->port, running->me->port) && !strcmp(conf->me->address_family, running->me->address_family); if(conf->me->proxy) { peer_addr = conf->me->proxy->inside_addr; peer_port = conf->me->proxy->inside_port; peer_af = conf->me->proxy->inside_af; } else { peer_addr = conf->peer->address; peer_port = conf->peer->port; peer_af = conf->peer->address_family; } equal = equal && conf->peer && !strcmp(peer_addr, running->peer->address) && !strcmp(peer_port, running->peer->port) && !strcmp(peer_af, running->peer->address_family); if (!equal && verbose > 2) err("Network addresses differ:\n" "\trunning: %s:%s:%s -- %s:%s:%s\n" "\t config: %s:%s:%s -- %s:%s:%s\n", running->me->address_family, running->me->address, running->me->port, running->peer->address_family, running->peer->address, running->peer->port, conf->me->address_family, conf->me->address, conf->me->port, peer_af, peer_addr, peer_port); return equal; } /* Are both internal, or are both not internal. */ static int int_eq(char* m_conf, char* m_running) { return !strcmp(m_conf,"internal") == !strcmp(m_running,"internal"); } static int disk_equal(struct d_volume *conf, struct d_volume *running) { int eq = 1; if (conf->disk == NULL && running->disk == NULL) return 1; if (conf->disk == NULL || running->disk == NULL) return 0; eq &= !strcmp(conf->disk, running->disk); eq &= int_eq(conf->meta_disk, running->meta_disk); if (!strcmp(conf->meta_disk, "internal")) return eq; eq &= !strcmp(conf->meta_disk, running->meta_disk); return eq; } /* NULL terminated */ static void find_option_in_resources(char *name, struct d_option *list, struct d_option **opt, ...) { va_list va; va_start(va, opt); /* We need to keep setting *opt to NULL, even if a list == NULL. */ while (list || opt) { while (list) { if (strcmp(list->name, name) == 0) break; list = list->next; } *opt = list; list = va_arg(va, struct d_option*); opt = va_arg(va, struct d_option**); } va_end(va); } static int do_proxy_reconf(struct cfg_ctx *ctx) { int rv; char *argv[4] = { drbd_proxy_ctl, "-c", (char*)ctx->arg, NULL }; rv = m_system_ex(argv, SLEEPS_SHORT, ctx->res->name); return rv; } #define MAX_PLUGINS (10) #define MAX_PLUGIN_NAME (16) /* The new name is appended to the alist. */ int _is_plugin_in_list(char *string, char slist[MAX_PLUGINS][MAX_PLUGIN_NAME], char alist[MAX_PLUGINS][MAX_PLUGIN_NAME], int list_len) { int word_len, i; char *copy; for(word_len=0; string[word_len]; word_len++) if (isspace(string[word_len])) break; if (word_len+1 >= MAX_PLUGIN_NAME) { err("Wrong proxy plugin name %*.*s", word_len, word_len, string); exit(E_CONFIG_INVALID); } copy = alist[list_len]; strncpy(copy, string, word_len); copy[word_len] = 0; for(i=0; i= MAX_PLUGINS) { err("Too many proxy plugins."); exit(E_CONFIG_INVALID); } return 0; } static int proxy_reconf(struct cfg_ctx *ctx, struct d_resource *running) { int reconn = 0; struct d_resource *res = ctx->res; struct d_option* res_o, *run_o; unsigned long long v1, v2, minimum; char *plugin_changes[MAX_PLUGINS], *cp, *conn_name; /* It's less memory usage when we're storing char[]. malloc overhead for * the few bytes + pointers is much more. */ char p_res[MAX_PLUGINS][MAX_PLUGIN_NAME], p_run[MAX_PLUGINS][MAX_PLUGIN_NAME]; int used, i, re_do; reconn = 0; if (!running) goto redo_whole_conn; find_option_in_resources("memlimit", res->me->proxy->options, &res_o, running->proxy_options, &run_o, NULL, NULL); v1 = res_o ? m_strtoll(res_o->value, 1) : 0; v2 = run_o ? m_strtoll(run_o->value, 1) : 0; minimum = v1 < v2 ? v1 : v2; /* We allow an Ñ” [epsilon] of 2%, so that small (rounding) deviations do * not cause the connection to be re-established. */ if (res_o && (!run_o || abs(v1-v2)/(float)minimum > 0.02)) { redo_whole_conn: /* As the memory is in use while the connection is allocated we have to * completely destroy and rebuild the connection. */ schedule_deferred_cmd( do_proxy_conn_down, ctx, NULL, CFG_NET_PREREQ); schedule_deferred_cmd( do_proxy_conn_up, ctx, NULL, CFG_NET_PREREQ); schedule_deferred_cmd( do_proxy_conn_plugins, ctx, NULL, CFG_NET_PREREQ); /* With connection cleanup and reopen everything is rebuild anyway, and * DRBD will get a reconnect too. */ return 0; } res_o = res->me->proxy->plugins; run_o = running->proxy_plugins; used = 0; conn_name = proxy_connection_name(res); for(i=0; i= sizeof(plugin_changes)-1) { err("Too many proxy plugin changes"); exit(E_CONFIG_INVALID); } /* Now we can be sure that we can store another pointer. */ if (!res_o) { if (run_o) { /* More plugins running than configured - just stop here. */ m_asprintf(&cp, "set plugin %s %d end", conn_name, i); plugin_changes[used++] = cp; } else { /* Both at the end? ok, quit loop */ } break; } /* res_o != NULL. */ if (!run_o) { p_run[i][0] = 0; if (_is_plugin_in_list(res_o->name, p_run, p_res, i)) { /* Current plugin was already active, just at another position. * Redo the whole connection. */ goto redo_whole_conn; } /* More configured than running - just add it, if it's not already * somewhere else. */ m_asprintf(&cp, "set plugin %s %d %s", conn_name, i, res_o->name); plugin_changes[used++] = cp; } else { /* If we get here, both lists have been filled in parallel, so we * can simply use the common counter. */ re_do = _is_plugin_in_list(res_o->name, p_run, p_res, i) || _is_plugin_in_list(run_o->name, p_res, p_run, i); if (re_do) { /* Plugin(s) were moved, not simple reconfigured. * Re-do the whole connection. */ goto redo_whole_conn; } /* TODO: We don't (yet) account for possible different ordering of * the parameters to the plugin. * plugin A 1 B 2 * should be treated as equal to * plugin B 2 A 1. */ if (strcmp(run_o->name, res_o->name) != 0) { /* Either a different plugin, or just different settings * - plugin can be overwritten. */ m_asprintf(&cp, "set plugin %s %d %s", conn_name, i, res_o->name); plugin_changes[used++] = cp; } } if (res_o) res_o = res_o->next; if (run_o) run_o = run_o->next; } /* change only a few plugin settings. */ for(i=0; iname); err = stat("/dev/drbd/by-res", &sbuf); if (err) /* probably no udev rules in use */ return 0; err = stat(link_name, &sbuf); if (err) /* resource link cannot be stat()ed. */ return 1; /* double check device information */ if (!S_ISBLK(sbuf.st_mode)) return 1; if (major(sbuf.st_rdev) != DRBD_MAJOR) return 1; if (minor(sbuf.st_rdev) != res->me->volumes->device_minor) return 1; /* Link exists, and is expected block major:minor. * Do nothing. */ return 0; } /* moves option to the head of the single linked option list, * and marks it as to be skiped for "adjust only" commands * like disk-options see e.g. adm_attach_and_or_disk_options(). */ static void move_opt_to_head(struct d_option **head, struct d_option *o) { struct d_option *t; if (!o) return; o->adj_skip = 1; if (o == *head) return; for (t = *head; t->next != o; t = t->next) ; t->next = o->next; o->next = *head; *head = o; } void compare_max_bio_bvecs(struct d_volume *conf, struct d_volume *kern) { struct d_option *c = find_opt(conf->disk_options, "max-bio-bvecs"); struct d_option *k = find_opt(kern->disk_options, "max-bio-bvecs"); /* move to front of list, so we can skip it * for the following opts_equal */ move_opt_to_head(&conf->disk_options, c); move_opt_to_head(&kern->disk_options, k); /* simplify logic below, would otherwise have to * (!x || is_default(x) all the time. */ if (k && is_default(&attach_cmd_ctx, k)) k = NULL; /* there was a bvec restriction set, * but it is no longer in config, or vice versa */ if (!k != !c) conf->adj_attach = 1; /* restrictions differ */ if (k && c && !is_equal(&attach_cmd_ctx, k, c)) conf->adj_attach = 1; } /* similar to compare_max_bio_bvecs above */ void compare_size(struct d_volume *conf, struct d_volume *kern) { struct d_option *c = find_opt(conf->disk_options, "size"); struct d_option *k = find_opt(kern->disk_options, "size"); /* Special-case "max-bio-bvecs", we do not allow to change that * while attached, yet. * Also special case "size", we need to issue a resize command to change that. * Move both options to the head of the disk_options list, * so we can easily skip them in the opts_equal, later. */ move_opt_to_head(&conf->disk_options, c); move_opt_to_head(&kern->disk_options, k); if (k && is_default(&attach_cmd_ctx, k)) k = NULL; if (!k != !c) conf->adj_resize = 1; if (k && c && !is_equal(&attach_cmd_ctx, c, k)) conf->adj_resize = 1; } void compare_volume(struct d_volume *conf, struct d_volume *kern) { struct d_option *c, *k; /* do we need to do a full attach, * potentially with a detach first? */ conf->adj_attach = (conf->device_minor != kern->device_minor) || !disk_equal(conf, kern); /* do we need to do a full (detach/)attach, * because max_bio_bvec setting differs? */ compare_max_bio_bvecs(conf, kern); /* do we need to resize? */ compare_size(conf, kern); /* skip these two options (if present) for the opts_equal below. * These have been move_opt_to_head()ed before already. */ k = kern->disk_options; while (k && (!strcmp(k->name, "size") || !strcmp(k->name, "max-bio-bvecs"))) k = k->next; c = conf->disk_options; while (c && (!strcmp(c->name, "size") || !strcmp(c->name, "max-bio-bvecs"))) c = c->next; /* is it sufficient to only adjust the disk options? */ if (!conf->adj_attach) conf->adj_disk_opts = !opts_equal(&disk_options_ctx, c, k); if (conf->adj_attach && kern->disk) conf->adj_detach = 1; } struct d_volume *new_to_be_deleted_minor_from_template(struct d_volume *kern) { /* need to delete it from kernel. * Create a minimal volume, * and flag it as "del_minor". */ struct d_volume *conf = calloc(1, sizeof(*conf)); conf->vnr = kern->vnr; /* conf->device: no need */ conf->device_minor = kern->device_minor; if (kern->disk) { conf->disk = strdup(kern->disk); conf->meta_disk = strdup(kern->meta_disk); conf->meta_index = strdup(kern->meta_index); conf->adj_detach = 1; } conf->adj_del_minor = 1; return conf; } #define ASSERT(x) do { if (!(x)) { \ err("%s:%u:%s: ASSERT(%s) failed.\n", __FILE__, \ __LINE__, __func__, #x); \ abort(); } \ } while (0) /* Both conf and kern are single linked lists * supposed to be ordered by ->vnr; * We may need to conjure dummy volumes to issue "del-minor" on, * and insert these into the conf list. * The resulting new conf list head is returned. */ struct d_volume *compare_volumes(struct d_volume *conf, struct d_volume *kern) { struct d_volume *to_be_deleted = NULL; struct d_volume *conf_head = conf; while (conf || kern) { if (kern && (conf == NULL || kern->vnr < conf->vnr)) { to_be_deleted = INSERT_SORTED(to_be_deleted, new_to_be_deleted_minor_from_template(kern), vnr); kern = kern->next; } else if (conf && (kern == NULL || kern->vnr > conf->vnr)) { conf->adj_add_minor = 1; conf->adj_attach = 1; conf = conf->next; } else { ASSERT(conf); ASSERT(kern); ASSERT(conf->vnr == kern->vnr); compare_volume(conf, kern); conf = conf->next; kern = kern->next; } } for_each_volume(conf, to_be_deleted) conf_head = INSERT_SORTED(conf_head, conf, vnr); return conf_head; } /* * CAUTION this modifies global static char * config_file! */ int adm_adjust(struct cfg_ctx *ctx) { char* argv[20]; int pid,argc, i; struct d_resource* running; struct d_volume *vol; /* necessary per resource actions */ int do_res_options = 0; /* necessary per connection actions * (currently we still only have one connection per resource */ int do_net_options = 0; int do_disconnect = 0; int do_connect = 0; /* necessary per volume actions are flagged * in the vol->adj_* members. */ int can_do_proxy = 1; char config_file_dummy[250]; char show_conn[128]; char *resource_name; /* disable check_uniq, so it won't interfere * with parsing of drbdsetup show output */ config_valid = 2; /* setup error reporting context for the parsing routines */ line = 1; sprintf(config_file_dummy,"drbdsetup show %s", ctx->res->name); config_file = config_file_dummy; argc=0; argv[argc++]=drbdsetup; argv[argc++]="show"; ssprintf(argv[argc++], "%s", ctx->res->name); argv[argc++]=0; /* actually parse drbdsetup show output */ yyin = m_popen(&pid,argv); running = parse_resource_for_adjust(ctx); fclose(yyin); waitpid(pid, 0, 0); if (running) { /* Sets "me" and "peer" pointer */ post_parse(running, 0); set_peer_in_resource(running, 0); } /* Parse proxy settings, if this host has a proxy definition. * FIXME what about "zombie" proxy settings, if we remove proxy * settings from the config file without prior proxy-down, this won't * clean them from the proxy. */ if (ctx->res->me->proxy) { line = 1; resource_name = proxy_connection_name(ctx->res); i=snprintf(show_conn, sizeof(show_conn), "show proxy-settings %s", resource_name); if (i>= sizeof(show_conn)-1) { err("connection name too long"); exit(E_THINKO); } sprintf(config_file_dummy,"drbd-proxy-ctl -c '%s'", show_conn); config_file = config_file_dummy; argc=0; argv[argc++]=drbd_proxy_ctl; argv[argc++]="-c"; argv[argc++]=show_conn; argv[argc++]=0; /* actually parse "drbd-proxy-ctl show" output */ yyin = m_popen(&pid,argv); can_do_proxy = !parse_proxy_options_section(running); fclose(yyin); waitpid(pid,0,0); } ctx->res->me->volumes = compare_volumes(ctx->res->me->volumes, running ? running->me->volumes : NULL); if (running) { do_connect = !addr_equal(ctx->res,running); do_net_options = !opts_equal(&net_options_ctx, ctx->res->net_options, running->net_options); do_res_options = !opts_equal(&resource_options_cmd_ctx, ctx->res->res_options, running->res_options); } else { do_res_options = 0; do_connect = 1; schedule_deferred_cmd(adm_new_resource, ctx, "new-resource", CFG_PREREQ); } if (ctx->res->me->proxy && can_do_proxy) do_connect |= proxy_reconf(ctx, running); do_disconnect = do_connect && running && (running->peer || running->net_options); if (do_res_options) schedule_deferred_cmd(adm_set_default_res_options, ctx, "resource-options", CFG_RESOURCE); /* do we need to attach, * do we need to detach first, * or is this just some attribute change? */ for_each_volume(vol, ctx->res->me->volumes) { struct cfg_ctx tmp_ctx = { .res = ctx->res, .vol = vol }; if (vol->adj_detach) schedule_deferred_cmd(adm_generic_s, &tmp_ctx, "detach", CFG_PREREQ); if (vol->adj_del_minor) schedule_deferred_cmd(adm_generic_s, &tmp_ctx, "del-minor", CFG_PREREQ); if (vol->adj_add_minor) schedule_deferred_cmd(adm_new_minor, &tmp_ctx, "new-minor", CFG_DISK_PREREQ); if (vol->adj_attach) schedule_deferred_cmd(adm_attach, &tmp_ctx, "attach", CFG_DISK); if (vol->adj_disk_opts) schedule_deferred_cmd(adm_set_default_disk_options, &tmp_ctx, "disk-options", CFG_DISK); if (vol->adj_resize) schedule_deferred_cmd(adm_resize, &tmp_ctx, "resize", CFG_DISK); } if (do_connect) { /* "disconnect" specifying the end-point addresses currently in-use, * before "connect"ing with the addresses currently in-config-file. */ if (do_disconnect) { struct cfg_ctx tmp_ctx = { .res = running, .vol = vol, }; schedule_deferred_cmd(adm_disconnect, &tmp_ctx, "disconnect", CFG_NET_PREREQ); } schedule_deferred_cmd(adm_connect, ctx, "connect", CFG_NET); do_net_options = 0; } if (do_net_options) schedule_deferred_cmd(adm_set_default_net_options, ctx, "net-options", CFG_NET); return 0; } drbd-utils-8.9.6/user/v84/drbdadm_main.c0000644000175000017500000027051012615625471017665 0ustar apoikosapoikos/* drbdadm_main.c This file is part of DRBD by Philipp Reisner and Lars Ellenberg. Copyright (C) 2002-2008, LINBIT Information Technologies GmbH. Copyright (C) 2002-2008, Philipp Reisner . Copyright (C) 2002-2008, Lars Ellenberg . drbd is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. drbd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with drbd; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #define _GNU_SOURCE #define _XOPEN_SOURCE 600 #define _FILE_OFFSET_BITS 64 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "linux/drbd_limits.h" #include "drbdtool_common.h" #include "drbdadm.h" #include "registry.h" #include "config_flags.h" #include "shared_main.h" #define MAX_ARGS 40 static int indent = 0; #define INDENT_WIDTH 4 #define BFMT "%s;\n" #define IPV4FMT "%-16s %s %s:%s;\n" #define IPV6FMT "%-16s %s [%s]:%s;\n" #define MDISK "%-16s %s;\n" #define MDISKI "%-16s %s [%s];\n" #define printI(fmt, args... ) printf("%*s" fmt,INDENT_WIDTH * indent,"" , ## args ) #define printA(name, val ) \ printf("%*s%*s %3s;\n", \ INDENT_WIDTH * indent,"" , \ -24+INDENT_WIDTH * indent, \ name, val ) char *progname; struct adm_cmd { const char *name; int (*function) (struct cfg_ctx *); /* which level this command is for. * 0: don't show this command, ever * 1: normal administrative commands, shown in normal help * 2-4: shown on "drbdadm hidden-commands" * 2: useful for shell scripts * 3: callbacks potentially called from kernel module on certain events * 4: advanced, experts and developers only */ unsigned int show_in_usage:3; /* if set, command requires an explicit resource name */ unsigned int res_name_required:1; /* if set, command requires an explicit volume number as well */ unsigned int vol_id_required:1; /* most commands need to iterate over all volumes in the resource */ unsigned int iterate_volumes:1; /* error out if the ip specified is not available/active now */ unsigned int verify_ips:1; /* if set, use the "cache" in /var/lib/drbd to figure out * which config file to use. * This is necessary for handlers (callbacks from kernel) to work * when using "drbdadm -c /some/other/config/file" */ unsigned int use_cached_config_file:1; unsigned int need_peer:1; unsigned int is_proxy_cmd:1; unsigned int uc_dialog:1; /* May show usage count dialog */ unsigned int test_config:1; /* Allow -t option */ const struct context_def *drbdsetup_ctx; }; struct deferred_cmd { int (*function) (struct cfg_ctx *); struct cfg_ctx ctx; struct deferred_cmd *next; }; struct option general_admopt[] = { {"stacked", no_argument, 0, 'S'}, {"dry-run", no_argument, 0, 'd'}, {"verbose", no_argument, 0, 'v'}, {"config-file", required_argument, 0, 'c'}, {"config-to-test", required_argument, 0, 't'}, {"drbdsetup", required_argument, 0, 's'}, {"drbdmeta", required_argument, 0, 'm'}, {"drbd-proxy-ctl", required_argument, 0, 'p'}, {"sh-varname", required_argument, 0, 'n'}, {"peer", required_argument, 0, 'P'}, {"version", no_argument, 0, 'V'}, {"setup-option", required_argument, 0, 'W'}, {"help", no_argument, 0, 'h'}, {0, 0, 0, 0} }; struct option *admopt = general_admopt; extern void my_parse(); extern int yydebug; extern FILE *yyin; static int adm_generic_l(struct cfg_ctx *); static int adm_up(struct cfg_ctx *); static int adm_dump(struct cfg_ctx *); static int adm_dump_xml(struct cfg_ctx *); static int adm_wait_c(struct cfg_ctx *); static int adm_wait_ci(struct cfg_ctx *); static int adm_proxy_up(struct cfg_ctx *); static int adm_proxy_down(struct cfg_ctx *); static int sh_nop(struct cfg_ctx *); static int sh_resources(struct cfg_ctx *); static int sh_resource(struct cfg_ctx *); static int sh_mod_parms(struct cfg_ctx *); static int sh_dev(struct cfg_ctx *); static int sh_udev(struct cfg_ctx *); static int sh_minor(struct cfg_ctx *); static int sh_ip(struct cfg_ctx *); static int sh_lres(struct cfg_ctx *); static int sh_ll_dev(struct cfg_ctx *); static int sh_md_dev(struct cfg_ctx *); static int sh_md_idx(struct cfg_ctx *); static int sh_b_pri(struct cfg_ctx *); static int sh_status(struct cfg_ctx *); static int admm_generic(struct cfg_ctx *); static int adm_khelper(struct cfg_ctx *); static int adm_generic_b(struct cfg_ctx *); static int hidden_cmds(struct cfg_ctx *); static int adm_outdate(struct cfg_ctx *); static int adm_chk_resize(struct cfg_ctx *); static void dump_options(char *name, struct d_option *opts); struct d_volume *volume_by_vnr(struct d_volume *volumes, int vnr); struct d_resource *res_by_name(const char *name); int ctx_by_name(struct cfg_ctx *ctx, const char *id); int ctx_set_implicit_volume(struct cfg_ctx *ctx); static char *get_opt_val(struct d_option *, const char *, char *); char ss_buffer[1024]; struct utsname nodeinfo; int line = 1; int fline; char *config_file = NULL; char *config_save = NULL; char *config_test = NULL; struct d_resource *config = NULL; struct d_resource *common = NULL; struct ifreq *ifreq_list = NULL; int is_drbd_top; enum { NORMAL, STACKED, IGNORED, __N_RESOURCE_TYPES }; int nr_resources[__N_RESOURCE_TYPES]; int nr_volumes[__N_RESOURCE_TYPES]; int number_of_minors = 0; int config_from_stdin = 0; int config_valid = 1; int no_tty; int dry_run = 0; int verbose = 0; int adjust_with_progress = 0; bool help; int do_verify_ips = 0; int do_register = 1; /* whether drbdadm was called with "all" instead of resource name(s) */ int all_resources = 0; char *drbdsetup = NULL; char *drbdmeta = NULL; char *drbdadm_83 = NULL; char *drbd_proxy_ctl; char *sh_varname = NULL; struct setup_option *setup_options; char *connect_to_host = NULL; struct deferred_cmd *deferred_cmds[__CFG_LAST] = { NULL, }; struct deferred_cmd *deferred_cmds_tail[__CFG_LAST] = { NULL, }; void add_setup_option(bool explicit, char *option) { int n = 0; if (setup_options) { while (setup_options[n].option) n++; } setup_options = realloc(setup_options, (n + 2) * sizeof(*setup_options)); if (!setup_options) { /* ... */ } setup_options[n].explicit = explicit; setup_options[n].option = option; n++; setup_options[n].option = NULL; } int adm_adjust_wp(struct cfg_ctx *ctx) { if (!verbose && !dry_run) adjust_with_progress = 1; return adm_adjust(ctx); } /* DRBD adm_cmd flags shortcuts, * to avoid merge conflicts and unreadable diffs * when we add the next flag */ #define DRBD_acf1_default \ .show_in_usage = 1, \ .res_name_required = 1, \ .iterate_volumes = 1, \ .verify_ips = 0, \ .uc_dialog = 1, \ #define DRBD_acf1_resname \ .show_in_usage = 1, \ .res_name_required = 1, \ .uc_dialog = 1, \ #define DRBD_acf1_connect \ .show_in_usage = 1, \ .res_name_required = 1, \ .iterate_volumes = 0, \ .verify_ips = 1, \ .need_peer = 1, \ .uc_dialog = 1, \ #define DRBD_acf1_up \ .show_in_usage = 1, \ .res_name_required = 1, \ .iterate_volumes = 1, \ .verify_ips = 1, \ .need_peer = 1, \ .uc_dialog = 1, \ #define DRBD_acf1_defnet \ .show_in_usage = 1, \ .res_name_required = 1, \ .iterate_volumes = 1, \ .verify_ips = 1, \ .uc_dialog = 1, \ #define DRBD_acf3_handler \ .show_in_usage = 3, \ .res_name_required = 1, \ .iterate_volumes = 0, \ .vol_id_required = 1, \ .verify_ips = 0, \ .use_cached_config_file = 1, \ #define DRBD_acf3_res_handler \ .show_in_usage = 3, \ .res_name_required = 1, \ .iterate_volumes = 0, \ .vol_id_required = 0, \ .verify_ips = 0, \ .use_cached_config_file = 1, \ #define DRBD_acf4_advanced \ .show_in_usage = 4, \ .res_name_required = 1, \ .iterate_volumes = 1, \ .verify_ips = 0, \ .uc_dialog = 1, \ #define DRBD_acf4_advanced_need_vol \ .show_in_usage = 4, \ .res_name_required = 1, \ .iterate_volumes = 0, \ .vol_id_required = 1, \ .verify_ips = 0, \ .uc_dialog = 1, \ #define DRBD_acf1_dump \ .show_in_usage = 1, \ .res_name_required = 1, \ .verify_ips = 1, \ .uc_dialog = 1, \ .test_config = 1, \ #define DRBD_acf2_shell \ .show_in_usage = 2, \ .iterate_volumes = 1, \ .res_name_required = 1, \ .verify_ips = 0, \ #define DRBD_acf2_sh_resname \ .show_in_usage = 2, \ .iterate_volumes = 0, \ .res_name_required = 1, \ .verify_ips = 0, \ #define DRBD_acf2_proxy \ .show_in_usage = 2, \ .res_name_required = 1, \ .verify_ips = 0, \ .need_peer = 1, \ .is_proxy_cmd = 1, \ #define DRBD_acf2_hook \ .show_in_usage = 2, \ .res_name_required = 1, \ .verify_ips = 0, \ .use_cached_config_file = 1, \ #define DRBD_acf2_gen_shell \ .show_in_usage = 2, \ .res_name_required = 0, \ .verify_ips = 0, \ struct adm_cmd cmds[] = { /* name, function, flags * sort order: * - normal config commands, * - normal meta data manipulation * - sh-* * - handler * - advanced ***/ {"attach", adm_attach, DRBD_acf1_default .drbdsetup_ctx = &attach_cmd_ctx, }, {"disk-options", adm_disk_options, DRBD_acf1_default .drbdsetup_ctx = &disk_options_ctx, }, {"detach", adm_generic_l, DRBD_acf1_default .drbdsetup_ctx = &detach_cmd_ctx, }, {"connect", adm_connect, DRBD_acf1_connect .drbdsetup_ctx = &connect_cmd_ctx, }, {"net-options", adm_net_options, DRBD_acf1_connect .drbdsetup_ctx = &net_options_ctx, }, {"disconnect", adm_disconnect, DRBD_acf1_resname .drbdsetup_ctx = &disconnect_cmd_ctx, }, {"up", adm_up, DRBD_acf1_up}, {"resource-options", adm_res_options, DRBD_acf1_resname .drbdsetup_ctx = &resource_options_cmd_ctx, }, {"down", adm_generic_l, DRBD_acf1_resname}, {"primary", adm_generic_l, DRBD_acf1_default .drbdsetup_ctx = &primary_cmd_ctx, }, {"secondary", adm_generic_l, DRBD_acf1_default}, {"invalidate", adm_generic_b, DRBD_acf1_default}, {"invalidate-remote", adm_generic_l, DRBD_acf1_defnet}, {"outdate", adm_outdate, DRBD_acf1_default}, {"resize", adm_resize, DRBD_acf1_defnet}, {"verify", adm_generic_s, DRBD_acf1_defnet}, {"pause-sync", adm_generic_s, DRBD_acf1_defnet}, {"resume-sync", adm_generic_s, DRBD_acf1_defnet}, {"adjust", adm_adjust, DRBD_acf1_connect}, {"adjust-with-progress", adm_adjust_wp, DRBD_acf1_connect}, {"wait-connect", adm_wait_c, DRBD_acf1_defnet}, {"wait-con-int", adm_wait_ci, .show_in_usage = 1,.verify_ips = 1,}, {"role", adm_generic_s, DRBD_acf1_default}, {"cstate", adm_generic_s, DRBD_acf1_default}, {"dstate", adm_generic_b, DRBD_acf1_default}, {"dump", adm_dump, DRBD_acf1_dump}, {"dump-xml", adm_dump_xml, DRBD_acf1_dump}, {"create-md", adm_create_md, DRBD_acf1_default}, {"show-gi", adm_generic_b, DRBD_acf1_default}, {"get-gi", adm_generic_b, DRBD_acf1_default}, {"dump-md", admm_generic, DRBD_acf1_default}, {"wipe-md", admm_generic, DRBD_acf1_default}, {"apply-al", admm_generic, DRBD_acf1_default}, {"hidden-commands", hidden_cmds,.show_in_usage = 1,}, {"sh-nop", sh_nop, DRBD_acf2_gen_shell .uc_dialog = 1, .test_config = 1}, {"sh-resources", sh_resources, DRBD_acf2_gen_shell}, {"sh-resource", sh_resource, DRBD_acf2_sh_resname}, {"sh-mod-parms", sh_mod_parms, DRBD_acf2_gen_shell}, {"sh-dev", sh_dev, DRBD_acf2_shell}, {"sh-udev", sh_udev, .vol_id_required = 1, DRBD_acf2_hook}, {"sh-minor", sh_minor, DRBD_acf2_shell}, {"sh-ll-dev", sh_ll_dev, DRBD_acf2_shell}, {"sh-md-dev", sh_md_dev, DRBD_acf2_shell}, {"sh-md-idx", sh_md_idx, DRBD_acf2_shell}, {"sh-ip", sh_ip, DRBD_acf2_shell}, {"sh-lr-of", sh_lres, DRBD_acf2_shell}, {"sh-b-pri", sh_b_pri, DRBD_acf2_shell}, {"sh-status", sh_status, DRBD_acf2_gen_shell}, {"proxy-up", adm_proxy_up, DRBD_acf2_proxy}, {"proxy-down", adm_proxy_down, DRBD_acf2_proxy}, {"new-resource", adm_new_resource, DRBD_acf2_sh_resname}, {"sh-new-minor", adm_new_minor, DRBD_acf4_advanced}, {"new-minor", adm_new_minor, DRBD_acf4_advanced}, /* alias for sh-new-minor */ {"before-resync-target", adm_khelper, DRBD_acf3_handler}, {"after-resync-target", adm_khelper, DRBD_acf3_handler}, {"before-resync-source", adm_khelper, DRBD_acf3_handler}, {"pri-on-incon-degr", adm_khelper, DRBD_acf3_handler}, {"pri-lost-after-sb", adm_khelper, DRBD_acf3_handler}, {"fence-peer", adm_khelper, DRBD_acf3_res_handler}, {"unfence-peer", adm_khelper, DRBD_acf3_res_handler}, {"local-io-error", adm_khelper, DRBD_acf3_handler}, {"pri-lost", adm_khelper, DRBD_acf3_handler}, {"initial-split-brain", adm_khelper, DRBD_acf3_handler}, {"split-brain", adm_khelper, DRBD_acf3_handler}, {"out-of-sync", adm_khelper, DRBD_acf3_handler}, {"suspend-io", adm_generic_s, DRBD_acf4_advanced}, {"resume-io", adm_generic_s, DRBD_acf4_advanced}, {"set-gi", admm_generic, DRBD_acf4_advanced_need_vol}, {"new-current-uuid", adm_generic_s, DRBD_acf4_advanced_need_vol .drbdsetup_ctx = &new_current_uuid_cmd_ctx, }, {"check-resize", adm_chk_resize, DRBD_acf4_advanced}, }; void schedule_deferred_cmd(int (*function) (struct cfg_ctx *), struct cfg_ctx *ctx, const char *arg, enum drbd_cfg_stage stage) { struct deferred_cmd *d, *t; d = calloc(1, sizeof(struct deferred_cmd)); if (d == NULL) { perror("calloc"); exit(E_EXEC_ERROR); } d->function = function; d->ctx.res = ctx->res; d->ctx.vol = ctx->vol; d->ctx.arg = arg; /* first to come is head */ if (!deferred_cmds[stage]) deferred_cmds[stage] = d; /* link it in at tail */ t = deferred_cmds_tail[stage]; if (t) t->next = d; /* advance tail */ deferred_cmds_tail[stage] = d; } enum on_error { KEEP_RUNNING, EXIT_ON_FAIL }; int call_cmd_fn(int (*function) (struct cfg_ctx *), struct cfg_ctx *ctx, enum on_error on_error) { int rv; rv = function(ctx); if (rv >= 20) { if (on_error == EXIT_ON_FAIL) exit(rv); } return rv; } /* If ctx->vol is NULL, and cmd->iterate_volumes is set, * iterate over all volumes in ctx->res. * Else, just pass it on. * */ int call_cmd(struct adm_cmd *cmd, struct cfg_ctx *ctx, enum on_error on_error) { struct cfg_ctx tmp_ctx = *ctx; struct d_resource *res = ctx->res; struct d_volume *vol; int ret; if (!res->peer) set_peer_in_resource(res, cmd->need_peer); if (!cmd->iterate_volumes || ctx->vol != NULL) return call_cmd_fn(cmd->function, &tmp_ctx, on_error); for_each_volume(vol, res->me->volumes) { tmp_ctx.vol = vol; ret = call_cmd_fn(cmd->function, &tmp_ctx, on_error); /* FIXME: Do we want to keep running? * When? * How would we determine which return value to return? */ if (ret) return ret; } return 0; } static char *drbd_cfg_stage_string[] = { [CFG_PREREQ] = "create res", [CFG_RESOURCE] = "adjust res", [CFG_DISK_PREREQ] = "prepare disk", [CFG_DISK] = "adjust disk", [CFG_NET_PREREQ] = "prepare net", [CFG_NET] = "adjust net", }; int _run_deferred_cmds(enum drbd_cfg_stage stage) { struct d_resource *last_res = NULL; struct deferred_cmd *d = deferred_cmds[stage]; struct deferred_cmd *t; int r; int rv = 0; if (d && adjust_with_progress) { printf("\n%15s:", drbd_cfg_stage_string[stage]); fflush(stdout); } while (d) { if (d->ctx.res->skip_further_deferred_command) { if (adjust_with_progress) { if (d->ctx.res != last_res) printf(" [skipped:%s]", d->ctx.res->name); } else err("%s: %s %s: skipped due to earlier error\n", progname, d->ctx.arg, d->ctx.res->name); r = 0; } else { if (adjust_with_progress) { if (d->ctx.res != last_res) printf(" %s", d->ctx.res->name); } r = call_cmd_fn(d->function, &d->ctx, KEEP_RUNNING); if (r) { /* If something in the "prerequisite" stages failed, * there is no point in trying to continue. * However if we just failed to adjust some * options, or failed to attach, we still want * to adjust other options, or try to connect. */ if (stage == CFG_PREREQ || stage == CFG_DISK_PREREQ) d->ctx.res->skip_further_deferred_command = 1; if (adjust_with_progress) printf(":failed(%s:%u)", d->ctx.arg, r); } } last_res = d->ctx.res; t = d->next; free(d); d = t; if (r > rv) rv = r; } return rv; } int run_deferred_cmds(void) { enum drbd_cfg_stage stage; int r; int ret = 0; if (adjust_with_progress) printf("["); for (stage = CFG_PREREQ; stage < __CFG_LAST; stage++) { r = _run_deferred_cmds(stage); if (r) { if (!adjust_with_progress) return 1; /* FIXME r? */ ret = 1; } } if (adjust_with_progress) printf("\n]\n"); return ret; } /*** These functions are used to the print the config ***/ static void dump_options2(char *name, struct d_option *opts, void(*within)(void*), void *ctx) { if (!opts && !(within && ctx)) return; printI("%s {\n", name); ++indent; while (opts) { if (opts->value) printA(opts->name, opts->is_escaped ? opts->value : esc(opts-> value)); else printI(BFMT, opts->name); opts = opts->next; } if (within) within(ctx); --indent; printI("}\n"); } static void dump_options(char *name, struct d_option *opts) { dump_options2(name, opts, NULL, NULL); } void dump_proxy_plugins(void *ctx) { struct d_option *opt = ctx; dump_options("plugin", opt); } static void dump_global_info() { static const char * const yes_no_ask[] = { [UC_YES] = "yes", [UC_NO] = "no", [UC_ASK] = "ask", }; if (!global_options.minor_count && !global_options.disable_ip_verification && global_options.dialog_refresh == 1 && global_options.usage_count == UC_ASK && !verbose) return; printI("global {\n"); ++indent; if (global_options.disable_ip_verification) printI("disable-ip-verification;\n"); if (global_options.minor_count) printI("minor-count %i;\n", global_options.minor_count); if (global_options.dialog_refresh != 1) printI("dialog-refresh %i;\n", global_options.dialog_refresh); if (global_options.usage_count != UC_ASK) printI("usage-count %s;\n", yes_no_ask[global_options.usage_count]); if (global_options.cmd_timeout_short != CMD_TIMEOUT_SHORT_DEF) printI("cmd-timeout-short %u;\n", global_options.cmd_timeout_short); if (global_options.cmd_timeout_medium != CMD_TIMEOUT_MEDIUM_DEF) printI("cmd-timeout-medium %u;\n", global_options.cmd_timeout_medium); if (global_options.cmd_timeout_long != CMD_TIMEOUT_LONG_DEF) printI("cmd-timeout-long %u;\n", global_options.cmd_timeout_long); --indent; printI("}\n\n"); } static void fake_startup_options(struct d_resource *res); static void dump_common_info() { if (!common) return; printI("common {\n"); ++indent; fake_startup_options(common); dump_options("options", common->res_options); dump_options("net", common->net_options); dump_options("disk", common->disk_options); dump_options("startup", common->startup_options); dump_options2("proxy", common->proxy_options, dump_proxy_plugins, common->proxy_plugins); dump_options("handlers", common->handlers); --indent; printf("}\n\n"); } static void dump_address(char *name, char *addr, char *port, char *af) { if (!strcmp(af, "ipv6")) printI(IPV6FMT, name, af, addr, port); else printI(IPV4FMT, name, af, addr, port); } static void dump_proxy_info(struct d_proxy_info *pi) { printI("proxy on %s {\n", names_to_str(pi->on_hosts)); ++indent; dump_address("inside", pi->inside_addr, pi->inside_port, pi->inside_af); dump_address("outside", pi->outside_addr, pi->outside_port, pi->outside_af); dump_options2("options", pi->options, dump_proxy_plugins, pi->plugins); --indent; printI("}\n"); } static void dump_volume(int has_lower, struct d_volume *vol) { if (!vol->implicit) { printI("volume %d {\n", vol->vnr); ++indent; } /* Handle volume of '_remote_host' */ if (!vol->device && !vol->disk && !vol->meta_disk && !vol->meta_index) goto out; dump_options("disk", vol->disk_options); printI("device%*s", -19 + INDENT_WIDTH * indent, ""); if (vol->device) printf("%s ", esc(vol->device)); printf("minor %d;\n", vol->device_minor); if (!has_lower) printA("disk", esc(vol->disk)); if (!has_lower) { if (!strcmp(vol->meta_index, "flexible")) printI(MDISK, "meta-disk", esc(vol->meta_disk)); else if (!strcmp(vol->meta_index, "internal")) printA("meta-disk", "internal"); else printI(MDISKI, "meta-disk", esc(vol->meta_disk), vol->meta_index); } if (!vol->implicit) { out: --indent; printI("}\n"); } } static void dump_host_info(struct d_host_info *hi) { struct d_volume *vol; if (!hi) { printI(" # No host section data available.\n"); return; } if (hi->lower) { printI("stacked-on-top-of %s {\n", esc(hi->lower->name)); ++indent; printI("# on %s \n", names_to_str(hi->on_hosts)); } else if (hi->by_address) { if (!strcmp(hi->address_family, "ipv6")) printI("floating ipv6 [%s]:%s {\n", hi->address, hi->port); else printI("floating %s %s:%s {\n", hi->address_family, hi->address, hi->port); ++indent; } else { printI("on %s {\n", names_to_str(hi->on_hosts)); ++indent; } dump_options("options", hi->res_options); for_each_volume(vol, hi->volumes) dump_volume(!!hi->lower, vol); if (!hi->by_address) dump_address("address", hi->address, hi->port, hi->address_family); if (hi->alt_address) dump_address("alternate-link-address", hi->alt_address, hi->alt_port, hi->alt_address_family); if (hi->proxy) dump_proxy_info(hi->proxy); --indent; printI("}\n"); } static void dump_options_xml2(char *name, struct d_option *opts, void(*within)(void*), void *ctx) { if (!opts && !(within && ctx)) return; printI("
\n", name); ++indent; while (opts) { if (opts->value) printI("
\n"); } static void dump_options_xml(char *name, struct d_option *opts) { dump_options_xml2(name, opts, NULL, NULL); } void dump_proxy_plugins_xml(void *ctx) { struct d_option *opt = ctx; dump_options_xml("plugin", opt); } static void dump_global_info_xml() { if (!global_options.minor_count && !global_options.disable_ip_verification && global_options.dialog_refresh == 1) return; printI("\n"); ++indent; if (global_options.disable_ip_verification) printI("\n"); if (global_options.minor_count) printI("\n", global_options.minor_count); if (global_options.dialog_refresh != 1) printI("\n", global_options.dialog_refresh); --indent; printI("\n"); } static void dump_common_info_xml() { if (!common) return; printI("\n"); ++indent; fake_startup_options(common); dump_options_xml("options", common->res_options); dump_options_xml("net", common->net_options); dump_options_xml("disk", common->disk_options); dump_options_xml("startup", common->startup_options); dump_options_xml2("proxy", common->proxy_options, dump_proxy_plugins_xml, common->proxy_plugins); dump_options_xml("handlers", common->handlers); --indent; printI("\n"); } static void dump_proxy_info_xml(struct d_proxy_info *pi) { printI("\n", names_to_str(pi->on_hosts)); ++indent; printI("%s\n", pi->inside_af, pi->inside_port, pi->inside_addr); printI("%s\n", pi->outside_af, pi->outside_port, pi->outside_addr); dump_options_xml2("options", pi->options, dump_proxy_plugins_xml, pi->plugins); --indent; printI("\n"); } static void dump_volume_xml(struct d_volume *vol) { printI("\n", vol->vnr); ++indent; dump_options_xml("disk", vol->disk_options); printI("%s\n", vol->device_minor, esc_xml(vol->device)); printI("%s\n", esc_xml(vol->disk)); if (!strcmp(vol->meta_index, "flexible")) printI("%s\n", esc_xml(vol->meta_disk)); else if (!strcmp(vol->meta_index, "internal")) printI("internal\n"); else { printI("%s\n", vol->meta_index, esc_xml(vol->meta_disk)); } --indent; printI("\n"); } static void dump_host_info_xml(struct d_host_info *hi) { struct d_volume *vol; if (!hi) { printI("\n"); return; } if (hi->by_address) printI("\n"); else printI("\n", names_to_str(hi->on_hosts)); ++indent; dump_options_xml("options", hi->res_options); for_each_volume(vol, hi->volumes) dump_volume_xml(vol); printI("
%s
\n", hi->address_family, hi->port, hi->address); if (hi->proxy) dump_proxy_info_xml(hi->proxy); --indent; printI("
\n"); } static void fake_startup_options(struct d_resource *res) { struct d_option *opt; char *val; if (res->stacked_timeouts) { opt = new_opt(strdup("stacked-timeouts"), NULL); res->startup_options = APPEND(res->startup_options, opt); } if (res->become_primary_on) { val = strdup(names_to_str(res->become_primary_on)); opt = new_opt(strdup("become-primary-on"), val); opt->is_escaped = 1; res->startup_options = APPEND(res->startup_options, opt); } } static int adm_dump(struct cfg_ctx *ctx) { struct d_host_info *host; struct d_resource *res = ctx->res; if (!res) { printI("# no resources configured\n"); return 0; } printI("# resource %s on %s: %s, %s\n", esc(res->name), nodeinfo.nodename, res->ignore ? "ignored" : "not ignored", res->stacked ? "stacked" : "not stacked"); printI("# defined at %s:%u\n", res->config_file, res->start_line); printI("resource %s {\n", esc(res->name)); ++indent; for (host = res->all_hosts; host; host = host->next) dump_host_info(host); fake_startup_options(res); dump_options("options", res->res_options); dump_options("net", res->net_options); dump_options("disk", res->disk_options); dump_options("startup", res->startup_options); dump_options2("proxy", res->proxy_options, dump_proxy_plugins, res->proxy_plugins); dump_options("handlers", res->handlers); --indent; printf("}\n\n"); return 0; } static int adm_dump_xml(struct cfg_ctx *ctx) { struct d_host_info *host; struct d_resource *res = ctx->res; if (!res) { printI("\n"); return 0; } printI("\n", esc_xml(res->name), esc_xml(res->config_file), res->start_line); ++indent; // else if (common && common->protocol) printA("# common protocol", common->protocol); for (host = res->all_hosts; host; host = host->next) dump_host_info_xml(host); fake_startup_options(res); dump_options_xml("options", res->res_options); dump_options_xml("net", res->net_options); dump_options_xml("disk", res->disk_options); dump_options_xml("startup", res->startup_options); dump_options_xml2("proxy", res->proxy_options, dump_proxy_plugins_xml, res->proxy_plugins); dump_options_xml("handlers", res->handlers); --indent; printI("\n"); return 0; } static int sh_nop(struct cfg_ctx *ctx) { return 0; } static int sh_resources(struct cfg_ctx *ctx) { struct d_resource *res, *t; int first = 1; for_each_resource(res, t, config) { if (res->ignore) continue; if (is_drbd_top != res->stacked) continue; printf(first ? "%s" : " %s", esc(res->name)); first = 0; } if (!first) printf("\n"); return 0; } static int sh_resource(struct cfg_ctx *ctx) { printf("%s\n", ctx->res->name); return 0; } static int sh_dev(struct cfg_ctx *ctx) { printf("%s\n", ctx->vol->device); return 0; } static int sh_udev(struct cfg_ctx *ctx) { struct d_resource *res = ctx->res; struct d_volume *vol = ctx->vol; /* No shell escape necessary. Udev does not handle it anyways... */ if (!vol) { err("volume not specified\n"); return 1; } if (vol->implicit) printf("RESOURCE=%s\n", res->name); else printf("RESOURCE=%s/%u\n", res->name, vol->vnr); if (!strncmp(vol->device, "/dev/drbd", 9)) printf("DEVICE=%s\n", vol->device + 5); else printf("DEVICE=drbd%u\n", vol->device_minor); if (!strncmp(vol->disk, "/dev/", 5)) printf("DISK=%s\n", vol->disk + 5); else printf("DISK=%s\n", vol->disk); return 0; } static int sh_minor(struct cfg_ctx *ctx) { printf("%d\n", ctx->vol->device_minor); return 0; } static int sh_ip(struct cfg_ctx *ctx) { printf("%s\n", ctx->res->me->address); return 0; } static int sh_lres(struct cfg_ctx *ctx) { struct d_resource *res = ctx->res; if (!is_drbd_top) { err("sh-lower-resource only available in stacked mode\n"); exit(E_USAGE); } if (!res->stacked) { err("'%s' is not stacked on this host (%s)\n", res->name, nodeinfo.nodename); exit(E_USAGE); } printf("%s\n", res->me->lower->name); return 0; } static int sh_ll_dev(struct cfg_ctx *ctx) { printf("%s\n", ctx->vol->disk); return 0; } static int sh_md_dev(struct cfg_ctx *ctx) { struct d_volume *vol = ctx->vol; char *r; if (strcmp("internal", vol->meta_disk) == 0) r = vol->disk; else r = vol->meta_disk; printf("%s\n", r); return 0; } static int sh_md_idx(struct cfg_ctx *ctx) { printf("%s\n", ctx->vol->meta_index); return 0; } static int sh_b_pri(struct cfg_ctx *ctx) { struct d_resource *res = ctx->res; int i, rv; if (name_in_names(nodeinfo.nodename, res->become_primary_on) || name_in_names("both", res->become_primary_on)) { /* upon connect resync starts, and both sides become primary at the same time. One's try might be declined since an other state transition happens. Retry. */ for (i = 0; i < 5; i++) { const char *old_arg = ctx->arg; ctx->arg = "primary"; rv = adm_generic_s(ctx); ctx->arg = old_arg; if (rv == 0) return rv; sleep(1); } return rv; } return 0; } /* FIXME this module parameter will go */ static int sh_mod_parms(struct cfg_ctx *ctx) { int mc = global_options.minor_count; if (mc == 0) { mc = number_of_minors + 3; if (mc > DRBD_MINOR_COUNT_MAX) mc = DRBD_MINOR_COUNT_MAX; if (mc < DRBD_MINOR_COUNT_DEF) mc = DRBD_MINOR_COUNT_DEF; } printf("minor_count=%d\n", mc); return 0; } static void free_volume(struct d_volume *vol) { if (!vol) return; free(vol->device); free(vol->disk); free(vol->meta_disk); free(vol->meta_index); free(vol); } static void free_host_info(struct d_host_info *hi) { struct d_volume *vol; if (!hi) return; free_names(hi->on_hosts); while ((vol = hi->volumes)) { hi->volumes = vol->next; free_volume(vol); } free(hi->address); free(hi->address_family); free(hi->port); free(hi); } static void free_options(struct d_option *opts) { struct d_option *f; while (opts) { free(opts->name); free(opts->value); f = opts; opts = opts->next; free(f); } } static void free_config(struct d_resource *res) { struct d_resource *f; struct d_host_info *host; while ((f = res)) { res = f->next; free(f->name); free_volume(f->volumes); while ((host = f->all_hosts)) { f->all_hosts = host->next; free_host_info(host); } free_options(f->net_options); free_options(f->disk_options); free_options(f->startup_options); free_options(f->proxy_options); free_options(f->handlers); free(f); } if (common) { free_options(common->net_options); free_options(common->disk_options); free_options(common->startup_options); free_options(common->proxy_options); free_options(common->handlers); free(common); } if (ifreq_list) free(ifreq_list); } static void expand_opts(struct d_option *co, struct d_option **opts) { struct d_option *no; while (co) { if (!find_opt(*opts, co->name)) { // prepend new item to opts no = new_opt(strdup(co->name), co->value ? strdup(co->value) : NULL); no->next = *opts; *opts = no; } co = co->next; } } static void expand_common(void) { struct d_resource *res, *tmp; struct d_volume *vol, *host_vol; struct d_host_info *h; /* make sure vol->device is non-NULL */ for_each_resource(res, tmp, config) { for (h = res->all_hosts; h; h = h->next) { for_each_volume(vol, h->volumes) { if (!vol->device) m_asprintf(&vol->device, "/dev/drbd%u", vol->device_minor); } } } for_each_resource(res, tmp, config) { if (!common) break; expand_opts(common->net_options, &res->net_options); expand_opts(common->disk_options, &res->disk_options); expand_opts(common->startup_options, &res->startup_options); expand_opts(common->proxy_options, &res->proxy_options); expand_opts(common->handlers, &res->handlers); expand_opts(common->res_options, &res->res_options); if (common->stacked_timeouts) res->stacked_timeouts = 1; if (!res->become_primary_on) res->become_primary_on = common->become_primary_on; if (common->proxy_plugins && !res->proxy_plugins) expand_opts(common->proxy_plugins, &res->proxy_plugins); } /* now that common disk options (if any) have been propagated to the * resource level, further propagate them to the volume level. */ for_each_resource(res, tmp, config) { for (h = res->all_hosts; h; h = h->next) { for_each_volume(vol, h->volumes) { expand_opts(res->disk_options, &vol->disk_options); } if (h->proxy) { expand_opts(res->proxy_options, &h->proxy->options); expand_opts(res->proxy_plugins, &h->proxy->plugins); } } } /* now from all volume/disk-options on resource level to host level */ for_each_resource(res, tmp, config) { for_each_volume(vol, res->volumes) { for (h = res->all_hosts; h; h = h->next) { host_vol = volume_by_vnr(h->volumes, vol->vnr); expand_opts(vol->disk_options, &host_vol->disk_options); } } } } static void find_drbdcmd(char **cmd, char **pathes) { char **path; path = pathes; while (*path) { if (access(*path, X_OK) == 0) { *cmd = *path; return; } path++; } err("Can not find command (drbdsetup/drbdmeta)\n"); exit(E_EXEC_ERROR); } #define NA(ARGC) \ ({ if((ARGC) >= MAX_ARGS) { err("MAX_ARGS too small\n"); \ exit(E_THINKO); \ } \ (ARGC)++; \ }) static void add_setup_options(char **argv, int *argcp) { int argc = *argcp; int i; if (!setup_options) return; for (i = 0; setup_options[i].option; i++) argv[NA(argc)] = setup_options[i].option; *argcp = argc; } #define make_options(OPT) \ while(OPT) { \ if(OPT->value) { \ ssprintf(argv[NA(argc)],"--%s=%s",OPT->name,OPT->value); \ } else { \ ssprintf(argv[NA(argc)],"--%s",OPT->name); \ } \ OPT=OPT->next; \ } /* FIXME: Don't leak the memory allocated by asprintf. */ #define make_address(ADDR, PORT, AF) \ if (!strcmp(AF, "ipv6")) { \ m_asprintf(&argv[NA(argc)], "%s:[%s]:%s", AF, ADDR, PORT); \ } else { \ m_asprintf(&argv[NA(argc)], "%s:%s:%s", AF, ADDR, PORT); \ } static int adm_attach_or_disk_options(struct cfg_ctx *ctx, bool do_attach, bool reset) { struct d_volume *vol = ctx->vol; char *argv[MAX_ARGS]; struct d_option *opt; int argc = 0; argv[NA(argc)] = drbdsetup; argv[NA(argc)] = do_attach ? "attach" : "disk-options"; ssprintf(argv[NA(argc)], "%d", vol->device_minor); if (do_attach) { argv[NA(argc)] = vol->disk; if (!strcmp(vol->meta_disk, "internal")) { argv[NA(argc)] = vol->disk; } else { argv[NA(argc)] = vol->meta_disk; } argv[NA(argc)] = vol->meta_index; } if (reset) argv[NA(argc)] = "--set-defaults"; if (reset || do_attach) { opt = ctx->vol->disk_options; if (!do_attach) { while (opt && opt->adj_skip) opt = opt->next; } make_options(opt); } add_setup_options(argv, &argc); argv[NA(argc)] = 0; return m_system_ex(argv, SLEEPS_LONG, ctx->res->name); } int adm_attach(struct cfg_ctx *ctx) { int rv; ctx->arg = "apply-al"; rv = admm_generic(ctx); if (rv) return rv; ctx->arg = "attach"; return adm_attach_or_disk_options(ctx, true, false); } int adm_disk_options(struct cfg_ctx *ctx) { return adm_attach_or_disk_options(ctx, false, false); } int adm_set_default_disk_options(struct cfg_ctx *ctx) { return adm_attach_or_disk_options(ctx, false, true); } struct d_option *find_opt(struct d_option *base, char *name) { while (base) { if (!strcmp(base->name, name)) { return base; } base = base->next; } return 0; } int adm_new_minor(struct cfg_ctx *ctx) { char *argv[MAX_ARGS]; int argc = 0, ex; argv[NA(argc)] = drbdsetup; argv[NA(argc)] = "new-minor"; ssprintf(argv[NA(argc)], "%s", ctx->res->name); ssprintf(argv[NA(argc)], "%u", ctx->vol->device_minor); ssprintf(argv[NA(argc)], "%u", ctx->vol->vnr); argv[NA(argc)] = NULL; ex = m_system_ex(argv, SLEEPS_SHORT, ctx->res->name); if (!ex && do_register) register_minor(ctx->vol->device_minor, config_save); return ex; } static int adm_new_resource_or_res_options(struct cfg_ctx *ctx, bool do_new_resource, bool reset) { char *argv[MAX_ARGS]; int argc = 0, ex; argv[NA(argc)] = drbdsetup; argv[NA(argc)] = do_new_resource ? "new-resource" : "resource-options"; ssprintf(argv[NA(argc)], "%s", ctx->res->name); if (reset) argv[NA(argc)] = "--set-defaults"; if (reset || do_new_resource) make_options(ctx->res->res_options); add_setup_options(argv, &argc); argv[NA(argc)] = NULL; ex = m_system_ex(argv, SLEEPS_SHORT, ctx->res->name); if (!ex && do_new_resource && do_register) register_resource(ctx->res->name, config_save); return ex; } int adm_new_resource(struct cfg_ctx *ctx) { return adm_new_resource_or_res_options(ctx, true, false); } int adm_res_options(struct cfg_ctx *ctx) { return adm_new_resource_or_res_options(ctx, false, false); } int adm_set_default_res_options(struct cfg_ctx *ctx) { return adm_new_resource_or_res_options(ctx, false, true); } int adm_resize(struct cfg_ctx *ctx) { char *argv[MAX_ARGS]; struct d_option *opt; int argc = 0; int silent; int ex; argv[NA(argc)] = drbdsetup; argv[NA(argc)] = "resize"; ssprintf(argv[NA(argc)], "%d", ctx->vol->device_minor); opt = find_opt(ctx->vol->disk_options, "size"); if (!opt) opt = find_opt(ctx->res->disk_options, "size"); if (opt) ssprintf(argv[NA(argc)], "--%s=%s", opt->name, opt->value); add_setup_options(argv, &argc); argv[NA(argc)] = 0; /* if this is not "resize", but "check-resize", be silent! */ silent = !strcmp(ctx->arg, "check-resize") ? SUPRESS_STDERR : 0; ex = m_system_ex(argv, SLEEPS_SHORT | silent, ctx->res->name); if (ex) return ex; /* Record last-known bdev info. * Unfortunately drbdsetup did not have enough information * when doing the "resize", and in theory, _our_ information * about the backing device may even be wrong. * Call drbdsetup again, tell it to ask the kernel for * current config, and update the last known bdev info * according to that. */ /* argv[0] = drbdsetup; */ argv[1] = "check-resize"; /* argv[2] = minor; */ argv[3] = NULL; /* ignore exit code */ m_system_ex(argv, SLEEPS_SHORT | silent, ctx->res->name); return 0; } int _admm_generic(struct cfg_ctx *ctx, int flags) { struct d_volume *vol = ctx->vol; char *argv[MAX_ARGS]; int argc = 0; argv[NA(argc)] = drbdmeta; ssprintf(argv[NA(argc)], "%d", vol->device_minor); argv[NA(argc)] = "v08"; if (!strcmp(vol->meta_disk, "internal")) { argv[NA(argc)] = vol->disk; } else { argv[NA(argc)] = vol->meta_disk; } if (!strcmp(vol->meta_index, "flexible")) { if (!strcmp(vol->meta_disk, "internal")) { argv[NA(argc)] = "flex-internal"; } else { argv[NA(argc)] = "flex-external"; } } else { argv[NA(argc)] = vol->meta_index; } argv[NA(argc)] = (char *)ctx->arg; add_setup_options(argv, &argc); argv[NA(argc)] = 0; return m_system_ex(argv, flags, ctx->res->name); } static int admm_generic(struct cfg_ctx *ctx) { return _admm_generic(ctx, SLEEPS_VERY_LONG); } static void _adm_generic(struct cfg_ctx *ctx, int flags, pid_t *pid, int *fd, int *ex) { char *argv[MAX_ARGS]; int argc = 0; if (!ctx->res) { /* ASSERT */ err("sorry, need at least a resource name to call drbdsetup\n"); abort(); } argv[NA(argc)] = drbdsetup; argv[NA(argc)] = (char *)ctx->arg; if (ctx->vol) ssprintf(argv[NA(argc)], "%d", ctx->vol->device_minor); else ssprintf(argv[NA(argc)], "%s", ctx->res->name); add_setup_options(argv, &argc); argv[NA(argc)] = 0; setenv("DRBD_RESOURCE", ctx->res->name, 1); m__system(argv, flags, ctx->res->name, pid, fd, ex); } static int adm_generic(struct cfg_ctx *ctx, int flags) { int ex; _adm_generic(ctx, flags, NULL, NULL, &ex); return ex; } int adm_generic_s(struct cfg_ctx *ctx) { return adm_generic(ctx, SLEEPS_SHORT); } int sh_status(struct cfg_ctx *ctx) { struct d_resource *r, *t; struct d_volume *vol, *lower_vol; int rv = 0; if (!dry_run) { printf("_drbd_version=%s\n_drbd_api=%u\n", shell_escape(PACKAGE_VERSION), API_VERSION); printf("_config_file=%s\n\n\n", shell_escape(config_save)); } for_each_resource(r, t, config) { if (r->ignore) continue; ctx->res = r; printf("_conf_res_name=%s\n", shell_escape(r->name)); printf("_conf_file_line=%s:%u\n\n", shell_escape(r->config_file), r->start_line); if (r->stacked && r->me->lower) { printf("_stacked_on=%s\n", shell_escape(r->me->lower->name)); lower_vol = r->me->lower->me->volumes; } else { /* reset stuff */ printf("_stacked_on=\n"); printf("_stacked_on_device=\n"); printf("_stacked_on_minor=\n"); lower_vol = NULL; } /* TODO: remove this loop, have drbdsetup use dump * and optionally filter on resource name. * "stacked" information is not directly known to drbdsetup, though. */ for_each_volume(vol, r->me->volumes) { /* do not continue in this loop, * or lower_vol will get out of sync */ if (lower_vol) { printf("_stacked_on_device=%s\n", shell_escape(lower_vol->device)); printf("_stacked_on_minor=%d\n", lower_vol->device_minor); } else if (r->stacked && r->me->lower) { /* ASSERT */ err("in %s: stacked volume[%u] without lower volume\n", r->name, vol->vnr); abort(); } printf("_conf_volume=%d\n", vol->vnr); ctx->vol = vol; rv = adm_generic(ctx, SLEEPS_SHORT); if (rv) return rv; if (lower_vol) lower_vol = lower_vol->next; /* vol is advanced by for_each_volume */ } } return 0; } int adm_generic_l(struct cfg_ctx *ctx) { return adm_generic(ctx, SLEEPS_LONG); } static int adm_outdate(struct cfg_ctx *ctx) { int rv; rv = adm_generic(ctx, SLEEPS_SHORT | SUPRESS_STDERR); /* special cases for outdate: * 17: drbdsetup outdate, but is primary and thus cannot be outdated. * 5: drbdsetup outdate, and is inconsistent or worse anyways. */ if (rv == 17) return rv; if (rv == 5) { /* That might mean it is diskless. */ rv = admm_generic(ctx); if (rv) rv = 5; return rv; } if (rv || dry_run) { rv = admm_generic(ctx); } return rv; } /* shell equivalent: * ( drbdsetup resize && drbdsetup check-resize ) || drbdmeta check-resize */ static int adm_chk_resize(struct cfg_ctx *ctx) { /* drbdsetup resize && drbdsetup check-resize */ int ex = adm_resize(ctx); if (ex == 0) return 0; /* try drbdmeta check-resize */ return admm_generic(ctx); } static int adm_generic_b(struct cfg_ctx *ctx) { char buffer[4096]; int fd, status, rv = 0, rr, s = 0; pid_t pid; _adm_generic(ctx, SLEEPS_SHORT | RETURN_STDERR_FD, &pid, &fd, NULL); if (!dry_run) { if (fd < 0) { err("Strange: got negative fd.\n"); exit(E_THINKO); } while (1) { rr = read(fd, buffer + s, 4096 - s); if (rr <= 0) break; s += rr; } close(fd); rr = waitpid(pid, &status, 0); alarm(0); if (WIFEXITED(status)) rv = WEXITSTATUS(status); if (alarm_raised) { rv = 0x100; } } /* see drbdsetup.c, print_config_error(): * 11: some unspecific state change error * 17: SS_NO_UP_TO_DATE_DISK * In both cases, we don't need to retry with drbdmeta, * it would fail anyways with "Device is configured!" */ if (rv == 11 || rv == 17) { /* Some state transition error, report it ... */ rr = write(fileno(stderr), buffer, s); return rv; } if (rv || dry_run) { /* On other errors rv = 10 .. no minor allocated rv = 20 .. module not loaded rv = 16 .. we are diskless here retry with drbdmeta. */ rv = admm_generic(ctx); } return rv; } static int adm_khelper(struct cfg_ctx *ctx) { struct d_resource *res = ctx->res; struct d_volume *vol = ctx->vol; int rv = 0; char *sh_cmd; char minor_string[8]; char volume_string[8]; char *argv[] = { "/bin/sh", "-c", NULL, NULL }; if (!res->peer) { /* Since 8.3.2 we get DRBD_PEER_AF and DRBD_PEER_ADDRESS from the kernel. If we do not know the peer by now, use these to find the peer. */ struct d_host_info *host; char *peer_address = getenv("DRBD_PEER_ADDRESS"); char *peer_af = getenv("DRBD_PEER_AF"); if (peer_address && peer_af) { for (host = res->all_hosts; host; host = host->next) { if (!strcmp(host->address_family, peer_af) && !strcmp(host->address, peer_address)) { res->peer = host; break; } } } } if (res->peer) { setenv("DRBD_PEER_AF", res->peer->address_family, 1); /* since 8.3.0 */ setenv("DRBD_PEER_ADDRESS", res->peer->address, 1); /* since 8.3.0 */ setenv("DRBD_PEER", res->peer->on_hosts->name, 1); /* deprecated */ setenv("DRBD_PEERS", names_to_str(res->peer->on_hosts), 1); /* since 8.3.0, but not usable when using a config with "floating" statements. */ } if (vol) { snprintf(minor_string, sizeof(minor_string), "%u", vol->device_minor); snprintf(volume_string, sizeof(volume_string), "%u", vol->vnr); setenv("DRBD_MINOR", minor_string, 1); setenv("DRBD_VOLUME", volume_string, 1); setenv("DRBD_LL_DISK", vol->disk, 1); } else { char *minor_list; char *separator = ""; char *pos; int volumes = 0; int bufsize; int n; for_each_volume(vol, res->me->volumes) volumes++; /* max minor number is 2**20 - 1, which is 7 decimal digits. * plus separator respective trailing zero. */ bufsize = volumes * 8 + 1; minor_list = alloca(bufsize); pos = minor_list; for_each_volume(vol, res->me->volumes) { n = snprintf(pos, bufsize, "%s%d", separator, vol->device_minor); if (n >= bufsize) { /* "can not happen" */ err("buffer too small when generating the minor list\n"); abort(); break; } bufsize -= n; pos += n; separator = " "; } setenv("DRBD_MINOR", minor_list, 1); } setenv("DRBD_RESOURCE", res->name, 1); setenv("DRBD_CONF", config_save, 1); if ((sh_cmd = get_opt_val(res->handlers, ctx->arg, NULL))) { argv[2] = sh_cmd; rv = m_system_ex(argv, SLEEPS_VERY_LONG, res->name); } return rv; } // need to convert discard-node-nodename to discard-local or discard-remote. void convert_discard_opt(struct d_resource *res) { struct d_option *opt; if (res == NULL) return; if ((opt = find_opt(res->net_options, "after-sb-0pri"))) { if (!strncmp(opt->value, "discard-node-", 13)) { if (!strcmp(nodeinfo.nodename, opt->value + 13)) { free(opt->value); opt->value = strdup("discard-local"); } else { free(opt->value); opt->value = strdup("discard-remote"); } } } } static int add_connection_endpoints(char **argv, int *argcp, struct d_resource *res) { int argc = *argcp; make_address(res->me->address, res->me->port, res->me->address_family); if (res->me->proxy) { make_address(res->me->proxy->inside_addr, res->me->proxy->inside_port, res->me->proxy->inside_af); } else if (res->peer) { make_address(res->peer->address, res->peer->port, res->peer->address_family); } else if (dry_run) { argv[NA(argc)] = "N/A"; } else { err("resource %s: cannot configure network without knowing my peer.\n", res->name); return 20; } *argcp = argc; return 0; } static int adm_connect_or_net_options(struct cfg_ctx *ctx, bool do_connect, bool reset) { struct d_resource *res = ctx->res; char *argv[MAX_ARGS]; struct d_option *opt; int argc = 0; int ret; argv[NA(argc)] = drbdsetup; argv[NA(argc)] = do_connect ? "connect" : "net-options"; if (do_connect) ssprintf(argv[NA(argc)], "%s", res->name); ret = add_connection_endpoints(argv, &argc, res); if (ret) return ret; if (do_connect && res->me->alt_address) { ssprintf(argv[NA(argc)], "--alternate-address"); make_address(res->me->alt_address, res->me->alt_port, res->me->alt_address_family); ssprintf(argv[NA(argc)], "--alternate-peer-address"); make_address(res->peer->alt_address, res->peer->alt_port, res->peer->alt_address_family); } if (reset) argv[NA(argc)] = "--set-defaults"; if (reset || do_connect) { opt = res->net_options; make_options(opt); } add_setup_options(argv, &argc); argv[NA(argc)] = 0; return m_system_ex(argv, SLEEPS_SHORT, res->name); } int adm_connect(struct cfg_ctx *ctx) { return adm_connect_or_net_options(ctx, true, false); } int adm_net_options(struct cfg_ctx *ctx) { return adm_connect_or_net_options(ctx, false, false); } int adm_set_default_net_options(struct cfg_ctx *ctx) { return adm_connect_or_net_options(ctx, false, true); } int adm_disconnect(struct cfg_ctx *ctx) { char *argv[MAX_ARGS]; int argc = 0; if (!ctx->res) { /* ASSERT */ err("sorry, need at least a resource name to call drbdsetup\n"); abort(); } argv[NA(argc)] = drbdsetup; argv[NA(argc)] = (char *)ctx->arg; add_connection_endpoints(argv, &argc, ctx->res); add_setup_options(argv, &argc); argv[NA(argc)] = 0; setenv("DRBD_RESOURCE", ctx->res->name, 1); return m_system_ex(argv, SLEEPS_SHORT, ctx->res->name); } struct d_option *del_opt(struct d_option *base, struct d_option *item) { struct d_option *i; if (base == item) { base = item->next; free(item->name); free(item->value); free(item); return base; } for (i = base; i; i = i->next) { if (i->next == item) { i->next = item->next; free(item->name); free(item->value); free(item); return base; } } return base; } // Need to convert after from resourcename to minor_number. void _convert_after_option(struct d_resource *res, struct d_volume *vol) { struct d_option *opt, *next; struct cfg_ctx depends_on_ctx = { }; int volumes; if (res == NULL) return; opt = vol->disk_options; while ((opt = find_opt(opt, "resync-after"))) { next = opt->next; ctx_by_name(&depends_on_ctx, opt->value); volumes = ctx_set_implicit_volume(&depends_on_ctx); if (volumes > 1) { err("%s:%d: in resource %s:\n\t" "resync-after contains '%s', which is ambiguous, since it contains %d volumes\n", res->config_file, res->start_line, res->name, opt->value, volumes); config_valid = 0; return; } if (!depends_on_ctx.res || depends_on_ctx.res->ignore) { vol->disk_options = del_opt(vol->disk_options, opt); } else { free(opt->value); m_asprintf(&opt->value, "%d", depends_on_ctx.vol->device_minor); } opt = next; } } // Need to convert after from resourcename/volume to minor_number. void convert_after_option(struct d_resource *res) { struct d_volume *vol; struct d_host_info *h; for (h = res->all_hosts; h; h = h->next) for_each_volume(vol, h->volumes) _convert_after_option(res, vol); } int _proxy_connect_name_len(struct d_resource *res) { return strlen(res->name) + strlen(names_to_str_c(res->peer->proxy->on_hosts, '_')) + strlen(names_to_str_c(res->me->proxy->on_hosts, '_')) + 3 /* for the two dashes and the trailing 0 character */; } char *_proxy_connection_name(char *conn_name, struct d_resource *res) { sprintf(conn_name, "%s-%s-%s", res->name, names_to_str_c(res->peer->proxy->on_hosts, '_'), names_to_str_c(res->me->proxy->on_hosts, '_')); return conn_name; } int do_proxy_conn_up(struct cfg_ctx *ctx) { struct d_resource *res = ctx->res; char *argv[4] = { drbd_proxy_ctl, "-c", NULL, NULL }; char *conn_name; int rv; conn_name = proxy_connection_name(res); ssprintf(argv[2], "add connection %s %s:%s %s:%s %s:%s %s:%s", conn_name, res->me->proxy->inside_addr, res->me->proxy->inside_port, res->peer->proxy->outside_addr, res->peer->proxy->outside_port, res->me->proxy->outside_addr, res->me->proxy->outside_port, res->me->address, res->me->port); rv = m_system_ex(argv, SLEEPS_SHORT, res->name); return rv; } int do_proxy_conn_plugins(struct cfg_ctx *ctx) { struct d_resource *res = ctx->res; char *argv[MAX_ARGS]; char *conn_name; int argc = 0; struct d_option *opt; int counter; conn_name = proxy_connection_name(res); argc = 0; argv[NA(argc)] = drbd_proxy_ctl; opt = res->me->proxy->options; while (opt) { argv[NA(argc)] = "-c"; ssprintf(argv[NA(argc)], "set %s %s %s", opt->name, conn_name, opt->value); opt = opt->next; } counter = 0; opt = res->me->proxy->plugins; /* Don't send the "set plugin ... END" line if no plugins are defined * - that's incompatible with the drbd proxy version 1. */ if (opt) { while (1) { argv[NA(argc)] = "-c"; ssprintf(argv[NA(argc)], "set plugin %s %d %s", conn_name, counter, opt ? opt->name : "END"); if (!opt) break; opt = opt->next; counter ++; } } argv[NA(argc)] = 0; if (argc > 2) return m_system_ex(argv, SLEEPS_SHORT, res->name); return 0; } int do_proxy_conn_down(struct cfg_ctx *ctx) { struct d_resource *res = ctx->res; char *conn_name; char *argv[4] = { drbd_proxy_ctl, "-c", NULL, NULL}; int rv; conn_name = proxy_connection_name(res); ssprintf(argv[2], "del connection %s", conn_name); rv = m_system_ex(argv, SLEEPS_SHORT, res->name); return rv; } static int check_proxy(struct cfg_ctx *ctx, int do_up) { struct d_resource *res = ctx->res; int rv; if (!res->me->proxy) { if (all_resources) return 0; err("There is no proxy config for host %s in resource %s.\n", nodeinfo.nodename, res->name); exit(E_CONFIG_INVALID); } if (!name_in_names(nodeinfo.nodename, res->me->proxy->on_hosts)) { if (all_resources) return 0; err("The proxy config in resource %s is not for %s.\n", res->name, nodeinfo.nodename); exit(E_CONFIG_INVALID); } if (!res->peer) { err("Cannot determine the peer in resource %s.\n", res->name); exit(E_CONFIG_INVALID); } if (!res->peer->proxy) { err("There is no proxy config for the peer in resource %s.\n", res->name); if (all_resources) return 0; exit(E_CONFIG_INVALID); } if (do_up) { rv = do_proxy_conn_up(ctx); if (!rv) rv = do_proxy_conn_plugins(ctx); } else rv = do_proxy_conn_down(ctx); return rv; } static int adm_proxy_up(struct cfg_ctx *ctx) { return check_proxy(ctx, 1); } static int adm_proxy_down(struct cfg_ctx *ctx) { return check_proxy(ctx, 0); } /* The "main" loop iterates over resources. * This "sorts" the drbdsetup commands to bring those up * so we will later first create all objects, * then attach all local disks, * adjust various settings, * and then configure the network part */ static int adm_up(struct cfg_ctx *ctx) { static char *current_res_name; if (!current_res_name || strcmp(current_res_name, ctx->res->name)) { free(current_res_name); current_res_name = strdup(ctx->res->name); schedule_deferred_cmd(adm_new_resource, ctx, "new-resource", CFG_PREREQ); schedule_deferred_cmd(adm_connect, ctx, "connect", CFG_NET); } schedule_deferred_cmd(adm_new_minor, ctx, "new-minor", CFG_PREREQ); schedule_deferred_cmd(adm_attach, ctx, "attach", CFG_DISK); return 0; } /* The stacked-timeouts switch in the startup sections allows us to enforce the use of the specified timeouts instead the use of a sane value. Should only be used if the third node should never become primary. */ static int adm_wait_c(struct cfg_ctx *ctx) { struct d_resource *res = ctx->res; struct d_volume *vol = ctx->vol; char *argv[MAX_ARGS]; struct d_option *opt; int argc = 0, rv; argv[NA(argc)] = drbdsetup; argv[NA(argc)] = "wait-connect"; ssprintf(argv[NA(argc)], "%d", vol->device_minor); if (is_drbd_top && !res->stacked_timeouts) { unsigned long timeout = 20; if ((opt = find_opt(res->net_options, "connect-int"))) { timeout = strtoul(opt->value, NULL, 10); // one connect-interval? two? timeout *= 2; } argv[argc++] = "--wfc-timeout"; ssprintf(argv[argc], "%lu", timeout); argc++; } else { opt = res->startup_options; make_options(opt); } argv[NA(argc)] = 0; rv = m_system_ex(argv, SLEEPS_FOREVER, res->name); return rv; } int ctx_by_minor(struct cfg_ctx *ctx, const char *id) { struct d_resource *res, *t; struct d_volume *vol; unsigned int mm; mm = minor_by_id(id); if (mm == -1U) return -ENOENT; for_each_resource(res, t, config) { if (res->ignore) continue; for_each_volume(vol, res->me->volumes) { if (mm == vol->device_minor) { is_drbd_top = res->stacked; ctx->res = res; ctx->vol = vol; return 0; } } } return -ENOENT; } struct d_resource *res_by_name(const char *name) { struct d_resource *res, *t; for_each_resource(res, t, config) { if (strcmp(name, res->name) == 0) return res; } return NULL; } struct d_volume *volume_by_vnr(struct d_volume *volumes, int vnr) { struct d_volume *vol; for_each_volume(vol, volumes) if (vnr == vol->vnr) return vol; return NULL; } int ctx_by_name(struct cfg_ctx *ctx, const char *id) { struct d_resource *res, *t; struct d_volume *vol; char *name = strdupa(id); char *vol_id = strchr(name, '/'); unsigned vol_nr = ~0U; if (vol_id) { *vol_id++ = '\0'; vol_nr = m_strtoll(vol_id, 0); } for_each_resource(res, t, config) { if (res->ignore) continue; if (strcmp(name, res->name) == 0) break; } if (!res) return -ENOENT; if (!vol_id) { /* We could assign implicit volumes here. * But that broke "drbdadm up specific-resource". */ ctx->res = res; ctx->vol = NULL; return 0; } vol = volume_by_vnr(res->me->volumes, vol_nr); if (vol) { ctx->res = res; ctx->vol = vol; return 0; } return -ENOENT; } int ctx_set_implicit_volume(struct cfg_ctx *ctx) { struct d_volume *vol, *v; int volumes = 0; if (ctx->vol || !ctx->res) return 0; if (!ctx->res->me) { return 0; } for_each_volume(vol, ctx->res->me->volumes) { volumes++; v = vol; } if (volumes == 1) ctx->vol = v; return volumes; } /* In case a child exited, or exits, its return code is stored as negative number in the pids[i] array */ static int childs_running(pid_t * pids, int opts) { int i = 0, wr, rv = 0, status; int N = nr_volumes[is_drbd_top ? STACKED : NORMAL]; for (i = 0; i < N; i++) { if (pids[i] <= 0) continue; wr = waitpid(pids[i], &status, opts); if (wr == -1) { // Wait error. if (errno == ECHILD) { printf("No exit code for %d\n", pids[i]); pids[i] = 0; // Child exited before ? continue; } perror("waitpid"); exit(E_EXEC_ERROR); } if (wr == 0) rv = 1; // Child still running. if (wr > 0) { pids[i] = 0; if (WIFEXITED(status)) pids[i] = -WEXITSTATUS(status); if (WIFSIGNALED(status)) pids[i] = -1000; } } return rv; } static void kill_childs(pid_t * pids) { int i; int N = nr_volumes[is_drbd_top ? STACKED : NORMAL]; for (i = 0; i < N; i++) { if (pids[i] <= 0) continue; kill(pids[i], SIGINT); } } /* returns: -1 ... all childs terminated 0 ... timeout expired 1 ... a string was read */ int gets_timeout(pid_t * pids, char *s, int size, int timeout) { int pr, rr, n = 0; struct pollfd pfd; if (s) { pfd.fd = fileno(stdin); pfd.events = POLLIN | POLLHUP | POLLERR | POLLNVAL; n = 1; } redo_without_fd: if (!childs_running(pids, WNOHANG)) { pr = -1; goto out; } do { pr = poll(&pfd, n, timeout); if (pr == -1) { // Poll error. if (errno == EINTR) { if (childs_running(pids, WNOHANG)) continue; goto out; // pr = -1 here. } perror("poll"); exit(E_EXEC_ERROR); } } while (pr == -1); if (pr == 1) { // Input available. rr = read(fileno(stdin), s, size - 1); if (rr == -1) { perror("read"); exit(E_EXEC_ERROR); } else if (size > 1 && rr == 0) { /* WTF. End-of-file... avoid busy loop. */ s[0] = 0; n = 0; goto redo_without_fd; } s[rr] = 0; } out: return pr; } static char *get_opt_val(struct d_option *base, const char *name, char *def) { while (base) { if (!strcmp(base->name, name)) { return base->value; } base = base->next; } return def; } static int check_exit_codes(pid_t * pids) { struct d_resource *res, *t; int i = 0, rv = 0; for_each_resource(res, t, config) { if (res->ignore) continue; if (is_drbd_top != res->stacked) continue; if (pids[i] == -5 || pids[i] == -1000) { pids[i] = 0; } if (pids[i] == -20) rv = 20; i++; } return rv; } static int adm_wait_ci(struct cfg_ctx *ctx) { struct d_resource *res, *t; char *argv[20], answer[40]; pid_t *pids; struct d_option *opt; int rr, wtime, argc, i = 0; time_t start; int saved_stdin, saved_stdout, fd; int N; struct sigaction so, sa; int have_tty = 1; saved_stdin = -1; saved_stdout = -1; if (no_tty) { err("WARN: stdin/stdout is not a TTY; using /dev/console"); fprintf(stdout, "WARN: stdin/stdout is not a TTY; using /dev/console"); saved_stdin = dup(fileno(stdin)); if (saved_stdin == -1) perror("dup(stdin)"); saved_stdout = dup(fileno(stdout)); if (saved_stdin == -1) perror("dup(stdout)"); fd = open("/dev/console", O_RDONLY); if (fd == -1) { perror("open('/dev/console, O_RDONLY)"); have_tty = 0; } else { dup2(fd, fileno(stdin)); fd = open("/dev/console", O_WRONLY); if (fd == -1) perror("open('/dev/console, O_WRONLY)"); dup2(fd, fileno(stdout)); } } sa.sa_handler = chld_sig_hand; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_NOCLDSTOP; sigaction(SIGCHLD, &sa, &so); N = nr_volumes[is_drbd_top ? STACKED : NORMAL]; pids = alloca(N * sizeof(pid_t)); /* alloca can not fail, it can "only" overflow the stack :) * but it needs to be initialized anyways! */ memset(pids, 0, N * sizeof(pid_t)); for_each_resource(res, t, config) { struct d_volume *vol; if (res->ignore) continue; if (is_drbd_top != res->stacked) continue; for_each_volume(vol, res->me->volumes) { /* ctx is not used */ argc = 0; argv[NA(argc)] = drbdsetup; argv[NA(argc)] = "wait-connect"; ssprintf(argv[NA(argc)], "%u", vol->device_minor); opt = res->startup_options; make_options(opt); argv[NA(argc)] = 0; m__system(argv, RETURN_PID, res->name, &pids[i++], NULL, NULL); } } wtime = global_options.dialog_refresh ? : -1; start = time(0); for (i = 0; i < 10; i++) { // no string, but timeout rr = gets_timeout(pids, 0, 0, 1 * 1000); if (rr < 0) break; putchar('.'); fflush(stdout); check_exit_codes(pids); } if (rr == 0) { /* track a "yes", as well as ctrl-d and ctrl-c, * in case our tty is stuck in "raw" mode, and * we get it one character a time (-icanon) */ char yes_string[] = "yes\n"; char *yes_expect = yes_string; int ctrl_c_count = 0; int ctrl_d_count = 0; /* Just in case, if plymouth or usplash is running, * tell them to step aside. * Also try to force canonical tty mode. */ printf ("\n***************************************************************\n" " DRBD's startup script waits for the peer node(s) to appear.\n" " - If this node was already a degraded cluster before the\n" " reboot, the timeout is %s seconds. [degr-wfc-timeout]\n" " - If the peer was available before the reboot, the timeout\n" " is %s seconds. [wfc-timeout]\n" " (These values are for resource '%s'; 0 sec -> wait forever)\n", get_opt_val(config->startup_options, "degr-wfc-timeout", "0"), get_opt_val(config->startup_options, "wfc-timeout", "0"), config->name); if (!have_tty) { printf(" To abort waiting for DRBD connections, kill this process: kill %u\n", getpid()); fflush(stdout); /* wait untill killed, or all drbdsetup children have finished. */ do { rr = poll(NULL, 0, -1); if (rr == -1) { if (errno == EINTR) { if (childs_running(pids, WNOHANG)) continue; break; } perror("poll"); exit(E_EXEC_ERROR); } } while (rr != -1); kill_childs(pids); childs_running(pids, 0); check_exit_codes(pids); return 0; } if (system("exec > /dev/null 2>&1; plymouth quit ; usplash_write QUIT ; " "stty echo icanon icrnl")) /* Ignore return value. Cannot do anything about it anyways. */; printf(" To abort waiting enter 'yes' [ -- ]: "); do { printf("\e[s\e[31G[%4d]:\e[u", (int)(time(0) - start)); // Redraw sec. fflush(stdout); rr = gets_timeout(pids, answer, 40, wtime * 1000); check_exit_codes(pids); if (rr != 1) continue; /* If our tty is in "sane" or "canonical" mode, * we get whole lines. * If it still is in "raw" mode, even though we * tried to set ICANON above, possibly some other * "boot splash thingy" is in operation. * We may be lucky to get single characters. * If a sysadmin sees things stuck during boot, * I expect that ctrl-c or ctrl-d will be one * of the first things that are tried. * In raw mode, we get these characters directly. * But I want them to try that three times ;) */ if (answer[0] && answer[1] == 0) { if (answer[0] == '\3') ++ctrl_c_count; if (answer[0] == '\4') ++ctrl_d_count; if (yes_expect && answer[0] == *yes_expect) ++yes_expect; else if (answer[0] == '\n') yes_expect = yes_string; else yes_expect = NULL; } if (!strcmp(answer, "yes\n") || (yes_expect && *yes_expect == '\0') || ctrl_c_count >= 3 || ctrl_d_count >= 3) { kill_childs(pids); childs_running(pids, 0); check_exit_codes(pids); break; } printf(" To abort waiting enter 'yes' [ -- ]:"); } while (rr != -1); printf("\n"); } if (saved_stdin != -1) { dup2(saved_stdin, fileno(stdin)); dup2(saved_stdout, fileno(stdout)); } return 0; } static void print_cmds(int level) { size_t i; int j = 0; for (i = 0; i < ARRAY_SIZE(cmds); i++) { if (cmds[i].show_in_usage != level) continue; if (j++ % 2) { printf("%-35s\n", cmds[i].name); } else { printf(" %-35s", cmds[i].name); } } if (j % 2) printf("\n"); } static int hidden_cmds(struct cfg_ctx *ignored __attribute((unused))) { printf("\nThese additional commands might be useful for writing\n" "nifty shell scripts around drbdadm:\n\n"); print_cmds(2); printf("\nThese commands are used by the kernel part of DRBD to\n" "invoke user mode helper programs:\n\n"); print_cmds(3); printf ("\nThese commands ought to be used by experts and developers:\n\n"); print_cmds(4); printf("\n"); exit(0); } static void field_to_option(const struct field_def *field, struct option *option) { option->name = field->name; option->has_arg = field->argument_is_optional ? optional_argument : required_argument; option->flag = NULL; option->val = 257; } static void print_option(struct option *opt) { if (opt->has_arg == required_argument) { printf(" --%s=...", opt->name); if (opt->val > 1 && opt->val < 256) printf(", -%c ...", opt->val); printf("\n"); } else if (opt->has_arg == optional_argument) { printf(" --%s[=...]", opt->name); if (opt->val > 1 && opt->val < 256) printf(", -%c...", opt->val); printf("\n"); } else { printf(" --%s", opt->name); if (opt->val > 1 && opt->val < 256) printf(", -%c", opt->val); printf("\n"); } } void print_usage_and_exit(struct adm_cmd *cmd, const char *addinfo, int status) { struct option *opt; printf("\nUSAGE: %s %s [OPTION...] {all|RESOURCE...}\n\n" "GENERAL OPTIONS:\n", progname, cmd ? cmd->name : "COMMAND"); for (opt = general_admopt; opt->name; opt++) print_option(opt); if (cmd && cmd->drbdsetup_ctx) { const struct field_def *field; printf("\nOPTIONS FOR %s:\n", cmd->name); for (field = cmd->drbdsetup_ctx->fields; field->name; field++) { struct option opt; field_to_option(field, &opt); print_option(&opt); } } if (!cmd) { printf("\nCOMMANDS:\n"); print_cmds(1); } printf("\nVersion: " PACKAGE_VERSION " (api:%d)\n%s\n", API_VERSION, drbd_buildtag()); if (addinfo) printf("\n%s\n", addinfo); exit(status); } void verify_ips(struct d_resource *res) { if (global_options.disable_ip_verification) return; if (dry_run == 1 || do_verify_ips == 0) return; if (res->ignore) return; if (res->stacked && !is_drbd_top) return; if (!have_ip(res->me->address_family, res->me->address)) { ENTRY e, *ep; e.key = e.data = ep = NULL; m_asprintf(&e.key, "%s:%s", res->me->address, res->me->port); hsearch_r(e, FIND, &ep, &global_htable); err("%s: in resource %s, on %s:\n\t" "IP %s not found on this host.\n", ep ? (char *)ep->data : res->config_file, res->name, names_to_str(res->me->on_hosts), res->me->address); if (INVALID_IP_IS_INVALID_CONF) config_valid = 0; } } static char *conf_file[] = { DRBD_CONFIG_DIR "/drbd-84.conf", DRBD_CONFIG_DIR "/drbd-83.conf", DRBD_CONFIG_DIR "/drbd-82.conf", DRBD_CONFIG_DIR "/drbd-08.conf", DRBD_CONFIG_DIR "/drbd.conf", 0 }; int sanity_check_abs_cmd(char *cmd_name) { struct stat sb; if (stat(cmd_name, &sb)) { /* If stat fails, just ignore this sanity check, * we are still iterating over $PATH probably. */ return 0; } if (!(sb.st_mode & S_ISUID) || sb.st_mode & S_IXOTH || sb.st_gid == 0) { static int did_header = 0; if (!did_header) err( "WARN:\n" " You are using the 'drbd-peer-outdater' as fence-peer program.\n" " If you use that mechanism the dopd heartbeat plugin program needs\n" " to be able to call drbdsetup and drbdmeta with root privileges.\n\n" " You need to fix this with these commands:\n"); did_header = 1; err( " chgrp haclient %s\n" " chmod o-x %s\n" " chmod u+s %s\n\n", cmd_name, cmd_name, cmd_name); } return 1; } void sanity_check_cmd(char *cmd_name) { char *path, *pp, *c; char abs_path[100]; if (strchr(cmd_name, '/')) { sanity_check_abs_cmd(cmd_name); } else { path = pp = c = strdup(getenv("PATH")); while (1) { c = strchr(pp, ':'); if (c) *c = 0; snprintf(abs_path, 100, "%s/%s", pp, cmd_name); if (sanity_check_abs_cmd(abs_path)) break; if (!c) break; c++; if (!*c) break; pp = c; } free(path); } } /* if the config file is not readable by haclient, * dopd cannot work. * NOTE: we assume that any gid != 0 will be the group dopd will run as, * typically haclient. */ void sanity_check_conf(char *c) { struct stat sb; /* if we cannot stat the config file, * we have other things to worry about. */ if (stat(c, &sb)) return; /* permissions are funny: if it is world readable, * but not group readable, and it belongs to my group, * I am denied access. * For the file to be readable by dopd (hacluster:haclient), * it is not enough to be world readable. */ /* ok if world readable, and NOT group haclient (see NOTE above) */ if (sb.st_mode & S_IROTH && sb.st_gid == 0) return; /* ok if group readable, and group haclient (see NOTE above) */ if (sb.st_mode & S_IRGRP && sb.st_gid != 0) return; err( "WARN:\n" " You are using the 'drbd-peer-outdater' as fence-peer program.\n" " If you use that mechanism the dopd heartbeat plugin program needs\n" " to be able to read the drbd.config file.\n\n" " You need to fix this with these commands:\n" " chgrp haclient %s\n" " chmod g+r %s\n\n", c, c); } void sanity_check_perm() { static int checked = 0; if (checked) return; sanity_check_cmd(drbdsetup); sanity_check_cmd(drbdmeta); sanity_check_conf(config_file); checked = 1; } void validate_resource(struct d_resource *res, enum pp_flags flags) { struct d_option *opt, *next; struct d_name *bpo; /* there may be more than one "resync-after" statement, * see commit 89cd0585 */ opt = res->disk_options; while ((opt = find_opt(opt, "resync-after"))) { struct d_resource *rs_after_res = res_by_name(opt->value); next = opt->next; if (rs_after_res == NULL || (rs_after_res->ignore && !(flags & MATCH_ON_PROXY))) { err( "%s:%d: in resource %s:\n\tresource '%s' mentioned in " "'resync-after' option is not known%s.\n", res->config_file, res->start_line, res->name, opt->value, rs_after_res ? " on this host" : ""); /* Non-fatal if run from some script. * When deleting resources, it is an easily made * oversight to leave references to the deleted * resources in resync-after statements. Don't fail on * every pacemaker-induced action, as it would * ultimately lead to all nodes committing suicide. */ if (no_tty) res->disk_options = del_opt(res->disk_options, opt); else config_valid = 0; } opt = next; } if (res->ignore) return; if (!res->me) { err( "%s:%d: in resource %s:\n\tmissing section 'on %s { ... }'.\n", res->config_file, res->start_line, res->name, nodeinfo.nodename); config_valid = 0; } // need to verify that in the discard-node-nodename options only known // nodenames are mentioned. if ((opt = find_opt(res->net_options, "after-sb-0pri"))) { if (!strncmp(opt->value, "discard-node-", 13)) { if (res->peer && !name_in_names(opt->value + 13, res->peer->on_hosts) && !name_in_names(opt->value + 13, res->me->on_hosts)) { err( "%s:%d: in resource %s:\n\t" "the nodename in the '%s' option is " "not known.\n\t" "valid nodenames are: '%s %s'.\n", res->config_file, res->start_line, res->name, opt->value, names_to_str(res->me->on_hosts), names_to_str(res->peer->on_hosts)); config_valid = 0; } } } if ((opt = find_opt(res->handlers, "fence-peer"))) { if (strstr(opt->value, "drbd-peer-outdater")) sanity_check_perm(); } opt = find_opt(res->net_options, "allow-two-primaries"); if (name_in_names("both", res->become_primary_on) && opt == NULL) { err( "%s:%d: in resource %s:\n" "become-primary-on is set to both, but allow-two-primaries " "is not set.\n", res->config_file, res->start_line, res->name); config_valid = 0; } if (!res->peer) set_peer_in_resource(res, 0); if (res->peer && ((res->me->proxy == NULL) != (res->peer->proxy == NULL))) { err( "%s:%d: in resource %s:\n\t" "Either both 'on' sections must contain a proxy subsection, or none.\n", res->config_file, res->start_line, res->name); config_valid = 0; } for (bpo = res->become_primary_on; bpo; bpo = bpo->next) { if (res->peer && !name_in_names(bpo->name, res->me->on_hosts) && !name_in_names(bpo->name, res->peer->on_hosts) && strcmp(bpo->name, "both")) { err( "%s:%d: in resource %s:\n\t" "become-primary-on contains '%s', which is not named with the 'on' sections.\n", res->config_file, res->start_line, res->name, bpo->name); config_valid = 0; } } } static void global_validate_maybe_expand_die_if_invalid(int expand, enum pp_flags flags) { struct d_resource *res, *tmp; for_each_resource(res, tmp, config) { validate_resource(res, flags); if (!config_valid) exit(E_CONFIG_INVALID); if (expand) { convert_after_option(res); convert_discard_opt(res); } if (!config_valid) exit(E_CONFIG_INVALID); } } /* * returns a pointer to an malloced area that contains * an absolute, canonical, version of path. * aborts if any allocation or syscall fails. * return value should be free()d, once no longer needed. */ char *canonify_path(char *path) { int cwd_fd = -1; char *last_slash; char *tmp; char *that_wd; char *abs_path; if (!path || !path[0]) { err("cannot canonify an empty path\n"); exit(E_USAGE); } tmp = strdupa(path); last_slash = strrchr(tmp, '/'); if (last_slash) { *last_slash++ = '\0'; cwd_fd = open(".", O_RDONLY | O_CLOEXEC); if (cwd_fd < 0) { err("open(\".\") failed: %m\n"); exit(E_USAGE); } if (chdir(tmp)) { err("chdir(\"%s\") failed: %m\n", tmp); exit(E_USAGE); } } else { last_slash = tmp; } that_wd = getcwd(NULL, 0); if (!that_wd) { err("getcwd() failed: %m\n"); exit(E_USAGE); } if (!strcmp("/", that_wd)) m_asprintf(&abs_path, "/%s", last_slash); else m_asprintf(&abs_path, "%s/%s", that_wd, last_slash); free(that_wd); if (cwd_fd >= 0) { if (fchdir(cwd_fd) < 0) { err("fchdir() failed: %m\n"); exit(E_USAGE); } close(cwd_fd); } return abs_path; } void assign_command_names_from_argv0(char **argv) { struct cmd_helper { char *name; char **var; }; static struct cmd_helper helpers[] = { {"drbdsetup-84", &drbdsetup}, {"drbdmeta", &drbdmeta}, {"drbd-proxy-ctl", &drbd_proxy_ctl}, {"drbdadm-83", &drbdadm_83}, {NULL, NULL} }; struct cmd_helper *c; /* in case drbdadm is called with an absolute or relative pathname * look for the drbdsetup binary in the same location, * otherwise, just let execvp sort it out... */ if ((progname = strrchr(argv[0], '/')) == NULL) { progname = argv[0]; for (c = helpers; c->name; ++c) *(c->var) = strdup(c->name); } else { size_t len_dir, l; ++progname; len_dir = progname - argv[0]; for (c = helpers; c->name; ++c) { l = len_dir + strlen(c->name) + 1; *(c->var) = malloc(l); if (*(c->var)) { strncpy(*(c->var), argv[0], len_dir); strcpy(*(c->var) + len_dir, c->name); if (access(*(c->var), X_OK)) strcpy(*(c->var), c->name); /* see add_lib_drbd_to_path() */ } } /* for pretty printing, truncate to basename */ argv[0] = progname; } } static void recognize_all_drbdsetup_options(void) { int i; for (i = 0; i < ARRAY_SIZE(cmds); i++) { const struct adm_cmd *cmd = &cmds[i]; const struct field_def *field; if (!cmd->drbdsetup_ctx) continue; for (field = cmd->drbdsetup_ctx->fields; field->name; field++) { struct option opt; int n; field_to_option(field, &opt); for (n = 0; admopt[n].name; n++) { if (!strcmp(admopt[n].name, field->name)) { if (admopt[n].val == 257) assert (admopt[n].has_arg == opt.has_arg); else { err("Warning: drbdsetup %s option --%s " "can only be passed as -W--%s\n", cmd->name, admopt[n].name, admopt[n].name); goto skip; } } } if (admopt == general_admopt) { admopt = malloc((n + 2) * sizeof(*admopt)); memcpy(admopt, general_admopt, (n + 1) * sizeof(*admopt)); } else admopt = realloc(admopt, (n + 2) * sizeof(*admopt)); memcpy(&admopt[n+1], &admopt[n], sizeof(*admopt)); admopt[n] = opt; skip: /* dummy statement required because of label */ ; } } } struct adm_cmd *find_cmd(char *cmdname); int parse_options(int argc, char **argv, struct adm_cmd **cmd, char ***resource_names) { const char *optstring = make_optstring(admopt); int longindex, first_arg_index; int i; *cmd = NULL; *resource_names = malloc(sizeof(char *)); (*resource_names)[0] = NULL; opterr = 1; optind = 0; while (1) { int c; c = getopt_long(argc, argv, optstring, admopt, &longindex); if (c == -1) break; switch (c) { case 257: /* drbdsetup option */ { struct option *option = &admopt[longindex]; char *opt; int len; len = strlen(option->name) + 2; if (optarg) len += 1 + strlen(optarg); opt = malloc(len + 1); if (optarg) sprintf(opt, "--%s=%s", option->name, optarg); else sprintf(opt, "--%s", option->name); add_setup_option(false, opt); } break; case 'S': is_drbd_top = 1; break; case 'v': verbose++; break; case 'd': dry_run++; break; case 'c': if (!strcmp(optarg, "-")) { yyin = stdin; if (asprintf(&config_file, "STDIN") < 0) { err("asprintf(config_file): %m\n"); return 20; } config_from_stdin = 1; } else { yyin = fopen(optarg, "r"); if (!yyin) { err("Can not open '%s'.\n.", optarg); exit(E_EXEC_ERROR); } if (asprintf(&config_file, "%s", optarg) < 0) { err("asprintf(config_file): %m\n"); return 20; } } break; case 't': config_test = optarg; break; case 's': { char *pathes[2]; pathes[0] = optarg; pathes[1] = 0; find_drbdcmd(&drbdsetup, pathes); } break; case 'm': { char *pathes[2]; pathes[0] = optarg; pathes[1] = 0; find_drbdcmd(&drbdmeta, pathes); } break; case 'p': { char *pathes[2]; pathes[0] = optarg; pathes[1] = 0; find_drbdcmd(&drbd_proxy_ctl, pathes); } break; case 'n': { char *c; int shell_var_name_ok = 1; for (c = optarg; *c && shell_var_name_ok; c++) { switch (*c) { case 'a'...'z': case 'A'...'Z': case '0'...'9': case '_': break; default: shell_var_name_ok = 0; } } if (shell_var_name_ok) sh_varname = optarg; else err("ignored --sh-varname=%s: " "contains suspect characters, allowed set is [a-zA-Z0-9_]\n", optarg); } break; case 'V': printf("DRBDADM_BUILDTAG=%s\n", shell_escape(drbd_buildtag())); printf("DRBDADM_API_VERSION=%u\n", API_VERSION); printf("DRBD_KERNEL_VERSION_CODE=0x%06x\n", version_code_kernel()); printf("DRBDADM_VERSION_CODE=0x%06x\n", version_code_userland()); printf("DRBDADM_VERSION=%s\n", shell_escape(PACKAGE_VERSION)); exit(0); break; case 'P': connect_to_host = optarg; break; case 'W': add_setup_option(true, optarg); break; case 'h': help = true; break; case '?': goto help; } } first_arg_index = optind; for (; optind < argc; optind++) { optarg = argv[optind]; if (*cmd) { int n; ensure_sanity_of_res_name(optarg); for (n = 0; (*resource_names)[n]; n++) /* do nothing */ ; *resource_names = realloc(*resource_names, (n + 2) * sizeof(char *)); (*resource_names)[n++] = optarg; (*resource_names)[n] = NULL; } else if (!strcmp(optarg, "help")) help = true; else { *cmd = find_cmd(optarg); if (!*cmd) { /* Passing drbdsetup options like this is discouraged! */ add_setup_option(true, optarg); } } } if (help) print_usage_and_exit(*cmd, 0, 0); if (*cmd == NULL) { if (first_arg_index < argc) { err("%s: Unknown command '%s'\n", progname, argv[first_arg_index]); return E_USAGE; } print_usage_and_exit(*cmd, "No command specified", E_USAGE); } if (setup_options) { /* * The drbdsetup options are command specific. Make sure that only * setup options that this command recognizes are used. */ for (i = 0; setup_options[i].option; i++) { const struct field_def *field; const char *option; int len; if (setup_options[i].explicit) continue; option = setup_options[i].option; for (len = 0; option[len]; len++) if (option[len] == '=') break; field = NULL; if (option[0] == '-' && option[1] == '-' && (*cmd)->drbdsetup_ctx) { for (field = (*cmd)->drbdsetup_ctx->fields; field->name; field++) { if (strlen(field->name) == len - 2 && !strncmp(option + 2, field->name, len - 2)) break; } if (!field->name) field = NULL; } if (!field) { err("%s: unrecognized option '%.*s'\n", progname, len, option); goto help; } } } return 0; help: if (*cmd) err("try '%s help %s'\n", progname, (*cmd)->name); else err("try '%s help'\n", progname); return E_USAGE; } struct adm_cmd *find_cmd(char *cmdname) { struct adm_cmd *cmd = NULL; unsigned int i; if (!strcmp("hidden-commands", cmdname)) { // before parsing the configuration file... hidden_cmds(NULL); exit(0); } /* R_PRIMARY / R_SECONDARY is not a state, but a role. Whatever that * means, actually. But anyways, we decided to start using _role_ as * the terminus of choice, and deprecate "state". */ substitute_deprecated_cmd(&cmdname, "state", "role"); /* "outdate-peer" got renamed to fence-peer, * it is not required to actually outdate the peer, * depending on situation it may be sufficient to power-reset it * or do some other fencing action, or even call out to "meatware". * The name of the handler should not imply something that is not done. */ substitute_deprecated_cmd(&cmdname, "outdate-peer", "fence-peer"); for (i = 0; i < ARRAY_SIZE(cmds); i++) { if (!strcmp(cmds[i].name, cmdname)) { cmd = cmds + i; break; } } return cmd; } char *config_file_from_arg(char *arg) { char *f; int minor = minor_by_id(arg); if (minor >= 0) { f = lookup_minor(minor); if (!f) { err("Don't know which config file belongs to minor %d, trying default ones...\n", minor); return NULL; } } else { f = lookup_resource(arg); if (!f) { err("Don't know which config file belongs to resource %s, trying default ones...\n", arg); return NULL; } } yyin = fopen(f, "r"); if (yyin == NULL) { err("Couldn't open file %s for reading, reason: %m\ntrying default config file...\n", config_file); return NULL; } return f; } void assign_default_config_file(void) { int i; for (i = 0; conf_file[i]; i++) { yyin = fopen(conf_file[i], "r"); if (yyin) { config_file = conf_file[i]; break; } } if (!config_file) { err("Can not open '%s': %m\n", conf_file[i - 1]); exit(E_CONFIG_INVALID); } } void count_resources(void) { struct d_resource *res, *tmp; struct d_volume *vol; number_of_minors = 0; for_each_resource(res, tmp, config) { if (res->ignore) { nr_resources[IGNORED]++; /* How can we count ignored volumes? * Do we want to? */ continue; } else if (res->stacked) nr_resources[STACKED]++; else nr_resources[NORMAL]++; for_each_volume(vol, res->me->volumes) { number_of_minors++; if (res->stacked) nr_volumes[STACKED]++; /* res->ignored won't come here */ else nr_volumes[NORMAL]++; } } } void die_if_no_resources(void) { if (!is_drbd_top && nr_resources[IGNORED] > 0 && nr_resources[NORMAL] == 0) { err("WARN: no normal resources defined for this host (%s)!?\n" "Misspelled name of the local machine with the 'on' keyword ?\n", nodeinfo.nodename); exit(E_USAGE); } if (!is_drbd_top && nr_resources[NORMAL] == 0) { err("WARN: no normal resources defined for this host (%s)!?\n", nodeinfo.nodename); exit(E_USAGE); } if (is_drbd_top && nr_resources[STACKED] == 0) { err("WARN: nothing stacked for this host (%s), " "nothing to do in stacked mode!\n", nodeinfo.nodename); exit(E_USAGE); } } void print_dump_xml_header(void) { printf("\n", config_save); ++indent; dump_global_info_xml(); dump_common_info_xml(); } void print_dump_header(void) { printf("# %s\n", config_save); dump_global_info(); dump_common_info(); } int main(int argc, char **argv) { size_t i; int rv = 0, r; struct adm_cmd *cmd = NULL; char **resource_names = NULL; struct d_resource *res, *tmp; char *env_drbd_nodename = NULL; int is_dump_xml; int is_dump; struct cfg_ctx ctx = { .arg = NULL }; initialize_err(); yyin = NULL; uname(&nodeinfo); /* FIXME maybe fold to lower case ? */ no_tty = (!isatty(fileno(stdin)) || !isatty(fileno(stdout))); env_drbd_nodename = getenv("__DRBD_NODE__"); if (env_drbd_nodename && *env_drbd_nodename) { strncpy(nodeinfo.nodename, env_drbd_nodename, sizeof(nodeinfo.nodename) - 1); nodeinfo.nodename[sizeof(nodeinfo.nodename) - 1] = 0; err("\n" " found __DRBD_NODE__ in environment\n" " PRETENDING that I am >>%s<<\n\n", nodeinfo.nodename); } assign_command_names_from_argv0(argv); if (drbdsetup == NULL || drbdmeta == NULL || drbd_proxy_ctl == NULL) { err("could not strdup argv[0].\n"); exit(E_EXEC_ERROR); } if (!getenv("DRBD_DONT_WARN_ON_VERSION_MISMATCH")) warn_on_version_mismatch(); maybe_exec_drbdadm_83(argv); recognize_all_drbdsetup_options(); rv = parse_options(argc, argv, &cmd, &resource_names); if (rv) return rv; if (config_test && !cmd->test_config) { err("The --config-to-test (-t) option is only allowed " "with the dump and sh-nop commands\n"); exit(E_USAGE); } do_verify_ips = cmd->verify_ips; is_dump_xml = (cmd->function == adm_dump_xml); is_dump = (is_dump_xml || cmd->function == adm_dump); if (!resource_names[0]) { if (is_dump) all_resources = 1; else if (cmd->res_name_required) print_usage_and_exit(cmd, "No resource names specified", E_USAGE); } else if (resource_names[0]) { if (!cmd->res_name_required) err("This command will ignore resource names!\n"); else if (resource_names[1] && cmd->use_cached_config_file) err("You should not use this command with multiple resources!\n"); } if (!config_file && cmd->use_cached_config_file) config_file = config_file_from_arg(resource_names[0]); if (!config_file) /* may exit if no config file can be used! */ assign_default_config_file(); /* for error-reporting reasons config_file may be re-assigned by adm_adjust, * we need the current value for register_minor, though. * save that. */ if (config_from_stdin) config_save = config_file; else config_save = canonify_path(config_file); my_parse(); if (config_test) { char *saved_config_file = config_file; char *saved_config_save = config_save; config_file = config_test; config_save = canonify_path(config_test); fclose(yyin); yyin = fopen(config_test, "r"); if (!yyin) { err("Can not open '%s'.\n.", config_test); exit(E_EXEC_ERROR); } my_parse(); config_file = saved_config_file; config_save = saved_config_save; } if (!config_valid) exit(E_CONFIG_INVALID); post_parse(config, cmd->is_proxy_cmd ? MATCH_ON_PROXY : 0); if (!is_dump || dry_run || verbose) expand_common(); if (dry_run || config_from_stdin) do_register = 0; count_resources(); if (cmd->uc_dialog) uc_node(global_options.usage_count); ctx.arg = cmd->name; if (cmd->res_name_required) { if (config == NULL && !is_dump) { err("no resources defined!\n"); exit(E_USAGE); } global_validate_maybe_expand_die_if_invalid(!is_dump, cmd->is_proxy_cmd ? MATCH_ON_PROXY : 0); if (!resource_names[0] || !strcmp(resource_names[0], "all")) { /* either no resource arguments at all, * but command is dump / dump-xml, so implicit "all", * or an explicit "all" argument is given */ all_resources = 1; if (!is_dump) die_if_no_resources(); /* verify ips first, for all of them */ for_each_resource(res, tmp, config) { verify_ips(res); } if (!config_valid) exit(E_CONFIG_INVALID); if (is_dump_xml) print_dump_xml_header(); else if (is_dump) print_dump_header(); for_each_resource(res, tmp, config) { if (!is_dump && res->ignore) continue; if (!is_dump && is_drbd_top != res->stacked) continue; ctx.res = res; ctx.vol = NULL; r = call_cmd(cmd, &ctx, EXIT_ON_FAIL); /* does exit for r >= 20! */ /* this super positioning of return values is soo ugly * anyone any better idea? */ if (r > rv) rv = r; } if (is_dump_xml) { --indent; printf("\n"); } } else { /* explicit list of resources to work on */ for (i = 0; resource_names[i]; i++) { ctx.res = NULL; ctx.vol = NULL; ctx_by_name(&ctx, resource_names[i]); if (!ctx.res) ctx_by_minor(&ctx, resource_names[i]); if (!ctx.res) { err("'%s' not defined in your config (for this host).\n", resource_names[i]); exit(E_USAGE); } if (!cmd->vol_id_required && !cmd->iterate_volumes && ctx.vol != NULL) { if (ctx.vol->implicit) ctx.vol = NULL; else { err("%s operates on whole resources, but you specified a specific volume!\n", cmd->name); exit(E_USAGE); } } if (cmd->vol_id_required && !ctx.vol && ctx.res->me->volumes->implicit) ctx.vol = ctx.res->me->volumes; if (cmd->vol_id_required && !ctx.vol) { err("%s requires a specific volume id, but none is specified.\n" "Try '%s minor-' or '%s %s/'\n", cmd->name, cmd->name, cmd->name, resource_names[i]); exit(E_USAGE); } if (ctx.res->ignore && !is_dump) { err("'%s' ignored, since this host (%s) is not mentioned with an 'on' keyword.\n", ctx.res->name, nodeinfo.nodename); rv = E_USAGE; continue; } if (is_drbd_top != ctx.res->stacked && !is_dump) { err("'%s' is a %s resource, and not available in %s mode.\n", ctx.res->name, ctx.res->stacked ? "stacked" : "normal", is_drbd_top ? "stacked" : "normal"); rv = E_USAGE; continue; } verify_ips(ctx.res); if (!is_dump && !config_valid) exit(E_CONFIG_INVALID); r = call_cmd(cmd, &ctx, EXIT_ON_FAIL); /* does exit for rv >= 20! */ if (r > rv) rv = r; } } } else { // Commands which do not need a resource name /* no call_cmd, as that implies register_minor, * which does not make sense for resource independent commands. * It does also not need to iterate over volumes: it does not even know the resource. */ rv = cmd->function(&ctx); if (rv >= 10) { /* why do we special case the "generic sh-*" commands? */ err("command %s exited with code %d\n", cmd->name, rv); exit(rv); } } r = run_deferred_cmds(); if (r > rv) rv = r; free_config(config); free(resource_names); if (admopt != general_admopt) free(admopt); return rv; } void yyerror(char *text) { err("%s:%d: %s\n", config_file, line, text); exit(E_SYNTAX); } drbd-utils-8.9.6/user/v84/registry.h0000644000175000017500000000056112466702074017135 0ustar apoikosapoikos#ifndef __REGISTRY_H #define __REGISTRY_H extern int register_minor(int minor, const char *path); extern int unregister_minor(int minor); extern char *lookup_minor(int minor); extern int unregister_resource(const char *name); extern int register_resource(const char *name, const char *path); extern char *lookup_resource(const char *name); #endif /* __REGISTRY_H */ drbd-utils-8.9.6/user/v84/Makefile.in0000644000175000017500000000757312634271674017177 0ustar apoikosapoikos# Makefile for drbd.o # # This file is part of DRBD by Philipp Reisner and Lars Ellenberg. # # drbd is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # drbd is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with drbd; see the file COPYING. If not, write to # the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. # VPATH = ../shared # variables set by configure DISTRO = @DISTRO@ prefix = @prefix@ exec_prefix = @exec_prefix@ localstatedir = @localstatedir@ datarootdir = @datarootdir@ datadir = @datadir@ sbindir = @sbindir@ sysconfdir = @sysconfdir@ BASH_COMPLETION_SUFFIX = @BASH_COMPLETION_SUFFIX@ UDEV_RULE_SUFFIX = @UDEV_RULE_SUFFIX@ INITDIR = @INITDIR@ LIBDIR = @prefix@/lib/@PACKAGE_TARNAME@ CC = @CC@ CFLAGS = @CFLAGS@ LDFLAGS = @LDFLAGS@ LN_S = @LN_S@ # features enabled or disabled by configure WITH_84_SUPPORT = @WITH_84_SUPPORT@ WITH_UDEV = @WITH_UDEV@ WITH_XEN = @WITH_XEN@ WITH_PACEMAKER = @WITH_PACEMAKER@ WITH_RGMANAGER = @WITH_RGMANAGER@ WITH_BASHCOMPLETION = @WITH_BASHCOMPLETION@ # variables meant to be overridden from the make command line DESTDIR ?= / CFLAGS += -Wall -I. -I../shared GENETLINK_H := /usr/include/linux/genetlink.h libgenl.o: CFLAGS += $(shell for w in CTRL_ATTR_VERSION CTRL_ATTR_HDRSIZE CTRL_ATTR_MCAST_GROUPS; do grep -qw $$w $(GENETLINK_H) && echo -DHAVE_$$w; done) drbdadm-obj = drbdadm_scanner.o drbdadm_parser.o drbdadm_main.o \ drbdadm_adjust.o drbdtool_common.o drbdadm_usage_cnt.o \ drbd_buildtag.o registry.o config_flags.o libgenl.o \ drbd_nla.o shared_tool.o shared_main.o shared_parser.o drbdsetup-obj = libgenl.o registry.o drbdsetup.o drbdtool_common.o \ drbd_buildtag.o drbd_strings.o config_flags.o drbd_nla.o \ wrap_printf.o drbdsetup_colors.o shared_tool.o all-obj := $(drbdadm-obj) $(drbdsetup-obj) all: tools ../shared_prereqs.mk: ; include ../shared_prereqs.mk ifeq ($(WITH_84_SUPPORT),yes) tools: drbdadm-84 drbdsetup-84 else tools: endif .PHONY: drbdadm drbdsetup drbdadm drbdsetup: echo >&2 "You meant to ask for $@-84" ; exit 1 drbdadm-84: $(drbdadm-obj) $(LINK.c) $(LDFLAGS) -o $@ $^ drbdadm_scanner.c: drbdadm_scanner.fl drbdadm_parser.h flex -s -odrbdadm_scanner.c drbdadm_scanner.fl drbdsetup-84: $(drbdsetup-obj) $(LINK.c) $(LDFLAGS) -o $@ $^ clean: rm -f drbdadm_scanner.c rm -f drbdsetup-84 drbdadm-84 $(all-obj) rm -f *~ distclean: clean rm -f $(all-dep) install: ifeq ($(WITH_84_SUPPORT),yes) install -d $(DESTDIR)$(localstatedir)/lib/drbd install -d $(DESTDIR)$(localstatedir)/lock install -d $(DESTDIR)/lib/drbd/ if getent group haclient > /dev/null 2> /dev/null ; then \ install -g haclient -m 4750 drbdsetup-84 $(DESTDIR)/lib/drbd/ ; \ install -m 755 drbdadm-84 $(DESTDIR)/lib/drbd/ ; \ else \ install -m 755 drbdsetup-84 $(DESTDIR)/lib/drbd/ ; \ install -m 755 drbdadm-84 $(DESTDIR)/lib/drbd/ ; \ fi endif uninstall: rm -f $(DESTDIR)/lib/drbd/drbdsetup-84 rm -f $(DESTDIR)/lib/drbd/drbdadm-84 spell: for f in drbdadm_adjust.c drbdadm_main.c drbdadm_parser.c drbdadm_usage_cnt.c drbdsetup.c drbdtool_common.c; do \ aspell --save-repl --dont-backup --personal=./../documentation/aspell.en.per check $$f; \ done .PHONY: install uninstall clean distclean ../../configure: @echo "please (re-)run ./autogen.sh with appropriate arguments"; exit 1 ../../config.status: ../../configure @echo "please (re-)run ./configure with appropriate arguments"; exit 1 Makefile.in: ; Makefile: Makefile.in ../../config.status cd ../.. && ./config.status user/v84/Makefile drbd-utils-8.9.6/user/v84/drbdadm.h0000644000175000017500000002247312477305373016673 0ustar apoikosapoikos#ifndef DRBDADM_H #define DRBDADM_H #include #include #include #include #include #include #include #ifndef O_CLOEXEC #warning "O_CLOEXEC undefined, redefining to 0" #define O_CLOEXEC 0 #endif #include "config.h" #include "shared_main.h" #define API_VERSION 1 struct d_name { char *name; struct d_name *next; }; struct d_proxy_info { struct d_name *on_hosts; char* inside_addr; char* inside_port; char* inside_af; char* outside_addr; char* outside_port; char* outside_af; struct d_option *options; /* named proxy_options in other places */ struct d_option *plugins; /* named proxy_plugins in other places */ }; struct d_volume { unsigned vnr; char* device; unsigned device_minor; char* disk; char* meta_disk; char* meta_index; int meta_major; int meta_minor; struct d_volume *next; struct d_option* disk_options; /* Additional per volume options */ /* Do not dump an explicit volume section */ unsigned int implicit :1 ; /* flags for "drbdadm adjust" */ unsigned int adj_del_minor :1; unsigned int adj_add_minor :1; unsigned int adj_detach :1; unsigned int adj_attach :1; unsigned int adj_resize :1; unsigned int adj_disk_opts :1; }; struct d_host_info { struct d_name *on_hosts; struct d_volume *volumes; char* address; char* port; char* address_family; char* alt_address; char* alt_port; char* alt_address_family; struct d_proxy_info *proxy; struct d_host_info* next; struct d_resource* lower; /* for device stacking */ char *lower_name; /* for device stacking, before bind_stacked_res() */ int config_line; unsigned int by_address:1; /* Match to machines by address, not by names (=on_hosts) */ struct d_option* res_options; /* Additional per host options */ }; struct d_option { char* name; char* value; struct d_option* next; unsigned int mentioned :1 ; // for the adjust command. unsigned int is_escaped :1 ; unsigned int adj_skip :1; }; struct d_resource { char* name; struct d_volume *volumes; /* gets propagated to host_info sections later. */ struct d_host_info* me; struct d_host_info* peer; struct d_host_info* all_hosts; struct d_option* net_options; struct d_option* disk_options; struct d_option* res_options; struct d_option* startup_options; struct d_option* handlers; struct d_option* proxy_options; struct d_option* proxy_plugins; struct d_resource* next; struct d_name *become_primary_on; char *config_file; /* The config file this resource is define in.*/ int start_line; unsigned int stacked_timeouts:1; unsigned int ignore:1; unsigned int stacked:1; /* Stacked on this node */ unsigned int stacked_on_one:1; /* Stacked either on me or on peer */ /* if a prerequisite command failed, don't try any further commands. * see run_deferred_cmds() */ unsigned int skip_further_deferred_command:1; }; struct adm_cmd; struct cfg_ctx { /* res == NULL: does not care for resources, or iterates over all * resources in the global "struct d_resource *config" */ struct d_resource *res; /* vol == NULL: operate on the resource itself, or iterates over all * volumes in res */ struct d_volume *vol; const char *arg; }; extern char *canonify_path(char *path); extern int adm_adjust(struct cfg_ctx *); extern int adm_new_minor(struct cfg_ctx *ctx); extern int adm_new_resource(struct cfg_ctx *); extern int adm_res_options(struct cfg_ctx *); extern int adm_set_default_res_options(struct cfg_ctx *); extern int adm_attach(struct cfg_ctx *); extern int adm_disk_options(struct cfg_ctx *); extern int adm_set_default_disk_options(struct cfg_ctx *); extern int adm_resize(struct cfg_ctx *); extern int adm_connect(struct cfg_ctx *); extern int adm_net_options(struct cfg_ctx *); extern int adm_set_default_net_options(struct cfg_ctx *); extern int adm_disconnect(struct cfg_ctx *); extern int adm_generic_s(struct cfg_ctx *); extern int adm_create_md(struct cfg_ctx *); extern int _admm_generic(struct cfg_ctx *, int flags); extern struct d_option* find_opt(struct d_option*,char*); extern void validate_resource(struct d_resource *, enum pp_flags); /* stages of configuration, as performed on "drbdadm up" * or "drbdadm adjust": */ enum drbd_cfg_stage { /* prerequisite stage: create objects, start daemons, ... */ CFG_PREREQ, /* run time changeable settings of resources */ CFG_RESOURCE, /* detach/attach local disks, */ CFG_DISK_PREREQ, CFG_DISK, /* The stage to discard network configuration, during adjust. * This is after the DISK stage, because we don't want to cut access to * good data while in primary role. And before the SETTINGS stage, as * some proxy or syncer settings may cause side effects and additional * handshakes while we have an established connection. */ CFG_NET_PREREQ, /* discard/set connection parameters */ CFG_NET, __CFG_LAST }; extern void schedule_deferred_cmd( int (*function)(struct cfg_ctx *), struct cfg_ctx *ctx, const char *arg, enum drbd_cfg_stage stage); extern int version_code_kernel(void); extern int version_code_userland(void); extern void warn_on_version_mismatch(void); extern void maybe_exec_drbdadm_83(char **argv); extern void uc_node(enum usage_count_type type); extern void convert_discard_opt(struct d_resource* res); extern void convert_after_option(struct d_resource* res); extern int have_ip(const char *af, const char *ip); enum pr_flags { NoneHAllowed = 4, PARSE_FOR_ADJUST = 8 }; extern struct d_resource* parse_resource_for_adjust(struct cfg_ctx *ctx); extern struct d_resource* parse_resource(char*, enum pr_flags); extern void post_parse(struct d_resource *config, enum pp_flags); extern struct d_option *new_opt(char *name, char *value); extern int name_in_names(char *name, struct d_name *names); extern char *_names_to_str(char* buffer, struct d_name *names); extern char *_names_to_str_c(char* buffer, struct d_name *names, char c); #define NAMES_STR_SIZE 255 #define names_to_str(N) _names_to_str(alloca(NAMES_STR_SIZE+1), N) #define names_to_str_c(N, C) _names_to_str_c(alloca(NAMES_STR_SIZE+1), N, C) extern void free_names(struct d_name *names); extern void set_me_in_resource(struct d_resource* res, int match_on_proxy); extern void set_peer_in_resource(struct d_resource* res, int peer_required); extern void set_on_hosts_in_res(struct d_resource *res); extern void set_disk_in_res(struct d_resource *res); extern int _proxy_connect_name_len(struct d_resource *res); extern char *_proxy_connection_name(char *conn_name, struct d_resource *res); #define proxy_connection_name(RES) \ _proxy_connection_name(alloca(_proxy_connect_name_len(RES)), RES) int parse_proxy_options_section(struct d_resource *res); /* conn_name is optional and mostly for compatibility with dcmd */ int do_proxy_conn_up(struct cfg_ctx *ctx); int do_proxy_conn_down(struct cfg_ctx *ctx); int do_proxy_conn_plugins(struct cfg_ctx *ctx); extern char *config_file; extern char *config_save; extern int config_valid; extern struct d_resource* config; extern struct d_resource* common; extern int line, fline; extern struct hsearch_data global_htable; extern int no_tty; extern int dry_run; extern int verbose; extern char* drbdsetup; extern char* drbd_proxy_ctl; extern char* drbdadm_83; extern char ss_buffer[1024]; extern struct utsname nodeinfo; extern char* connect_to_host; struct setup_option { bool explicit; char *option; }; struct setup_option *setup_options; extern void add_setup_option(bool explicit, char *option); /* ssprintf() places the result of the printf in the current stack frame and sets ptr to the resulting string. If the current stack frame is destroyed (=function returns), the allocated memory is freed automatically */ /* // This is the nicer version, that does not need the ss_buffer. // But it only works with very new glibcs. #define ssprintf(...) \ ({ int _ss_size = snprintf(0, 0, ##__VA_ARGS__); \ char *_ss_ret = __builtin_alloca(_ss_size+1); \ snprintf(_ss_ret, _ss_size+1, ##__VA_ARGS__); \ _ss_ret; }) */ #define ssprintf(ptr,...) \ ptr=strcpy(alloca(snprintf(ss_buffer,sizeof(ss_buffer),##__VA_ARGS__)+1),ss_buffer) /* CAUTION: arguments may not have side effects! */ #define for_each_resource(res,tmp,config) \ for (res = (config); res && (tmp = res->next, 1); res = tmp) #define for_each_volume(v_,volumes_) \ for (v_ = volumes_; v_; v_ = v_->next) #define APPEND(LIST,ITEM) ({ \ typeof((LIST)) _l = (LIST); \ typeof((ITEM)) _i = (ITEM); \ typeof((ITEM)) _t; \ _i->next = NULL; \ if (_l == NULL) { _l = _i; } \ else { \ for (_t = _l; _t->next; _t = _t->next); \ _t->next = _i; \ }; \ _l; \ }) #define INSERT_SORTED(LIST,ITEM,SORT) ({ \ typeof((LIST)) _l = (LIST); \ typeof((ITEM)) _i = (ITEM); \ typeof((ITEM)) _t, _p = NULL; \ for (_t = _l; _t && _t->SORT <= _i->SORT; _p = _t, _t = _t->next); \ if (_p) \ _p->next = _i; \ else \ _l = _i; \ _i->next = _t; \ _l; \ }) #define SPLICE(LIST,ITEMS) ({ \ typeof((LIST)) _l = (LIST); \ typeof((ITEMS)) _i = (ITEMS); \ typeof((ITEMS)) _t; \ if (_l == NULL) { _l = _i; } \ else { \ for (_t = _l; _t->next; _t = _t->next); \ _t->next = _i; \ }; \ _l; \ }) #endif drbd-utils-8.9.6/user/v84/drbdadm_parser.c0000644000175000017500000015064212615625471020240 0ustar apoikosapoikos/* * drbdadm_parser.c a hand crafted parser This file is part of DRBD by Philipp Reisner and Lars Ellenberg. Copyright (C) 2006-2008, LINBIT Information Technologies GmbH Copyright (C) 2006-2008, Philipp Reisner Copyright (C) 2006-2008, Lars Ellenberg drbd is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. drbd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with drbd; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #define _GNU_SOURCE #define _XOPEN_SOURCE 600 #define _FILE_OFFSET_BITS 64 #include #include #include #include #include #include #include #include #include "drbdadm.h" #include "linux/drbd_limits.h" #include "drbdtool_common.h" #include "drbdadm_parser.h" #include "shared_parser.h" YYSTYPE yylval; ///////////////////// static int c_section_start; static int parse_proxy_options(struct d_option **, struct d_option **); void my_parse(void); struct d_name *names_from_str(char* str) { struct d_name *names; names = malloc(sizeof(struct d_name)); names->next = NULL; names->name = strdup(str); return names; } char *_names_to_str_c(char* buffer, struct d_name *names, char c) { int n = 0; if (!names) { snprintf(buffer, NAMES_STR_SIZE, "UNKNOWN"); return buffer; } while (1) { n += snprintf(buffer + n, NAMES_STR_SIZE - n, "%s", names->name); names = names->next; if (!names) return buffer; n += snprintf(buffer + n, NAMES_STR_SIZE - n, "%c", c); } } char *_names_to_str(char* buffer, struct d_name *names) { return _names_to_str_c(buffer, names, ' '); } int name_in_names(char *name, struct d_name *names) { while (names) { if (!strcmp(names->name, name)) return 1; names = names->next; } return 0; } void free_names(struct d_name *names) { struct d_name *nf; while (names) { nf = names->next; free(names->name); free(names); names = nf; } } static void append_names(struct d_name **head, struct d_name ***last, struct d_name *to_copy) { struct d_name *new; while (to_copy) { new = malloc(sizeof(struct d_name)); if (!*head) *head = new; new->name = strdup(to_copy->name); new->next = NULL; if (*last) **last = new; *last = &new->next; to_copy = to_copy->next; } } struct d_name *concat_names(struct d_name *to_copy1, struct d_name *to_copy2) { struct d_name *head = NULL, **last = NULL; append_names(&head, &last, to_copy1); append_names(&head, &last, to_copy2); return head; } void m_strtoll_range(const char *s, char def_unit, const char *name, unsigned long long min, unsigned long long max) { unsigned long long r = m_strtoll(s, def_unit); char unit[] = { def_unit != '1' ? def_unit : 0, 0 }; if (min > r || r > max) { err("%s:%d: %s %s => %llu%s out of range [%llu..%llu]%s.\n", config_file, fline, name, s, r, unit, min, max, unit); if (config_valid <= 1) { config_valid = 0; return; } } if (DEBUG_RANGE_CHECK) { err("%s:%d: %s %s => %llu%s in range [%llu..%llu]%s.\n", config_file, fline, name, s, r, unit, min, max, unit); } } void range_check(const enum range_checks what, const char *name, char *value) { char proto = 0; /* * FIXME: Handle signed/unsigned values correctly by checking the * F_field_name_IS_SIGNED defines. */ #define M_STRTOLL_RANGE(x) \ m_strtoll_range(value, DRBD_ ## x ## _SCALE, name, \ DRBD_ ## x ## _MIN, \ DRBD_ ## x ## _MAX) switch (what) { case R_NO_CHECK: break; default: err("%s:%d: unknown range for %s => %s\n", config_file, fline, name, value); break; case R_MINOR_COUNT: M_STRTOLL_RANGE(MINOR_COUNT); break; case R_DIALOG_REFRESH: M_STRTOLL_RANGE(DIALOG_REFRESH); break; case R_DISK_SIZE: M_STRTOLL_RANGE(DISK_SIZE); break; case R_TIMEOUT: M_STRTOLL_RANGE(TIMEOUT); break; case R_CONNECT_INT: M_STRTOLL_RANGE(CONNECT_INT); break; case R_PING_INT: M_STRTOLL_RANGE(PING_INT); break; case R_MAX_BUFFERS: M_STRTOLL_RANGE(MAX_BUFFERS); break; case R_MAX_EPOCH_SIZE: M_STRTOLL_RANGE(MAX_EPOCH_SIZE); break; case R_SNDBUF_SIZE: M_STRTOLL_RANGE(SNDBUF_SIZE); break; case R_RCVBUF_SIZE: M_STRTOLL_RANGE(RCVBUF_SIZE); break; case R_KO_COUNT: M_STRTOLL_RANGE(KO_COUNT); break; case R_RATE: M_STRTOLL_RANGE(RESYNC_RATE); break; case R_AL_EXTENTS: /* ignore; auto-clamped by kernel. * M_STRTOLL_RANGE(AL_EXTENTS); */ break; case R_PORT: M_STRTOLL_RANGE(PORT); break; /* FIXME not yet implemented! case R_META_IDX: M_STRTOLL_RANGE(META_IDX); break; */ case R_WFC_TIMEOUT: M_STRTOLL_RANGE(WFC_TIMEOUT); break; case R_DEGR_WFC_TIMEOUT: M_STRTOLL_RANGE(DEGR_WFC_TIMEOUT); break; case R_OUTDATED_WFC_TIMEOUT: M_STRTOLL_RANGE(OUTDATED_WFC_TIMEOUT); break; case R_C_PLAN_AHEAD: M_STRTOLL_RANGE(C_PLAN_AHEAD); break; case R_C_DELAY_TARGET: M_STRTOLL_RANGE(C_DELAY_TARGET); break; case R_C_FILL_TARGET: M_STRTOLL_RANGE(C_FILL_TARGET); break; case R_C_MAX_RATE: M_STRTOLL_RANGE(C_MAX_RATE); break; case R_C_MIN_RATE: M_STRTOLL_RANGE(C_MIN_RATE); break; case R_CONG_FILL: M_STRTOLL_RANGE(CONG_FILL); break; case R_CONG_EXTENTS: M_STRTOLL_RANGE(CONG_EXTENTS); break; case R_PROTOCOL: if (value && value[0] && value[1] == 0) { proto = value[0] & ~0x20; /* toupper */ if (proto == 'A' || proto == 'B' || proto == 'C') value[0] = proto; else proto = 0; } if (!proto && config_valid <= 1) { config_valid = 0; err("unknown protocol '%s', should be one of A,B,C\n", value); } break; } } struct d_option *new_opt(char *name, char *value) { struct d_option *cn = calloc(1, sizeof(struct d_option)); /* err("%s:%d: %s = %s\n",config_file,line,name,value); */ cn->name = name; cn->value = value; return cn; } static void derror(struct d_host_info *host, struct d_resource *res, char *text) { config_valid = 0; err("%s:%d: in resource %s, on %s { ... }:" " '%s' keyword missing.\n", config_file, c_section_start, res->name, names_to_str(host->on_hosts), text); } void pdperror(char *text) { config_valid = 0; err("%s:%d: in proxy plugin section: %s.\n", config_file, line, text); exit(E_CONFIG_INVALID); } static void pperror(struct d_host_info *host, struct d_proxy_info *proxy, char *text) { config_valid = 0; err("%s:%d: in section: on %s { proxy on %s { ... } }: '%s' keyword missing.\n", config_file, c_section_start, names_to_str(host->on_hosts), names_to_str(proxy->on_hosts), text); } #define typecheck(type,x) \ ({ type __dummy; \ typeof(x) __dummy2; \ (void)(&__dummy == &__dummy2); \ 1; \ }) #define for_each_host(h_,hosts_) \ for ( ({ typecheck(struct d_name*, h_); \ h_ = hosts_; }); \ h_; h_ = h_->next) /* * for check_uniq: check uniqueness of * resource names, ip:port, node:disk and node:device combinations * as well as resource:section ... * hash table to test for uniqueness of these values... * 256 (max minors) * *( * 2 (host sections) * 4 (res ip:port node:disk node:device) * + 4 (other sections) * + some more, * if we want to check for scoped uniqueness of *every* option * ) * since nobody (?) will actually use more than a dozen minors, * this should be more than enough. * * Furthermore, the names of files that have been read are * registered here, to avoid reading the same file multiple times. */ struct hsearch_data global_htable; void check_uniq_init(void) { memset(&global_htable, 0, sizeof(global_htable)); if (!hcreate_r(256 * ((2 * 4) + 4), &global_htable)) { err("Insufficient memory.\n"); exit(E_EXEC_ERROR); }; } /* some settings need only be unique within one resource definition. * we need currently about 8 + (number of host) * 8 entries, * 200 should be much more than enough. */ struct hsearch_data per_resource_htable; void check_upr_init(void) { static int created = 0; if (config_valid >= 2) return; if (created) hdestroy_r(&per_resource_htable); memset(&per_resource_htable, 0, sizeof(per_resource_htable)); if (!hcreate_r(256, &per_resource_htable)) { err("Insufficient memory.\n"); exit(E_EXEC_ERROR); }; created = 1; } /* FIXME * strictly speaking we don't need to check for uniqueness of disk and device names, * but for uniqueness of their major:minor numbers ;-) */ int vcheck_uniq(struct hsearch_data *ht, const char *what, const char *fmt, va_list ap) { int rv; ENTRY e, *ep; e.key = e.data = ep = NULL; /* if we are done parsing the config file, * switch off this paranoia */ if (config_valid >= 2) return 1; rv = vasprintf(&e.key, fmt, ap); if (rv < 0) { err("vasprintf: %m\n"); exit(E_THINKO); } if (EXIT_ON_CONFLICT && !what) { err("Oops, unset argument in %s:%d.\n", __FILE__, __LINE__); exit(E_THINKO); } m_asprintf((char **)&e.data, "%s:%u", config_file, fline); hsearch_r(e, FIND, &ep, ht); //err("FIND %s: %p\n", e.key, ep); if (ep) { if (what) { err("%s: conflicting use of %s '%s' ...\n%s: %s '%s' first used here.\n", (char *)e.data, what, ep->key, (char *)ep->data, what, ep->key); } free(e.key); free(e.data); config_valid = 0; } else { //err("ENTER %s\t=>\t%s\n", e.key, (char *)e.data); hsearch_r(e, ENTER, &ep, ht); if (!ep) { err("hash table entry (%s => %s) failed\n", e.key, (char *)e.data); exit(E_THINKO); } ep = NULL; } if (EXIT_ON_CONFLICT && ep) exit(E_CONFIG_INVALID); return !ep; } void check_meta_disk(struct d_volume *vol, struct d_host_info *host) { struct d_name *h; /* when parsing "drbdsetup show[-all]" output, * a detached volume will only have device/minor, * but no disk or meta disk. */ if (vol->meta_disk == NULL) return; if (strcmp(vol->meta_disk, "internal") != 0) { /* index either some number, or "flexible" */ for_each_host(h, host->on_hosts) check_uniq("meta-disk", "%s:%s[%s]", h->name, vol->meta_disk, vol->meta_index); } } static void pe_expected(const char *exp) { const char *s = yytext; err("%s:%u: Parse error: '%s' expected,\n\tbut got '%.20s%s'\n", config_file, line, exp, s, strlen(s) > 20 ? "..." : ""); exit(E_CONFIG_INVALID); } static void check_string_error(int got) { const char *msg; switch(got) { case TK_ERR_STRING_TOO_LONG: msg = "Token too long"; break; case TK_ERR_DQSTRING_TOO_LONG: msg = "Double quoted string too long"; break; case TK_ERR_DQSTRING: msg = "Unterminated double quoted string\n we don't allow embedded newlines\n "; break; default: return; } err("%s:%u: %s >>>%.20s...<<<\n", config_file, line, msg, yytext); exit(E_CONFIG_INVALID); } static void pe_expected_got(const char *exp, int got) { static char tmp[2] = "\0"; const char *s = yytext; if (exp[0] == '\'' && exp[1] && exp[2] == '\'' && exp[3] == 0) { tmp[0] = exp[1]; } err("%s:%u: Parse error: '%s' expected,\n\tbut got '%.20s%s' (TK %d)\n", config_file, line, tmp[0] ? tmp : exp, s, strlen(s) > 20 ? "..." : "", got); exit(E_CONFIG_INVALID); } #define EXP(TOKEN1) \ ({ \ int token; \ token = yylex(); \ if (token != TOKEN1) { \ if (TOKEN1 == TK_STRING) \ check_string_error(token); \ pe_expected_got( #TOKEN1, token); \ } \ token; \ }) static void expect_STRING_or_INT(void) { int token = yylex(); switch(token) { case TK_INTEGER: case TK_STRING: break; case TK_ON: yylval.txt = strdup(yytext); break; default: check_string_error(token); pe_expected_got("TK_STRING | TK_INTEGER", token); } } static void parse_global(void) { fline = line; check_uniq("global section", "global"); if (config) { err("%s:%u: You should put the global {} section\n\tin front of any resource {} section\n", config_file, line); } EXP('{'); while (1) { int token = yylex(); fline = line; switch (token) { case TK_DISABLE_IP_VERIFICATION: global_options.disable_ip_verification = 1; break; case TK_MINOR_COUNT: EXP(TK_INTEGER); range_check(R_MINOR_COUNT, "minor-count", yylval.txt); global_options.minor_count = atoi(yylval.txt); break; case TK_DIALOG_REFRESH: EXP(TK_INTEGER); range_check(R_DIALOG_REFRESH, "dialog-refresh", yylval.txt); global_options.dialog_refresh = atoi(yylval.txt); break; case TK_CMD_TIMEOUT_SHORT: EXP(TK_INTEGER); m_strtoll_range(yylval.txt, '1', "cmd-timeout-short", 0, 900); global_options.cmd_timeout_short = atoi(yylval.txt); break; case TK_CMD_TIMEOUT_MEDIUM: EXP(TK_INTEGER); m_strtoll_range(yylval.txt, '1', "cmd-timeout-medium", 0, 900); global_options.cmd_timeout_medium = atoi(yylval.txt); break; case TK_CMD_TIMEOUT_LONG: EXP(TK_INTEGER); m_strtoll_range(yylval.txt, '1', "cmd-timeout-long", 0, 900); global_options.cmd_timeout_long = atoi(yylval.txt); break; case TK_USAGE_COUNT: switch (yylex()) { case TK_YES: global_options.usage_count = UC_YES; break; case TK_NO: global_options.usage_count = UC_NO; break; case TK_ASK: global_options.usage_count = UC_ASK; break; default: pe_expected("yes | no | ask"); } break; case '}': return; default: pe_expected("dialog-refresh | minor-count | " "disable-ip-verification"); } EXP(';'); } } static void check_and_change_deprecated_alias(char **name, int token) { int i; static struct { enum yytokentype token; char *old_name, *new_name; } table[] = { { TK_HANDLER_OPTION, "outdate-peer", "fence-peer" }, { TK_DISK_OPTION, "rate", "resync-rate" }, { TK_DISK_OPTION, "after", "resync-after" }, }; for (i = 0; i < ARRAY_SIZE(table); i++) { if (table[i].token == token && !strcmp(table[i].old_name, *name)) { free(*name); *name = strdup(table[i].new_name); } } } /* The syncer section is deprecated. Distribute the options to the disk or net options. */ void parse_options_syncer(struct d_resource *res) { char *opt_name; int token; enum range_checks rc; struct d_option **options = NULL, *current_option = NULL; c_section_start = line; fline = line; while (1) { token = yylex(); fline = line; if (token >= TK_GLOBAL && !(token & TK_SYNCER_OLD_OPT)) pe_expected("a syncer option keyword"); token &= ~TK_SYNCER_OLD_OPT; switch (token) { case TK_NET_FLAG: case TK_NET_NO_FLAG: case TK_NET_OPTION: options = &res->net_options; break; case TK_DISK_FLAG: case TK_DISK_NO_FLAG: case TK_DISK_OPTION: options = &res->disk_options; break; case TK_RES_OPTION: options = &res->res_options; break; case '}': return; default: pe_expected("a syncer option keyword"); } opt_name = yylval.txt; switch (token) { case TK_NET_FLAG: case TK_DISK_FLAG: token = yylex(); switch(token) { case TK_NO: current_option = new_opt(opt_name, strdup("no")); *options = APPEND(*options, current_option); token = yylex(); break; default: current_option = new_opt(opt_name, strdup("yes")); *options = APPEND(*options, current_option); if (token == TK_YES) token = yylex(); break; } break; case TK_NET_NO_FLAG: case TK_DISK_NO_FLAG: /* Backward compatibility with the old config file syntax. */ assert(!strncmp(opt_name, "no-", 3)); current_option = new_opt(strdup(opt_name + 3), strdup("no")); *options = APPEND(*options, current_option); free(opt_name); token = yylex(); break; case TK_NET_OPTION: case TK_DISK_OPTION: case TK_RES_OPTION: check_and_change_deprecated_alias(&opt_name, token); rc = yylval.rc; expect_STRING_or_INT(); range_check(rc, opt_name, yylval.txt); current_option = new_opt(opt_name, yylval.txt); *options = APPEND(*options, current_option); token = yylex(); break; } switch (token) { case ';': break; default: pe_expected(";"); } } } static struct d_option *parse_options_d(int token_flag, int token_no_flag, int token_option, int token_delegate, void (*delegate)(void*), void *ctx) { char *opt_name; int token, token_group; enum range_checks rc; struct d_option *options = NULL, *current_option = NULL; c_section_start = line; fline = line; while (1) { token_group = yylex(); /* Keep the higher bits in token_option, remove them from token. */ token = REMOVE_GROUP_FROM_TOKEN(token_group); fline = line; opt_name = yylval.txt; if (token <= 0) { pe_expected("an option"); } else if (token == token_flag) { switch(yylex()) { case TK_YES: current_option = new_opt(opt_name, strdup("yes")); options = APPEND(options, current_option); break; case TK_NO: current_option = new_opt(opt_name, strdup("no")); options = APPEND(options, current_option); break; case ';': /* Flag value missing; assume yes. */ options = APPEND(options, new_opt(opt_name, strdup("yes"))); continue; default: pe_expected("yes | no | ;"); } } else if (token == token_no_flag) { /* Backward compatibility with the old config file syntax. */ assert(!strncmp(opt_name, "no-", 3)); current_option = new_opt(strdup(opt_name + 3), strdup("no")); options = APPEND(options, current_option); free(opt_name); } else if (token == token_option || GET_TOKEN_GROUP(token_option & token_group)) { check_and_change_deprecated_alias(&opt_name, token_option); rc = yylval.rc; expect_STRING_or_INT(); range_check(rc, opt_name, yylval.txt); current_option = new_opt(opt_name, yylval.txt); options = APPEND(options, current_option); } else if (ctx && (token == token_delegate || GET_TOKEN_GROUP(token_delegate & token_group))) { delegate(ctx); continue; } else if (token == TK_DEPRECATED_OPTION) { /* err("Warn: Ignoring deprecated option '%s'\n", yylval.txt); */ expect_STRING_or_INT(); } else if (token == '}') { return options; } else { pe_expected("an option keyword"); } EXP(';'); } } static struct d_option *parse_options(int token_flag, int token_no_flag, int token_option) { return parse_options_d(token_flag, token_no_flag, token_option, 0, NULL, NULL); } static void __parse_address(char** addr, char** port, char** af) { switch(yylex()) { case TK_SCI: /* 'ssocks' was names 'sci' before. */ if (af) *af = strdup("ssocks"); EXP(TK_IPADDR); break; case TK_SSOCKS: case TK_SDP: case TK_IPV4: if (af) *af = yylval.txt; EXP(TK_IPADDR); break; case TK_IPV6: if (af) *af = yylval.txt; EXP('['); EXP(TK_IPADDR6); break; case TK_IPADDR: if (af) *af = strdup("ipv4"); break; /* case '[': // Do not foster people's laziness ;) EXP(TK_IPADDR6); *af = strdup("ipv6"); break; */ default: pe_expected("ssocks | sdp | ipv4 | ipv6 | "); } if (addr) *addr = yylval.txt; if (af && !strcmp(*af, "ipv6")) EXP(']'); EXP(':'); EXP(TK_INTEGER); if (port) *port = yylval.txt; range_check(R_PORT, "port", yylval.txt); } static void parse_address(struct d_name *on_hosts, char** addr, char** port, char** af) { struct d_name *h; __parse_address(addr, port, af); if (addr_scope_local(*addr)) for_each_host(h, on_hosts) check_uniq("IP", "%s:%s:%s", h->name, *addr, *port); else check_uniq("IP", "%s:%s", *addr, *port); EXP(';'); } static void parse_hosts(struct d_name **pnp, char delimeter) { char errstr[20]; struct d_name *name; int hosts = 0; int token; while (1) { token = yylex(); switch (token) { case TK_STRING: name = malloc(sizeof(struct d_name)); name->name = yylval.txt; name->next = NULL; *pnp = name; pnp = &name->next; hosts++; break; default: if (token == delimeter) { if (!hosts) pe_expected_got("TK_STRING", token); return; } else { sprintf(errstr, "TK_STRING | '%c'", delimeter); pe_expected_got(errstr, token); } } } } static void parse_proxy_section(struct d_host_info *host) { struct d_proxy_info *proxy; proxy=calloc(1,sizeof(struct d_proxy_info)); host->proxy = proxy; EXP(TK_ON); parse_hosts(&proxy->on_hosts, '{'); while (1) { switch (yylex()) { case TK_INSIDE: parse_address(proxy->on_hosts, &proxy->inside_addr, &proxy->inside_port, &proxy->inside_af); break; case TK_OUTSIDE: parse_address(proxy->on_hosts, &proxy->outside_addr, &proxy->outside_port, &proxy->outside_af); break; case TK_OPTIONS: parse_proxy_options(&proxy->options, &proxy->plugins); break; case '}': goto break_loop; default: pe_expected("inside | outside"); } } break_loop: if (!proxy->inside_addr) pperror(host, proxy, "inside"); if (!proxy->outside_addr) pperror(host, proxy, "outside"); return; } void parse_meta_disk(struct d_volume *vol) { EXP(TK_STRING); vol->meta_disk = yylval.txt; if (strcmp("internal", yylval.txt) == 0) { /* internal, flexible size */ vol->meta_index = strdup("internal"); EXP(';'); } else { switch(yylex()) { case '[': EXP(TK_INTEGER); /* external, static size */ vol->meta_index = yylval.txt; EXP(']'); EXP(';'); break; case ';': /* external, flexible size */ vol->meta_index = strdup("flexible"); break; default: pe_expected("[ | ;"); } } } static void check_minor_nonsense(const char *devname, const int explicit_minor) { if (!devname) return; /* if devname is set, it starts with /dev/drbd */ if (only_digits(devname + 9)) { int m = strtol(devname + 9, NULL, 10); if (m == explicit_minor) return; err("%s:%d: explicit minor number must match with device name\n" "\tTry \"device /dev/drbd%u minor %u;\",\n" "\tor leave off either device name or explicit minor.\n" "\tArbitrary device names must start with /dev/drbd_\n" "\tmind the '_'! (/dev/ is optional, but drbd_ is required)\n", config_file, fline, explicit_minor, explicit_minor); config_valid = 0; return; } else if (devname[9] == '_') return; err("%s:%d: arbitrary device name must start with /dev/drbd_\n" "\tmind the '_'! (/dev/ is optional, but drbd_ is required)\n", config_file, fline); config_valid = 0; return; } static void parse_device(struct d_name* on_hosts, struct d_volume *vol) { struct d_name *h; int m; switch (yylex()) { case TK_STRING: if (!strncmp("drbd", yylval.txt, 4)) { m_asprintf(&vol->device, "/dev/%s", yylval.txt); free(yylval.txt); } else vol->device = yylval.txt; if (strncmp("/dev/drbd", vol->device, 9)) { err("%s:%d: device name must start with /dev/drbd\n" "\t(/dev/ is optional, but drbd is required)\n", config_file, fline); config_valid = 0; /* no goto out yet, * as that would additionally throw a parse error */ } switch (yylex()) { default: pe_expected("minor | ;"); /* fall through */ case ';': m = dt_minor_of_dev(vol->device); if (m < 0) { err("%s:%d: no minor given nor device name contains a minor number\n", config_file, fline); config_valid = 0; } vol->device_minor = m; goto out; case TK_MINOR: ; /* double fall through */ } case TK_MINOR: EXP(TK_INTEGER); vol->device_minor = atoi(yylval.txt); EXP(';'); /* if both device name and minor number are explicitly given, * force /dev/drbd or /dev/drbd_ */ check_minor_nonsense(vol->device, vol->device_minor); } out: for_each_host(h, on_hosts) { check_uniq("device-minor", "device-minor:%s:%u", h->name, vol->device_minor); if (vol->device) check_uniq("device", "device:%s:%s", h->name, vol->device); } } struct d_volume *find_volume(struct d_volume *vol, int vnr) { while (vol) { if (vol->vnr == vnr) return vol; vol = vol->next; } return NULL; } struct d_volume *volume0(struct d_volume **volp) { struct d_volume *vol; if (!*volp) { vol = calloc(1, sizeof(struct d_volume)); vol->device_minor = -1; *volp = vol; vol->implicit = 1; return vol; } else { vol = *volp; if (vol->vnr == 0 && vol->next == NULL && vol->implicit) return vol; config_valid = 0; err("%s:%d: Explicit and implicit volumes not allowed\n", config_file, line); return vol; } } int parse_volume_stmt(struct d_volume *vol, struct d_name* on_hosts, int token) { switch (token) { case TK_DISK: token = yylex(); switch (token) { case TK_STRING: vol->disk = yylval.txt; EXP(';'); break; case '{': vol->disk_options = parse_options(TK_DISK_FLAG, TK_DISK_NO_FLAG, TK_DISK_OPTION); break; default: check_string_error(token); pe_expected_got( "TK_STRING | {", token); } break; case TK_DEVICE: parse_device(on_hosts, vol); break; case TK_META_DISK: parse_meta_disk(vol); break; case TK_FLEX_META_DISK: EXP(TK_STRING); vol->meta_disk = yylval.txt; if (strcmp("internal", yylval.txt) != 0) { /* external, flexible ize */ vol->meta_index = strdup("flexible"); } else { /* internal, flexible size */ vol->meta_index = strdup("internal"); } EXP(';'); break; default: return 0; } return 1; } struct d_volume *parse_volume(int vnr, struct d_name* on_hosts) { struct d_volume *vol; int token; vol = calloc(1,sizeof(struct d_volume)); vol->device_minor = -1; vol->vnr = vnr; EXP('{'); while (1) { token = yylex(); if (token == '}') break; if (!parse_volume_stmt(vol, on_hosts, token)) pe_expected_got("device | disk | meta-disk | flex-meta-disk | }", token); } return vol; } struct d_volume *parse_stacked_volume(int vnr) { struct d_volume *vol; vol = calloc(1,sizeof(struct d_volume)); vol->device_minor = -1; vol->vnr = vnr; EXP('{'); EXP(TK_DEVICE); parse_device(NULL, vol); EXP('}'); vol->meta_disk = strdup("internal"); vol->meta_index = strdup("internal"); return vol; } void inherit_volumes(struct d_volume *from, struct d_host_info *host) { struct d_volume *s, *t; struct d_name *h; for (s = from; s != NULL ; s = s->next) { t = find_volume(host->volumes, s->vnr); if (!t) { t = calloc(1, sizeof(struct d_volume)); t->device_minor = -1; t->vnr = s->vnr; host->volumes = INSERT_SORTED(host->volumes, t, vnr); } if (!t->disk && s->disk) { t->disk = strdup(s->disk); for_each_host(h, host->on_hosts) check_uniq("disk", "disk:%s:%s", h->name, t->disk); } if (!t->device && s->device) t->device = strdup(s->device); if (t->device_minor == -1U && s->device_minor != -1U) { t->device_minor = s->device_minor; for_each_host(h, host->on_hosts) check_uniq("device-minor", "device-minor:%s:%d", h->name, t->device_minor); } if (!t->meta_disk && s->meta_disk) { t->meta_disk = strdup(s->meta_disk); if (s->meta_index) t->meta_index = strdup(s->meta_index); } } } void check_volume_complete(struct d_resource *res, struct d_host_info *host, struct d_volume *vol) { if (!vol->device && vol->device_minor == -1U) derror(host, res, "device"); if (!vol->disk) derror(host, res, "disk"); if (!vol->meta_disk) derror(host, res, "meta-disk"); if (!vol->meta_index) derror(host, res, "meta-index"); } void check_volumes_complete(struct d_resource *res, struct d_host_info *host) { struct d_volume *vol = host->volumes; unsigned vnr = -1U; while (vol) { if (vnr == -1U || vnr < vol->vnr) vnr = vol->vnr; else err("internal error: in %s: unsorted volumes list\n", res->name); check_volume_complete(res, host, vol); vol = vol->next; } } void check_volume_sets_equal(struct d_resource *res, struct d_host_info *host1, struct d_host_info *host2) { struct d_volume *a, *b; /* change the error output, if we have been called to * compare stacked with lower resource volumes */ int compare_stacked = host1->lower && host1->lower->me == host2; a = host1->volumes; b = host2->volumes; /* volume lists are supposed to be sorted on vnr */ while (a || b) { while (a && (!b || a->vnr < b->vnr)) { err("%s:%d: in resource %s, on %s { ... }: volume %d not defined on %s\n", config_file, line, res->name, names_to_str(host1->on_hosts), a->vnr, compare_stacked ? host1->lower->name : names_to_str(host2->on_hosts)); a = a->next; config_valid = 0; } while (b && (!a || a->vnr > b->vnr)) { /* Though unusual, it is "legal" for a lower resource * to have more volumes than the resource stacked on * top of it. Warn (if we have a terminal), * but consider it as valid. */ if (!(compare_stacked && no_tty)) err("%s:%d: in resource %s, on %s { ... }: " "volume %d missing (present on %s)\n", config_file, line, res->name, names_to_str(host1->on_hosts), b->vnr, compare_stacked ? host1->lower->name : names_to_str(host2->on_hosts)); if (!compare_stacked) config_valid = 0; b = b->next; } if (a && b && a->vnr == b->vnr) { a = a->next; b = b->next; } } } /* Ensure that in all host sections the same volumes are defined */ void check_volumes_hosts(struct d_resource *res) { struct d_host_info *host1, *host2; host1 = res->all_hosts; if (!host1) return; for (host2 = host1->next; host2; host2 = host2->next) check_volume_sets_equal(res, host1, host2); } enum parse_host_section_flags { REQUIRE_ALL = 1, BY_ADDRESS = 2, }; void parse_host_section(struct d_resource *res, struct d_name* on_hosts, enum parse_host_section_flags flags) { struct d_host_info *host; struct d_volume *vol; struct d_name *h; int in_braces = 1; c_section_start = line; fline = line; host = calloc(1,sizeof(struct d_host_info)); host->on_hosts = on_hosts; host->config_line = c_section_start; if (flags & BY_ADDRESS) { /* floating
{} */ char *fake_uname = NULL; int token; host->by_address = 1; __parse_address(&host->address, &host->port, &host->address_family); check_uniq("IP", "%s:%s", host->address, host->port); if (!strcmp(host->address_family, "ipv6")) m_asprintf(&fake_uname, "ipv6 [%s]:%s", host->address, host->port); else m_asprintf(&fake_uname, "%s:%s", host->address, host->port); on_hosts = names_from_str(fake_uname); host->on_hosts = on_hosts; token = yylex(); switch(token) { case '{': break; case ';': in_braces = 0; break; default: pe_expected_got("{ | ;", token); } } for_each_host(h, on_hosts) check_upr("host section", "%s: on %s", res->name, h->name); res->all_hosts = APPEND(res->all_hosts, host); while (in_braces) { int token = yylex(); fline = line; switch (token) { case TK_DISK: for_each_host(h, on_hosts) check_upr("disk statement", "%s:%s:disk", res->name, h->name); goto vol0stmt; /* for_each_host(h, on_hosts) check_uniq("disk", "disk:%s:%s", h->name, yylval.txt); */ case TK_DEVICE: for_each_host(h, on_hosts) check_upr("device statement", "%s:%s:device", res->name, h->name); goto vol0stmt; case TK_META_DISK: for_each_host(h, on_hosts) check_upr("meta-disk statement", "%s:%s:meta-disk", res->name, h->name); goto vol0stmt; case TK_FLEX_META_DISK: for_each_host(h, on_hosts) check_upr("meta-disk statement", "%s:%s:meta-disk", res->name, h->name); goto vol0stmt; break; case TK_ADDRESS: if (host->by_address) { err("%s:%d: address statement not allowed for floating {} host sections\n", config_file, fline); config_valid = 0; exit(E_CONFIG_INVALID); } for_each_host(h, on_hosts) check_upr("address statement", "%s:%s:address", res->name, h->name); parse_address(on_hosts, &host->address, &host->port, &host->address_family); range_check(R_PORT, "port", host->port); break; case TK_ALT_ADDRESS: if (host->by_address) { err("%s:%d: address statement not allowed for floating {} host sections\n", config_file, fline); config_valid = 0; exit(E_CONFIG_INVALID); } for_each_host(h, on_hosts) check_upr("alt-address statement", "%s:%s:alt-address", res->name, h->name); parse_address(on_hosts, &host->alt_address, &host->alt_port, &host->alt_address_family); range_check(R_PORT, "port", host->alt_port); break; case TK_PROXY: parse_proxy_section(host); break; case TK_VOLUME: EXP(TK_INTEGER); host->volumes = INSERT_SORTED(host->volumes, parse_volume(atoi(yylval.txt), on_hosts), vnr); break; case TK_OPTIONS: EXP('{'); host->res_options = parse_options(0, 0, TK_RES_OPTION); break; case '}': in_braces = 0; break; vol0stmt: if (parse_volume_stmt(volume0(&host->volumes), on_hosts, token)) break; /* else fall through */ default: pe_expected("disk | device | address | meta-disk " "| flexible-meta-disk"); } } inherit_volumes(res->volumes, host); for_each_volume(vol, host->volumes) check_meta_disk(vol, host); if (!(flags & REQUIRE_ALL)) return; if (!host->address) derror(host, res, "address"); check_volumes_complete(res, host); } void parse_skip() { int level; int token; fline = line; token = yylex(); switch (token) { case TK_STRING: EXP('{'); break; case '{': break; default: check_string_error(token); pe_expected("[ some_text ] {"); } level = 1; while (level) { switch (yylex()) { case '{': /* if you really want to, you can wrap this with a GB size config file :) */ level++; break; case '}': level--; break; case 0: err("%s:%u: reached eof while parsing this skip block.\n", config_file, fline); exit(E_CONFIG_INVALID); } } while (level) ; } void parse_stacked_section(struct d_resource* res) { struct d_host_info *host; struct d_name *h; c_section_start = line; fline = line; host=calloc(1,sizeof(struct d_host_info)); res->all_hosts = APPEND(res->all_hosts, host); EXP(TK_STRING); check_uniq("stacked-on-top-of", "stacked:%s", yylval.txt); host->lower_name = yylval.txt; EXP('{'); while (1) { switch(yylex()) { case TK_DEVICE: /* for_each_host(h, host->on_hosts) check_upr("device statement", "%s:%s:device", res->name, h->name); */ parse_device(host->on_hosts, volume0(&host->volumes)); volume0(&host->volumes)->meta_disk = strdup("internal"); volume0(&host->volumes)->meta_index = strdup("internal"); break; case TK_ADDRESS: for_each_host(h, host->on_hosts) check_upr("address statement", "%s:%s:address", res->name, h->name); parse_address(NULL, &host->address, &host->port, &host->address_family); range_check(R_PORT, "port", yylval.txt); break; case TK_ALT_ADDRESS: for_each_host(h, host->on_hosts) check_upr("alt-address statement", "%s:%s:alt-address", res->name, h->name); parse_address(NULL, &host->alt_address, &host->alt_port, &host->alt_address_family); range_check(R_PORT, "port", yylval.txt); break; case TK_PROXY: parse_proxy_section(host); break; case TK_VOLUME: EXP(TK_INTEGER); host->volumes = INSERT_SORTED(host->volumes, parse_stacked_volume(atoi(yylval.txt)), vnr); break; case '}': goto break_loop; default: pe_expected("device | address | proxy"); } } break_loop: res->stacked_on_one = 1; inherit_volumes(res->volumes, host); if (!host->address) derror(host,res,"address"); } void startup_delegate(void *ctx) { struct d_resource *res = (struct d_resource *)ctx; if (!strcmp(yytext, "become-primary-on")) { parse_hosts(&res->become_primary_on, ';'); } else if (!strcmp(yytext, "stacked-timeouts")) { res->stacked_timeouts = 1; EXP(';'); } else pe_expected(" | become-primary-on | stacked-timeouts"); } void net_delegate(void *ctx) { enum pr_flags flags = (enum pr_flags)ctx; if (!strcmp(yytext, "discard-my-data") && flags & PARSE_FOR_ADJUST) { switch(yylex()) { case TK_YES: case TK_NO: /* Ignore this option. */ EXP(';'); break; case ';': /* Ignore this option. */ return; default: pe_expected("yes | no | ;"); } } else pe_expected("an option keyword"); } void set_me_in_resource(struct d_resource* res, int match_on_proxy) { struct d_host_info *host; /* Determine the local host section */ for (host = res->all_hosts; host; host=host->next) { /* do we match this host? */ if (match_on_proxy) { if (!host->proxy || !name_in_names(nodeinfo.nodename, host->proxy->on_hosts)) continue; } else if (host->by_address) { if (!have_ip(host->address_family, host->address) && /* for debugging only, e.g. __DRBD_NODE__=10.0.0.1 */ strcmp(nodeinfo.nodename, host->address)) continue; } else if (host->lower) { if (!host->lower->me) continue; } else if (!host->on_hosts) { /* huh? a resource without hosts to run on?! */ continue; } else { if (!name_in_names(nodeinfo.nodename, host->on_hosts) && strcmp("_this_host", host->on_hosts->name)) continue; } /* we matched. */ if (res->ignore) { config_valid = 0; err("%s:%d: in resource %s, %s %s { ... }:\n" "\tYou cannot ignore and define at the same time.\n", res->config_file, host->config_line, res->name, host->lower ? "stacked-on-top-of" : "on", host->lower ? host->lower->name : names_to_str(host->on_hosts)); } if (res->me) { config_valid = 0; err("%s:%d: in resource %s, %s %s { ... } ... %s %s { ... }:\n" "\tThere are multiple host sections for this node.\n", res->config_file, host->config_line, res->name, res->me->lower ? "stacked-on-top-of" : "on", res->me->lower ? res->me->lower->name : names_to_str(res->me->on_hosts), host->lower ? "stacked-on-top-of" : "on", host->lower ? host->lower->name : names_to_str(host->on_hosts)); } res->me = host; if (host->lower) res->stacked = 1; } /* If there is no me, implicitly ignore that resource */ if (!res->me) { res->ignore = 1; return; } } void set_peer_in_resource(struct d_resource* res, int peer_required) { struct d_host_info *host = NULL; if (res->ignore) return; /* me must be already set */ if (!res->me) { /* should have been implicitly ignored. */ err("%s:%d: in resource %s:\n" "\tcannot determine the peer, don't even know myself!\n", res->config_file, res->start_line, res->name); exit(E_THINKO); } /* only one host section? */ if (!res->all_hosts->next) { if (peer_required) { fprintf(stderr, "%s:%d: in resource %s:\n" "\tMissing section 'on { ... }'.\n", res->config_file, res->start_line, res->name); config_valid = 0; } return; } /* short cut for exactly two host sections. * silently ignore any --peer connect_to_host option. */ if (res->all_hosts->next->next == NULL) { res->peer = res->all_hosts == res->me ? res->all_hosts->next : res->all_hosts; if (dry_run > 1 && connect_to_host) err("%s:%d: in resource %s:\n" "\tIgnoring --peer '%s': there are only two host sections.\n", res->config_file, res->start_line, res->name, connect_to_host); return; } /* Multiple peer hosts to choose from. * we need some help! */ if (!connect_to_host) { if (peer_required) { err("%s:%d: in resource %s:\n" "\tThere are multiple host sections for the peer node.\n" "\tUse the --peer option to select which peer section to use.\n", res->config_file, res->start_line, res->name); config_valid = 0; } return; } for (host = res->all_hosts; host; host=host->next) { if (host->by_address && strcmp(connect_to_host, host->address)) continue; if (host->proxy && !name_in_names(nodeinfo.nodename, host->proxy->on_hosts)) continue; if (!name_in_names(connect_to_host, host->on_hosts)) continue; if (host == res->me) { err("%s:%d: in resource %s\n" "\tInvoked with --peer '%s', but that matches myself!\n", res->config_file, res->start_line, res->name, connect_to_host); res->peer = NULL; break; } if (res->peer) { err("%s:%d: in resource %s:\n" "\tInvoked with --peer '%s', but that matches multiple times!\n", res->config_file, res->start_line, res->name, connect_to_host); res->peer = NULL; break; } res->peer = host; } if (peer_required && !res->peer) { config_valid = 0; if (!host) err("%s:%d: in resource %s:\n" "\tNo host ('on' or 'floating') section matches --peer '%s'\n", res->config_file, res->start_line, res->name, connect_to_host); } } void set_on_hosts_in_res(struct d_resource *res) { struct d_resource *l_res, *tmp; struct d_host_info *host, *host2; struct d_name *h, **last; for (host = res->all_hosts; host; host=host->next) { if (host->lower_name) { for_each_resource(l_res, tmp, config) { if (!strcmp(l_res->name, host->lower_name)) break; } if (l_res == NULL) { err("%s:%d: in resource %s, " "referenced resource '%s' not defined.\n", res->config_file, res->start_line, res->name, host->lower_name); config_valid = 0; continue; } /* Simple: host->on_hosts = concat_names(l_res->me->on_hosts, l_res->peer->on_hosts); */ last = NULL; for (host2 = l_res->all_hosts; host2; host2 = host2->next) if (!host2->lower_name) { append_names(&host->on_hosts, &last, host2->on_hosts); for_each_host(h, host2->on_hosts) { struct d_volume *vol; for_each_volume(vol, host->volumes) check_uniq("device-minor", "device-minor:%s:%u", h->name, vol->device_minor); for_each_volume(vol, host->volumes) if (vol->device) check_uniq("device", "device:%s:%s", h->name, vol->device); } } host->lower = l_res; /* */ if (addr_scope_local(host->address)) for_each_host(h, host->on_hosts) check_uniq("IP", "%s:%s:%s", h->name, host->address, host->port); } } } void set_disk_in_res(struct d_resource *res) { struct d_host_info *host; struct d_volume *a, *b; if (res->ignore) return; for (host = res->all_hosts; host; host=host->next) { if (!host->lower) continue; if (host->lower->ignore) continue; check_volume_sets_equal(res, host, host->lower->me); if (!config_valid) /* don't even bother for broken config. */ continue; /* volume lists are sorted on vnr */ a = host->volumes; b = host->lower->me->volumes; while (a) { while (b && a->vnr > b->vnr) { /* Lower resource has more volumes. * Probably unusual, but we decided * that it should be legal. * Skip those that do not match */ b = b->next; } if (a && b && a->vnr == b->vnr) { if (b->device) m_asprintf(&a->disk, "%s", b->device); else m_asprintf(&a->disk, "/dev/drbd%u", b->device_minor); /* stacked implicit volumes need internal meta data, too */ if (!a->meta_disk) m_asprintf(&a->meta_disk, "internal"); if (!a->meta_index) m_asprintf(&a->meta_index, "internal"); a = a->next; b = b->next; } else { /* config_invalid should have been set * by check_volume_sets_equal */ assert(0); } } } } void proxy_delegate(void *ctx) { struct d_option **proxy_plugins = (struct d_option **)ctx; int token; struct d_option *options, *opt; struct d_name *line, *word, **pnp; opt = NULL; token = yylex(); if (token != '{') { err("%s:%d: expected \"{\" after \"proxy\" keyword\n", config_file, fline); exit(E_CONFIG_INVALID); } options = NULL; while (1) { line = NULL; pnp = &line; while (1) { yylval.txt = NULL; token = yylex(); if (token <= 0) { err("%s:%d: Unexpected end-of-file\n", config_file, fline); exit(E_CONFIG_INVALID); } if (token == ';') break; if (token == '}') { if (pnp == &line) goto out; err("%s:%d: Missing \";\" before \"}\"\n", config_file, fline); exit(E_CONFIG_INVALID); } word = malloc(sizeof(struct d_name)); if (!word) pdperror("out of memory."); word->name = yylval.txt ? yylval.txt : strdup(yytext); word->next = NULL; *pnp = word; pnp = &word->next; } opt = calloc(1, sizeof(struct d_option)); if (!opt) pdperror("out of memory."); opt->name = strdup(names_to_str(line)); options = APPEND(options, opt); free_names(line); } out: if (proxy_plugins) *proxy_plugins = options; } static int parse_proxy_options(struct d_option **proxy_options, struct d_option **proxy_plugins) { struct d_option *opts; EXP('{'); opts = parse_options_d(0, 0, TK_PROXY_OPTION | TK_PROXY_GROUP, TK_PROXY_DELEGATE, proxy_delegate, proxy_plugins); if (proxy_options) *proxy_options = opts; return 0; } int parse_proxy_options_section(struct d_resource *res) { int token; struct d_resource dummy_res = { "dummy", }; token = yylex(); if (token != TK_PROXY) { yyrestart(yyin); /* flushes flex's buffers */ return 1; } if (!res) res = &dummy_res; return parse_proxy_options(&res->proxy_options, &res->proxy_plugins); } struct d_resource* parse_resource(char* res_name, enum pr_flags flags) { struct d_resource* res; struct d_name *host_names; char *opt_name; int token; check_upr_init(); check_uniq("resource section", res_name); res=calloc(1,sizeof(struct d_resource)); res->name = res_name; res->config_file = config_save; res->start_line = line; while(1) { token = yylex(); fline = line; switch(token) { case TK_NET_OPTION: if (strcmp(yylval.txt, "protocol")) goto goto_default; check_upr("protocol statement","%s: protocol",res->name); opt_name = yylval.txt; EXP(TK_STRING); range_check(R_PROTOCOL, opt_name, yylval.txt); res->net_options = APPEND(res->net_options, new_opt(opt_name, yylval.txt)); EXP(';'); break; case TK_ON: parse_hosts(&host_names, '{'); parse_host_section(res, host_names, REQUIRE_ALL); break; case TK_STACKED: parse_stacked_section(res); break; case TK_IGNORE: if (res->me || res->peer) { err("%s:%d: in resource %s, " "'ignore-on' statement must precede any real host section (on ... { ... }).\n", config_file, line, res->name); exit(E_CONFIG_INVALID); } EXP(TK_STRING); err("%s:%d: in resource %s, WARN: The 'ignore-on' keyword is deprecated.\n", config_file, line, res->name); EXP(';'); break; case TK__THIS_HOST: EXP('{'); host_names = names_from_str("_this_host"); parse_host_section(res, host_names, 0); break; case TK__REMOTE_HOST: EXP('{'); host_names = names_from_str("_remote_host"); parse_host_section(res, host_names, 0); break; case TK_FLOATING: parse_host_section(res, NULL, REQUIRE_ALL + BY_ADDRESS); break; case TK_DISK: switch (token=yylex()) { case TK_STRING: /* open coded parse_volume_stmt() */ volume0(&res->volumes)->disk = yylval.txt; EXP(';'); break; case '{': check_upr("disk section", "%s:disk", res->name); res->disk_options = SPLICE(res->disk_options, parse_options(TK_DISK_FLAG, TK_DISK_NO_FLAG, TK_DISK_OPTION)); break; default: check_string_error(token); pe_expected_got( "TK_STRING | {", token); } break; case TK_NET: check_upr("net section", "%s:net", res->name); EXP('{'); res->net_options = SPLICE(res->net_options, parse_options_d(TK_NET_FLAG, TK_NET_NO_FLAG, TK_NET_OPTION, TK_NET_DELEGATE, &net_delegate, (void *)flags)); break; case TK_SYNCER: check_upr("syncer section", "%s:syncer", res->name); EXP('{'); parse_options_syncer(res); break; case TK_STARTUP: check_upr("startup section", "%s:startup", res->name); EXP('{'); res->startup_options = parse_options_d(TK_STARTUP_FLAG, 0, TK_STARTUP_OPTION, TK_STARTUP_DELEGATE, &startup_delegate, res); break; case TK_HANDLER: check_upr("handlers section", "%s:handlers", res->name); EXP('{'); res->handlers = parse_options(0, 0, TK_HANDLER_OPTION); break; case TK_PROXY: check_upr("proxy section", "%s:proxy", res->name); parse_proxy_options(&res->proxy_options, &res->proxy_plugins); break; case TK_DEVICE: check_upr("device statement", "%s:device", res->name); case TK_META_DISK: case TK_FLEX_META_DISK: parse_volume_stmt(volume0(&res->volumes), NULL, token); break; case TK_VOLUME: EXP(TK_INTEGER); res->volumes = INSERT_SORTED(res->volumes, parse_volume(atoi(yylval.txt), NULL), vnr); break; case TK_OPTIONS: check_upr("resource options section", "%s:res_options", res->name); EXP('{'); res->res_options = SPLICE(res->res_options, parse_options(0, 0, TK_RES_OPTION)); break; case '}': case 0: goto exit_loop; default: goto_default: pe_expected_got("protocol | on | disk | net | syncer |" " startup | handlers |" " ignore-on | stacked-on-top-of",token); } } exit_loop: if (flags == NoneHAllowed && res->all_hosts) { config_valid = 0; err("%s:%d: in the %s section, there are no host sections allowed.\n", config_file, c_section_start, res->name); } if (!(flags & PARSE_FOR_ADJUST)) check_volumes_hosts(res); return res; } struct d_resource* parse_resource_for_adjust(struct cfg_ctx *ctx) { int token; token = yylex(); if (token != TK_RESOURCE) return NULL; token = yylex(); if (token != TK_STRING) return NULL; /* FIXME assert that string and ctx->res->name match? */ token = yylex(); if (token != '{') return NULL; return parse_resource(ctx->res->name, PARSE_FOR_ADJUST); } void post_parse(struct d_resource *config, enum pp_flags flags) { struct d_resource *res,*tmp; for_each_resource(res, tmp, config) if (res->stacked_on_one) set_on_hosts_in_res(res); /* sets on_hosts and host->lower */ /* Needs "on_hosts" and host->lower already set */ for_each_resource(res, tmp, config) if (!res->stacked_on_one) set_me_in_resource(res, flags & MATCH_ON_PROXY); /* Needs host->lower->me already set */ for_each_resource(res, tmp, config) if (res->stacked_on_one) set_me_in_resource(res, flags & MATCH_ON_PROXY); // Needs "me" set already for_each_resource(res, tmp, config) if (res->stacked_on_one) set_disk_in_res(res); } /* Returns the "previous" count, ie. 0 if this file wasn't seen before. */ int was_file_already_seen(char *fn) { ENTRY e, *ep; char *real_path; real_path = realpath(fn, NULL); if (!real_path) real_path = fn; ep = NULL; e.key = real_path; e.data = real_path; hsearch_r(e, FIND, &ep, &global_htable); if (ep) { /* Can be freed, it's just a queried key. */ if (real_path != fn) free(real_path); return 1; } e.key = real_path; e.data = real_path; hsearch_r(e, ENTER, &ep, &global_htable); if (!ep) { err("hash table entry (%s => %s) failed\n", e.key, (char *)e.data); exit(E_THINKO); } /* Must not be freed, because it's still referenced by the hash table. */ /* free(real_path); */ return 0; } void include_stmt(char *str) { char *last_slash, *tmp; glob_t glob_buf; int cwd_fd; FILE *f; size_t i; int r; /* in order to allow relative paths in include statements we change directory to the location of the current configuration file. */ cwd_fd = open(".", O_RDONLY | O_CLOEXEC); if (cwd_fd < 0) { err("open(\".\") failed: %m\n"); exit(E_USAGE); } tmp = strdupa(config_save); last_slash = strrchr(tmp, '/'); if (last_slash) *last_slash = 0; if (chdir(tmp)) { err("chdir(\"%s\") failed: %m\n", tmp); exit(E_USAGE); } r = glob(str, 0, NULL, &glob_buf); if (r == 0) { for (i=0; i Copyright (C) 2006-2008, Lars Ellenberg drbd is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. drbd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with drbd; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "drbdadm.h" #include "drbdtool_common.h" #include "drbd_endian.h" #include "linux/drbd.h" /* only use DRBD_MAGIC from here! */ #define HTTP_PORT 80 #define HTTP_HOST "usage.drbd.org" #define HTTP_ADDR "212.69.161.111" #define NODE_ID_FILE DRBD_LIB_DIR"/node_id" #define GIT_HASH_BYTE 20 #define SRCVERSION_BYTE 12 /* actually 11 and a half. */ #define SRCVERSION_PAD (GIT_HASH_BYTE - SRCVERSION_BYTE) #define SVN_STYLE_OD 16 struct vcs_rel { uint32_t svn_revision; char git_hash[GIT_HASH_BYTE]; struct { unsigned major, minor, sublvl; } version; unsigned version_code; }; struct node_info { uint64_t node_uuid; struct vcs_rel rev; }; struct node_info_od { uint32_t magic; struct node_info ni; } __packed; /* For our purpose (finding the revision) SLURP_SIZE is always enough. */ static char* slurp_proc_drbd() { const int SLURP_SIZE = 4096; char* buffer; int rr, fd; fd = open("/proc/drbd",O_RDONLY); if( fd == -1) return 0; buffer = malloc(SLURP_SIZE); if(!buffer) return 0; rr = read(fd, buffer, SLURP_SIZE-1); if( rr == -1) { free(buffer); return 0; } buffer[rr]=0; close(fd); return buffer; } void read_hex(char* dst, char* src, int dst_size, int src_size) { int dst_i, u, src_i=0; for(dst_i=0;dst_i= src_size) break; if(src[src_i] == 0) break; if(++src_i >= src_size) break; } } void vcs_ver_from_str(struct vcs_rel *rel, const char *token) { char *dot; long maj, min, sub; maj = strtol(token, &dot, 10); if (*dot != '.') return; min = strtol(dot+1, &dot, 10); if (*dot != '.') return; sub = strtol(dot+1, &dot, 10); /* don't check on *dot == 0, * we may want to add some extraversion tag sometime if (*dot != 0) return; */ rel->version.major = maj; rel->version.minor = min; rel->version.sublvl = sub; rel->version_code = (maj << 16) + (min << 8) + sub; } void vcs_from_str(struct vcs_rel *rel, const char *text) { char token[80]; int plus=0; enum { begin, f_ver, f_svn, f_rev, f_git, f_srcv } ex = begin; while (sget_token(token, sizeof(token), &text) != EOF) { switch(ex) { case begin: if(!strcmp(token,"version:")) ex = f_ver; if(!strcmp(token,"SVN")) ex = f_svn; if(!strcmp(token,"GIT-hash:")) ex = f_git; if(!strcmp(token,"srcversion:")) ex = f_srcv; break; case f_ver: if(!strcmp(token,"plus")) plus = 1; /* still waiting for version */ else { vcs_ver_from_str(rel, token); ex = begin; } break; case f_svn: if(!strcmp(token,"Revision:")) ex = f_rev; break; case f_rev: rel->svn_revision = atol(token) * 10; if( plus ) rel->svn_revision += 1; memset(rel->git_hash, 0, GIT_HASH_BYTE); return; case f_git: read_hex(rel->git_hash, token, GIT_HASH_BYTE, strlen(token)); rel->svn_revision = 0; return; case f_srcv: memset(rel->git_hash, 0, SRCVERSION_PAD); read_hex(rel->git_hash + SRCVERSION_PAD, token, SRCVERSION_BYTE, strlen(token)); rel->svn_revision = 0; return; } } } static int current_vcs_is_from_proc_drbd; static struct vcs_rel current_vcs_rel; static struct vcs_rel userland_version; static void vcs_get_current(void) { char* version_txt; if (current_vcs_rel.version_code) return; version_txt = slurp_proc_drbd(); if(version_txt) { vcs_from_str(¤t_vcs_rel, version_txt); current_vcs_is_from_proc_drbd = 1; free(version_txt); } else { vcs_from_str(¤t_vcs_rel, drbd_buildtag()); vcs_ver_from_str(¤t_vcs_rel, PACKAGE_VERSION); } } static void vcs_get_userland(void) { if (userland_version.version_code) return; vcs_ver_from_str(&userland_version, PACKAGE_VERSION); } int version_code_kernel(void) { vcs_get_current(); return current_vcs_is_from_proc_drbd ? current_vcs_rel.version_code : 0; } int version_code_userland(void) { vcs_get_userland(); return userland_version.version_code; } static int vcs_eq(struct vcs_rel *rev1, struct vcs_rel *rev2) { if( rev1->svn_revision || rev2->svn_revision ) { return rev1->svn_revision == rev2->svn_revision; } else { return !memcmp(rev1->git_hash,rev2->git_hash,GIT_HASH_BYTE); } } static int vcs_ver_cmp(struct vcs_rel *rev1, struct vcs_rel *rev2) { return rev1->version_code - rev2->version_code; } void warn_on_version_mismatch(void) { char *msg; int cmp; /* get the kernel module version from /proc/drbd */ vcs_get_current(); /* get the userland version from PACKAGE_VERSION */ vcs_get_userland(); cmp = vcs_ver_cmp(&userland_version, ¤t_vcs_rel); /* no message if equal */ if (cmp == 0) return; if (cmp > 0xffff || cmp < -0xffff) /* major version differs! */ msg = "mixing different major numbers will not work!"; else if (cmp < 0) /* userland is older. always warn. */ msg = "you should upgrade your drbd tools!"; else if (cmp & 0xff00) /* userland is newer minor version */ msg = "please don't mix different DRBD series."; else /* userland is newer, but only differ in sublevel. */ msg = "preferably kernel and userland versions should match."; fprintf(stderr, "DRBD module version: %u.%u.%u\n" " userland version: %u.%u.%u\n%s\n", current_vcs_rel.version.major, current_vcs_rel.version.minor, current_vcs_rel.version.sublvl, userland_version.version.major, userland_version.version.minor, userland_version.version.sublvl, msg); } void add_lib_drbd_to_path(void) { char *new_path = NULL; char *old_path = getenv("PATH"); m_asprintf(&new_path, "%s%s%s", old_path, old_path ? ":" : "", "/lib/drbd"); setenv("PATH", new_path, 1); } void maybe_exec_drbdadm_83(char **argv) { if (current_vcs_rel.version.major == 8 && current_vcs_rel.version.minor == 3) { #ifdef DRBD_LEGACY_83 /* This drbdadm warned already... */ setenv("DRBD_DONT_WARN_ON_VERSION_MISMATCH", "1", 0); add_lib_drbd_to_path(); execvp(drbdadm_83, argv); fprintf(stderr, "execvp() failed to exec %s: %m\n", drbdadm_83); #else fprintf(stderr, "This drbdadm was not built with support for drbd-8.3\n" "Consider to rebuild with ./configure --with-83-support\n"); #endif exit(E_EXEC_ERROR); } } static char *vcs_to_str(struct vcs_rel *rev) { static char buffer[80]; // Not generic, sufficient for the purpose. if( rev->svn_revision ) { snprintf(buffer,80,"nv="U32,rev->svn_revision); } else { int len=20,p; unsigned char *bytes; p = sprintf(buffer,"git="); bytes = (unsigned char*)rev->git_hash; while(len--) p += sprintf(buffer+p,"%02x",*bytes++); } return buffer; } static void write_node_id(struct node_info *ni) { int fd; struct node_info_od on_disk; int size; fd = open(NODE_ID_FILE,O_WRONLY|O_CREAT,S_IRUSR|S_IWUSR); if( fd == -1 && errno == ENOENT) { mkdir(DRBD_LIB_DIR,S_IRWXU); fd = open(NODE_ID_FILE,O_WRONLY|O_CREAT,S_IRUSR|S_IWUSR); } if( fd == -1) { perror("Creation of "NODE_ID_FILE" failed."); exit(20); } if(ni->rev.svn_revision != 0) { // SVN style (old) on_disk.magic = cpu_to_be32(DRBD_MAGIC); on_disk.ni.node_uuid = cpu_to_be64(ni->node_uuid); on_disk.ni.rev.svn_revision = cpu_to_be32(ni->rev.svn_revision); memset(on_disk.ni.rev.git_hash,0,GIT_HASH_BYTE); size = SVN_STYLE_OD; } else { on_disk.magic = cpu_to_be32(DRBD_MAGIC+1); on_disk.ni.node_uuid = cpu_to_be64(ni->node_uuid); on_disk.ni.rev.svn_revision = 0; memcpy(on_disk.ni.rev.git_hash,ni->rev.git_hash,GIT_HASH_BYTE); size = sizeof(on_disk); } if( write(fd,&on_disk, size) != size) { perror("Write to "NODE_ID_FILE" failed."); exit(20); } close(fd); } static int read_node_id(struct node_info *ni) { int rr,fd; struct node_info_od on_disk; fd = open(NODE_ID_FILE,O_RDONLY); if( fd == -1) { return 0; } rr = read(fd,&on_disk, sizeof(on_disk)); if( rr != sizeof(on_disk) && rr != SVN_STYLE_OD ) { close(fd); return 0; } switch(be32_to_cpu(on_disk.magic)) { case DRBD_MAGIC: ni->node_uuid = be64_to_cpu(on_disk.ni.node_uuid); ni->rev.svn_revision = be32_to_cpu(on_disk.ni.rev.svn_revision); memset(ni->rev.git_hash,0,GIT_HASH_BYTE); break; case DRBD_MAGIC+1: ni->node_uuid = be64_to_cpu(on_disk.ni.node_uuid); ni->rev.svn_revision = 0; memcpy(ni->rev.git_hash,on_disk.ni.rev.git_hash,GIT_HASH_BYTE); break; default: return 0; } close(fd); return 1; } /* to interrupt gethostbyname, * we not only need a signal, * but also the long jump: * gethostbyname would otherwise just restart the syscall * and timeout again. */ static jmp_buf timed_out; static void gethostbyname_timeout(int __attribute((unused)) signo) { longjmp(timed_out, 1); } #define DNS_TIMEOUT 3 /* seconds */ #define SOCKET_TIMEOUT 3 /* seconds */ struct hostent *my_gethostbyname(const char *name) { struct sigaction sa; struct sigaction so; struct hostent *h; alarm(0); sa.sa_handler = &gethostbyname_timeout; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sigaction(SIGALRM, &sa, &so); if (!setjmp(timed_out)) { alarm(DNS_TIMEOUT); h = gethostbyname(name); } else /* timed out, longjmp of SIGALRM jumped here */ h = NULL; alarm(0); sigaction(SIGALRM, &so, NULL); return h; } /** * insert_usage_with_socket: * * Return codes: * * 0 - success * 1 - failed to create socket * 2 - unknown server * 3 - cannot connect to server * 5 - other error */ static int make_get_request(char *uri) { struct sockaddr_in server; struct hostent *host_info; unsigned long addr; int sock; char *req_buf; char *http_host = HTTP_HOST; int buf_len = 1024; char buffer[buf_len]; FILE *sockfd; int writeit; struct timeval timeout = { .tv_sec = SOCKET_TIMEOUT }; sock = socket( PF_INET, SOCK_STREAM, 0); if (sock < 0) return 1; setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)); memset (&server, 0, sizeof(server)); /* convert host name to ip */ host_info = my_gethostbyname(http_host); if (host_info == NULL) { /* unknown host, try with ip */ if ((addr = inet_addr( HTTP_ADDR )) != INADDR_NONE) memcpy((char *)&server.sin_addr, &addr, sizeof(addr)); else { close(sock); return 2; } } else { memcpy((char *)&server.sin_addr, host_info->h_addr, host_info->h_length); } ssprintf(req_buf, "GET %s HTTP/1.0\r\n" "Host: "HTTP_HOST"\r\n" "User-Agent: drbdadm/"PACKAGE_VERSION" (%s; %s; %s; %s)\r\n" "\r\n", uri, nodeinfo.sysname, nodeinfo.release, nodeinfo.version, nodeinfo.machine); server.sin_family = AF_INET; server.sin_port = htons(HTTP_PORT); if (connect(sock, (struct sockaddr*)&server, sizeof(server))<0) { /* cannot connect to server */ close(sock); return 3; } if ((sockfd = fdopen(sock, "r+")) == NULL) { close(sock); return 5; } if (fputs(req_buf, sockfd) == EOF) { fclose(sockfd); close(sock); return 5; } writeit = 0; while (fgets(buffer, buf_len, sockfd) != NULL) { /* ignore http headers */ if (writeit == 0) { if (buffer[0] == '\r' || buffer[0] == '\n') writeit = 1; } else { fprintf(stderr,"%s", buffer); } } fclose(sockfd); close(sock); return 0; } static void url_encode(char* in, char* out) { char *h = "0123456789abcdef"; char c; while( (c = *in++) != 0 ) { if( c == '\n' ) break; if( ( 'a' <= c && c <= 'z' ) || ( 'A' <= c && c <= 'Z' ) || ( '0' <= c && c <= '9' ) || c == '-' || c == '_' || c == '.' ) *out++ = c; else if( c == ' ' ) *out++ = '+'; else { *out++ = '%'; *out++ = h[c >> 4]; *out++ = h[c & 0x0f]; } } *out = 0; } /* Ensure that the node is counted on http://usage.drbd.org */ #define ANSWER_SIZE 80 void uc_node(enum usage_count_type type) { struct node_info ni; char *uri; int send = 0; int update = 0; char answer[ANSWER_SIZE]; char n_comment[ANSWER_SIZE*3]; char *r; if( type == UC_NO ) return; if( getuid() != 0 ) return; /* not when running directly from init, * or if stdout is no tty. * you do not want to have the "user information message" * as output from `drbdadm sh-resources all` */ if (getenv("INIT_VERSION")) return; if (no_tty) return; vcs_get_current(); if( ! read_node_id(&ni) ) { get_random_bytes(&ni.node_uuid,sizeof(ni.node_uuid)); ni.rev = current_vcs_rel; send = 1; } else if (current_vcs_is_from_proc_drbd == 0) { /* Avoid flapping between drbd-utils git-hash and * kernel module git-hash. */ send = 0; } else { // read_node_id() was successful if (!vcs_eq(&ni.rev,¤t_vcs_rel)) { ni.rev = current_vcs_rel; update = 1; send = 1; } } if(!send) return; n_comment[0]=0; if (type == UC_ASK ) { fprintf(stderr, "\n" "\t\t--== This is %s of DRBD ==--\n" "Please take part in the global DRBD usage count at http://"HTTP_HOST".\n\n" "The counter works anonymously. It creates a random number to identify\n" "your machine and sends that random number, along with the kernel and\n" "DRBD version, to "HTTP_HOST".\n\n" "The benefits for you are:\n" " * In response to your submission, the server ("HTTP_HOST") will tell you\n" " how many users before you have installed this version (%s).\n" " * With a high counter LINBIT has a strong motivation to\n" " continue funding DRBD's development.\n\n" "http://"HTTP_HOST"/cgi-bin/insert_usage.pl?nu="U64"&%s\n\n" "In case you want to participate but know that this machine is firewalled,\n" "simply issue the query string with your favorite web browser or wget.\n" "You can control all of this by setting 'usage-count' in your drbd.conf.\n\n" "* You may enter a free form comment about your machine, that gets\n" " used on "HTTP_HOST" instead of the big random number.\n" "* If you wish to opt out entirely, simply enter 'no'.\n" "* To count this node without comment, just press [RETURN]\n", update ? "an update" : "a new installation", PACKAGE_VERSION,ni.node_uuid, vcs_to_str(&ni.rev)); r = fgets(answer, ANSWER_SIZE, stdin); if(r && !strcmp(answer,"no\n")) send = 0; url_encode(answer,n_comment); } ssprintf(uri,"http://"HTTP_HOST"/cgi-bin/insert_usage.pl?nu="U64"&%s%s%s", ni.node_uuid, vcs_to_str(&ni.rev), n_comment[0] ? "&nc=" : "", n_comment); if (send) { write_node_id(&ni); fprintf(stderr, "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" " --== Thank you for participating in the global usage survey ==--\n" "The server's response is:\n\n"); make_get_request(uri); if (type == UC_ASK) { fprintf(stderr, "\n" "From now on, drbdadm will contact "HTTP_HOST" only when you update\n" "DRBD or when you use 'drbdadm create-md'. Of course it will continue\n" "to ask you for confirmation as long as 'usage-count' is at its default\n" "value of 'ask'.\n\n" "Just press [RETURN] to continue: "); r = fgets(answer, 9, stdin); } } } /* For our purpose (finding the revision) SLURP_SIZE is always enough. */ static char* run_admm_generic(struct cfg_ctx *ctx, const char *arg_override) { const int SLURP_SIZE = 4096; int rr,pipes[2]; char* buffer; pid_t pid; buffer = malloc(SLURP_SIZE); if(!buffer) return 0; if(pipe(pipes)) return 0; pid = fork(); if(pid == -1) { fprintf(stderr,"Can not fork\n"); exit(E_EXEC_ERROR); } if(pid == 0) { // child close(pipes[0]); // close reading end dup2(pipes[1],1); // 1 = stdout close(pipes[1]); /* local modification in child, * no propagation to parent */ ctx->arg = arg_override; rr = _admm_generic(ctx, SLEEPS_VERY_LONG| DONT_REPORT_FAILED); exit(rr); } close(pipes[1]); // close writing end rr = read(pipes[0], buffer, SLURP_SIZE-1); if( rr == -1) { free(buffer); // FIXME cleanup return 0; } buffer[rr]=0; close(pipes[0]); waitpid(pid,0,0); return buffer; } int adm_create_md(struct cfg_ctx *ctx) { char answer[ANSWER_SIZE]; struct node_info ni; uint64_t device_uuid=0; uint64_t device_size=0; char *uri; int send=0; char *tb; int rv,fd; char *r; tb = run_admm_generic(ctx, "read-dev-uuid"); device_uuid = strto_u64(tb,NULL,16); free(tb); /* this is "drbdmeta ... create-md" */ rv = _admm_generic(ctx, SLEEPS_VERY_LONG); if(rv || dry_run) return rv; fd = open(ctx->vol->disk,O_RDONLY); if( fd != -1) { device_size = bdev_size(fd); close(fd); } if( read_node_id(&ni) && device_size && !device_uuid) { get_random_bytes(&device_uuid, sizeof(uint64_t)); if( global_options.usage_count == UC_YES ) send = 1; if( global_options.usage_count == UC_ASK ) { fprintf(stderr, "\n" "\t\t--== Creating metadata ==--\n" "As with nodes, we count the total number of devices mirrored by DRBD\n" "at http://"HTTP_HOST".\n\n" "The counter works anonymously. It creates a random number to identify\n" "the device and sends that random number, along with the kernel and\n" "DRBD version, to "HTTP_HOST".\n\n" "http://"HTTP_HOST"/cgi-bin/insert_usage.pl?nu="U64"&ru="U64"&rs="U64"\n\n" "* If you wish to opt out entirely, simply enter 'no'.\n" "* To continue, just press [RETURN]\n", ni.node_uuid,device_uuid,device_size ); r = fgets(answer, ANSWER_SIZE, stdin); if(r && strcmp(answer,"no\n")) send = 1; } } if(!device_uuid) { get_random_bytes(&device_uuid, sizeof(uint64_t)); } if (send) { ssprintf(uri,"http://"HTTP_HOST"/cgi-bin/insert_usage.pl?" "nu="U64"&ru="U64"&rs="U64, ni.node_uuid, device_uuid, device_size); make_get_request(uri); } /* HACK */ { struct cfg_ctx local_ctx = *ctx; struct setup_option *old_setup_options; char *opt; ssprintf(opt, X64(016), device_uuid); old_setup_options = setup_options; setup_options = NULL; add_setup_option(false, opt); local_ctx.arg = "write-dev-uuid"; _admm_generic(&local_ctx, SLEEPS_VERY_LONG); free(setup_options); setup_options = old_setup_options; } return rv; } drbd-utils-8.9.6/user/v84/registry.c0000644000175000017500000001136012466702074017127 0ustar apoikosapoikos/* drbdadm_registry.c This file is part of DRBD by Philipp Reisner and Lars Ellenberg. It was written by Johannes Thoma Copyright (C) 2002-2008, LINBIT Information Technologies GmbH. Copyright (C) 2002-2008, Philipp Reisner . Copyright (C) 2002-2008, Lars Ellenberg . drbd is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. drbd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with drbd; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ /* This keeps track of which DRBD minor was configured in which * config file. This is required to have alternative config files * (-c switch) and userland event handlers. */ #include #include #include #include #include #include #include #include #include #include #include "config.h" #include "registry.h" static void linkname_from_minor(char *linkname, int minor) { sprintf(linkname, "%s/drbd-minor-%d.conf", DRBD_RUN_DIR, minor); } int unregister_minor(int minor) { char linkname[PATH_MAX]; linkname_from_minor(linkname, minor); if (unlink(linkname) < 0) { if (errno != ENOENT) { perror("unlink"); return -1; } } return 0; } static ssize_t __readlink(const char *path, char *buf, size_t bufsiz) { ssize_t ret; ret = readlink(path, buf, bufsiz); if (ret >= 0) { if (ret >= bufsiz) { errno = ENAMETOOLONG; return -1; } buf[ret] = 0; } return ret; } static int register_path(const char *linkname, const char *path) { char target[PATH_MAX]; if (path[0] != '/') { fprintf(stderr, "File %s: absolute path expected; won't " "register relative path.", path); return -1; } /* safeguard against symlink loops in DRBD_RUN_DIR */ if (!strncmp(path, DRBD_RUN_DIR "/", strlen(DRBD_RUN_DIR "/"))) return -1; if (__readlink(linkname, target, sizeof(target)) >= 0 && !strcmp(target, path)) return 0; if (unlink(linkname) != 0 && errno != ENOENT) { perror(linkname); return -1; } if (mkdir(DRBD_RUN_DIR, S_IRWXU) != 0 && errno != EEXIST) { perror(DRBD_RUN_DIR); return -1; } if (symlink(path, linkname) != 0) { fprintf(stderr, "symlink(%s, %s): %m\n", path, linkname); return -1; } return 0; } int register_minor(int minor, const char *path) { char linkname[PATH_MAX]; linkname_from_minor(linkname, minor); return register_path(linkname, path); } static char *resolve_symlink(const char *linkname) { static char target[PATH_MAX]; if (__readlink(linkname, target, sizeof(target)) < 0) return NULL; return target; } char *lookup_minor(int minor) { static char linkname[PATH_MAX]; struct stat stat_buf; linkname_from_minor(linkname, minor); if (stat(linkname, &stat_buf) != 0) { if (errno != ENOENT) perror(linkname); return NULL; } return resolve_symlink(linkname); } static void linkname_from_resource_name(char *linkname, const char *name) { sprintf(linkname, "%s/drbd-resource-%s.conf", DRBD_RUN_DIR, name); } int unregister_resource(const char *name) { char linkname[PATH_MAX]; linkname_from_resource_name(linkname, name); if (unlink(linkname) != 0) { if (errno != ENOENT) { perror(linkname); return -1; } } return 0; } int register_resource(const char *name, const char *path) { char linkname[PATH_MAX]; linkname_from_resource_name(linkname, name); return register_path(linkname, path); } /* This returns a static buffer containing the real * configuration file known to be used last for this minor. * If you need the return value longer, stuff it away with strdup. */ char *lookup_resource(const char *name) { static char linkname[PATH_MAX]; struct stat stat_buf; linkname_from_resource_name(linkname, name); if (stat(linkname, &stat_buf) != 0) { if (errno != ENOENT) perror(linkname); return NULL; } return resolve_symlink(linkname); } #ifdef TEST int main(int argc, char ** argv) { register_minor(1, "/etc/drbd-xy.conf"); register_minor(15, "/etc/drbd-82.conf"); register_minor(14, "/../../../../../../etc/drbd-82.conf"); printf("Minor 1 is %s.\n", lookup_minor(1)); printf("Minor 2 is %s.\n", lookup_minor(2)); printf("Minor 14 is %s.\n", lookup_minor(14)); printf("Minor 15 is %s.\n", lookup_minor(15)); return 0; } #endif drbd-utils-8.9.6/user/v84/config_flags.c0000644000175000017500000006645112634271674017717 0ustar apoikosapoikos#define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include "libgenl.h" #include #include #include #include #include "drbd_nla.h" #include #include "drbdtool_common.h" #include "config_flags.h" #ifndef AF_INET_SDP #define AF_INET_SDP 27 #define PF_INET_SDP AF_INET_SDP #endif #ifndef ARRAY_SIZE #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) #endif #define NLA_POLICY(p) \ .nla_policy = p ## _nl_policy, \ .nla_policy_size = ARRAY_SIZE(p ## _nl_policy) /* ============================================================================================== */ static int enum_string_to_int(const char **map, int size, const char *value, int (*strcmp)(const char *, const char *)) { int n; if (!value) return -1; for (n = 0; n < size; n++) { if (map[n] && !strcmp(value, map[n])) return n; } return -1; } static bool enum_is_default(struct field_def *field, const char *value) { int n; n = enum_string_to_int(field->u.e.map, field->u.e.size, value, strcmp); return n == field->u.e.def; } static bool enum_is_equal(struct field_def *field, const char *a, const char *b) { return !strcmp(a, b); } static int type_of_field(struct context_def *ctx, struct field_def *field) { return ctx->nla_policy[__nla_type(field->nla_type)].type; } static int len_of_field(struct context_def *ctx, struct field_def *field) { return ctx->nla_policy[__nla_type(field->nla_type)].len; } static const char *get_enum(struct context_def *ctx, struct field_def *field, struct nlattr *nla) { int i; assert(type_of_field(ctx, field) == NLA_U32); i = nla_get_u32(nla); if (i < 0 || i >= field->u.e.size) return NULL; return field->u.e.map[i]; } static bool put_enum(struct context_def *ctx, struct field_def *field, struct msg_buff *msg, const char *value) { int n; n = enum_string_to_int(field->u.e.map, field->u.e.size, value, strcmp); if (n == -1) return false; assert(type_of_field(ctx, field) == NLA_U32); nla_put_u32(msg, field->nla_type, n); return true; } static int enum_usage(struct field_def *field, char *str, int size) { const char** map = field->u.e.map; char sep = '{'; int n, len = 0, l; l = snprintf(str, size, "[--%s=", field->name); len += l; size -= l; for (n = 0; n < field->u.e.size; n++) { if (!map[n]) continue; l = snprintf(str + len, size, "%c%s", sep, map[n]); len += l; size -= l; sep = '|'; } assert (sep != '{'); l = snprintf(str+len, size, "}]"); len += l; size -= l; return len; } static bool enum_is_default_nocase(struct field_def *field, const char *value) { int n; n = enum_string_to_int(field->u.e.map, field->u.e.size, value, strcasecmp); return n == field->u.e.def; } static bool enum_is_equal_nocase(struct field_def *field, const char *a, const char *b) { return !strcasecmp(a, b); } static bool put_enum_nocase(struct context_def *ctx, struct field_def *field, struct msg_buff *msg, const char *value) { int n; n = enum_string_to_int(field->u.e.map, field->u.e.size, value, strcasecmp); if (n == -1) return false; assert(type_of_field(ctx, field) == NLA_U32); nla_put_u32(msg, field->nla_type, n); return true; } static void enum_describe_xml(struct field_def *field) { const char **map = field->u.e.map; int n; printf("\t\n"); } /* ---------------------------------------------------------------------------------------------- */ static bool numeric_is_default(struct field_def *field, const char *value) { long long l; /* FIXME: unsigned long long values are broken. */ l = m_strtoll(value, field->u.n.scale); return l == field->u.n.def; } static bool numeric_is_equal(struct field_def *field, const char *a, const char *b) { long long la, lb; /* FIXME: unsigned long long values are broken. */ la = m_strtoll(a, field->u.n.scale); lb = m_strtoll(b, field->u.n.scale); return la == lb; } static const char *get_numeric(struct context_def *ctx, struct field_def *field, struct nlattr *nla) { static char buffer[1 + 20 + 2]; char scale = field->u.n.scale; unsigned long long l; int n; switch(type_of_field(ctx, field)) { case NLA_U8: l = nla_get_u8(nla); break; case NLA_U16: l = nla_get_u16(nla); break; case NLA_U32: l = nla_get_u32(nla); break; case NLA_U64: l = nla_get_u64(nla); break; default: return NULL; } if (field->u.n.is_signed) { /* Sign extend. */ switch(type_of_field(ctx, field)) { case NLA_U8: l = (int8_t)l; break; case NLA_U16: l = (int16_t)l; break; case NLA_U32: l = (int32_t)l; break; case NLA_U64: l = (int64_t)l; break; } n = snprintf(buffer, sizeof(buffer), "%lld%c", l, scale == '1' ? 0 : scale); } else n = snprintf(buffer, sizeof(buffer), "%llu%c", l, scale == '1' ? 0 : scale); assert(n < sizeof(buffer)); return buffer; } static bool put_numeric(struct context_def *ctx, struct field_def *field, struct msg_buff *msg, const char *value) { long long l; /* FIXME: unsigned long long values are broken. */ l = m_strtoll(value, field->u.n.scale); switch(type_of_field(ctx, field)) { case NLA_U8: nla_put_u8(msg, field->nla_type, l); break; case NLA_U16: nla_put_u16(msg, field->nla_type, l); break; case NLA_U32: nla_put_u32(msg, field->nla_type, l); break; case NLA_U64: nla_put_u64(msg, field->nla_type, l); break; default: return false; } return true; } static int numeric_usage(struct field_def *field, char *str, int size) { return snprintf(str, size,"[--%s=(%lld ... %lld)]", field->name, field->u.n.min, field->u.n.max); } static void numeric_describe_xml(struct field_def *field) { printf("\t\n"); } /* ---------------------------------------------------------------------------------------------- */ static int boolean_string_to_int(const char *value) { if (!value || !strcmp(value, "yes")) return 1; else if (!strcmp(value, "no")) return 0; else return -1; } static bool boolean_is_default(struct field_def *field, const char *value) { int yesno; yesno = boolean_string_to_int(value); return yesno == field->u.b.def; } static bool boolean_is_equal(struct field_def *field, const char *a, const char *b) { return boolean_string_to_int(a) == boolean_string_to_int(b); } static const char *get_boolean(struct context_def *ctx, struct field_def *field, struct nlattr *nla) { int i; assert(type_of_field(ctx, field) == NLA_U8); i = nla_get_u8(nla); return i ? "yes" : "no"; } static bool put_boolean(struct context_def *ctx, struct field_def *field, struct msg_buff *msg, const char *value) { int yesno; yesno = boolean_string_to_int(value); if (yesno == -1) return false; assert(type_of_field(ctx, field) == NLA_U8); nla_put_u8(msg, field->nla_type, yesno); return true; } static bool put_flag(struct context_def *ctx, struct field_def *field, struct msg_buff *msg, const char *value) { int yesno; yesno = boolean_string_to_int(value); if (yesno == -1) return false; assert(type_of_field(ctx, field) == NLA_U8); if (yesno) nla_put_u8(msg, field->nla_type, yesno); return true; } static int boolean_usage(struct field_def *field, char *str, int size) { return snprintf(str, size,"[--%s={yes|no}]", field->name); } static void boolean_describe_xml(struct field_def *field) { printf("\t\n", field->name, field->u.b.def ? "yes" : "no"); } /* ---------------------------------------------------------------------------------------------- */ static bool string_is_default(struct field_def *field, const char *value) { return value && !strcmp(value, ""); } static bool string_is_equal(struct field_def *field, const char *a, const char *b) { return !strcmp(a, b); } static const char *get_string(struct context_def *ctx, struct field_def *field, struct nlattr *nla) { char *str; int len; assert(type_of_field(ctx, field) == NLA_NUL_STRING); str = (char *)nla_data(nla); len = len_of_field(ctx, field); assert(memchr(str, 0, len + 1) != NULL); return str; } static bool put_string(struct context_def *ctx, struct field_def *field, struct msg_buff *msg, const char *value) { assert(type_of_field(ctx, field) == NLA_NUL_STRING); nla_put_string(msg, field->nla_type, value); return true; } static int string_usage(struct field_def *field, char *str, int size) { return snprintf(str, size,"[--%s=]", field->name); } static void string_describe_xml(struct field_def *field) { printf("\t\n", field->name); } const char *double_quote_string(const char *str) { static char *buffer; const char *s; char *b; int len = 0; for (s = str; *s; s++) { if (*s == '\\' || *s == '"') len++; len++; } b = realloc(buffer, len + 3); if (!b) return NULL; buffer = b; *b++ = '"'; for (s = str; *s; s++) { if (*s == '\\' || *s == '"') *b++ = '\\'; *b++ = *s; } *b++ = '"'; *b++ = 0; return buffer; } /* ---------------------------------------------------------------------------------------------- */ static bool address_is_default(struct field_def *field, const char *value) { return true; } static bool address_is_equal(struct field_def *field, const char *a, const char *b) { return !strcmp(a, b); } /* It will only print the WARNING if the warn flag is set with the _first_ call! */ #define PROC_NET_AF_SCI_FAMILY "/proc/net/af_sci/family" #define PROC_NET_AF_SSOCKS_FAMILY "/proc/net/af_ssocks/family" int get_af_ssocks(int warn_and_use_default) { char buf[16]; int c, fd; static int af = -1; if (af > 0) return af; fd = open(PROC_NET_AF_SSOCKS_FAMILY, O_RDONLY); if (fd < 0) fd = open(PROC_NET_AF_SCI_FAMILY, O_RDONLY); if (fd < 0) { if (warn_and_use_default) { fprintf(stderr, "open(" PROC_NET_AF_SSOCKS_FAMILY ") " "failed: %m\n WARNING: assuming AF_SSOCKS = 27. " "Socket creation may fail.\n"); af = 27; } return af; } c = read(fd, buf, sizeof(buf)-1); if (c > 0) { buf[c] = 0; if (buf[c-1] == '\n') buf[c-1] = 0; af = m_strtoll(buf,1); } else { if (warn_and_use_default) { fprintf(stderr, "read(" PROC_NET_AF_SSOCKS_FAMILY ") " "failed: %m\n WARNING: assuming AF_SSOCKS = 27. " "Socket creation may fail.\n"); af = 27; } } close(fd); return af; } static char *af_to_str(int af) { if (af == AF_INET) return "ipv4"; else if (af == AF_INET6) return "ipv6"; /* AF_SSOCKS typically is 27, the same as AF_INET_SDP. * But with warn_and_use_default = 0, it will stay at -1 if not available. * Just keep the test on ssocks before the one on SDP (which is hard-coded), * and all should be fine. */ else if (af == get_af_ssocks(0)) return "ssocks"; else if (af == AF_INET_SDP) return "sdp"; else return "unknown"; } void sprint_address(char *buffer, void *address, int addr_len) { union { struct sockaddr addr; struct sockaddr_in addr4; struct sockaddr_in6 addr6; } a; memset(&a, 0, sizeof(a)); memcpy(&a.addr, address, addr_len); if (a.addr.sa_family == AF_INET || a.addr.sa_family == get_af_ssocks(0) || a.addr.sa_family == AF_INET_SDP) { sprintf(buffer, "%s %s:%d", af_to_str(a.addr4.sin_family), inet_ntoa(a.addr4.sin_addr), ntohs(a.addr4.sin_port)); } else if (a.addr.sa_family == AF_INET6) { char buf2[ADDRESS_STR_MAX]; int n; buf2[0] = 0; getnameinfo(&a.addr, addr_len, buf2, sizeof(buf2), NULL, 0, NI_NUMERICHOST|NI_NUMERICSERV); n = snprintf(buffer, ADDRESS_STR_MAX, "%s [%s]:%d", af_to_str(a.addr6.sin6_family), buf2, ntohs(a.addr6.sin6_port)); assert(n > 0); assert(n < ADDRESS_STR_MAX); /* there should be no need to truncate */ } else { sprintf(buffer, "[unknown af=%d, len=%d]", a.addr.sa_family, addr_len); } } static const char *get_address(struct context_def *ctx, struct field_def *field, struct nlattr *nla) { static char buffer[ADDRESS_STR_MAX]; sprint_address(buffer, nla_data(nla), nla_len(nla)); return buffer; } static void resolv6(const char *name, struct sockaddr_in6 *addr) { struct addrinfo hints, *res, *tmp; int err; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET6; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; err = getaddrinfo(name, 0, &hints, &res); if (err) { fprintf(stderr, "getaddrinfo %s: %s\n", name, gai_strerror(err)); exit(20); } /* Yes, it is a list. We use only the first result. The loop is only * there to document that we know it is a list */ for (tmp = res; tmp; tmp = tmp->ai_next) { memcpy(addr, tmp->ai_addr, sizeof(*addr)); break; } freeaddrinfo(res); if (0) { /* debug output */ char ip[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, &addr->sin6_addr, ip, sizeof(ip)); fprintf(stderr, "%s -> %02x %04x %08x %s %08x\n", name, addr->sin6_family, addr->sin6_port, addr->sin6_flowinfo, ip, addr->sin6_scope_id); } } static unsigned long resolv(const char* name) { unsigned long retval; if((retval = inet_addr(name)) == INADDR_NONE ) { struct hostent *he; he = gethostbyname(name); if (!he) { fprintf(stderr, "can not resolve the hostname: gethostbyname(%s): %s\n", name, hstrerror(h_errno)); exit(20); } retval = ((struct in_addr *)(he->h_addr_list[0]))->s_addr; } return retval; } static void split_ipv6_addr(char **address, int *port) { /* ipv6:[fe80::0234:5678:9abc:def1]:8000; */ char *b = strrchr(*address,']'); if (address[0][0] != '[' || b == NULL || (b[1] != ':' && b[1] != '\0')) { fprintf(stderr, "unexpected ipv6 format: %s\n", *address); exit(20); } *b = 0; *address += 1; /* skip '[' */ if (b[1] == ':') *port = m_strtoll(b+2,1); /* b+2: "]:" */ else *port = 7788; /* will we ever get rid of that default port? */ } static void split_address(int *af, char** address, int* port) { static struct { char* text; int af; } afs[] = { { "ipv4:", AF_INET }, { "ipv6:", AF_INET6 }, { "sdp:", AF_INET_SDP }, { "ssocks:", -1 }, }; unsigned int i; char *b; *af=AF_INET; for (i=0; inla_type, value); return true; } static int address_usage(struct field_def *field, char *str, int size) { return snprintf(str, size,"[--%s=[{af}:]{local_addr}[:{port}]]", field->name); } static void address_describe_xml(struct field_def *field) { printf("\t\n", field->name); } /* ============================================================================================== */ #define ENUM(f, d) \ .nla_type = T_ ## f, \ .is_default = enum_is_default, \ .is_equal = enum_is_equal, \ .get = get_enum, \ .put = put_enum, \ .usage = enum_usage, \ .describe_xml = enum_describe_xml, \ .u = { .e = { \ .map = f ## _map, \ .size = ARRAY_SIZE(f ## _map), \ .def = DRBD_ ## d ## _DEF } } #define ENUM_NOCASE(f, d) \ .nla_type = T_ ## f, \ .is_default = enum_is_default_nocase, \ .is_equal = enum_is_equal_nocase, \ .get = get_enum, \ .put = put_enum_nocase, \ .usage = enum_usage, \ .describe_xml = enum_describe_xml, \ .u = { .e = { \ .map = f ## _map, \ .size = ARRAY_SIZE(f ## _map), \ .def = DRBD_ ## d ## _DEF } } #define NUMERIC(f, d) \ .nla_type = T_ ## f, \ .is_default = numeric_is_default, \ .is_equal = numeric_is_equal, \ .get = get_numeric, \ .put = put_numeric, \ .usage = numeric_usage, \ .describe_xml = numeric_describe_xml, \ .u = { .n = { \ .min = DRBD_ ## d ## _MIN, \ .max = DRBD_ ## d ## _MAX, \ .def = DRBD_ ## d ## _DEF, \ .is_signed = F_ ## f ## _IS_SIGNED, \ .scale = DRBD_ ## d ## _SCALE } } #define BOOLEAN(f, d) \ .nla_type = T_ ## f, \ .is_default = boolean_is_default, \ .is_equal = boolean_is_equal, \ .get = get_boolean, \ .put = put_boolean, \ .usage = boolean_usage, \ .describe_xml = boolean_describe_xml, \ .u = { .b = { \ .def = DRBD_ ## d ## _DEF } }, \ .argument_is_optional = true #define FLAG(f) \ .nla_type = T_ ## f, \ .is_default = boolean_is_default, \ .is_equal = boolean_is_equal, \ .get = get_boolean, \ .put = put_flag, \ .usage = boolean_usage, \ .describe_xml = boolean_describe_xml, \ .u = { .b = { \ .def = false } }, \ .argument_is_optional = true #define STRING(f) \ .nla_type = T_ ## f, \ .is_default = string_is_default, \ .is_equal = string_is_equal, \ .get = get_string, \ .put = put_string, \ .usage = string_usage, \ .describe_xml = string_describe_xml, \ .needs_double_quoting = true #define ADDRESS(f) \ .nla_type = T_ ## f, \ .is_default = address_is_default, \ .is_equal = address_is_equal, \ .get = get_address, \ .put = put_address, \ .usage = address_usage, \ .describe_xml = address_describe_xml, \ .needs_double_quoting = false /* ============================================================================================== */ const char *wire_protocol_map[] = { [DRBD_PROT_A] = "A", [DRBD_PROT_B] = "B", [DRBD_PROT_C] = "C", }; const char *on_io_error_map[] = { [EP_PASS_ON] = "pass_on", [EP_CALL_HELPER] = "call-local-io-error", [EP_DETACH] = "detach", }; const char *fencing_map[] = { [FP_DONT_CARE] = "dont-care", [FP_RESOURCE] = "resource-only", [FP_STONITH] = "resource-and-stonith", }; const char *after_sb_0p_map[] = { [ASB_DISCONNECT] = "disconnect", [ASB_DISCARD_YOUNGER_PRI] = "discard-younger-primary", [ASB_DISCARD_OLDER_PRI] = "discard-older-primary", [ASB_DISCARD_ZERO_CHG] = "discard-zero-changes", [ASB_DISCARD_LEAST_CHG] = "discard-least-changes", [ASB_DISCARD_LOCAL] = "discard-local", [ASB_DISCARD_REMOTE] = "discard-remote", }; const char *after_sb_1p_map[] = { [ASB_DISCONNECT] = "disconnect", [ASB_CONSENSUS] = "consensus", [ASB_VIOLENTLY] = "violently-as0p", [ASB_DISCARD_SECONDARY] = "discard-secondary", [ASB_CALL_HELPER] = "call-pri-lost-after-sb", }; const char *after_sb_2p_map[] = { [ASB_DISCONNECT] = "disconnect", [ASB_VIOLENTLY] = "violently-as0p", [ASB_CALL_HELPER] = "call-pri-lost-after-sb", }; const char *rr_conflict_map[] = { [ASB_DISCONNECT] = "disconnect", [ASB_VIOLENTLY] = "violently", [ASB_CALL_HELPER] = "call-pri-lost", }; const char *on_no_data_map[] = { [OND_IO_ERROR] = "io-error", [OND_SUSPEND_IO] = "suspend-io", }; const char *on_congestion_map[] = { [OC_BLOCK] = "block", [OC_PULL_AHEAD] = "pull-ahead", [OC_DISCONNECT] = "disconnect", }; const char *read_balancing_map[] = { [RB_PREFER_LOCAL] = "prefer-local", [RB_PREFER_REMOTE] = "prefer-remote", [RB_ROUND_ROBIN] = "round-robin", [RB_LEAST_PENDING] = "least-pending", [RB_CONGESTED_REMOTE] = "when-congested-remote", [RB_32K_STRIPING] = "32K-striping", [RB_64K_STRIPING] = "64K-striping", [RB_128K_STRIPING] = "128K-striping", [RB_256K_STRIPING] = "256K-striping", [RB_512K_STRIPING] = "512K-striping", [RB_1M_STRIPING] = "1M-striping" }; #define CHANGEABLE_DISK_OPTIONS \ { "on-io-error", ENUM(on_io_error, ON_IO_ERROR) }, \ { "fencing", ENUM(fencing, FENCING) }, \ { "disk-barrier", BOOLEAN(disk_barrier, DISK_BARRIER) }, \ { "disk-flushes", BOOLEAN(disk_flushes, DISK_FLUSHES) }, \ { "disk-drain", BOOLEAN(disk_drain, DISK_DRAIN) }, \ { "md-flushes", BOOLEAN(md_flushes, MD_FLUSHES) }, \ { "resync-rate", NUMERIC(resync_rate, RESYNC_RATE), \ .unit = "bytes/second" }, \ { "resync-after", NUMERIC(resync_after, MINOR_NUMBER) }, \ { "al-extents", NUMERIC(al_extents, AL_EXTENTS) }, \ { "al-updates", BOOLEAN(al_updates, AL_UPDATES) }, \ { "discard-zeroes-if-aligned", \ BOOLEAN(discard_zeroes_if_aligned, DISCARD_ZEROES_IF_ALIGNED) }, \ { "c-plan-ahead", NUMERIC(c_plan_ahead, C_PLAN_AHEAD), \ .unit = "1/10 seconds" }, \ { "c-delay-target", NUMERIC(c_delay_target, C_DELAY_TARGET), \ .unit = "1/10 seconds" }, \ { "c-fill-target", NUMERIC(c_fill_target, C_FILL_TARGET), \ .unit = "bytes" }, \ { "c-max-rate", NUMERIC(c_max_rate, C_MAX_RATE), \ .unit = "bytes/second" }, \ { "c-min-rate", NUMERIC(c_min_rate, C_MIN_RATE), \ .unit = "bytes/second" }, \ { "disk-timeout", NUMERIC(disk_timeout, DISK_TIMEOUT), \ .unit = "1/10 seconds" }, \ { "read-balancing", ENUM(read_balancing, READ_BALANCING) }, \ { "rs-discard-granularity", \ NUMERIC(rs_discard_granularity, RS_DISCARD_GRANULARITY) } \ #define CHANGEABLE_NET_OPTIONS \ { "protocol", ENUM_NOCASE(wire_protocol, PROTOCOL) }, \ { "timeout", NUMERIC(timeout, TIMEOUT), \ .unit = "1/10 seconds" }, \ { "max-epoch-size", NUMERIC(max_epoch_size, MAX_EPOCH_SIZE) }, \ { "max-buffers", NUMERIC(max_buffers, MAX_BUFFERS) }, \ { "unplug-watermark", NUMERIC(unplug_watermark, UNPLUG_WATERMARK) }, \ { "connect-int", NUMERIC(connect_int, CONNECT_INT), \ .unit = "seconds" }, \ { "ping-int", NUMERIC(ping_int, PING_INT), \ .unit = "seconds" }, \ { "sndbuf-size", NUMERIC(sndbuf_size, SNDBUF_SIZE), \ .unit = "bytes" }, \ { "rcvbuf-size", NUMERIC(rcvbuf_size, RCVBUF_SIZE), \ .unit = "bytes" }, \ { "ko-count", NUMERIC(ko_count, KO_COUNT) }, \ { "allow-two-primaries", BOOLEAN(two_primaries, ALLOW_TWO_PRIMARIES) }, \ { "cram-hmac-alg", STRING(cram_hmac_alg) }, \ { "shared-secret", STRING(shared_secret) }, \ { "after-sb-0pri", ENUM(after_sb_0p, AFTER_SB_0P) }, \ { "after-sb-1pri", ENUM(after_sb_1p, AFTER_SB_1P) }, \ { "after-sb-2pri", ENUM(after_sb_2p, AFTER_SB_2P) }, \ { "always-asbp", BOOLEAN(always_asbp, ALWAYS_ASBP) }, \ { "rr-conflict", ENUM(rr_conflict, RR_CONFLICT) }, \ { "ping-timeout", NUMERIC(ping_timeo, PING_TIMEO), \ .unit = "1/10 seconds" }, \ { "data-integrity-alg", STRING(integrity_alg) }, \ { "tcp-cork", BOOLEAN(tcp_cork, TCP_CORK) }, \ { "on-congestion", ENUM(on_congestion, ON_CONGESTION) }, \ { "congestion-fill", NUMERIC(cong_fill, CONG_FILL), \ .unit = "bytes" }, \ { "congestion-extents", NUMERIC(cong_extents, CONG_EXTENTS) }, \ { "csums-alg", STRING(csums_alg) }, \ { "csums-after-crash-only", BOOLEAN(csums_after_crash_only, \ CSUMS_AFTER_CRASH_ONLY) }, \ { "verify-alg", STRING(verify_alg) }, \ { "use-rle", BOOLEAN(use_rle, USE_RLE) }, \ { "socket-check-timeout", NUMERIC(sock_check_timeo, SOCKET_CHECK_TIMEO) } struct context_def disk_options_ctx = { NLA_POLICY(disk_conf), .fields = { CHANGEABLE_DISK_OPTIONS, { } }, }; struct context_def net_options_ctx = { NLA_POLICY(net_conf), .fields = { CHANGEABLE_NET_OPTIONS, { } }, }; struct context_def primary_cmd_ctx = { NLA_POLICY(set_role_parms), .fields = { { "force", FLAG(assume_uptodate) }, { } }, }; struct context_def attach_cmd_ctx = { NLA_POLICY(disk_conf), .fields = { { "size", NUMERIC(disk_size, DISK_SIZE), .unit = "bytes" }, { "max-bio-bvecs", NUMERIC(max_bio_bvecs, MAX_BIO_BVECS) }, CHANGEABLE_DISK_OPTIONS, /* { "*", STRING(backing_dev) }, */ /* { "*", STRING(meta_dev) }, */ /* { "*", NUMERIC(meta_dev_idx, MINOR_NUMBER) }, */ { } }, }; struct context_def detach_cmd_ctx = { NLA_POLICY(detach_parms), .fields = { { "force", FLAG(force_detach) }, { } }, }; struct context_def connect_cmd_ctx = { NLA_POLICY(net_conf), .fields = { { "tentative", FLAG(tentative) }, { "discard-my-data", FLAG(discard_my_data) }, { "alternate-address", ADDRESS(my_addr2) }, { "alternate-peer-address", ADDRESS(peer_addr2) }, CHANGEABLE_NET_OPTIONS, { } }, }; struct context_def disconnect_cmd_ctx = { NLA_POLICY(disconnect_parms), .fields = { { "force", FLAG(force_disconnect) }, { } }, }; struct context_def resize_cmd_ctx = { NLA_POLICY(resize_parms), .fields = { { "size", NUMERIC(resize_size, DISK_SIZE), .unit = "bytes" }, { "assume-peer-has-space", FLAG(resize_force) }, { "assume-clean", FLAG(no_resync) }, { "al-stripes", NUMERIC(al_stripes, AL_STRIPES) }, { "al-stripe-size-kB", NUMERIC(al_stripe_size, AL_STRIPE_SIZE) }, { } }, }; struct context_def resource_options_cmd_ctx = { NLA_POLICY(res_opts), .fields = { { "cpu-mask", STRING(cpu_mask) }, { "on-no-data-accessible", ENUM(on_no_data, ON_NO_DATA) }, { } }, }; struct context_def new_current_uuid_cmd_ctx = { NLA_POLICY(new_c_uuid_parms), .fields = { { "clear-bitmap", FLAG(clear_bm) }, { } }, }; struct context_def verify_cmd_ctx = { NLA_POLICY(start_ov_parms), .fields = { { "start", NUMERIC(ov_start_sector, DISK_SIZE), .unit = "bytes" }, { "stop", NUMERIC(ov_stop_sector, DISK_SIZE), .unit = "bytes" }, { } }, }; struct context_def new_minor_cmd_ctx = { NLA_POLICY(drbd_cfg_context), .fields = { /* { "*", STRING(ctx_resource_name) }, */ /* { "*", NUMERIC(ctx_volume, >= 0) }, */ /* { "*", BINARY(ctx_my_addr) }, */ /* { "*", BINARY(ctx_peer_addr) }, */ { } }, }; drbd-utils-8.9.6/user/v84/drbd_strings.h0000644000175000017500000000045412466702074017752 0ustar apoikosapoikos#ifndef __DRBD_STRINGS_H #define __DRBD_STRINGS_H extern const char *drbd_conn_str(enum drbd_conns); extern const char *drbd_role_str(enum drbd_role); extern const char *drbd_disk_str(enum drbd_disk_state); extern const char *drbd_set_st_err_str(enum drbd_state_rv); #endif /* __DRBD_STRINGS_H */ drbd-utils-8.9.6/user/v84/drbdsetup_colors.c0000644000175000017500000000703212511151661020624 0ustar apoikosapoikos#include #include "drbdtool_common.h" #include "drbdsetup_colors.h" enum when_color opt_color; enum colors { COLOR_TRANSITIONAL, /* default */ COLOR_NORMAL, COLOR_PRIMARY, COLOR_GOOD, COLOR_BAD, }; #define LC "\033[" #define RC "m" const char *local_color_codes[] = { [COLOR_TRANSITIONAL] = LC "1" RC, /* bold */ [COLOR_NORMAL] = NULL, [COLOR_PRIMARY] = LC "1;36" RC, /* cyan */ [COLOR_GOOD] = LC "1;32" RC, /* green */ [COLOR_BAD] = LC "1;31" RC, /* red */ }; const char *peer_color_codes[] = { [COLOR_TRANSITIONAL] = NULL, [COLOR_NORMAL] = NULL, [COLOR_PRIMARY] = LC "36" RC, /* cyan */ [COLOR_GOOD] = LC "32" RC, /* green */ [COLOR_BAD] = LC "31" RC, /* red */ }; int role_colors[] = { [R_PRIMARY] = COLOR_PRIMARY, [R_SECONDARY] = COLOR_NORMAL, [R_UNKNOWN] = COLOR_TRANSITIONAL, }; int cstate_colors[] = { [C_STANDALONE] = COLOR_BAD, [C_WF_CONNECTION] = COLOR_BAD, [C_WF_REPORT_PARAMS] = COLOR_NORMAL, }; int repl_state_colors[] = { [C_WF_REPORT_PARAMS] = COLOR_TRANSITIONAL, [C_CONNECTED] = COLOR_NORMAL, [C_SYNC_SOURCE] = COLOR_BAD, [C_SYNC_TARGET] = COLOR_BAD, [C_VERIFY_S] = COLOR_NORMAL, [C_VERIFY_T] = COLOR_NORMAL, [C_PAUSED_SYNC_S] = COLOR_NORMAL, [C_PAUSED_SYNC_T] = COLOR_BAD, [C_AHEAD] = COLOR_NORMAL, [C_BEHIND] = COLOR_TRANSITIONAL, }; int disk_state_colors[] = { [D_DISKLESS] = COLOR_BAD, [D_INCONSISTENT] = COLOR_BAD, [D_OUTDATED] = COLOR_BAD, [D_CONSISTENT] = COLOR_TRANSITIONAL, [D_UP_TO_DATE] = COLOR_GOOD, }; const char *stop_color_code(void) { return LC "0" RC; } static const char *color_code(int index, int *array, int size, bool start, bool local) { const char **color_codes = local ? local_color_codes : peer_color_codes; int i; if (opt_color == AUTO_COLOR) opt_color = isatty(fileno(stdout)) ? ALWAYS_COLOR : NEVER_COLOR; if (opt_color == NEVER_COLOR) return ""; if (index < size) i = array[index]; else i = COLOR_TRANSITIONAL; if (color_codes[i]) return start ? color_codes[i] : stop_color_code(); else return ""; } const char *role_color_start(enum drbd_role role, bool local) { return color_code(role, role_colors, ARRAY_SIZE(role_colors), true, local); } const char *role_color_stop(enum drbd_role role, bool local) { return color_code(role, role_colors, ARRAY_SIZE(role_colors), false, local); } const char *cstate_color_start(enum drbd_conns cstate) { return color_code(cstate, cstate_colors, ARRAY_SIZE(cstate_colors), true, true); } const char *cstate_color_stop(enum drbd_conns cstate) { return color_code(cstate, cstate_colors, ARRAY_SIZE(cstate_colors), false, true); } static bool is_local_repl_state(enum drbd_conns repl_state) { switch(repl_state) { case C_SYNC_TARGET: case C_PAUSED_SYNC_T: case C_BEHIND: return true; default: return false; } } const char *repl_state_color_start(enum drbd_conns repl_state) { return color_code(repl_state, repl_state_colors, ARRAY_SIZE(repl_state_colors), true, is_local_repl_state(repl_state)); } const char *repl_state_color_stop(enum drbd_conns repl_state) { return color_code(repl_state, repl_state_colors, ARRAY_SIZE(repl_state_colors), false, is_local_repl_state(repl_state)); } const char *disk_state_color_start(enum drbd_disk_state disk_state, bool local) { return color_code(disk_state, disk_state_colors, ARRAY_SIZE(disk_state_colors), true, local); } const char *disk_state_color_stop(enum drbd_disk_state disk_state, bool local) { return color_code(disk_state, disk_state_colors, ARRAY_SIZE(disk_state_colors), false, local); } drbd-utils-8.9.6/user/v84/drbdsetup_colors.h0000644000175000017500000000135712466702074020646 0ustar apoikosapoikos#ifndef DRBDSETUP_COLORS_H #define DRBDSETUP_COLORS_H #include enum when_color { NEVER_COLOR = -1, AUTO_COLOR = 0, ALWAYS_COLOR = 1 }; extern enum when_color opt_color; extern const char *stop_color_code(void); extern const char *role_color_start(enum drbd_role, bool); extern const char *role_color_stop(enum drbd_role, bool); extern const char *cstate_color_start(enum drbd_conns); extern const char *cstate_color_stop(enum drbd_conns); extern const char *repl_state_color_start(enum drbd_conns); extern const char *repl_state_color_stop(enum drbd_conns); extern const char *disk_state_color_start(enum drbd_disk_state, bool); extern const char *disk_state_color_stop(enum drbd_disk_state, bool); #endif /* DRBDSETUP_COLORS_H */ drbd-utils-8.9.6/user/v83/0000755000175000017500000000000012654475367015124 5ustar apoikosapoikosdrbd-utils-8.9.6/user/v83/drbdtool_common.h0000644000175000017500000000164112466702074020445 0ustar apoikosapoikos#ifndef DRBDTOOL_COMMON_H #define DRBDTOOL_COMMON_H #include "drbd_endian.h" #include #include #include #include #include "shared_tool.h" #define LANANA_DRBD_MAJOR 147 /* we should get this into linux/major.h */ #ifndef DRBD_MAJOR #define DRBD_MAJOR LANANA_DRBD_MAJOR #elif (DRBD_MAJOR != LANANA_DRBD_MAJOR) # error "FIXME unexpected DRBD_MAJOR" #endif #ifndef __packed #define __packed __attribute__((packed)) #endif #ifndef ARRAY_SIZE #define ARRAY_SIZE(A) (sizeof(A)/sizeof(A[0])) #endif struct option; extern void dt_release_lockfile(int drbd_fd); extern void dt_print_uuids(const uint64_t* uuid, unsigned int flags); extern void dt_pretty_print_uuids(const uint64_t* uuid, unsigned int flags); extern int fget_token(char *s, int size, FILE* stream); extern int force; /* global option to force implicit confirmation */ extern int confirmed(const char *text); #endif drbd-utils-8.9.6/user/v83/drbd_strings.c0000644000175000017500000001025312466702074017742 0ustar apoikosapoikos/* drbd.h This file is part of DRBD by Philipp Reisner and Lars Ellenberg. Copyright (C) 2003-2008, LINBIT Information Technologies GmbH. Copyright (C) 2003-2008, Philipp Reisner . Copyright (C) 2003-2008, Lars Ellenberg . drbd is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. drbd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with drbd; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include static const char *drbd_conn_s_names[] = { [C_STANDALONE] = "StandAlone", [C_DISCONNECTING] = "Disconnecting", [C_UNCONNECTED] = "Unconnected", [C_TIMEOUT] = "Timeout", [C_BROKEN_PIPE] = "BrokenPipe", [C_NETWORK_FAILURE] = "NetworkFailure", [C_PROTOCOL_ERROR] = "ProtocolError", [C_WF_CONNECTION] = "WFConnection", [C_WF_REPORT_PARAMS] = "WFReportParams", [C_TEAR_DOWN] = "TearDown", [C_CONNECTED] = "Connected", [C_STARTING_SYNC_S] = "StartingSyncS", [C_STARTING_SYNC_T] = "StartingSyncT", [C_WF_BITMAP_S] = "WFBitMapS", [C_WF_BITMAP_T] = "WFBitMapT", [C_WF_SYNC_UUID] = "WFSyncUUID", [C_SYNC_SOURCE] = "SyncSource", [C_SYNC_TARGET] = "SyncTarget", [C_PAUSED_SYNC_S] = "PausedSyncS", [C_PAUSED_SYNC_T] = "PausedSyncT", [C_VERIFY_S] = "VerifyS", [C_VERIFY_T] = "VerifyT", [C_AHEAD] = "Ahead", [C_BEHIND] = "Behind", }; static const char *drbd_role_s_names[] = { [R_PRIMARY] = "Primary", [R_SECONDARY] = "Secondary", [R_UNKNOWN] = "Unknown" }; static const char *drbd_disk_s_names[] = { [D_DISKLESS] = "Diskless", [D_ATTACHING] = "Attaching", [D_FAILED] = "Failed", [D_NEGOTIATING] = "Negotiating", [D_INCONSISTENT] = "Inconsistent", [D_OUTDATED] = "Outdated", [D_UNKNOWN] = "DUnknown", [D_CONSISTENT] = "Consistent", [D_UP_TO_DATE] = "UpToDate", }; static const char *drbd_state_sw_errors[] = { [-SS_TWO_PRIMARIES] = "Multiple primaries not allowed by config", [-SS_NO_UP_TO_DATE_DISK] = "Need access to UpToDate data", [-SS_NO_LOCAL_DISK] = "Can not resync without local disk", [-SS_NO_REMOTE_DISK] = "Can not resync without remote disk", [-SS_CONNECTED_OUTDATES] = "Refusing to be Outdated while Connected", [-SS_PRIMARY_NOP] = "Refusing to be Primary while peer is not outdated", [-SS_RESYNC_RUNNING] = "Can not start OV/resync since it is already active", [-SS_ALREADY_STANDALONE] = "Can not disconnect a StandAlone device", [-SS_CW_FAILED_BY_PEER] = "State change was refused by peer node", [-SS_IS_DISKLESS] = "Device is diskless, the requested operation requires a disk", [-SS_DEVICE_IN_USE] = "Device is held open by someone", [-SS_NO_NET_CONFIG] = "Have no net/connection configuration", [-SS_NO_VERIFY_ALG] = "Need a verify algorithm to start online verify", [-SS_NEED_CONNECTION] = "Need a connection to start verify or resync", [-SS_NOT_SUPPORTED] = "Peer does not support protocol", [-SS_LOWER_THAN_OUTDATED] = "Disk state is lower than outdated", [-SS_IN_TRANSIENT_STATE] = "In transient state, retry after next state change", [-SS_CONCURRENT_ST_CHG] = "Concurrent state changes detected and aborted", }; const char *drbd_conn_str(enum drbd_conns s) { /* enums are unsigned... */ return s > C_BEHIND ? "TOO_LARGE" : drbd_conn_s_names[s]; } const char *drbd_role_str(enum drbd_role s) { return s > R_SECONDARY ? "TOO_LARGE" : drbd_role_s_names[s]; } const char *drbd_disk_str(enum drbd_disk_state s) { return s > D_UP_TO_DATE ? "TOO_LARGE" : drbd_disk_s_names[s]; } const char *drbd_set_st_err_str(enum drbd_state_rv err) { return err <= SS_AFTER_LAST_ERROR ? "TOO_SMALL" : err > SS_TWO_PRIMARIES ? "TOO_LARGE" : drbd_state_sw_errors[-err]; } drbd-utils-8.9.6/user/v83/drbdtool_common.c0000644000175000017500000000507712466702074020447 0ustar apoikosapoikos#define _GNU_SOURCE #define _XOPEN_SOURCE 600 #define _FILE_OFFSET_BITS 64 #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* for BLKGETSIZE64 */ #include #include "drbdtool_common.h" #include "config.h" int force = 0; int confirmed(const char *text) { const char yes[] = "yes"; const ssize_t N = sizeof(yes); char *answer = NULL; size_t n = 0; int ok; printf("\n%s\n", text); if (force) { printf("*** confirmation forced via --force option ***\n"); ok = 1; } else { printf("[need to type '%s' to confirm] ", yes); ok = getline(&answer,&n,stdin) == N && strncmp(answer,yes,N-1) == 0; if (answer) free(answer); printf("\n"); } return ok; } /* input size is expected to be in KB */ void dt_pretty_print_uuids(const uint64_t* uuid, unsigned int flags) { printf( "\n" " +--< Current data generation UUID >-\n" " | +--< Bitmap's base data generation UUID >-\n" " | | +--< younger history UUID >-\n" " | | | +-< older history >-\n" " V V V V\n"); dt_print_uuids(uuid, flags); printf( " ^ ^ ^ ^ ^ ^ ^\n" " -< Data consistency flag >--+ | | | | | |\n" " -< Data was/is currently up-to-date >--+ | | | | |\n" " -< Node was/is currently primary >--+ | | | |\n" " -< Node was/is currently connected >--+ | | |\n" " -< Node was in the progress of setting all bits in the bitmap >--+ | |\n" " -< The peer's disk was out-dated or inconsistent >--+ |\n" " -< This node was a crashed primary, and has not seen its peer since >--+\n" "\n"); printf("flags:%s %s, %s, %s%s%s\n", (flags & MDF_CRASHED_PRIMARY) ? " crashed" : "", (flags & MDF_PRIMARY_IND) ? "Primary" : "Secondary", (flags & MDF_CONNECTED_IND) ? "Connected" : "StandAlone", (flags & MDF_CONSISTENT) ? ((flags & MDF_WAS_UP_TO_DATE) ? "UpToDate" : "Outdated") : "Inconsistent", (flags & MDF_FULL_SYNC) ? ", need full sync" : "", (flags & MDF_PEER_OUT_DATED) ? ", peer Outdated" : ""); } drbd-utils-8.9.6/user/v83/drbdsetup.c0000644000175000017500000023157612477305373017272 0ustar apoikosapoikos/* drbdsetup.c This file is part of DRBD by Philipp Reisner and Lars Ellenberg. Copyright (C) 2001-2008, LINBIT Information Technologies GmbH. Copyright (C) 1999-2008, Philipp Reisner . Copyright (C) 2002-2008, Lars Ellenberg . drbd is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. drbd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with drbd; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define __bitwise /* Build-workaround for broken RHEL4 kernels (2.6.9_78.0.1) */ #include #include #include #include #include #include #include "unaligned.h" #include "drbdtool_common.h" #ifndef __CONNECTOR_H #error "You need to set KDIR while building drbdsetup." #endif #ifndef AF_INET_SDP #define AF_INET_SDP 27 #define PF_INET_SDP AF_INET_SDP #endif enum usage_type { BRIEF, FULL, XML, }; struct drbd_tag_list { struct nlmsghdr *nl_header; struct cn_msg *cn_header; struct drbd_nl_cfg_req* drbd_p_header; unsigned short *tag_list_start; unsigned short *tag_list_cpos; int tag_size; }; struct drbd_argument { const char* name; const enum drbd_tags tag; int (*convert_function)(struct drbd_argument *, struct drbd_tag_list *, char *); }; struct drbd_option { const char* name; const char short_name; const enum drbd_tags tag; int (*convert_function)(struct drbd_option *, struct drbd_tag_list *, char *); void (*show_function)(struct drbd_option *,unsigned short*); int (*usage_function)(struct drbd_option *, char*, int); void (*xml_function)(struct drbd_option *); union { struct { const long long min; const long long max; const long long def; const unsigned char unit_prefix; const char* unit; } numeric_param; // for conv_numeric struct { const char** handler_names; const int number_of_handlers; const int def; } handler_param; // conv_handler }; }; struct drbd_cmd { const char* cmd; const int packet_id; int (*function)(struct drbd_cmd *, unsigned, int, char **); void (*usage)(struct drbd_cmd *, enum usage_type); union { struct { struct drbd_argument *args; struct drbd_option *options; } cp; // for generic_config_cmd, config_usage struct { int (*show_function)(struct drbd_cmd *, unsigned, unsigned short* ); } gp; // for generic_get_cmd, get_usage struct { struct option *options; int (*proc_event)(unsigned int, int, struct drbd_nl_cfg_reply *); } ep; // for events_cmd, events_usage }; }; // Connector functions #define NL_TIME (COMM_TIMEOUT*1000) static int open_cn(); static int send_cn(int sk_nl, struct nlmsghdr* nl_hdr, int size); static int receive_cn(int sk_nl, struct nlmsghdr* nl_hdr, int size, int timeout_ms); static int call_drbd(int sk_nl, struct drbd_tag_list *tl, struct nlmsghdr* nl_hdr, int size, int timeout_ms); static void close_cn(int sk_nl); // other functions static int get_af_ssocks(int warn); static void print_command_usage(int i, const char *addinfo, enum usage_type); // command functions static int generic_config_cmd(struct drbd_cmd *cm, unsigned minor, int argc, char **argv); static int down_cmd(struct drbd_cmd *cm, unsigned minor, int argc, char **argv); static int generic_get_cmd(struct drbd_cmd *cm, unsigned minor, int argc, char **argv); static int events_cmd(struct drbd_cmd *cm, unsigned minor, int argc,char **argv); // usage functions static void config_usage(struct drbd_cmd *cm, enum usage_type); static void get_usage(struct drbd_cmd *cm, enum usage_type); static void events_usage(struct drbd_cmd *cm, enum usage_type); // sub usage functions for config_usage static int numeric_opt_usage(struct drbd_option *option, char* str, int strlen); static int handler_opt_usage(struct drbd_option *option, char* str, int strlen); static int bit_opt_usage(struct drbd_option *option, char* str, int strlen); static int string_opt_usage(struct drbd_option *option, char* str, int strlen); // sub usage function for config_usage as xml static void numeric_opt_xml(struct drbd_option *option); static void handler_opt_xml(struct drbd_option *option); static void bit_opt_xml(struct drbd_option *option); static void string_opt_xml(struct drbd_option *option); // sub commands for generic_get_cmd static int show_scmd(struct drbd_cmd *cm, unsigned minor, unsigned short *rtl); static int role_scmd(struct drbd_cmd *cm, unsigned minor, unsigned short *rtl); static int status_xml_scmd(struct drbd_cmd *cm, unsigned minor, unsigned short *rtl); static int sh_status_scmd(struct drbd_cmd *cm, unsigned minor, unsigned short *rtl); static int cstate_scmd(struct drbd_cmd *cm, unsigned minor, unsigned short *rtl); static int dstate_scmd(struct drbd_cmd *cm, unsigned minor, unsigned short *rtl); static int uuids_scmd(struct drbd_cmd *cm, unsigned minor, unsigned short *rtl); static int lk_bdev_scmd(struct drbd_cmd *cm, unsigned minor, unsigned short *rtl); // convert functions for arguments static int conv_block_dev(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg); static int conv_md_idx(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg); static int conv_address(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg); static int conv_protocol(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg); // convert functions for options static int conv_numeric(struct drbd_option *od, struct drbd_tag_list *tl, char* arg); static int conv_sndbuf(struct drbd_option *od, struct drbd_tag_list *tl, char* arg); static int conv_handler(struct drbd_option *od, struct drbd_tag_list *tl, char* arg); static int conv_bit(struct drbd_option *od, struct drbd_tag_list *tl, char* arg); static int conv_string(struct drbd_option *od, struct drbd_tag_list *tl, char* arg); // show functions for options (used by show_scmd) static void show_numeric(struct drbd_option *od, unsigned short* tp); static void show_handler(struct drbd_option *od, unsigned short* tp); static void show_bit(struct drbd_option *od, unsigned short* tp); static void show_string(struct drbd_option *od, unsigned short* tp); // sub functions for events_cmd static int print_broadcast_events(unsigned int seq, int, struct drbd_nl_cfg_reply *reply); static int w_connected_state(unsigned int seq, int, struct drbd_nl_cfg_reply *reply); static int w_synced_state(unsigned int seq, int, struct drbd_nl_cfg_reply *reply); const char *on_error[] = { [EP_PASS_ON] = "pass_on", [EP_CALL_HELPER] = "call-local-io-error", [EP_DETACH] = "detach", }; const char *fencing_n[] = { [FP_DONT_CARE] = "dont-care", [FP_RESOURCE] = "resource-only", [FP_STONITH] = "resource-and-stonith", }; const char *asb0p_n[] = { [ASB_DISCONNECT] = "disconnect", [ASB_DISCARD_YOUNGER_PRI] = "discard-younger-primary", [ASB_DISCARD_OLDER_PRI] = "discard-older-primary", [ASB_DISCARD_ZERO_CHG] = "discard-zero-changes", [ASB_DISCARD_LEAST_CHG] = "discard-least-changes", [ASB_DISCARD_LOCAL] = "discard-local", [ASB_DISCARD_REMOTE] = "discard-remote" }; const char *asb1p_n[] = { [ASB_DISCONNECT] = "disconnect", [ASB_CONSENSUS] = "consensus", [ASB_VIOLENTLY] = "violently-as0p", [ASB_DISCARD_SECONDARY] = "discard-secondary", [ASB_CALL_HELPER] = "call-pri-lost-after-sb" }; const char *asb2p_n[] = { [ASB_DISCONNECT] = "disconnect", [ASB_VIOLENTLY] = "violently-as0p", [ASB_CALL_HELPER] = "call-pri-lost-after-sb" }; const char *rrcf_n[] = { [ASB_DISCONNECT] = "disconnect", [ASB_VIOLENTLY] = "violently", [ASB_CALL_HELPER] = "call-pri-lost" }; const char *on_no_data_n[] = { [OND_IO_ERROR] = "io-error", [OND_SUSPEND_IO] = "suspend-io" }; const char *on_congestion_n[] = { [OC_BLOCK] = "block", [OC_PULL_AHEAD] = "pull-ahead", [OC_DISCONNECT] = "disconnect" }; struct option wait_cmds_options[] = { { "wfc-timeout",required_argument, 0, 't' }, { "degr-wfc-timeout",required_argument,0,'d'}, { "outdated-wfc-timeout",required_argument,0,'o'}, { "wait-after-sb",no_argument,0,'w'}, { 0, 0, 0, 0 } }; #define EN(N,U,UN) \ conv_numeric, show_numeric, numeric_opt_usage, numeric_opt_xml, \ { .numeric_param = { DRBD_ ## N ## _MIN, DRBD_ ## N ## _MAX, \ DRBD_ ## N ## _DEF ,U,UN } } #define EN_sndbuf(N,U,UN) \ conv_sndbuf, show_numeric, numeric_opt_usage, numeric_opt_xml, \ { .numeric_param = { DRBD_ ## N ## _MIN, DRBD_ ## N ## _MAX, \ DRBD_ ## N ## _DEF ,U,UN } } #define EH(N,D) \ conv_handler, show_handler, handler_opt_usage, handler_opt_xml, \ { .handler_param = { N, ARRAY_SIZE(N), \ DRBD_ ## D ## _DEF } } #define EB conv_bit, show_bit, bit_opt_usage, bit_opt_xml, { } #define ES conv_string, show_string, string_opt_usage, string_opt_xml, { } #define CLOSE_OPTIONS { NULL,0,0,NULL,NULL,NULL, NULL, { } } #define F_CONFIG_CMD generic_config_cmd, config_usage #define F_GET_CMD generic_get_cmd, get_usage #define F_EVENTS_CMD events_cmd, events_usage struct drbd_cmd commands[] = { {"primary", P_primary, F_CONFIG_CMD, {{ NULL, (struct drbd_option[]) { { "overwrite-data-of-peer",'o',T_primary_force, EB }, /* legacy name */ { "force",'f', T_primary_force, EB }, CLOSE_OPTIONS }} }, }, {"secondary", P_secondary, F_CONFIG_CMD, {{NULL, NULL}} }, {"disk", P_disk_conf, F_CONFIG_CMD, {{ (struct drbd_argument[]) { { "lower_dev", T_backing_dev, conv_block_dev }, { "meta_data_dev", T_meta_dev, conv_block_dev }, { "meta_data_index", T_meta_dev_idx, conv_md_idx }, { NULL, 0, NULL}, }, (struct drbd_option[]) { { "size",'d', T_disk_size, EN(DISK_SIZE_SECT,'s',"bytes") }, { "on-io-error",'e', T_on_io_error, EH(on_error,ON_IO_ERROR) }, { "fencing",'f', T_fencing, EH(fencing_n,FENCING) }, { "use-bmbv",'b', T_use_bmbv, EB }, { "no-disk-barrier",'a',T_no_disk_barrier,EB }, { "no-disk-flushes",'i',T_no_disk_flush,EB }, { "no-disk-drain",'D', T_no_disk_drain,EB }, { "no-md-flushes",'m', T_no_md_flush, EB }, { "max-bio-bvecs",'s', T_max_bio_bvecs,EN(MAX_BIO_BVECS,1,NULL) }, { "disk-timeout",'t', T_disk_timeout, EN(DISK_TIMEOUT,1,"1/10 seconds") }, CLOSE_OPTIONS }} }, }, {"detach", P_detach, F_CONFIG_CMD, {{NULL, (struct drbd_option[]) { { "force",'f', T_detach_force, EB }, CLOSE_OPTIONS }} }, }, {"net", P_net_conf, F_CONFIG_CMD, {{ (struct drbd_argument[]) { { "[af:]local_addr[:port]",T_my_addr, conv_address }, { "[af:]remote_addr[:port]",T_peer_addr,conv_address }, { "protocol", T_wire_protocol,conv_protocol }, { NULL, 0, NULL}, }, (struct drbd_option[]) { { "timeout",'t', T_timeout, EN(TIMEOUT,1,"1/10 seconds") }, { "max-epoch-size",'e',T_max_epoch_size,EN(MAX_EPOCH_SIZE,1,NULL) }, { "max-buffers",'b', T_max_buffers, EN(MAX_BUFFERS,1,NULL) }, { "unplug-watermark",'u',T_unplug_watermark, EN(UNPLUG_WATERMARK,1,NULL) }, { "connect-int",'c', T_try_connect_int, EN(CONNECT_INT,1,"seconds") }, { "ping-int",'i', T_ping_int, EN(PING_INT,1,"seconds") }, { "sndbuf-size",'S', T_sndbuf_size, EN_sndbuf(SNDBUF_SIZE,1,"bytes") }, { "rcvbuf-size",'r', T_rcvbuf_size, EN_sndbuf(RCVBUF_SIZE,1,"bytes") }, { "ko-count",'k', T_ko_count, EN(KO_COUNT,1,NULL) }, { "allow-two-primaries",'m',T_two_primaries, EB }, { "cram-hmac-alg",'a', T_cram_hmac_alg, ES }, { "shared-secret",'x', T_shared_secret, ES }, { "after-sb-0pri",'A', T_after_sb_0p,EH(asb0p_n,AFTER_SB_0P) }, { "after-sb-1pri",'B', T_after_sb_1p,EH(asb1p_n,AFTER_SB_1P) }, { "after-sb-2pri",'C', T_after_sb_2p,EH(asb2p_n,AFTER_SB_2P) }, { "always-asbp",'P', T_always_asbp, EB }, { "rr-conflict",'R', T_rr_conflict,EH(rrcf_n,RR_CONFLICT) }, { "ping-timeout",'p', T_ping_timeo, EN(PING_TIMEO,1,"1/10 seconds") }, { "discard-my-data",'D', T_want_lose, EB }, { "data-integrity-alg",'d', T_integrity_alg, ES }, { "no-tcp-cork",'o', T_no_cork, EB }, { "dry-run",'n', T_dry_run, EB }, { "on-congestion", 'g', T_on_congestion, EH(on_congestion_n,ON_CONGESTION) }, { "congestion-fill", 'f', T_cong_fill, EN(CONG_FILL,'s',"byte") }, { "congestion-extents", 'h', T_cong_extents, EN(CONG_EXTENTS,1,NULL) }, CLOSE_OPTIONS }} }, }, {"disconnect", P_disconnect, F_CONFIG_CMD, {{NULL, (struct drbd_option[]) { { "force", 'F', T_force, EB }, CLOSE_OPTIONS }} }, }, {"resize", P_resize, F_CONFIG_CMD, {{ NULL, (struct drbd_option[]) { { "size",'s',T_resize_size, EN(DISK_SIZE_SECT,'s',"bytes") }, { "assume-peer-has-space",'f',T_resize_force, EB }, { "assume-clean", 'c', T_no_resync, EB }, CLOSE_OPTIONS }} }, }, {"syncer", P_syncer_conf, F_CONFIG_CMD, {{ NULL, (struct drbd_option[]) { { "rate",'r',T_rate, EN(RATE,'k',"bytes/second") }, { "after",'a',T_after, EN(AFTER,1,NULL) }, { "al-extents",'e',T_al_extents, EN(AL_EXTENTS,1,NULL) }, { "csums-alg", 'C',T_csums_alg, ES }, { "verify-alg", 'v',T_verify_alg, ES }, { "cpu-mask",'c',T_cpu_mask, ES }, { "use-rle",'R',T_use_rle, EB }, { "on-no-data-accessible",'n', T_on_no_data, EH(on_no_data_n,ON_NO_DATA) }, { "c-plan-ahead", 'p', T_c_plan_ahead, EN(C_PLAN_AHEAD,1,"1/10 seconds") }, { "c-delay-target", 'd', T_c_delay_target, EN(C_DELAY_TARGET,1,"1/10 seconds") }, { "c-fill-target", 's', T_c_fill_target, EN(C_FILL_TARGET,'s',"bytes") }, { "c-max-rate", 'M', T_c_max_rate, EN(C_MAX_RATE,'k',"bytes/second") }, { "c-min-rate", 'm', T_c_min_rate, EN(C_MIN_RATE,'k',"bytes/second") }, CLOSE_OPTIONS }} }, }, {"new-current-uuid", P_new_c_uuid, F_CONFIG_CMD, {{NULL, (struct drbd_option[]) { { "clear-bitmap",'c',T_clear_bm, EB }, CLOSE_OPTIONS }} }, }, {"invalidate", P_invalidate, F_CONFIG_CMD, {{ NULL, NULL }} }, {"invalidate-remote", P_invalidate_peer, F_CONFIG_CMD, {{NULL, NULL}} }, {"pause-sync", P_pause_sync, F_CONFIG_CMD, {{ NULL, NULL }} }, {"resume-sync", P_resume_sync, F_CONFIG_CMD, {{ NULL, NULL }} }, {"suspend-io", P_suspend_io, F_CONFIG_CMD, {{ NULL, NULL }} }, {"resume-io", P_resume_io, F_CONFIG_CMD, {{ NULL, NULL }} }, {"outdate", P_outdate, F_CONFIG_CMD, {{ NULL, NULL }} }, {"verify", P_start_ov, F_CONFIG_CMD, {{ NULL, (struct drbd_option[]) { { "start",'s',T_start_sector, EN(DISK_SIZE_SECT,'s',"bytes") }, { "stop",'S',T_stop_sector, EN(DISK_SIZE_SECT,'s',"bytes") }, CLOSE_OPTIONS }} }, }, {"down", 0, down_cmd, get_usage, { {NULL, NULL }} }, {"state", P_get_state, F_GET_CMD, { .gp={ role_scmd} } }, {"role", P_get_state, F_GET_CMD, { .gp={ role_scmd} } }, {"status", P_get_state, F_GET_CMD, {.gp={ status_xml_scmd } } }, {"sh-status", P_get_state, F_GET_CMD, {.gp={ sh_status_scmd } } }, {"cstate", P_get_state, F_GET_CMD, {.gp={ cstate_scmd} } }, {"dstate", P_get_state, F_GET_CMD, {.gp={ dstate_scmd} } }, {"show-gi", P_get_uuids, F_GET_CMD, {.gp={ uuids_scmd} }}, {"get-gi", P_get_uuids, F_GET_CMD, {.gp={ uuids_scmd} } }, {"show", P_get_config, F_GET_CMD, {.gp={ show_scmd} } }, {"check-resize", P_get_config, F_GET_CMD, {.gp={ lk_bdev_scmd} } }, {"events", 0, F_EVENTS_CMD, { .ep = { (struct option[]) { { "unfiltered", no_argument, 0, 'u' }, { "all-devices",no_argument, 0, 'a' }, { 0, 0, 0, 0 } }, print_broadcast_events } } }, {"wait-connect", 0, F_EVENTS_CMD, { .ep = { wait_cmds_options, w_connected_state } } }, {"wait-sync", 0, F_EVENTS_CMD, { .ep = { wait_cmds_options, w_synced_state } } }, }; #define OTHER_ERROR 900 #define EM(C) [ C - ERR_CODE_BASE ] /* The EM(123) are used for old error messages. */ static const char *error_messages[] = { EM(NO_ERROR) = "No further Information available.", EM(ERR_LOCAL_ADDR) = "Local address(port) already in use.", EM(ERR_PEER_ADDR) = "Remote address(port) already in use.", EM(ERR_OPEN_DISK) = "Can not open backing device.", EM(ERR_OPEN_MD_DISK) = "Can not open meta device.", EM(106) = "Lower device already in use.", EM(ERR_DISK_NOT_BDEV) = "Lower device is not a block device.", EM(ERR_MD_NOT_BDEV) = "Meta device is not a block device.", EM(109) = "Open of lower device failed.", EM(110) = "Open of meta device failed.", EM(ERR_DISK_TOO_SMALL) = "Low.dev. smaller than requested DRBD-dev. size.", EM(ERR_MD_DISK_TOO_SMALL) = "Meta device too small.", EM(113) = "You have to use the disk command first.", EM(ERR_BDCLAIM_DISK) = "Lower device is already claimed. This usually means it is mounted.", EM(ERR_BDCLAIM_MD_DISK) = "Meta device is already claimed. This usually means it is mounted.", EM(ERR_MD_IDX_INVALID) = "Lower device / meta device / index combination invalid.", EM(117) = "Currently we only support devices up to 3.998TB.\n" "(up to 2TB in case you do not have CONFIG_LBD set)\n" "Contact office@linbit.com, if you need more.", EM(ERR_IO_MD_DISK) = "IO error(s) occurred during initial access to meta-data.\n", EM(ERR_MD_INVALID) = "No valid meta-data signature found.\n\n" "\t==> Use 'drbdadm create-md res' to initialize meta-data area. <==\n", EM(ERR_AUTH_ALG) = "The 'cram-hmac-alg' you specified is not known in " "the kernel. (Maybe you need to modprobe it, or modprobe hmac?)", EM(ERR_AUTH_ALG_ND) = "The 'cram-hmac-alg' you specified is not a digest.", EM(ERR_NOMEM) = "kmalloc() failed. Out of memory?", EM(ERR_DISCARD_IMPOSSIBLE) = "--discard-my-data not allowed when primary.", EM(ERR_DISK_CONFIGURED) = "Device is attached to a disk (use detach first)", EM(ERR_NET_CONFIGURED) = "Device has a net-config (use disconnect first)", EM(ERR_MANDATORY_TAG) = "UnknownMandatoryTag", EM(ERR_MINOR_INVALID) = "Device minor not allocated", EM(128) = "Resulting device state would be invalid", EM(ERR_INTR) = "Interrupted by Signal", EM(ERR_RESIZE_RESYNC) = "Resize not allowed during resync.", EM(ERR_NO_PRIMARY) = "Need one Primary node to resize.", EM(ERR_SYNC_AFTER) = "The sync-after minor number is invalid", EM(ERR_SYNC_AFTER_CYCLE) = "This would cause a sync-after dependency cycle", EM(ERR_PAUSE_IS_SET) = "Sync-pause flag is already set", EM(ERR_PAUSE_IS_CLEAR) = "Sync-pause flag is already cleared", EM(136) = "Disk state is lower than outdated", EM(ERR_PACKET_NR) = "Kernel does not know how to handle your request.\n" "Maybe API_VERSION mismatch?", EM(ERR_NO_DISK) = "Device does not have a disk-config", EM(ERR_NOT_PROTO_C) = "Protocol C required", EM(ERR_NOMEM_BITMAP) = "vmalloc() failed. Out of memory?", EM(ERR_INTEGRITY_ALG) = "The 'data-integrity-alg' you specified is not known in " "the kernel. (Maybe you need to modprobe it, or modprobe hmac?)", EM(ERR_INTEGRITY_ALG_ND) = "The 'data-integrity-alg' you specified is not a digest.", EM(ERR_CPU_MASK_PARSE) = "Invalid cpu-mask.", EM(ERR_VERIFY_ALG) = "VERIFYAlgNotAvail", EM(ERR_VERIFY_ALG_ND) = "VERIFYAlgNotDigest", EM(ERR_VERIFY_RUNNING) = "Can not change verify-alg while online verify runs", EM(ERR_DATA_NOT_CURRENT) = "Can only attach to the data we lost last (see kernel log).", EM(ERR_CONNECTED) = "Need to be StandAlone", EM(ERR_CSUMS_ALG) = "CSUMSAlgNotAvail", EM(ERR_CSUMS_ALG_ND) = "CSUMSAlgNotDigest", EM(ERR_CSUMS_RESYNC_RUNNING) = "Can not change csums-alg while resync is in progress", EM(ERR_PERM) = "Permission denied. CAP_SYS_ADMIN necessary", EM(ERR_NEED_APV_93) = "Protocol version 93 required to use --assume-clean", EM(ERR_STONITH_AND_PROT_A) = "Fencing policy resource-and-stonith only with prot B or C allowed", EM(ERR_CONG_NOT_PROTO_A) = "on-congestion policy pull-ahead only with prot A allowed", EM(ERR_PIC_AFTER_DEP) = "Sync-pause flag is already cleared.\n" "Note: Resync pause caused by a local sync-after dependency.", EM(ERR_PIC_PEER_DEP) = "Sync-pause flag is already cleared.\n" "Note: Resync pause caused by the peer node.", }; #define MAX_ERROR (sizeof(error_messages)/sizeof(*error_messages)) const char * error_to_string(int err_no) { const unsigned int idx = err_no - ERR_CODE_BASE; if (idx >= MAX_ERROR) return "Unknown... maybe API_VERSION mismatch?"; return error_messages[idx]; } #undef MAX_ERROR char *cmdname = NULL; /* "drbdsetup" for reporting in usage etc. */ char *devname = NULL; /* "/dev/drbd12" for reporting in print_config_error */ char *resname = NULL; /* for pretty printing in "status" only, taken from environment variable DRBD_RESOURCE */ int debug_dump_argv = 0; /* enabled by setting DRBD_DEBUG_DUMP_ARGV in the environment */ int lock_fd = -1; unsigned int cn_idx; static int dump_tag_list(unsigned short *tlc) { enum drbd_tags tag; unsigned int tag_nr; int len; int integer; char bit; uint64_t int64; const char* string; int found_unknown=0; while( (tag = *tlc++ ) != TT_END) { len = *tlc++; if(tag == TT_REMOVED) goto skip; tag_nr = tag_number(tag); if(tag_nrnl_header = malloc(NLMSG_SPACE( sizeof(struct cn_msg) + sizeof(struct drbd_nl_cfg_req) + size) ); tl->cn_header = NLMSG_DATA(tl->nl_header); tl->drbd_p_header = (struct drbd_nl_cfg_req*) tl->cn_header->data; tl->tag_list_start = tl->drbd_p_header->tag_list; tl->tag_list_cpos = tl->tag_list_start; tl->tag_size = size; return tl; } static void add_tag(struct drbd_tag_list *tl, short int tag, void *data, short int data_len) { if(data_len > tag_descriptions[tag_number(tag)].max_len) { fprintf(stderr, "The value for %s may only be %d byte long." " You requested %d.\n", tag_descriptions[tag_number(tag)].name, tag_descriptions[tag_number(tag)].max_len, data_len); exit(20); } if( (tl->tag_list_cpos - tl->tag_list_start) + data_len > tl->tag_size ) { fprintf(stderr, "Tag list size exceeded!\n"); exit(20); } put_unaligned(tag, tl->tag_list_cpos++); put_unaligned(data_len, tl->tag_list_cpos++); memcpy(tl->tag_list_cpos, data, data_len); tl->tag_list_cpos = (unsigned short*)((char*)tl->tag_list_cpos + data_len); } static void free_tag_list(struct drbd_tag_list *tl) { free(tl->nl_header); free(tl); } static int conv_block_dev(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg) { struct stat sb; int device_fd; if ((device_fd = open(arg,O_RDWR))==-1) { PERROR("Can not open device '%s'", arg); return OTHER_ERROR; } if (fstat(device_fd, &sb)) { PERROR("fstat(%s) failed", arg); return OTHER_ERROR; } if(!S_ISBLK(sb.st_mode)) { fprintf(stderr, "%s is not a block device!\n", arg); return OTHER_ERROR; } close(device_fd); add_tag(tl,ad->tag,arg,strlen(arg)+1); // include the null byte. return NO_ERROR; } static int conv_md_idx(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg) { int idx; if(!strcmp(arg,"internal")) idx = DRBD_MD_INDEX_FLEX_INT; else if(!strcmp(arg,"flexible")) idx = DRBD_MD_INDEX_FLEX_EXT; else idx = m_strtoll(arg,1); add_tag(tl,ad->tag,&idx,sizeof(idx)); return NO_ERROR; } static void resolv6(char *name, struct sockaddr_in6 *addr) { struct addrinfo hints, *res, *tmp; int err; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET6; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; err = getaddrinfo(name, 0, &hints, &res); if (err) { fprintf(stderr, "getaddrinfo %s: %s\n", name, gai_strerror(err)); exit(20); } /* Yes, it is a list. We use only the first result. The loop is only * there to document that we know it is a list */ for (tmp = res; tmp; tmp = tmp->ai_next) { memcpy(addr, tmp->ai_addr, sizeof(*addr)); break; } freeaddrinfo(res); if (0) { /* debug output */ char ip[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, &addr->sin6_addr, ip, sizeof(ip)); fprintf(stderr, "%s -> %02x %04x %08x %s %08x\n", name, addr->sin6_family, addr->sin6_port, addr->sin6_flowinfo, ip, addr->sin6_scope_id); } } static unsigned long resolv(const char* name) { unsigned long retval; if((retval = inet_addr(name)) == INADDR_NONE ) { struct hostent *he; he = gethostbyname(name); if (!he) { fprintf(stderr, "can not resolve the hostname: gethostbyname(%s): %s\n", name, hstrerror(h_errno)); exit(20); } retval = ((struct in_addr *)(he->h_addr_list[0]))->s_addr; } return retval; } static void split_ipv6_addr(char **address, int *port) { /* ipv6:[fe80::0234:5678:9abc:def1]:8000; */ char *b = strrchr(*address,']'); if (address[0][0] != '[' || b == NULL || (b[1] != ':' && b[1] != '\0')) { fprintf(stderr, "unexpected ipv6 format: %s\n", *address); exit(20); } *b = 0; *address += 1; /* skip '[' */ if (b[1] == ':') *port = m_strtoll(b+2,1); /* b+2: "]:" */ else *port = 7788; /* will we ever get rid of that default port? */ } static void split_address(char* text, int *af, char** address, int* port) { static struct { char* text; int af; } afs[] = { { "ipv4:", AF_INET }, { "ipv6:", AF_INET6 }, { "sdp:", AF_INET_SDP }, { "ssocks:", -1 }, }; unsigned int i; char *b; *af=AF_INET; *address = text; for (i=0; itag,&addr6,sizeof(addr6)); } else { /* AF_INET, AF_SDP, AF_SSOCKS, * all use the IPv4 addressing scheme */ addr.sin_port = htons(port); addr.sin_family = af; addr.sin_addr.s_addr = resolv(address); add_tag(tl,ad->tag,&addr,sizeof(addr)); } return NO_ERROR; } static int conv_protocol(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg) { int prot; if(!strcmp(arg,"A") || !strcmp(arg,"a")) { prot=DRBD_PROT_A; } else if (!strcmp(arg,"B") || !strcmp(arg,"b")) { prot=DRBD_PROT_B; } else if (!strcmp(arg,"C") || !strcmp(arg,"c")) { prot=DRBD_PROT_C; } else { fprintf(stderr, "'%s' is no valid protocol.\n", arg); return OTHER_ERROR; } add_tag(tl,ad->tag,&prot,sizeof(prot)); return NO_ERROR; } static int conv_bit(struct drbd_option *od, struct drbd_tag_list *tl, char* arg __attribute((unused))) { char bit=1; add_tag(tl,od->tag,&bit,sizeof(bit)); return NO_ERROR; } /* It will only print the WARNING if the warn flag is set with the _first_ call! */ #define PROC_NET_AF_SCI_FAMILY "/proc/net/af_sci/family" #define PROC_NET_AF_SSOCKS_FAMILY "/proc/net/af_ssocks/family" static int get_af_ssocks(int warn_and_use_default) { char buf[16]; int c, fd; static int af = -1; if (af > 0) return af; fd = open(PROC_NET_AF_SSOCKS_FAMILY, O_RDONLY); if (fd < 0) fd = open(PROC_NET_AF_SCI_FAMILY, O_RDONLY); if (fd < 0) { if (warn_and_use_default) { fprintf(stderr, "open(" PROC_NET_AF_SSOCKS_FAMILY ") " "failed: %m\n WARNING: assuming AF_SSOCKS = 27. " "Socket creation may fail.\n"); af = 27; } return af; } c = read(fd, buf, sizeof(buf)-1); if (c > 0) { buf[c] = 0; if (buf[c-1] == '\n') buf[c-1] = 0; af = m_strtoll(buf,1); } else { if (warn_and_use_default) { fprintf(stderr, "read(" PROC_NET_AF_SSOCKS_FAMILY ") " "failed: %m\n WARNING: assuming AF_SSOCKS = 27. " "Socket creation may fail.\n"); af = 27; } } close(fd); return af; } static int conv_sndbuf(struct drbd_option *od, struct drbd_tag_list *tl, char* arg) { int err = conv_numeric(od, tl, arg); long long l = m_strtoll(arg, 0); char bit = 0; if (err != NO_ERROR || l != 0) return err; /* this is a mandatory bit, * to avoid newer userland to configure older modules with * a sndbuf size of zero, which would lead to Oops. */ add_tag(tl, T_auto_sndbuf_size, &bit, sizeof(bit)); return NO_ERROR; } static int conv_numeric(struct drbd_option *od, struct drbd_tag_list *tl, char* arg) { const long long min = od->numeric_param.min; const long long max = od->numeric_param.max; const unsigned char unit_prefix = od->numeric_param.unit_prefix; long long l; int i; char unit[] = {0,0}; l = m_strtoll(arg, unit_prefix); if (min > l || l > max) { unit[0] = unit_prefix > 1 ? unit_prefix : 0; fprintf(stderr,"%s %s => %llu%s out of range [%llu..%llu]%s\n", od->name, arg, l, unit, min, max, unit); return OTHER_ERROR; } switch(tag_type(od->tag)) { case TT_INT64: add_tag(tl,od->tag,&l,sizeof(l)); break; case TT_INTEGER: i=l; add_tag(tl,od->tag,&i,sizeof(i)); break; default: fprintf(stderr, "internal error in conv_numeric()\n"); } return NO_ERROR; } static int conv_handler(struct drbd_option *od, struct drbd_tag_list *tl, char* arg) { const char** handler_names = od->handler_param.handler_names; const int number_of_handlers = od->handler_param.number_of_handlers; int i; for(i=0;itag,&i,sizeof(i)); return NO_ERROR; } } fprintf(stderr, "%s-handler '%s' not known\n", od->name, arg); fprintf(stderr, "known %s-handlers:\n", od->name); for (i = 0; i < number_of_handlers; i++) { if (handler_names[i]) printf("\t%s\n", handler_names[i]); } return OTHER_ERROR; } static int conv_string(struct drbd_option *od, struct drbd_tag_list *tl, char* arg) { add_tag(tl,od->tag,arg,strlen(arg)+1); return NO_ERROR; } static struct option * make_longoptions(struct drbd_option* od) { /* room for up to N options, * plus set-defaults, create-device, and the terminating NULL */ #define N 30 static struct option buffer[N+3]; int i=0; while(od && od->name) { buffer[i].name = od->name; buffer[i].has_arg = tag_type(od->tag) == TT_BIT ? no_argument : required_argument ; buffer[i].flag = NULL; buffer[i].val = od->short_name; if (i++ == N) { /* we must not leave this loop with i > N */ fprintf(stderr,"buffer in make_longoptions to small.\n"); abort(); } od++; } #undef N // The two omnipresent options: buffer[i].name = "set-defaults"; buffer[i].has_arg = 0; buffer[i].flag = NULL; buffer[i].val = '('; i++; buffer[i].name = "create-device"; buffer[i].has_arg = 0; buffer[i].flag = NULL; buffer[i].val = ')'; i++; buffer[i].name = NULL; buffer[i].has_arg = 0; buffer[i].flag = NULL; buffer[i].val = 0; return buffer; } static struct drbd_option *find_opt_by_short_name(struct drbd_option *od, int c) { if(!od) return NULL; while(od->name) { if(od->short_name == c) return od; od++; } return NULL; } /* prepends global devname to output (if any) */ static int print_config_error(int err_no) { int rv=0; if (err_no == NO_ERROR || err_no == SS_SUCCESS) return 0; if (err_no == OTHER_ERROR) return 20; if ( ( err_no >= AFTER_LAST_ERR_CODE || err_no <= ERR_CODE_BASE ) && ( err_no > SS_CW_NO_NEED || err_no <= SS_AFTER_LAST_ERROR) ) { fprintf(stderr,"Error code %d unknown.\n" "You should update the drbd userland tools.\n",err_no); rv = 20; } else { if(err_no > ERR_CODE_BASE ) { fprintf(stderr,"%s: Failure: (%d) %s\n", devname, err_no, error_to_string(err_no)); rv = 10; } else if (err_no == SS_UNKNOWN_ERROR) { fprintf(stderr,"%s: State change failed: (%d)" "unknown error.\n", devname, err_no); rv = 11; } else if (err_no > SS_TWO_PRIMARIES) { // Ignore SS_SUCCESS, SS_NOTHING_TO_DO, SS_CW_Success... } else { fprintf(stderr,"%s: State change failed: (%d) %s\n", devname, err_no, drbd_set_st_err_str(err_no)); if (err_no == SS_NO_UP_TO_DATE_DISK) { /* all available disks are inconsistent, * or I am consistent, but cannot outdate the peer. */ rv = 17; } else if (err_no == SS_LOWER_THAN_OUTDATED) { /* was inconsistent anyways */ rv = 5; } else if (err_no == SS_NO_LOCAL_DISK) { /* Can not start resync, no local disks, try with drbdmeta */ rv = 16; } else { rv = 11; } } } return rv; } #define RCV_SIZE NLMSG_SPACE(sizeof(struct cn_msg)+sizeof(struct drbd_nl_cfg_reply)) static void warn_print_excess_args(int argc, char **argv, int i) { fprintf(stderr, "Excess arguments:"); for (; i < argc; i++) fprintf(stderr, " %s", argv[i]); printf("\n"); } static void dump_argv(int argc, char **argv, int first_non_option, int n_known_args) { int i; if (!debug_dump_argv) return; fprintf(stderr, ",-- ARGV dump (optind %d, known_args %d, argc %u):\n", first_non_option, n_known_args, argc); for (i = 0; i < argc; i++) { if (i == 1) fprintf(stderr, "-- consumed options:"); if (i == first_non_option) fprintf(stderr, "-- known args:"); if (i == (first_non_option + n_known_args)) fprintf(stderr, "-- unexpected args:"); fprintf(stderr, "| %2u: %s\n", i, argv[i]); } fprintf(stderr, "`--\n"); } static int _generic_config_cmd(struct drbd_cmd *cm, unsigned minor, int argc, char **argv) { char buffer[ RCV_SIZE ]; struct drbd_nl_cfg_reply *reply; struct drbd_argument *ad = cm->cp.args; struct drbd_option *od; struct option *lo; struct drbd_tag_list *tl; int c,i=1,rv=NO_ERROR,sk_nl; int flags=0; int n_args; tl = create_tag_list(4096); while(ad && ad->name) { if(argc < i+1) { fprintf(stderr,"Missing argument '%s'\n", ad->name); print_command_usage(cm-commands, "",FULL); rv = OTHER_ERROR; goto error; } rv = ad->convert_function(ad,tl,argv[i++]); if (rv != NO_ERROR) goto error; ad++; } n_args = i - 1; lo = make_longoptions(cm->cp.options); if (!lo) { static struct option none[] = { { } }; lo = none; } for(;;) { c = getopt_long(argc, argv, make_optstring(lo), lo, 0); if (c == -1) break; od = find_opt_by_short_name(cm->cp.options,c); if (od) rv = od->convert_function(od,tl,optarg); else { if(c=='(') flags |= DRBD_NL_SET_DEFAULTS; else if(c==')') flags |= DRBD_NL_CREATE_DEVICE; else { rv = OTHER_ERROR; goto error; } } if (rv != NO_ERROR) goto error; } /* argc should be cmd + n options + n args; * if it is more, we did not understand some */ if (n_args + optind < argc) { warn_print_excess_args(argc, argv, optind + n_args); rv = OTHER_ERROR; goto error; } dump_argv(argc, argv, optind, i - 1); add_tag(tl,TT_END,NULL,0); // close the tag list if(rv == NO_ERROR) { //dump_tag_list(tl->tag_list_start); int received; sk_nl = open_cn(); if (sk_nl < 0) { rv = OTHER_ERROR; goto error; } tl->drbd_p_header->packet_type = cm->packet_id; tl->drbd_p_header->drbd_minor = minor; tl->drbd_p_header->flags = flags; received = call_drbd(sk_nl,tl, (struct nlmsghdr*)buffer,RCV_SIZE,NL_TIME); close_cn(sk_nl); if (received >= 0) { reply = (struct drbd_nl_cfg_reply *) ((struct cn_msg *)NLMSG_DATA(buffer))->data; rv = reply->ret_code; } } error: free_tag_list(tl); return rv; } static int generic_config_cmd(struct drbd_cmd *cm, unsigned minor, int argc, char **argv) { return print_config_error(_generic_config_cmd(cm, minor, argc, argv)); } #define ASSERT(exp) if (!(exp)) \ fprintf(stderr,"ASSERT( " #exp " ) in %s:%d\n", __FILE__,__LINE__); static void show_numeric(struct drbd_option *od, unsigned short* tp) { long long val; const unsigned char unit_prefix = od->numeric_param.unit_prefix; switch(tag_type(get_unaligned(tp++))) { case TT_INTEGER: ASSERT( get_unaligned(tp++) == sizeof(int) ); val = get_unaligned((int*)tp); break; case TT_INT64: ASSERT( get_unaligned(tp++) == sizeof(uint64_t) ); val = get_unaligned((uint64_t*)tp); break; default: ASSERT(0); val=0; } if(unit_prefix == 1) printf("\t%-16s\t%lld",od->name,val); else printf("\t%-16s\t%lld%c",od->name,val,unit_prefix); if(val == (long long) od->numeric_param.def) printf(" _is_default"); if(od->numeric_param.unit) { printf("; # %s\n",od->numeric_param.unit); } else { printf(";\n"); } } static void show_handler(struct drbd_option *od, unsigned short* tp) { const char** handler_names = od->handler_param.handler_names; int i; ASSERT( tag_type(get_unaligned(tp++)) == TT_INTEGER ); ASSERT( get_unaligned(tp++) == sizeof(int) ); i = get_unaligned((int*)tp); printf("\t%-16s\t%s",od->name,handler_names[i]); if( i == (long long)od->numeric_param.def) printf(" _is_default"); printf(";\n"); } static void show_bit(struct drbd_option *od, unsigned short* tp) { ASSERT( tag_type(get_unaligned(tp++)) == TT_BIT ); ASSERT( get_unaligned(tp++) == sizeof(char) ); if(get_unaligned((char*)tp)) printf("\t%-16s;\n",od->name); } static void show_string(struct drbd_option *od, unsigned short* tp) { ASSERT( tag_type(get_unaligned(tp++)) == TT_STRING ); if( get_unaligned(tp++) > 0 && get_unaligned((char*)tp)) printf("\t%-16s\t\"%s\";\n",od->name,(char*)tp); } static unsigned short *look_for_tag(unsigned short *tlc, unsigned short tag) { enum drbd_tags t; int len; while( (t = get_unaligned(tlc)) != TT_END ) { if(t == tag) return tlc; tlc++; len = get_unaligned(tlc++); tlc = (unsigned short*)((char*)tlc + len); } return NULL; } static void print_options(struct drbd_option *od, unsigned short *tlc, const char* sect_name) { unsigned short *tp; int opened = 0; while(od->name) { tp = look_for_tag(tlc,od->tag); if(tp) { if(!opened) { opened=1; printf("%s {\n",sect_name); } od->show_function(od,tp); put_unaligned(TT_REMOVED, tp); } od++; } if(opened) { printf("}\n"); } } static void consume_everything(unsigned short *tlc) { enum drbd_tags t; int len; while( (t = get_unaligned(tlc)) != TT_END ) { put_unaligned(TT_REMOVED, tlc++); len = get_unaligned(tlc++); tlc = (unsigned short*)((char*)tlc + len); } } static int consume_tag_blob(enum drbd_tags tag, unsigned short *tlc, char** val, unsigned int* len) { unsigned short *tp; tp = look_for_tag(tlc,tag); if(tp) { put_unaligned(TT_REMOVED, tp++); *len = get_unaligned(tp++); *val = (char*)tp; return 1; } return 0; } static int consume_tag_string(enum drbd_tags tag, unsigned short *tlc, char** val) { unsigned short *tp; tp = look_for_tag(tlc,tag); if(tp) { put_unaligned(TT_REMOVED, tp++); if( get_unaligned(tp++) > 0 ) *val = (char*)tp; else *val = ""; return 1; } return 0; } static int consume_tag_int(enum drbd_tags tag, unsigned short *tlc, int* val) { unsigned short *tp; tp = look_for_tag(tlc,tag); if(tp) { put_unaligned(TT_REMOVED, tp++); tp++; *val = get_unaligned((int *)tp); return 1; } return 0; } static int consume_tag_u64(enum drbd_tags tag, unsigned short *tlc, unsigned long long* val) { unsigned short *tp; unsigned short len; tp = look_for_tag(tlc, tag); if(tp) { put_unaligned(TT_REMOVED, tp++); len = get_unaligned(tp++); /* check the data size. * actually it has to be long long, but I'm paranoid */ if (len == sizeof(int)) *val = get_unaligned((unsigned int*)tp); else if (len == sizeof(long)) *val = get_unaligned((unsigned long *)tp); else if (len == sizeof(long long)) *val = get_unaligned((unsigned long long *)tp); else { fprintf(stderr, "%s: unexpected tag len: %u\n", __func__ , len); return 0; } return 1; } return 0; } static int consume_tag_bit(enum drbd_tags tag, unsigned short *tlc, int* val) { unsigned short *tp; tp = look_for_tag(tlc,tag); if(tp) { put_unaligned(TT_REMOVED, tp++); tp++; *val = (int)(*(char *)tp); return 1; } return 0; } static int generic_get_cmd(struct drbd_cmd *cm, unsigned minor, int argc, char **argv __attribute((unused))) { char buffer[ 4096 ]; struct drbd_tag_list *tl; struct drbd_nl_cfg_reply *reply; int sk_nl,rv; int ignore_minor_not_known; int dummy; if (argc > 1) { warn_print_excess_args(argc, argv, 1); return 20; } dump_argv(argc, argv, 1, 0); tl = create_tag_list(2); add_tag(tl,TT_END,NULL,0); // close the tag list sk_nl = open_cn(); if(sk_nl < 0) return 20; tl->drbd_p_header->packet_type = cm->packet_id; tl->drbd_p_header->drbd_minor = minor; tl->drbd_p_header->flags = 0; memset(buffer,0,sizeof(buffer)); call_drbd(sk_nl,tl, (struct nlmsghdr*)buffer,4096,NL_TIME); close_cn(sk_nl); reply = (struct drbd_nl_cfg_reply *) ((struct cn_msg *)NLMSG_DATA(buffer))->data; /* if there was an error, report and abort -- * unless it was "this device is not there", * and command was "status" */ ignore_minor_not_known = cm->gp.show_function == status_xml_scmd || cm->gp.show_function == sh_status_scmd; if (reply->ret_code != NO_ERROR && !(reply->ret_code == ERR_MINOR_INVALID && ignore_minor_not_known)) return print_config_error(reply->ret_code); rv = cm->gp.show_function(cm,minor,reply->tag_list); /* in case cm->packet_id == P_get_state, and the gp.show_function did * nothing with the sync_progress info, consume it here, so it won't * confuse users because it gets dumped below. */ consume_tag_int(T_sync_progress, reply->tag_list, &dummy); if(dump_tag_list(reply->tag_list)) { printf("# Found unknown tags, you should update your\n" "# userland tools\n"); } return rv; } static char *af_to_str(int af) { if (af == AF_INET) return "ipv4"; else if (af == AF_INET6) return "ipv6"; /* AF_SSOCKS typically is 27, the same as AF_INET_SDP. * But with warn_and_use_default = 0, it will stay at -1 if not available. * Just keep the test on ssocks before the one on SDP (which is hard-coded), * and all should be fine. */ else if (af == get_af_ssocks(0)) return "ssocks"; else if (af == AF_INET_SDP) return "sdp"; else return "unknown"; } static void show_address(void* address, int addr_len) { union { struct sockaddr addr; struct sockaddr_in addr4; struct sockaddr_in6 addr6; } a; char buffer[INET6_ADDRSTRLEN]; /* avoid alignment issues on certain platforms (e.g. armel) */ memset(&a, 0, sizeof(a)); memcpy(&a.addr, address, addr_len); if (a.addr.sa_family == AF_INET || a.addr.sa_family == get_af_ssocks(0) || a.addr.sa_family == AF_INET_SDP) { printf("\taddress\t\t\t%s %s:%d;\n", af_to_str(a.addr4.sin_family), inet_ntoa(a.addr4.sin_addr), ntohs(a.addr4.sin_port)); } else if (a.addr.sa_family == AF_INET6) { printf("\taddress\t\t\t%s [%s]:%d;\n", af_to_str(a.addr6.sin6_family), inet_ntop(a.addr6.sin6_family, &a.addr6.sin6_addr, buffer, INET6_ADDRSTRLEN), ntohs(a.addr6.sin6_port)); } else { printf("\taddress\t\t\t[unknown af=%d, len=%d]\n", a.addr.sa_family, addr_len); } } static int show_scmd(struct drbd_cmd *cm, unsigned minor, unsigned short *rtl) { int idx = idx; char *str = NULL, *backing_dev, *address; unsigned int addr_len = 0; // find all commands that have options and print those... for ( cm = commands ; cm < commands + ARRAY_SIZE(commands) ; cm++ ) { if(cm->function == generic_config_cmd && cm->cp.options ) print_options(cm->cp.options, rtl, cm->cmd); } // start of spaghetti code... if(consume_tag_int(T_wire_protocol,rtl,&idx)) printf("protocol %c;\n",'A'+idx-1); backing_dev = address = NULL; consume_tag_string(T_backing_dev,rtl,&backing_dev); consume_tag_blob(T_my_addr, rtl, &address, &addr_len); if(backing_dev || address) { printf("_this_host {\n"); printf("\tdevice\t\t\tminor %d;\n",minor); if(backing_dev) { printf("\tdisk\t\t\t\"%s\";\n",backing_dev); consume_tag_int(T_meta_dev_idx,rtl,&idx); consume_tag_string(T_meta_dev,rtl,&str); switch(idx) { case DRBD_MD_INDEX_INTERNAL: case DRBD_MD_INDEX_FLEX_INT: printf("\tmeta-disk\t\tinternal;\n"); break; case DRBD_MD_INDEX_FLEX_EXT: printf("\tflexible-meta-disk\t\"%s\";\n",str); break; default: printf("\tmeta-disk\t\t\"%s\" [ %d ];\n",str, idx); } } if(address) show_address(address, addr_len); printf("}\n"); } if(consume_tag_blob(T_peer_addr, rtl, &address, &addr_len)) { printf("_remote_host {\n"); show_address(address, addr_len); printf("}\n"); } consume_tag_bit(T_mind_af, rtl, &idx); /* consume it, its value has no relevance */ consume_tag_bit(T_auto_sndbuf_size, rtl, &idx); /* consume it, its value has no relevance */ return 0; } static int lk_bdev_scmd(struct drbd_cmd *cm, unsigned minor, unsigned short *rtl) { struct bdev_info bd = { 0, }; char *backing_dev = NULL; uint64_t bd_size; int fd; int idx = idx; int index_valid = 0; consume_tag_string(T_backing_dev, rtl, &backing_dev); index_valid = consume_tag_int(T_meta_dev_idx, rtl, &idx); /* consume everything */ consume_everything(rtl); if (!backing_dev) { fprintf(stderr, "Has no disk config, try with drbdmeta.\n"); return 1; } if (!index_valid) { /* cannot happen, right? ;-) */ fprintf(stderr, "No meta data index!?\n"); return 1; } if (idx >= 0 || idx == DRBD_MD_INDEX_FLEX_EXT) { lk_bdev_delete(minor); return 0; } fd = open(backing_dev, O_RDONLY); if (fd == -1) { fprintf(stderr, "Could not open %s: %m.\n", backing_dev); return 1; } bd_size = bdev_size(fd); close(fd); if (lk_bdev_load(minor, &bd) == 0 && bd.bd_size == bd_size && bd.bd_name && !strcmp(bd.bd_name, backing_dev)) return 0; /* nothing changed. */ bd.bd_size = bd_size; bd.bd_name = backing_dev; lk_bdev_save(minor, &bd); return 0; } static int status_xml_scmd(struct drbd_cmd *cm __attribute((unused)), unsigned minor, unsigned short *rtl) { union drbd_state state = { .i = 0 }; int synced = 0; if (!consume_tag_int(T_state_i,rtl,(int*)&state.i)) { printf( "\n"); return 0; } printf("\n"); return 0; } printf( /* connection state */ " cs=\"%s\"" /* role */ " ro1=\"%s\" ro2=\"%s\"" /* disk state */ " ds1=\"%s\" ds2=\"%s\"", drbd_conn_str(state.conn), drbd_role_str(state.role), drbd_role_str(state.peer), drbd_disk_str(state.disk), drbd_disk_str(state.pdsk)); /* io suspended ? */ if (state.susp) printf(" suspended"); /* reason why sync is paused */ if (state.aftr_isp) printf(" aftr_isp"); if (state.peer_isp) printf(" peer_isp"); if (state.user_isp) printf(" user_isp"); if (consume_tag_int(T_sync_progress, rtl, &synced)) printf(" resynced_percent=\"%i.%i\"", synced / 10, synced % 10); printf(" />\n"); return 0; } static int sh_status_scmd(struct drbd_cmd *cm __attribute((unused)), unsigned minor, unsigned short *rtl) { /* variable prefix; maybe rather make that a command line parameter? * or use "drbd_sh_status"? */ #define _P "" union drbd_state state = { .i = 0 }; int available = 0; int synced = 0; printf("%s_minor=%u\n", _P, minor); printf("%s_res_name=%s\n", _P, shell_escape(resname ?: "UNKNOWN")); available = consume_tag_int(T_state_i,rtl,(int*)&state.i); if (state.conn == C_STANDALONE && state.disk == D_DISKLESS) { printf("%s_known=%s\n\n", _P, available ? "Unconfigured" : "NA # not available or not yet created"); printf("%s_cstate=Unconfigured\n", _P); printf("%s_role=\n", _P); printf("%s_peer=\n", _P); printf("%s_disk=\n", _P); printf("%s_pdsk=\n", _P); printf("%s_flags_susp=\n", _P); printf("%s_flags_aftr_isp=\n", _P); printf("%s_flags_peer_isp=\n", _P); printf("%s_flags_user_isp=\n", _P); printf("%s_resynced_percent=\n", _P); } else { printf( "%s_known=Configured\n\n" /* connection state */ "%s_cstate=%s\n" /* role */ "%s_role=%s\n" "%s_peer=%s\n" /* disk state */ "%s_disk=%s\n" "%s_pdsk=%s\n\n", _P, _P, drbd_conn_str(state.conn), _P, drbd_role_str(state.role), _P, drbd_role_str(state.peer), _P, drbd_disk_str(state.disk), _P, drbd_disk_str(state.pdsk)); /* io suspended ? */ printf("%s_flags_susp=%s\n", _P, state.susp ? "1" : ""); /* reason why sync is paused */ printf("%s_flags_aftr_isp=%s\n", _P, state.aftr_isp ? "1" : ""); printf("%s_flags_peer_isp=%s\n", _P, state.peer_isp ? "1" : ""); printf("%s_flags_user_isp=%s\n\n", _P, state.user_isp ? "1" : ""); printf("%s_resynced_percent=", _P); if (consume_tag_int(T_sync_progress, rtl, &synced)) printf("%i.%i\n", synced / 10, synced % 10); else printf("\n"); } printf("\n%s_sh_status_process\n\n\n", _P); fflush(stdout); return 0; #undef _P } static int role_scmd(struct drbd_cmd *cm __attribute((unused)), unsigned minor __attribute((unused)), unsigned short *rtl) { union drbd_state state = { .i = 0 }; if (!strcmp(cm->cmd, "state")) { fprintf(stderr, "'%s ... state' is deprecated, use '%s ... role' instead.\n", cmdname, cmdname); } consume_tag_int(T_state_i,rtl,(int*)&state.i); if ( state.conn == C_STANDALONE && state.disk == D_DISKLESS) { printf("Unconfigured\n"); } else { printf("%s/%s\n",drbd_role_str(state.role),drbd_role_str(state.peer)); } return 0; } static int cstate_scmd(struct drbd_cmd *cm __attribute((unused)), unsigned minor __attribute((unused)), unsigned short *rtl) { union drbd_state state = { .i = 0 }; consume_tag_int(T_state_i,rtl,(int*)&state.i); if ( state.conn == C_STANDALONE && state.disk == D_DISKLESS) { printf("Unconfigured\n"); } else { printf("%s\n",drbd_conn_str(state.conn)); } return 0; } static int dstate_scmd(struct drbd_cmd *cm __attribute((unused)), unsigned minor __attribute((unused)), unsigned short *rtl) { union drbd_state state = { .i = 0 }; consume_tag_int(T_state_i,rtl,(int*)&state.i); if ( state.conn == C_STANDALONE && state.disk == D_DISKLESS) { printf("Unconfigured\n"); } else { printf("%s/%s\n",drbd_disk_str(state.disk),drbd_disk_str(state.pdsk)); } return 0; } static int uuids_scmd(struct drbd_cmd *cm, unsigned minor __attribute((unused)), unsigned short *rtl) { uint64_t uuids[UI_SIZE]; char *tl_uuids; int flags = flags; unsigned int len; if (!consume_tag_blob(T_uuids, rtl, &tl_uuids, &len)) { fprintf(stderr,"Reply payload did not carry an uuid-tag,\n" "Probably the device has no disk!\n"); return 1; } consume_tag_int(T_uuids_flags,rtl,&flags); if( len == UI_SIZE * sizeof(uint64_t)) { memcpy(uuids, tl_uuids, len); if(!strcmp(cm->cmd,"show-gi")) { dt_pretty_print_uuids(uuids,flags); } else if(!strcmp(cm->cmd,"get-gi")) { dt_print_uuids(uuids,flags); } else { ASSERT( 0 ); } } else { fprintf(stderr, "Unexpected length of T_uuids tag. " "You should upgrade your userland tools\n"); } return 0; } static struct drbd_cmd *find_cmd_by_name(char *name) { unsigned int i; for (i = 0; i < ARRAY_SIZE(commands); i++) { if (!strcmp(name, commands[i].cmd)) { return commands + i; } } return NULL; } static int down_cmd(struct drbd_cmd *cm, unsigned minor, int argc, char **argv) { int rv; int success; if(argc > 1) { fprintf(stderr,"Ignoring excess arguments\n"); } cm = find_cmd_by_name("secondary"); rv = _generic_config_cmd(cm, minor, argc, argv); // No error messages if (rv == ERR_MINOR_INVALID) return 0; success = (rv >= SS_SUCCESS && rv < ERR_CODE_BASE) || rv == NO_ERROR; if (!success) return print_config_error(rv); cm = find_cmd_by_name("disconnect"); cm->function(cm,minor,argc,argv); cm = find_cmd_by_name("detach"); rv = cm->function(cm,minor,argc,argv); return rv; } static void print_digest(const char* label, const int len, const unsigned char *hash) { int i; printf("\t%s: ", label); for (i = 0; i < len; i++) printf("%02x",hash[i]); printf("\n"); } static char printable_or_dot(char c) { return (' ' < c && c <= '~') ? c : '.'; } static void print_hex_line(int offset, unsigned char *data) { printf( " %04x:" " %02x %02x %02x %02x %02x %02x %02x %02x " " %02x %02x %02x %02x %02x %02x %02x %02x" " %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n", offset, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15], printable_or_dot(data[0]), printable_or_dot(data[1]), printable_or_dot(data[2]), printable_or_dot(data[3]), printable_or_dot(data[4]), printable_or_dot(data[5]), printable_or_dot(data[6]), printable_or_dot(data[7]), printable_or_dot(data[8]), printable_or_dot(data[9]), printable_or_dot(data[10]), printable_or_dot(data[11]), printable_or_dot(data[12]), printable_or_dot(data[13]), printable_or_dot(data[14]), printable_or_dot(data[15])); } /* successive identical lines are collapsed into just printing one star */ static void print_hex_dump(int len, void *data) { int i; int star = 0; for (i = 0; i < len-15; i += 16) { if (i == 0 || memcmp(data + i, data + i - 16, 16)) { print_hex_line(i, data + i); star = 0; } else if (!star) { printf(" *\n"); star = 1; } } /* yes, I ignore remainders of len not modulo 16 here. * so what, usage is currently to dump bios, which are * multiple of 512. */ /* for good measure, print the total size as offset now, * last line may have been a '*' */ printf(" %04x.\n", len); } static void print_dump_ee(struct drbd_nl_cfg_reply *reply) { unsigned long long sector = -1ULL; unsigned long long block_id = 0; char *reason = "UNKNOWN REASON"; char *dig_in = NULL; char *dig_vv = NULL; unsigned int dgs_in = 0, dgs_vv = 0; unsigned int size = 0; char *data = NULL; if (!consume_tag_string(T_dump_ee_reason, reply->tag_list, &reason)) printf("\tno reason?\n"); if (!consume_tag_blob(T_seen_digest, reply->tag_list, &dig_in, &dgs_in)) printf("\tno digest in?\n"); if (!consume_tag_blob(T_calc_digest, reply->tag_list, &dig_vv, &dgs_vv)) printf("\tno digest out?\n"); if (!consume_tag_u64(T_ee_sector, reply->tag_list, §or)) printf("\tno sector?\n"); if (!consume_tag_u64(T_ee_block_id, reply->tag_list, &block_id)) printf("\tno block_id?\n"); if (!consume_tag_blob(T_ee_data, reply->tag_list, &data, &size)) printf("\tno data?\n"); printf("\tdumping ee, reason: %s\n", reason); printf("\tsector: %llu block_id: 0x%llx size: %u\n", sector, block_id, size); /* "input sanitation". Did I mention yet that I'm paranoid? */ if (!data) size = 0; if (!dig_in) dgs_in = 0; if (!dig_vv) dgs_vv = 0; if (dgs_in > SHARED_SECRET_MAX) dgs_in = SHARED_SECRET_MAX; if (dgs_vv > SHARED_SECRET_MAX) dgs_vv = SHARED_SECRET_MAX; print_digest("received digest", dgs_in, (unsigned char*)dig_in); print_digest("verified digest", dgs_vv, (unsigned char*)dig_vv); /* dump at most 32 K */ if (size > 0x8000) { size = 0x8000; printf("\tWARNING truncating data to %u!\n", 0x8000); } print_hex_dump(size,data); } /* this is not pretty; but it's api... ;-( */ const char *pretty_print_return_code(int e) { return e == NO_ERROR ? "No error" : e > ERR_CODE_BASE ? error_to_string(e) : e > SS_AFTER_LAST_ERROR && e <= SS_TWO_PRIMARIES ? drbd_set_st_err_str(e) : e == SS_CW_NO_NEED ? "Cluster wide state change: nothing to do" : e == SS_CW_SUCCESS ? "Cluster wide state change successful" : e == SS_NOTHING_TO_DO ? "State change: nothing to do" : e == SS_SUCCESS ? "State change successful" : e == SS_UNKNOWN_ERROR ? "Unspecified error" : "Unknown return code"; } static int print_broadcast_events(unsigned int seq, int u __attribute((unused)), struct drbd_nl_cfg_reply *reply) { union drbd_state state; char* str; int synced = 0; switch (reply->packet_type) { case 0: /* used to be this way in drbd_nl.c for some responses :-( */ case P_return_code_only: /* used by drbd_nl.c for most "empty" responses */ printf("%u ZZ %d ret_code: %d %s\n", seq, reply->minor, reply->ret_code, pretty_print_return_code(reply->ret_code)); break; case P_get_state: if(consume_tag_int(T_state_i,reply->tag_list,(int*)&state.i)) { printf("%u ST %d { cs:%s ro:%s/%s ds:%s/%s %c%c%c%c }\n", seq, reply->minor, drbd_conn_str(state.conn), drbd_role_str(state.role), drbd_role_str(state.peer), drbd_disk_str(state.disk), drbd_disk_str(state.pdsk), state.susp ? 's' : 'r', state.aftr_isp ? 'a' : '-', state.peer_isp ? 'p' : '-', state.user_isp ? 'u' : '-' ); } else fprintf(stderr,"Missing tag !?\n"); break; case P_call_helper: if(consume_tag_string(T_helper,reply->tag_list,&str)) { printf("%u UH %d %s\n", seq, reply->minor, str); } else fprintf(stderr,"Missing tag !?\n"); break; case P_sync_progress: if (consume_tag_int(T_sync_progress, reply->tag_list, &synced)) { printf("%u SP %d %i.%i\n", seq, reply->minor, synced / 10, synced % 10); } else fprintf(stderr,"Missing tag !?\n"); break; case P_dump_ee: printf("%u DE %d\n", seq, reply->minor); print_dump_ee(reply); break; default: printf("%u ?? %d \n",seq, reply->minor, reply->packet_type); break; } fflush(stdout); return 1; } void print_failure_code(int ret_code) { if (ret_code > ERR_CODE_BASE) fprintf(stderr,"%s: Failure: (%d) %s\n", devname, ret_code, error_to_string(ret_code)); else fprintf(stderr,"%s: Failure: (ret_code=%d)\n", devname, ret_code); } static int w_connected_state(unsigned int seq __attribute((unused)), int wait_after_sb, struct drbd_nl_cfg_reply *reply) { union drbd_state state; if (reply->ret_code != NO_ERROR) { print_failure_code(reply->ret_code); return 0; } if(reply->packet_type == P_get_state) { if(consume_tag_int(T_state_i,reply->tag_list,(int*)&state.i)) { if(state.conn >= C_CONNECTED) return 0; if(!wait_after_sb && state.conn < C_UNCONNECTED) return 0; } else fprintf(stderr,"Missing tag !?\n"); } return 1; } static int w_synced_state(unsigned int seq __attribute((unused)), int wait_after_sb, struct drbd_nl_cfg_reply *reply) { union drbd_state state; if (reply->ret_code != NO_ERROR) { print_failure_code(reply->ret_code); return 0; } if(reply->packet_type == P_get_state) { if(consume_tag_int(T_state_i,reply->tag_list,(int*)&state.i)) { if(state.conn == C_CONNECTED) return 0; if(!wait_after_sb && state.conn < C_UNCONNECTED) return 0; } else fprintf(stderr,"Missing tag !?\n"); } return 1; } static int events_cmd(struct drbd_cmd *cm, unsigned minor, int argc ,char **argv) { void *buffer; struct cn_msg *cn_reply; struct drbd_nl_cfg_reply *reply; struct drbd_tag_list *tl; struct option *lo; unsigned int b_seq=0, r_seq=0; int sk_nl,c,cont=1,rr = rr,i,last; int unfiltered=0, all_devices=0, timeout_ms=0; int wfc_timeout=DRBD_WFC_TIMEOUT_DEF; int degr_wfc_timeout=DRBD_DEGR_WFC_TIMEOUT_DEF; int outdated_wfc_timeout=DRBD_OUTDATED_WFC_TIMEOUT_DEF; struct timeval before,after; int wasb=0; lo = cm->ep.options; if (!lo) { static struct option none[] = { { } }; lo = none; } for(;;) { c = getopt_long(argc, argv, make_optstring(lo), lo, 0); if (c == -1) break; switch(c) { default: case '?': return 20; case 'u': unfiltered=1; break; case 'a': all_devices=1; break; case 't': wfc_timeout=m_strtoll(optarg,1); if(DRBD_WFC_TIMEOUT_MIN > wfc_timeout || wfc_timeout > DRBD_WFC_TIMEOUT_MAX) { fprintf(stderr, "wfc_timeout => %d" " out of range [%d..%d]\n", wfc_timeout, DRBD_WFC_TIMEOUT_MIN, DRBD_WFC_TIMEOUT_MAX); return 20; } break; case 'd': degr_wfc_timeout=m_strtoll(optarg,1); if(DRBD_DEGR_WFC_TIMEOUT_MIN > degr_wfc_timeout || degr_wfc_timeout > DRBD_DEGR_WFC_TIMEOUT_MAX) { fprintf(stderr, "degr_wfc_timeout => %d" " out of range [%d..%d]\n", degr_wfc_timeout, DRBD_DEGR_WFC_TIMEOUT_MIN, DRBD_DEGR_WFC_TIMEOUT_MAX); return 20; } break; case 'o': outdated_wfc_timeout=m_strtoll(optarg,1); if(DRBD_OUTDATED_WFC_TIMEOUT_MIN > degr_wfc_timeout || degr_wfc_timeout > DRBD_OUTDATED_WFC_TIMEOUT_MAX) { fprintf(stderr, "degr_wfc_timeout => %d" " out of range [%d..%d]\n", outdated_wfc_timeout, DRBD_OUTDATED_WFC_TIMEOUT_MIN, DRBD_OUTDATED_WFC_TIMEOUT_MAX); return 20; } break; case 'w': wasb=1; break; } } if (optind < argc) { warn_print_excess_args(argc, argv, optind); return 20; } dump_argv(argc, argv, optind, 0); tl = create_tag_list(2); add_tag(tl,TT_END,NULL,0); // close the tag list sk_nl = open_cn(); if(sk_nl < 0) return 20; /* allocate 64k to be on the safe side. */ #define NL_BUFFER_SIZE (64 << 10) buffer = malloc(NL_BUFFER_SIZE); if (!buffer) { fprintf(stderr, "could not allocate buffer of %u bytes\n", NL_BUFFER_SIZE); exit(20); } /* drbdsetup events should not ask for timeout "type", * this is only useful with wait-sync and wait-connected callbacks. */ if (cm->ep.proc_event != print_broadcast_events) { // Find out which timeout value to use. tl->drbd_p_header->packet_type = P_get_timeout_flag; tl->drbd_p_header->drbd_minor = minor; tl->drbd_p_header->flags = 0; if (0 >= call_drbd(sk_nl,tl, buffer, NL_BUFFER_SIZE, NL_TIME)) exit(20); cn_reply = (struct cn_msg *)NLMSG_DATA(buffer); reply = (struct drbd_nl_cfg_reply *)cn_reply->data; if (reply->ret_code != NO_ERROR) return print_config_error(reply->ret_code); consume_tag_bit(T_use_degraded,reply->tag_list,&rr); if (rr != UT_DEFAULT) { if (0 < wfc_timeout && (wfc_timeout < degr_wfc_timeout || degr_wfc_timeout == 0)) { degr_wfc_timeout = wfc_timeout; fprintf(stderr, "degr-wfc-timeout has to be shorter than wfc-timeout\n" "degr-wfc-timeout implicitly set to wfc-timeout (%ds)\n", degr_wfc_timeout); } if (0 < degr_wfc_timeout && (degr_wfc_timeout < outdated_wfc_timeout || outdated_wfc_timeout == 0)) { outdated_wfc_timeout = wfc_timeout; fprintf(stderr, "outdated-wfc-timeout has to be shorter than degr-wfc-timeout\n" "outdated-wfc-timeout implicitly set to degr-wfc-timeout (%ds)\n", degr_wfc_timeout); } } switch (rr) { case UT_DEFAULT: timeout_ms = wfc_timeout; break; case UT_DEGRADED: timeout_ms = degr_wfc_timeout; break; case UT_PEER_OUTDATED: timeout_ms = outdated_wfc_timeout; break; } } timeout_ms = timeout_ms * 1000 - 1; /* 0 -> -1 "infinite", 1000 -> 999, nobody cares... */ // ask for the current state before waiting for state updates... if (all_devices) { i = 0; last = 255; } else { i = last = minor; } while (i <= last) { tl->drbd_p_header->packet_type = P_get_state; tl->drbd_p_header->drbd_minor = i; tl->drbd_p_header->flags = 0; send_cn(sk_nl,tl->nl_header,(char*)tl->tag_list_cpos-(char*)tl->nl_header); i++; } dt_unlock_drbd(lock_fd); lock_fd=-1; do { gettimeofday(&before,NULL); rr = receive_cn(sk_nl, buffer, NL_BUFFER_SIZE, timeout_ms); gettimeofday(&after,NULL); if(rr == -2) break; // timeout expired. if(timeout_ms > 0 ) { timeout_ms -= ( (after.tv_sec - before.tv_sec) * 1000 + (after.tv_usec - before.tv_usec) / 1000 ); } cn_reply = (struct cn_msg *)NLMSG_DATA(buffer); reply = (struct drbd_nl_cfg_reply *)cn_reply->data; // dump_tag_list(reply->tag_list); /* There are two value spaces for sequence numbers. The first is the one created by this drbdsetup instance, the kernel's reply packets simply echo those sequence numbers. The second is created by the kernel's broadcast packets. */ if (!unfiltered) { if (cn_reply->ack == 0) { // broadcasts /* Careful, potential wrap around! * Will skip a lot of packets if you * unload/reload the module in between, * but keep this drbdsetup events running. * So don't do that. */ if ((int)(cn_reply->seq - b_seq) <= 0) continue; b_seq = cn_reply->seq; } else if ((all_devices || minor == reply->minor) && cn_reply->ack == (uint32_t)getpid() + 1) { // replies to drbdsetup packets and for this device. if ((int)(cn_reply->seq - r_seq) <= 0) continue; r_seq = cn_reply->seq; } else { /* or reply to configuration request of other drbdsetup */ continue; } } if( all_devices || minor == reply->minor ) { cont=cm->ep.proc_event(cn_reply->seq, wasb, reply); } } while(cont); free(buffer); close_cn(sk_nl); /* return code becomes exit code. * timeout? => exit 5 * else => exit 0 */ return (rr == -2) ? 5 : 0; } static int numeric_opt_usage(struct drbd_option *option, char* str, int strlen) { return snprintf(str,strlen," [{--%s|-%c} %lld ... %lld]", option->name, option->short_name, option->numeric_param.min, option->numeric_param.max); } static int handler_opt_usage(struct drbd_option *option, char* str, int strlen) { const char** handlers; int i, chars=0,first=1; chars += snprintf(str,strlen," [{--%s|-%c} {", option->name, option->short_name); handlers = option->handler_param.handler_names; for(i=0;ihandler_param.number_of_handlers;i++) { if(handlers[i]) { if(!first) chars += snprintf(str+chars,strlen,"|"); first=0; chars += snprintf(str+chars,strlen, "%s",handlers[i]); } } chars += snprintf(str+chars,strlen,"}]"); return chars; } static int bit_opt_usage(struct drbd_option *option, char* str, int strlen) { return snprintf(str,strlen," [{--%s|-%c}]", option->name, option->short_name); } static int string_opt_usage(struct drbd_option *option, char* str, int strlen) { return snprintf(str,strlen," [{--%s|-%c} ]", option->name, option->short_name); } static void numeric_opt_xml(struct drbd_option *option) { printf("\t\n"); } static void handler_opt_xml(struct drbd_option *option) { const char** handlers; int i; printf("\t\n"); } static void bit_opt_xml(struct drbd_option *option) { printf("\t\n"); } static void string_opt_xml(struct drbd_option *option) { printf("\t\n"); } static void config_usage(struct drbd_cmd *cm, enum usage_type ut) { struct drbd_argument *args; struct drbd_option *options; static char line[300]; int maxcol,col,prevcol,startcol,toolong; char *colstr; if(ut == XML) { printf("\n",cm->cmd); if( (args = cm->cp.args) ) { while (args->name) { printf("\t%s\n", args->name); args++; } } options = cm->cp.options; while (options && options->name) { options->xml_function(options); options++; } printf("\n"); return; } prevcol=col=0; maxcol=100; if((colstr=getenv("COLUMNS"))) maxcol=atoi(colstr)-1; col += snprintf(line+col, maxcol-col, " %s", cm->cmd); if( (args = cm->cp.args) ) { if(ut == BRIEF) { col += snprintf(line+col, maxcol-col, " [args...]"); } else { while (args->name) { col += snprintf(line+col, maxcol-col, " %s", args->name); args++; } } } if (col > maxcol) { printf("%s\n",line); col=0; } startcol=prevcol=col; options = cm->cp.options; if(ut == BRIEF) { if(options) col += snprintf(line+col, maxcol-col, " [opts...]"); printf("%-40s",line); return; } while (options && options->name) { col += options->usage_function(options, line+col, maxcol-col); if (col >= maxcol) { toolong = (prevcol == startcol); if( !toolong ) line[prevcol]=0; printf("%s\n",line); startcol=prevcol=col = sprintf(line," "); if( toolong) options++; } else { prevcol=col; options++; } } line[col]=0; printf("%s\n",line); } static void get_usage(struct drbd_cmd *cm, enum usage_type ut) { if(ut == BRIEF) { printf(" %-39s", cm->cmd); } else { printf(" %s\n", cm->cmd); } } static void events_usage(struct drbd_cmd *cm, enum usage_type ut) { struct option *lo; char line[41]; if(ut == BRIEF) { sprintf(line,"%s [opts...]", cm->cmd); printf(" %-39s",line); } else { printf(" %s", cm->cmd); lo = cm->ep.options; while(lo && lo->name) { printf(" [{--%s|-%c}]",lo->name,lo->val); lo++; } printf("\n"); } } static void print_command_usage(int i, const char *addinfo, enum usage_type ut) { if(ut != XML) printf("USAGE:\n"); commands[i].usage(commands+i,ut); if (addinfo) { printf("%s\n",addinfo); exit(20); } } static void print_usage(const char* addinfo) { size_t i; printf("\nUSAGE: %s device command arguments options\n\n" "Device is usually /dev/drbdX or /dev/drbd/X.\n" "General options: --create-device, --set-defaults\n" "\nCommands are:\n",cmdname); for (i = 0; i < ARRAY_SIZE(commands); i++) { commands[i].usage(commands+i,BRIEF); if(i%2==1) printf("\n"); } printf("\n\n" "To get more details about a command issue " "'drbdsetup help cmd'.\n" "\n"); /* printf("\n\nVersion: "PACKAGE_VERSION" (api:%d)\n%s\n", API_VERSION, drbd_buildtag()); */ if (addinfo) printf("\n%s\n",addinfo); exit(20); } static int open_cn() { int sk_nl; int err; struct sockaddr_nl my_nla; sk_nl = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR); if (sk_nl == -1) { perror("socket() failed"); return -1; } my_nla.nl_family = AF_NETLINK; my_nla.nl_groups = -1; //cn_idx my_nla.nl_pid = getpid(); err = bind(sk_nl, (struct sockaddr *)&my_nla, sizeof(my_nla)); if (err == -1) { err = errno; perror("bind() failed"); switch(err) { case ENOENT: fprintf(stderr,"Connector module not loaded? Try 'modprobe cn'.\n"); break; case EPERM: fprintf(stderr,"Missing privileges? You should run this as root.\n"); break; } return -1; } return sk_nl; } static void prepare_nl_header(struct nlmsghdr* nl_hdr, int size) { static uint32_t cn_seq = 1; struct cn_msg *cn_hdr; cn_hdr = (struct cn_msg *)NLMSG_DATA(nl_hdr); /* fill the netlink header */ nl_hdr->nlmsg_len = NLMSG_LENGTH(size - sizeof(struct nlmsghdr)); nl_hdr->nlmsg_type = NLMSG_DONE; nl_hdr->nlmsg_flags = 0; nl_hdr->nlmsg_seq = cn_seq; nl_hdr->nlmsg_pid = getpid(); /* fill the connector header */ cn_hdr->id.val = CN_VAL_DRBD; cn_hdr->id.idx = cn_idx; cn_hdr->seq = cn_seq++; cn_hdr->ack = getpid(); cn_hdr->len = size - sizeof(struct nlmsghdr) - sizeof(struct cn_msg); } static int send_cn(int sk_nl, struct nlmsghdr* nl_hdr, int size) { int rr; prepare_nl_header(nl_hdr,size); rr = send(sk_nl,nl_hdr,nl_hdr->nlmsg_len,0); if( rr != (ssize_t)nl_hdr->nlmsg_len) { perror("send() failed"); return -1; } return rr; } static int receive_cn(int sk_nl, struct nlmsghdr* nl_hdr, int size, int timeout_ms) { struct pollfd pfd; int rr; pfd.fd = sk_nl; pfd.events = POLLIN; rr = poll(&pfd,1,timeout_ms); if(rr == 0) return -2; // timeout expired. rr = recv(sk_nl,nl_hdr,size,0); if( rr < 0 ) { perror("recv() failed"); return -1; } return rr; } int receive_reply_cn(int sk_nl, struct drbd_tag_list *tl, struct nlmsghdr* nl_hdr, int size, int timeout_ms) { struct cn_msg *request_cn_hdr; struct cn_msg *reply_cn_hdr; int rr; request_cn_hdr = (struct cn_msg *)NLMSG_DATA(tl->nl_header); reply_cn_hdr = (struct cn_msg *)NLMSG_DATA(nl_hdr); while(1) { rr = receive_cn(sk_nl,nl_hdr,size,timeout_ms); if( rr < 0 ) return rr; if(reply_cn_hdr->seq == request_cn_hdr->seq && reply_cn_hdr->ack == request_cn_hdr->ack+1 ) return rr; /* printf("INFO: got other message \n" "got seq: %d ; ack %d \n" "exp seq: %d ; ack %d \n", reply_cn_hdr->seq,reply_cn_hdr->ack, request_cn_hdr->seq,request_cn_hdr->ack); */ } return rr; } static int call_drbd(int sk_nl, struct drbd_tag_list *tl, struct nlmsghdr* nl_hdr, int size, int timeout_ms) { int rr; prepare_nl_header(tl->nl_header, (char*)tl->tag_list_cpos - (char*)tl->nl_header); rr = send(sk_nl,tl->nl_header,tl->nl_header->nlmsg_len,0); if( rr != (ssize_t)tl->nl_header->nlmsg_len) { perror("send() failed"); return -1; } rr = receive_reply_cn(sk_nl,tl,nl_hdr,size,timeout_ms); if( rr == -2) { fprintf(stderr,"No response from the DRBD driver!" " Is the module loaded?\n"); } return rr; } static void close_cn(int sk_nl) { close(sk_nl); } static int is_drbd_driver_missing(void) { struct stat sb; FILE *cn_idx_file; int err; cn_idx = CN_IDX_DRBD; cn_idx_file = fopen("/sys/module/drbd/parameters/cn_idx", "r"); if (cn_idx_file) { unsigned int idx; /* gcc is picky */ if (fscanf(cn_idx_file, "%u", &idx)) cn_idx = idx; fclose(cn_idx_file); } err = stat("/proc/drbd", &sb); if (!err) return 0; if (err == ENOENT) fprintf(stderr, "DRBD driver appears to be missing\n"); else fprintf(stderr, "Could not stat(\"/proc/drbd\"): %m\n"); return 1; } int main(int argc, char** argv) { unsigned minor; struct drbd_cmd *cmd; int rv=0; if (chdir("/")) { /* highly unlikely, but gcc is picky */ perror("cannot chdir /"); return -111; } cmdname = strrchr(argv[0],'/'); if (cmdname) argv[0] = ++cmdname; else cmdname = argv[0]; /* == '-' catches -h, --help, and similar */ if (argc > 1 && (!strcmp(argv[1],"help") || argv[1][0] == '-')) { if(argc >= 3) { cmd=find_cmd_by_name(argv[2]); if(cmd) print_command_usage(cmd-commands,NULL,FULL); else print_usage("unknown command"); exit(0); } } /* * The v83 drbdsetup takes the object to operate on as its first argument, * followed by the command. For forward compatibility, check if we got the * command name first. */ if (argc >= 3 && !find_cmd_by_name(argv[2]) && find_cmd_by_name(argv[1])) { char *swap = argv[1]; argv[1] = argv[2]; argv[2] = swap; } /* it is enough to set it, value is ignored */ if (getenv("DRBD_DEBUG_DUMP_ARGV")) debug_dump_argv = 1; resname = getenv("DRBD_RESOURCE"); if (argc > 1 && (!strcmp(argv[1],"xml"))) { if(argc >= 3) { cmd=find_cmd_by_name(argv[2]); if(cmd) print_command_usage(cmd-commands,NULL,XML); else print_usage("unknown command"); exit(0); } } if (argc < 3) print_usage(argc==1 ? 0 : " Insufficient arguments"); cmd=find_cmd_by_name(argv[2]); if (is_drbd_driver_missing()) { if (!strcmp(argv[2], "down") || !strcmp(argv[2], "secondary") || !strcmp(argv[2], "disconnect") || !strcmp(argv[2], "detach")) return 0; /* "down" succeeds even if drbd is missing */ fprintf(stderr, "do you need to load the module?\n" "try: modprobe drbd\n"); return 20; } if(cmd) { minor = dt_minor_of_dev(argv[1]); if (minor < 0) { fprintf(stderr, "Cannot determine minor device number of " "drbd device '%s'", argv[1]); exit(20); } lock_fd = dt_lock_drbd(minor); /* maybe rather canonicalize, using asprintf? */ devname = argv[1]; // by passing argc-2, argv+2 the function has the command name // in argv[0], e.g. "syncer" rv = cmd->function(cmd,minor,argc-2,argv+2); dt_unlock_drbd(lock_fd); } else { print_usage("invalid command"); } return rv; } drbd-utils-8.9.6/user/v83/linux/0000755000175000017500000000000012654475367016263 5ustar apoikosapoikosdrbd-utils-8.9.6/user/v83/linux/drbd_nl.h0000644000175000017500000001173012466702074020027 0ustar apoikosapoikos/* PAKET( name, TYPE ( pn, pr, member ) ... ) You may never reissue one of the pn arguments */ #if !defined(NL_PACKET) || !defined(NL_STRING) || !defined(NL_INTEGER) || !defined(NL_BIT) || !defined(NL_INT64) #error "The macros NL_PACKET, NL_STRING, NL_INTEGER, NL_INT64 and NL_BIT needs to be defined" #endif NL_PACKET(primary, 1, NL_BIT( 1, T_MAY_IGNORE, primary_force) ) NL_PACKET(secondary, 2, ) NL_PACKET(disk_conf, 3, NL_INT64( 2, T_MAY_IGNORE, disk_size) NL_STRING( 3, T_MANDATORY, backing_dev, 128) NL_STRING( 4, T_MANDATORY, meta_dev, 128) NL_INTEGER( 5, T_MANDATORY, meta_dev_idx) NL_INTEGER( 6, T_MAY_IGNORE, on_io_error) NL_INTEGER( 7, T_MAY_IGNORE, fencing) NL_BIT( 37, T_MAY_IGNORE, use_bmbv) NL_BIT( 53, T_MAY_IGNORE, no_disk_flush) NL_BIT( 54, T_MAY_IGNORE, no_md_flush) /* 55 max_bio_size was available in 8.2.6rc2 */ NL_INTEGER( 56, T_MAY_IGNORE, max_bio_bvecs) NL_BIT( 57, T_MAY_IGNORE, no_disk_barrier) NL_BIT( 58, T_MAY_IGNORE, no_disk_drain) NL_INTEGER( 89, T_MAY_IGNORE, disk_timeout) ) NL_PACKET(detach, 4, NL_BIT( 88, T_MANDATORY, detach_force) ) NL_PACKET(net_conf, 5, NL_STRING( 8, T_MANDATORY, my_addr, 128) NL_STRING( 9, T_MANDATORY, peer_addr, 128) NL_STRING( 10, T_MAY_IGNORE, shared_secret, SHARED_SECRET_MAX) NL_STRING( 11, T_MAY_IGNORE, cram_hmac_alg, SHARED_SECRET_MAX) NL_STRING( 44, T_MAY_IGNORE, integrity_alg, SHARED_SECRET_MAX) NL_INTEGER( 14, T_MAY_IGNORE, timeout) NL_INTEGER( 15, T_MANDATORY, wire_protocol) NL_INTEGER( 16, T_MAY_IGNORE, try_connect_int) NL_INTEGER( 17, T_MAY_IGNORE, ping_int) NL_INTEGER( 18, T_MAY_IGNORE, max_epoch_size) NL_INTEGER( 19, T_MAY_IGNORE, max_buffers) NL_INTEGER( 20, T_MAY_IGNORE, unplug_watermark) NL_INTEGER( 21, T_MAY_IGNORE, sndbuf_size) NL_INTEGER( 22, T_MAY_IGNORE, ko_count) NL_INTEGER( 24, T_MAY_IGNORE, after_sb_0p) NL_INTEGER( 25, T_MAY_IGNORE, after_sb_1p) NL_INTEGER( 26, T_MAY_IGNORE, after_sb_2p) NL_INTEGER( 39, T_MAY_IGNORE, rr_conflict) NL_INTEGER( 40, T_MAY_IGNORE, ping_timeo) NL_INTEGER( 67, T_MAY_IGNORE, rcvbuf_size) NL_INTEGER( 81, T_MAY_IGNORE, on_congestion) NL_INTEGER( 82, T_MAY_IGNORE, cong_fill) NL_INTEGER( 83, T_MAY_IGNORE, cong_extents) /* 59 addr_family was available in GIT, never released */ NL_BIT( 60, T_MANDATORY, mind_af) NL_BIT( 27, T_MAY_IGNORE, want_lose) NL_BIT( 28, T_MAY_IGNORE, two_primaries) NL_BIT( 41, T_MAY_IGNORE, always_asbp) NL_BIT( 61, T_MAY_IGNORE, no_cork) NL_BIT( 62, T_MANDATORY, auto_sndbuf_size) NL_BIT( 70, T_MANDATORY, dry_run) ) NL_PACKET(disconnect, 6, NL_BIT( 84, T_MAY_IGNORE, force) ) NL_PACKET(resize, 7, NL_INT64( 29, T_MAY_IGNORE, resize_size) NL_BIT( 68, T_MAY_IGNORE, resize_force) NL_BIT( 69, T_MANDATORY, no_resync) ) NL_PACKET(syncer_conf, 8, NL_INTEGER( 30, T_MAY_IGNORE, rate) NL_INTEGER( 31, T_MAY_IGNORE, after) NL_INTEGER( 32, T_MAY_IGNORE, al_extents) /* NL_INTEGER( 71, T_MAY_IGNORE, dp_volume) */ /* NL_INTEGER( 72, T_MAY_IGNORE, dp_interval) */ /* NL_INTEGER( 73, T_MAY_IGNORE, throttle_th) removed */ /* NL_INTEGER( 74, T_MAY_IGNORE, hold_off_th) removed */ NL_STRING( 52, T_MAY_IGNORE, verify_alg, SHARED_SECRET_MAX) NL_STRING( 51, T_MAY_IGNORE, cpu_mask, 32) NL_STRING( 64, T_MAY_IGNORE, csums_alg, SHARED_SECRET_MAX) NL_BIT( 65, T_MAY_IGNORE, use_rle) NL_INTEGER( 75, T_MAY_IGNORE, on_no_data) NL_INTEGER( 76, T_MAY_IGNORE, c_plan_ahead) NL_INTEGER( 77, T_MAY_IGNORE, c_delay_target) NL_INTEGER( 78, T_MAY_IGNORE, c_fill_target) NL_INTEGER( 79, T_MAY_IGNORE, c_max_rate) NL_INTEGER( 80, T_MAY_IGNORE, c_min_rate) ) NL_PACKET(invalidate, 9, ) NL_PACKET(invalidate_peer, 10, ) NL_PACKET(pause_sync, 11, ) NL_PACKET(resume_sync, 12, ) NL_PACKET(suspend_io, 13, ) NL_PACKET(resume_io, 14, ) NL_PACKET(outdate, 15, ) NL_PACKET(get_config, 16, ) NL_PACKET(get_state, 17, NL_INTEGER( 33, T_MAY_IGNORE, state_i) ) NL_PACKET(get_uuids, 18, NL_STRING( 34, T_MAY_IGNORE, uuids, (UI_SIZE*sizeof(__u64))) NL_INTEGER( 35, T_MAY_IGNORE, uuids_flags) ) NL_PACKET(get_timeout_flag, 19, NL_BIT( 36, T_MAY_IGNORE, use_degraded) ) NL_PACKET(call_helper, 20, NL_STRING( 38, T_MAY_IGNORE, helper, 32) ) /* Tag nr 42 already allocated in drbd-8.1 development. */ NL_PACKET(sync_progress, 23, NL_INTEGER( 43, T_MAY_IGNORE, sync_progress) ) NL_PACKET(dump_ee, 24, NL_STRING( 45, T_MAY_IGNORE, dump_ee_reason, 32) NL_STRING( 46, T_MAY_IGNORE, seen_digest, SHARED_SECRET_MAX) NL_STRING( 47, T_MAY_IGNORE, calc_digest, SHARED_SECRET_MAX) NL_INT64( 48, T_MAY_IGNORE, ee_sector) NL_INT64( 49, T_MAY_IGNORE, ee_block_id) NL_STRING( 50, T_MAY_IGNORE, ee_data, 32 << 10) ) NL_PACKET(start_ov, 25, NL_INT64( 66, T_MAY_IGNORE, start_sector) NL_INT64( 90, T_MANDATORY, stop_sector) ) NL_PACKET(new_c_uuid, 26, NL_BIT( 63, T_MANDATORY, clear_bm) ) #ifdef NL_RESPONSE NL_RESPONSE(return_code_only, 27) #endif #undef NL_PACKET #undef NL_INTEGER #undef NL_INT64 #undef NL_BIT #undef NL_STRING #undef NL_RESPONSE drbd-utils-8.9.6/user/v83/linux/drbd_tag_magic.h0000644000175000017500000000540512466702074021333 0ustar apoikosapoikos#ifndef DRBD_TAG_MAGIC_H #define DRBD_TAG_MAGIC_H #define TT_END 0 #define TT_REMOVED 0xE000 /* declare packet_type enums */ enum packet_types { #define NL_PACKET(name, number, fields) P_ ## name = number, #define NL_RESPONSE(name, number) P_ ## name = number, #define NL_INTEGER(pn, pr, member) #define NL_INT64(pn, pr, member) #define NL_BIT(pn, pr, member) #define NL_STRING(pn, pr, member, len) #include "drbd_nl.h" P_nl_after_last_packet, }; /* These struct are used to deduce the size of the tag lists: */ #define NL_PACKET(name, number, fields) \ struct name ## _tag_len_struct { fields }; #define NL_INTEGER(pn, pr, member) \ int member; int tag_and_len ## member; #define NL_INT64(pn, pr, member) \ __u64 member; int tag_and_len ## member; #define NL_BIT(pn, pr, member) \ unsigned char member:1; int tag_and_len ## member; #define NL_STRING(pn, pr, member, len) \ unsigned char member[len]; int member ## _len; \ int tag_and_len ## member; #include "drbd_nl.h" /* declare tag-list-sizes */ static const int tag_list_sizes[] = { #define NL_PACKET(name, number, fields) 2 fields , #define NL_INTEGER(pn, pr, member) + 4 + 4 #define NL_INT64(pn, pr, member) + 4 + 8 #define NL_BIT(pn, pr, member) + 4 + 1 #define NL_STRING(pn, pr, member, len) + 4 + (len) #include "drbd_nl.h" }; /* The two highest bits are used for the tag type */ #define TT_MASK 0xC000 #define TT_INTEGER 0x0000 #define TT_INT64 0x4000 #define TT_BIT 0x8000 #define TT_STRING 0xC000 /* The next bit indicates if processing of the tag is mandatory */ #define T_MANDATORY 0x2000 #define T_MAY_IGNORE 0x0000 #define TN_MASK 0x1fff /* The remaining 13 bits are used to enumerate the tags */ #define tag_type(T) ((T) & TT_MASK) #define tag_number(T) ((T) & TN_MASK) /* declare tag enums */ #define NL_PACKET(name, number, fields) fields enum drbd_tags { #define NL_INTEGER(pn, pr, member) T_ ## member = pn | TT_INTEGER | pr , #define NL_INT64(pn, pr, member) T_ ## member = pn | TT_INT64 | pr , #define NL_BIT(pn, pr, member) T_ ## member = pn | TT_BIT | pr , #define NL_STRING(pn, pr, member, len) T_ ## member = pn | TT_STRING | pr , #include "drbd_nl.h" }; struct tag { const char *name; int type_n_flags; int max_len; }; /* declare tag names */ #define NL_PACKET(name, number, fields) fields static const struct tag tag_descriptions[] = { #define NL_INTEGER(pn, pr, member) [ pn ] = { #member, TT_INTEGER | pr, sizeof(int) }, #define NL_INT64(pn, pr, member) [ pn ] = { #member, TT_INT64 | pr, sizeof(__u64) }, #define NL_BIT(pn, pr, member) [ pn ] = { #member, TT_BIT | pr, sizeof(int) }, #define NL_STRING(pn, pr, member, len) [ pn ] = { #member, TT_STRING | pr, (len) }, #include "drbd_nl.h" }; #endif drbd-utils-8.9.6/user/v83/linux/drbd.h0000644000175000017500000002454712466702074017350 0ustar apoikosapoikos/* drbd.h Kernel module for 2.6.x Kernels This file is part of DRBD by Philipp Reisner and Lars Ellenberg. Copyright (C) 2001-2008, LINBIT Information Technologies GmbH. Copyright (C) 2001-2008, Philipp Reisner . Copyright (C) 2001-2008, Lars Ellenberg . drbd is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. drbd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with drbd; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef DRBD_H #define DRBD_H #include #include #ifdef __KERNEL__ #include #include #else #include #include #include /* Altough the Linux source code makes a difference between generic endianness and the bitfields' endianness, there is no architecture as of Linux-2.6.24-rc4 where the bitfileds' endianness does not match the generic endianness. */ #if __BYTE_ORDER == __LITTLE_ENDIAN #define __LITTLE_ENDIAN_BITFIELD #elif __BYTE_ORDER == __BIG_ENDIAN #define __BIG_ENDIAN_BITFIELD #else # error "sorry, weird endianness on this box" #endif #endif enum drbd_io_error_p { EP_PASS_ON, /* FIXME should the better be named "Ignore"? */ EP_CALL_HELPER, EP_DETACH }; enum drbd_fencing_p { FP_DONT_CARE, FP_RESOURCE, FP_STONITH }; enum drbd_disconnect_p { DP_RECONNECT, DP_DROP_NET_CONF, DP_FREEZE_IO }; enum drbd_after_sb_p { ASB_DISCONNECT, ASB_DISCARD_YOUNGER_PRI, ASB_DISCARD_OLDER_PRI, ASB_DISCARD_ZERO_CHG, ASB_DISCARD_LEAST_CHG, ASB_DISCARD_LOCAL, ASB_DISCARD_REMOTE, ASB_CONSENSUS, ASB_DISCARD_SECONDARY, ASB_CALL_HELPER, ASB_VIOLENTLY }; enum drbd_on_no_data { OND_IO_ERROR, OND_SUSPEND_IO }; enum drbd_on_congestion { OC_BLOCK, OC_PULL_AHEAD, OC_DISCONNECT, }; /* KEEP the order, do not delete or insert. Only append. */ enum drbd_ret_code { ERR_CODE_BASE = 100, NO_ERROR = 101, ERR_LOCAL_ADDR = 102, ERR_PEER_ADDR = 103, ERR_OPEN_DISK = 104, ERR_OPEN_MD_DISK = 105, ERR_DISK_NOT_BDEV = 107, ERR_MD_NOT_BDEV = 108, ERR_DISK_TOO_SMALL = 111, ERR_MD_DISK_TOO_SMALL = 112, ERR_BDCLAIM_DISK = 114, ERR_BDCLAIM_MD_DISK = 115, ERR_MD_IDX_INVALID = 116, ERR_IO_MD_DISK = 118, ERR_MD_INVALID = 119, ERR_AUTH_ALG = 120, ERR_AUTH_ALG_ND = 121, ERR_NOMEM = 122, ERR_DISCARD_IMPOSSIBLE = 123, ERR_DISK_CONFIGURED = 124, ERR_NET_CONFIGURED = 125, ERR_MANDATORY_TAG = 126, ERR_MINOR_INVALID = 127, ERR_INTR = 129, /* EINTR */ ERR_RESIZE_RESYNC = 130, ERR_NO_PRIMARY = 131, ERR_SYNC_AFTER = 132, ERR_SYNC_AFTER_CYCLE = 133, ERR_PAUSE_IS_SET = 134, ERR_PAUSE_IS_CLEAR = 135, ERR_PACKET_NR = 137, ERR_NO_DISK = 138, ERR_NOT_PROTO_C = 139, ERR_NOMEM_BITMAP = 140, ERR_INTEGRITY_ALG = 141, /* DRBD 8.2 only */ ERR_INTEGRITY_ALG_ND = 142, /* DRBD 8.2 only */ ERR_CPU_MASK_PARSE = 143, /* DRBD 8.2 only */ ERR_CSUMS_ALG = 144, /* DRBD 8.2 only */ ERR_CSUMS_ALG_ND = 145, /* DRBD 8.2 only */ ERR_VERIFY_ALG = 146, /* DRBD 8.2 only */ ERR_VERIFY_ALG_ND = 147, /* DRBD 8.2 only */ ERR_CSUMS_RESYNC_RUNNING= 148, /* DRBD 8.2 only */ ERR_VERIFY_RUNNING = 149, /* DRBD 8.2 only */ ERR_DATA_NOT_CURRENT = 150, ERR_CONNECTED = 151, /* DRBD 8.3 only */ ERR_PERM = 152, ERR_NEED_APV_93 = 153, ERR_STONITH_AND_PROT_A = 154, ERR_CONG_NOT_PROTO_A = 155, ERR_PIC_AFTER_DEP = 156, ERR_PIC_PEER_DEP = 157, /* insert new ones above this line */ AFTER_LAST_ERR_CODE }; #define DRBD_PROT_A 1 #define DRBD_PROT_B 2 #define DRBD_PROT_C 3 enum drbd_role { R_UNKNOWN = 0, R_PRIMARY = 1, /* role */ R_SECONDARY = 2, /* role */ R_MASK = 3, }; /* The order of these constants is important. * The lower ones (=C_WF_REPORT_PARAMS ==> There is a socket */ enum drbd_conns { C_STANDALONE, C_DISCONNECTING, /* Temporal state on the way to StandAlone. */ C_UNCONNECTED, /* >= C_UNCONNECTED -> inc_net() succeeds */ /* These temporal states are all used on the way * from >= C_CONNECTED to Unconnected. * The 'disconnect reason' states * I do not allow to change beween them. */ C_TIMEOUT, C_BROKEN_PIPE, C_NETWORK_FAILURE, C_PROTOCOL_ERROR, C_TEAR_DOWN, C_WF_CONNECTION, C_WF_REPORT_PARAMS, /* we have a socket */ C_CONNECTED, /* we have introduced each other */ C_STARTING_SYNC_S, /* starting full sync by admin request. */ C_STARTING_SYNC_T, /* stariing full sync by admin request. */ C_WF_BITMAP_S, C_WF_BITMAP_T, C_WF_SYNC_UUID, /* All SyncStates are tested with this comparison * xx >= C_SYNC_SOURCE && xx <= C_PAUSED_SYNC_T */ C_SYNC_SOURCE, C_SYNC_TARGET, C_VERIFY_S, C_VERIFY_T, C_PAUSED_SYNC_S, C_PAUSED_SYNC_T, C_AHEAD, C_BEHIND, C_MASK = 31 }; enum drbd_disk_state { D_DISKLESS, D_ATTACHING, /* In the process of reading the meta-data */ D_FAILED, /* Becomes D_DISKLESS as soon as we told it the peer */ /* when >= D_FAILED it is legal to access mdev->bc */ D_NEGOTIATING, /* Late attaching state, we need to talk to the peer */ D_INCONSISTENT, D_OUTDATED, D_UNKNOWN, /* Only used for the peer, never for myself */ D_CONSISTENT, /* Might be D_OUTDATED, might be D_UP_TO_DATE ... */ D_UP_TO_DATE, /* Only this disk state allows applications' IO ! */ D_MASK = 15 }; union drbd_state { /* According to gcc's docs is the ... * The order of allocation of bit-fields within a unit (C90 6.5.2.1, C99 6.7.2.1). * Determined by ABI. * pointed out by Maxim Uvarov q * even though we transmit as "cpu_to_be32(state)", * the offsets of the bitfields still need to be swapped * on different endianess. */ struct { #if defined(__LITTLE_ENDIAN_BITFIELD) unsigned role:2 ; /* 3/4 primary/secondary/unknown */ unsigned peer:2 ; /* 3/4 primary/secondary/unknown */ unsigned conn:5 ; /* 17/32 cstates */ unsigned disk:4 ; /* 8/16 from D_DISKLESS to D_UP_TO_DATE */ unsigned pdsk:4 ; /* 8/16 from D_DISKLESS to D_UP_TO_DATE */ unsigned susp:1 ; /* 2/2 IO suspended no/yes (by user) */ unsigned aftr_isp:1 ; /* isp .. imposed sync pause */ unsigned peer_isp:1 ; unsigned user_isp:1 ; unsigned susp_nod:1 ; /* IO suspended because no data */ unsigned susp_fen:1 ; /* IO suspended because fence peer handler runs*/ unsigned _pad:9; /* 0 unused */ #elif defined(__BIG_ENDIAN_BITFIELD) unsigned _pad:9; unsigned susp_fen:1 ; unsigned susp_nod:1 ; unsigned user_isp:1 ; unsigned peer_isp:1 ; unsigned aftr_isp:1 ; /* isp .. imposed sync pause */ unsigned susp:1 ; /* 2/2 IO suspended no/yes */ unsigned pdsk:4 ; /* 8/16 from D_DISKLESS to D_UP_TO_DATE */ unsigned disk:4 ; /* 8/16 from D_DISKLESS to D_UP_TO_DATE */ unsigned conn:5 ; /* 17/32 cstates */ unsigned peer:2 ; /* 3/4 primary/secondary/unknown */ unsigned role:2 ; /* 3/4 primary/secondary/unknown */ #else # error "this endianess is not supported" #endif #ifndef DRBD_DEBUG_STATE_CHANGES # ifdef CONFIG_DYNAMIC_DEBUG # define DRBD_DEBUG_STATE_CHANGES 1 # else # define DRBD_DEBUG_STATE_CHANGES 0 # endif #endif #if DRBD_DEBUG_STATE_CHANGES unsigned int line; const char *func; unsigned long long seq; #endif }; unsigned int i; }; enum drbd_state_rv { SS_CW_NO_NEED = 4, SS_CW_SUCCESS = 3, SS_NOTHING_TO_DO = 2, SS_SUCCESS = 1, SS_UNKNOWN_ERROR = 0, /* Used to sleep longer in _drbd_request_state */ SS_TWO_PRIMARIES = -1, SS_NO_UP_TO_DATE_DISK = -2, SS_NO_LOCAL_DISK = -4, SS_NO_REMOTE_DISK = -5, SS_CONNECTED_OUTDATES = -6, SS_PRIMARY_NOP = -7, SS_RESYNC_RUNNING = -8, SS_ALREADY_STANDALONE = -9, SS_CW_FAILED_BY_PEER = -10, SS_IS_DISKLESS = -11, SS_DEVICE_IN_USE = -12, SS_NO_NET_CONFIG = -13, SS_NO_VERIFY_ALG = -14, /* drbd-8.2 only */ SS_NEED_CONNECTION = -15, /* drbd-8.2 only */ SS_LOWER_THAN_OUTDATED = -16, SS_NOT_SUPPORTED = -17, /* drbd-8.2 only */ SS_IN_TRANSIENT_STATE = -18, /* Retry after the next state change */ SS_CONCURRENT_ST_CHG = -19, /* Concurrent cluster side state change! */ SS_AFTER_LAST_ERROR = -20, /* Keep this at bottom */ }; /* from drbd_strings.c */ extern const char *drbd_conn_str(enum drbd_conns); extern const char *drbd_role_str(enum drbd_role); extern const char *drbd_disk_str(enum drbd_disk_state); extern const char *drbd_set_st_err_str(enum drbd_state_rv); #define SHARED_SECRET_MAX 64 #define MDF_CONSISTENT (1 << 0) #define MDF_PRIMARY_IND (1 << 1) #define MDF_CONNECTED_IND (1 << 2) #define MDF_FULL_SYNC (1 << 3) #define MDF_WAS_UP_TO_DATE (1 << 4) #define MDF_PEER_OUT_DATED (1 << 5) #define MDF_CRASHED_PRIMARY (1 << 6) enum drbd_uuid_index { UI_CURRENT, UI_BITMAP, UI_HISTORY_START, UI_HISTORY_END, UI_SIZE, /* nl-packet: number of dirty bits */ UI_FLAGS, /* nl-packet: flags */ UI_EXTENDED_SIZE /* Everything. */ }; enum drbd_timeout_flag { UT_DEFAULT = 0, UT_DEGRADED = 1, UT_PEER_OUTDATED = 2, }; #define UUID_JUST_CREATED ((__u64)4) #define DRBD_MAGIC 0x83740267 #define BE_DRBD_MAGIC __constant_cpu_to_be32(DRBD_MAGIC) #define DRBD_MAGIC_BIG 0x835a #define BE_DRBD_MAGIC_BIG __constant_cpu_to_be16(DRBD_MAGIC_BIG) /* these are of type "int" */ #define DRBD_MD_INDEX_INTERNAL -1 #define DRBD_MD_INDEX_FLEX_EXT -2 #define DRBD_MD_INDEX_FLEX_INT -3 /* Start of the new netlink/connector stuff */ #define DRBD_NL_CREATE_DEVICE 0x01 #define DRBD_NL_SET_DEFAULTS 0x02 /* The following line should be moved over to linux/connector.h * when the time comes */ #ifndef CN_IDX_DRBD # define CN_IDX_DRBD 0x4 /* Ubuntu "intrepid ibex" release defined CN_IDX_DRBD as 0x6 */ #endif #define CN_VAL_DRBD 0x1 /* For searching a vacant cn_idx value */ #define CN_IDX_STEP 6977 struct drbd_nl_cfg_req { int packet_type; unsigned int drbd_minor; int flags; unsigned short tag_list[]; }; struct drbd_nl_cfg_reply { int packet_type; unsigned int minor; /* FIXME: This is super ugly. */ int ret_code; /* enum drbd_ret_code or enum drbd_state_rv */ unsigned short tag_list[]; /* only used with get_* calls */ }; #endif drbd-utils-8.9.6/user/v83/linux/drbd_limits.h0000644000175000017500000001210512466702074020714 0ustar apoikosapoikos/* drbd_limits.h This file is part of DRBD by Philipp Reisner and Lars Ellenberg. */ /* * Our current limitations. * Some of them are hard limits, * some of them are arbitrary range limits, that make it easier to provide * feedback about nonsense settings for certain configurable values. */ #ifndef DRBD_LIMITS_H #define DRBD_LIMITS_H 1 #define DEBUG_RANGE_CHECK 0 #define DRBD_MINOR_COUNT_MIN 1 #define DRBD_MINOR_COUNT_MAX 256 #define DRBD_MINOR_COUNT_DEF 32 #define DRBD_DIALOG_REFRESH_MIN 0 #define DRBD_DIALOG_REFRESH_MAX 600 /* valid port number */ #define DRBD_PORT_MIN 1 #define DRBD_PORT_MAX 0xffff /* startup { */ /* if you want more than 3.4 days, disable */ #define DRBD_WFC_TIMEOUT_MIN 0 #define DRBD_WFC_TIMEOUT_MAX 300000 #define DRBD_WFC_TIMEOUT_DEF 0 #define DRBD_DEGR_WFC_TIMEOUT_MIN 0 #define DRBD_DEGR_WFC_TIMEOUT_MAX 300000 #define DRBD_DEGR_WFC_TIMEOUT_DEF 0 #define DRBD_OUTDATED_WFC_TIMEOUT_MIN 0 #define DRBD_OUTDATED_WFC_TIMEOUT_MAX 300000 #define DRBD_OUTDATED_WFC_TIMEOUT_DEF 0 /* }*/ /* net { */ /* timeout, unit centi seconds * more than one minute timeout is not usefull */ #define DRBD_TIMEOUT_MIN 1 #define DRBD_TIMEOUT_MAX 600 #define DRBD_TIMEOUT_DEF 60 /* 6 seconds */ /* If backing disk takes longer than disk_timeout, mark the disk as failed */ #define DRBD_DISK_TIMEOUT_MIN 0 /* 0 = disabled */ #define DRBD_DISK_TIMEOUT_MAX 6000 /* 10 Minutes */ #define DRBD_DISK_TIMEOUT_DEF 0 /* disabled */ /* active connection retries when C_WF_CONNECTION */ #define DRBD_CONNECT_INT_MIN 1 #define DRBD_CONNECT_INT_MAX 120 #define DRBD_CONNECT_INT_DEF 10 /* seconds */ /* keep-alive probes when idle */ #define DRBD_PING_INT_MIN 1 #define DRBD_PING_INT_MAX 120 #define DRBD_PING_INT_DEF 10 /* timeout for the ping packets.*/ #define DRBD_PING_TIMEO_MIN 1 #define DRBD_PING_TIMEO_MAX 100 #define DRBD_PING_TIMEO_DEF 5 /* max number of write requests between write barriers */ #define DRBD_MAX_EPOCH_SIZE_MIN 1 #define DRBD_MAX_EPOCH_SIZE_MAX 20000 #define DRBD_MAX_EPOCH_SIZE_DEF 2048 /* I don't think that a tcp send buffer of more than 10M is usefull */ #define DRBD_SNDBUF_SIZE_MIN 0 #define DRBD_SNDBUF_SIZE_MAX (10<<20) #define DRBD_SNDBUF_SIZE_DEF 0 #define DRBD_RCVBUF_SIZE_MIN 0 #define DRBD_RCVBUF_SIZE_MAX (10<<20) #define DRBD_RCVBUF_SIZE_DEF 0 /* @4k PageSize -> 128kB - 512MB */ #define DRBD_MAX_BUFFERS_MIN 32 #define DRBD_MAX_BUFFERS_MAX 131072 #define DRBD_MAX_BUFFERS_DEF 2048 /* @4k PageSize -> 4kB - 512MB */ #define DRBD_UNPLUG_WATERMARK_MIN 1 #define DRBD_UNPLUG_WATERMARK_MAX 131072 #define DRBD_UNPLUG_WATERMARK_DEF (DRBD_MAX_BUFFERS_DEF/16) /* 0 is disabled. * 200 should be more than enough even for very short timeouts */ #define DRBD_KO_COUNT_MIN 0 #define DRBD_KO_COUNT_MAX 200 #define DRBD_KO_COUNT_DEF 0 /* } */ /* syncer { */ /* FIXME allow rate to be zero? */ #define DRBD_RATE_MIN 1 /* channel bonding 10 GbE, or other hardware */ #define DRBD_RATE_MAX (4 << 20) #define DRBD_RATE_DEF 250 /* kb/second */ /* less than 7 would hit performance unneccessarily. * 3833 is the largest prime that still does fit * into 64 sectors of activity log */ #define DRBD_AL_EXTENTS_MIN 7 #define DRBD_AL_EXTENTS_MAX 3833 #define DRBD_AL_EXTENTS_DEF 127 #define DRBD_AFTER_MIN -1 #define DRBD_AFTER_MAX 255 #define DRBD_AFTER_DEF -1 /* } */ /* drbdsetup XY resize -d Z * you are free to reduce the device size to nothing, if you want to. * the upper limit with 64bit kernel, enough ram and flexible meta data * is 16 TB, currently. */ /* DRBD_MAX_SECTORS */ #define DRBD_DISK_SIZE_SECT_MIN 0 #define DRBD_DISK_SIZE_SECT_MAX (16 * (2LLU << 30)) #define DRBD_DISK_SIZE_SECT_DEF 0 /* = disabled = no user size... */ #define DRBD_ON_IO_ERROR_DEF EP_PASS_ON #define DRBD_FENCING_DEF FP_DONT_CARE #define DRBD_AFTER_SB_0P_DEF ASB_DISCONNECT #define DRBD_AFTER_SB_1P_DEF ASB_DISCONNECT #define DRBD_AFTER_SB_2P_DEF ASB_DISCONNECT #define DRBD_RR_CONFLICT_DEF ASB_DISCONNECT #define DRBD_ON_NO_DATA_DEF OND_IO_ERROR #define DRBD_ON_CONGESTION_DEF OC_BLOCK #define DRBD_MAX_BIO_BVECS_MIN 0 #define DRBD_MAX_BIO_BVECS_MAX 128 #define DRBD_MAX_BIO_BVECS_DEF 0 #define DRBD_C_PLAN_AHEAD_MIN 0 #define DRBD_C_PLAN_AHEAD_MAX 300 #define DRBD_C_PLAN_AHEAD_DEF 0 /* RS rate controller disabled by default */ #define DRBD_C_DELAY_TARGET_MIN 1 #define DRBD_C_DELAY_TARGET_MAX 100 #define DRBD_C_DELAY_TARGET_DEF 10 #define DRBD_C_FILL_TARGET_MIN 0 #define DRBD_C_FILL_TARGET_MAX (1<<20) /* 500MByte in sec */ #define DRBD_C_FILL_TARGET_DEF 0 /* By default disabled -> controlled by delay_target */ #define DRBD_C_MAX_RATE_MIN 250 /* kByte/sec */ #define DRBD_C_MAX_RATE_MAX (4 << 20) #define DRBD_C_MAX_RATE_DEF 102400 #define DRBD_C_MIN_RATE_MIN 0 /* kByte/sec */ #define DRBD_C_MIN_RATE_MAX (4 << 20) #define DRBD_C_MIN_RATE_DEF 4096 #define DRBD_CONG_FILL_MIN 0 #define DRBD_CONG_FILL_MAX (10<<21) /* 10GByte in sectors */ #define DRBD_CONG_FILL_DEF 0 #define DRBD_CONG_EXTENTS_MIN DRBD_AL_EXTENTS_MIN #define DRBD_CONG_EXTENTS_MAX DRBD_AL_EXTENTS_MAX #define DRBD_CONG_EXTENTS_DEF DRBD_AL_EXTENTS_DEF #endif drbd-utils-8.9.6/user/v83/linux/drbd_config.h0000644000175000017500000000153212466702074020662 0ustar apoikosapoikos/* drbd_config.h DRBD's compile time configuration. drbd is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. drbd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with drbd; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef DRBD_LEGACY_83_CONFIG_H #define DRBD_LEGACY_83_CONFIG_H extern const char *drbd_buildtag(void); #define API_VERSION 88 #endif drbd-utils-8.9.6/user/v83/drbdadm_parser.h0000644000175000017500000000606012466702074020235 0ustar apoikosapoikos/* drbdadm_parser.h a hand crafted parser This file is part of DRBD by Philipp Reisner and Lars Ellenberg. Copyright (C) 2006-2008, LINBIT Information Technologies GmbH Copyright (C) 2006-2008, Philipp Reisner Copyright (C) 2006-2008, Lars Ellenberg drbd is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. drbd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with drbd; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ enum range_checks { R_NO_CHECK, R_MINOR_COUNT, R_DIALOG_REFRESH, R_DISK_SIZE, R_TIMEOUT, R_CONNECT_INT, R_PING_INT, R_MAX_BUFFERS, R_MAX_EPOCH_SIZE, R_SNDBUF_SIZE, R_RCVBUF_SIZE, R_KO_COUNT, R_RATE, R_GROUP, R_AL_EXTENTS, R_PORT, R_META_IDX, R_WFC_TIMEOUT, R_DEGR_WFC_TIMEOUT, R_OUTDATED_WFC_TIMEOUT, R_C_PLAN_AHEAD, R_C_DELAY_TARGET, R_C_FILL_TARGET, R_C_MAX_RATE, R_C_MIN_RATE, R_CONG_FILL, R_CONG_EXTENTS, }; enum yytokentype { TK_GLOBAL = 258, TK_RESOURCE, TK_ON, TK_STACKED, TK_IGNORE, TK_NET, TK_DISK, TK_SKIP, TK_SYNCER, TK_STARTUP, TK_DISABLE_IP_VERIFICATION, TK_DIALOG_REFRESH, TK_PROTOCOL, TK_HANDLER, TK_COMMON, TK_ADDRESS, TK_DEVICE, TK_MINOR, TK_META_DISK, TK_FLEX_META_DISK, TK_MINOR_COUNT, TK_IPADDR, TK_INTEGER, TK_STRING, TK_ELSE, TK_DISK_SWITCH, TK_DISK_OPTION, TK_NET_SWITCH, TK_NET_OPTION, TK_SYNCER_SWITCH, TK_SYNCER_OPTION, TK_STARTUP_SWITCH, TK_STARTUP_OPTION, TK_STARTUP_DELEGATE, TK_HANDLER_OPTION, TK_USAGE_COUNT, TK_ASK, TK_YES, TK_NO, TK__IS_DEFAULT, TK__THIS_HOST, TK__REMOTE_HOST, TK_PROXY, TK_INSIDE, TK_OUTSIDE, TK_MEMLIMIT, TK_PROXY_OPTION, TK_PROXY_SWITCH, TK_PROXY_DELEGATE, TK_ERR_STRING_TOO_LONG, TK_ERR_DQSTRING_TOO_LONG, TK_ERR_DQSTRING, TK_SCI, TK_SDP, TK_SSOCKS, TK_IPV4, TK_IPV6, TK_IPADDR6, TK_NET_DELEGATE, TK_INCLUDE, TK_FLOATING, TK_DEPRECATED_OPTION, TK__GROUPING_BASE = 0x1000, TK_PROXY_GROUP = 0x2000, /* Gets or'ed to some options */ }; /* The higher bits define one or more token groups. */ #define GET_TOKEN_GROUP(__x) ((__x) & ~(TK__GROUPING_BASE - 1)) #define REMOVE_GROUP_FROM_TOKEN(__x) ((__x) & (TK__GROUPING_BASE - 1)) typedef struct YYSTYPE { char* txt; enum range_checks rc; } YYSTYPE; #define yystype YYSTYPE /* obsolescent; will be withdrawn */ #define YYSTYPE_IS_DECLARED 1 #define YYSTYPE_IS_TRIVIAL 1 extern yystype yylval; extern char* yytext; extern FILE* yyin; /* avoid compiler warnings about implicit declaration */ int yylex(void); void my_yypush_buffer_state(FILE *f); void yypop_buffer_state (void ); void yyrestart(FILE *input_file); drbd-utils-8.9.6/user/v83/drbdadm_scanner.fl0000644000175000017500000002045212466702074020545 0ustar apoikosapoikos%{ #include #include #include #include "drbdadm_parser.h" #include "drbdadm.h" #include "drbdtool_common.h" void long_string(char* text); void long_dqstring(char* text); void err_dqstring(char* text); #if 0 #define DP printf("'%s' ",yytext) #else #define DP #endif #define CP yylval.txt = strdup(yytext); yylval.rc = R_NO_CHECK #define RC(N) yylval.rc = R_ ## N #define YY_NO_INPUT 1 #define YY_NO_UNPUT 1 static void yyunput (int c, register char * yy_bp ) __attribute((unused)); #ifndef YY_FLEX_SUBMINOR_VERSION #define MAX_INCLUDE_DEPTH 10 YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH]; int include_stack_ptr = 0; #endif %} %option noyywrap NUM [0-9]{1,8}[MKGs]? SNUMB [0-9]{1,3} IPV4ADDR ({SNUMB}"."){3}{SNUMB} HEX4 [0-9a-fA-F]{1,4} IPV6ADDR ((({HEX4}":"){0,5}{HEX4})?":"{HEX4}?":"({HEX4}(":"{HEX4}){0,5})?("%"{STRING})?)|("::"[fF]{4}":"{IPV4ADDR}) WS [ \t\r] OPCHAR [{};\[\]:] DQSTRING \"([^\"\\\n]|\\[^\n]){0,255}\" LONG_DQSTRING \"([^\"\\\n]|\\[^\n]){255}. ERR_DQSTRING \"([^\"\\\n]|\\[^\n]){0,255}[\\\n] STRING [a-zA-Z0-9/._-]{1,80} LONG_STRING [a-zA-Z0-9/._-]{81} %% \n { line++; } \#.* /* ignore comments */ {WS} /* ignore whitespaces */ {OPCHAR} { DP; return yytext[0]; } on { DP; return TK_ON; } ignore-on { DP; return TK_IGNORE; } stacked-on-top-of { DP; return TK_STACKED; } floating { DP; return TK_FLOATING; } no { DP; return TK_NO; } net { DP; return TK_NET; } yes { DP; return TK_YES; } ask { DP; return TK_ASK; } skip { DP; return TK_SKIP; } disk { DP; return TK_DISK; } proxy { DP; return TK_PROXY; } minor { DP; return TK_MINOR; } inside { DP; return TK_INSIDE; } syncer { DP; return TK_SYNCER; } device { DP; return TK_DEVICE; } global { DP; return TK_GLOBAL; } common { DP; return TK_COMMON; } outside { DP; return TK_OUTSIDE; } address { DP; return TK_ADDRESS; } startup { DP; return TK_STARTUP; } include { DP; return TK_INCLUDE; } handlers { DP; return TK_HANDLER; } protocol { DP; return TK_PROTOCOL; } minor-count { DP; return TK_MINOR_COUNT; } disable-ip-verification { DP; return TK_DISABLE_IP_VERIFICATION;} dialog-refresh { DP; return TK_DIALOG_REFRESH; } resource { DP; return TK_RESOURCE; } meta-disk { DP; return TK_META_DISK; } flexible-meta-disk { DP; return TK_FLEX_META_DISK; } usage-count { DP; return TK_USAGE_COUNT; } _is_default { DP; return TK__IS_DEFAULT; } _this_host { DP; return TK__THIS_HOST; } _remote_host { DP; return TK__REMOTE_HOST; } sci { DP; CP; return TK_SCI; } ssocks { DP; CP; return TK_SSOCKS; } sdp { DP; CP; return TK_SDP; } ipv4 { DP; CP; return TK_IPV4; } ipv6 { DP; CP; return TK_IPV6; } size { DP; CP; RC(DISK_SIZE); return TK_DISK_OPTION; } on-io-error { DP; CP; return TK_DISK_OPTION; } fencing { DP; CP; return TK_DISK_OPTION; } max-bio-bvecs { DP; CP; return TK_DISK_OPTION; } disk-timeout { DP; CP; return TK_DISK_OPTION; } use-bmbv { DP; CP; return TK_DISK_SWITCH; } no-disk-barrier { DP; CP; return TK_DISK_SWITCH; } no-disk-flushes { DP; CP; return TK_DISK_SWITCH; } no-disk-drain { DP; CP; return TK_DISK_SWITCH; } no-md-flushes { DP; CP; return TK_DISK_SWITCH; } timeout { DP; CP; RC(TIMEOUT); return TK_NET_OPTION; } ko-count { DP; CP; RC(KO_COUNT); return TK_NET_OPTION; } ping-int { DP; CP; RC(PING_INT); return TK_NET_OPTION; } max-buffers { DP; CP; RC(MAX_BUFFERS); return TK_NET_OPTION;} sndbuf-size { DP; CP; RC(SNDBUF_SIZE); return TK_NET_OPTION | TK_PROXY_GROUP;} rcvbuf-size { DP; CP; RC(RCVBUF_SIZE); return TK_NET_OPTION | TK_PROXY_GROUP;} connect-int { DP; CP; RC(CONNECT_INT); return TK_NET_OPTION;} cram-hmac-alg { DP; CP; return TK_NET_OPTION; } shared-secret { DP; CP; return TK_NET_OPTION; } max-epoch-size { DP; CP; RC(MAX_EPOCH_SIZE); return TK_NET_OPTION;} after-sb-[012]pri { DP; CP; return TK_NET_OPTION; } rr-conflict { DP; CP; return TK_NET_OPTION; } ping-timeout { DP; CP; return TK_NET_OPTION | TK_PROXY_GROUP;} unplug-watermark { DP; CP; return TK_NET_OPTION; } data-integrity-alg { DP; CP; return TK_NET_OPTION; } on-congestion { DP; CP; return TK_NET_OPTION; } congestion-fill { DP; CP; RC(CONG_FILL); return TK_NET_OPTION; } congestion-extents { DP; CP; RC(CONG_EXTENTS); return TK_NET_OPTION;} allow-two-primaries { DP; CP; return TK_NET_SWITCH; } always-asbp { DP; CP; return TK_NET_SWITCH; } no-tcp-cork { DP; CP; return TK_NET_SWITCH; } discard-my-data { DP; CP; return TK_NET_DELEGATE; } rate { DP; CP; RC(RATE); return TK_SYNCER_OPTION; } after { DP; CP; return TK_SYNCER_OPTION; } verify-alg { DP; CP; return TK_SYNCER_OPTION; } csums-alg { DP; CP; return TK_SYNCER_OPTION; } al-extents { DP; CP; RC(AL_EXTENTS); return TK_SYNCER_OPTION;} cpu-mask { DP; CP; return TK_SYNCER_OPTION; } use-rle { DP; CP; return TK_SYNCER_SWITCH; } delay-probe-volume { DP; CP; return TK_DEPRECATED_OPTION; } delay-probe-interval { DP; CP; return TK_DEPRECATED_OPTION; } c-plan-ahead { DP; CP; RC(C_PLAN_AHEAD); return TK_SYNCER_OPTION; } c-delay-target { DP; CP; RC(C_DELAY_TARGET); return TK_SYNCER_OPTION; } c-fill-target { DP; CP; RC(C_FILL_TARGET); return TK_SYNCER_OPTION; } c-max-rate { DP; CP; RC(C_MAX_RATE); return TK_SYNCER_OPTION; } c-min-rate { DP; CP; RC(C_MIN_RATE); return TK_SYNCER_OPTION; } throttle-threshold { DP; CP; return TK_DEPRECATED_OPTION; } hold-off-threshold { DP; CP; return TK_DEPRECATED_OPTION; } on-no-data-accessible { DP; CP; return TK_SYNCER_OPTION; } wfc-timeout { DP; CP; RC(WFC_TIMEOUT); return TK_STARTUP_OPTION;} degr-wfc-timeout { DP; CP; RC(DEGR_WFC_TIMEOUT); return TK_STARTUP_OPTION;} outdated-wfc-timeout { DP; CP; RC(OUTDATED_WFC_TIMEOUT); return TK_STARTUP_OPTION;} stacked-timeouts { DP; return TK_STARTUP_DELEGATE; } become-primary-on { DP; return TK_STARTUP_DELEGATE; } wait-after-sb { DP; CP; return TK_STARTUP_SWITCH; } pri-on-incon-degr { DP; CP; return TK_HANDLER_OPTION; } pri-lost-after-sb { DP; CP; return TK_HANDLER_OPTION; } pri-lost { DP; CP; return TK_HANDLER_OPTION; } initial-split-brain { DP; CP; return TK_HANDLER_OPTION; } split-brain { DP; CP; return TK_HANDLER_OPTION; } outdate-peer { DP; CP; return TK_HANDLER_OPTION; } fence-peer { DP; CP; return TK_HANDLER_OPTION; } local-io-error { DP; CP; return TK_HANDLER_OPTION; } before-resync-target { DP; CP; return TK_HANDLER_OPTION; } after-resync-target { DP; CP; return TK_HANDLER_OPTION; } before-resync-source { DP; CP; return TK_HANDLER_OPTION; } memlimit { DP; CP; return TK_PROXY_OPTION | TK_PROXY_GROUP; } read-loops { DP; CP; return TK_PROXY_OPTION | TK_PROXY_GROUP; } compression { DP; CP; return TK_PROXY_OPTION | TK_PROXY_GROUP; } plugin { DP; CP; return TK_PROXY_DELEGATE; } out-of-sync { DP; CP; return TK_HANDLER_OPTION; } {IPV4ADDR} { DP; CP; return TK_IPADDR; } {IPV6ADDR} { DP; CP; return TK_IPADDR6; } {NUM} { DP; CP; return TK_INTEGER; } {DQSTRING} { unescape(yytext); DP; CP; return TK_STRING; } {STRING} { DP; CP; return TK_STRING; } {LONG_STRING} { return TK_ERR_STRING_TOO_LONG; } {LONG_DQSTRING} { return TK_ERR_DQSTRING_TOO_LONG; } {ERR_DQSTRING} { return TK_ERR_DQSTRING; } . { DP; return TK_ELSE; } %% /* Compatibility cruft for flex version 2.5.4a */ #ifndef YY_FLEX_SUBMINOR_VERSION /** Pushes the new state onto the stack. The new state becomes * the current state. This function will allocate the stack * if necessary. * @param new_buffer The new state. * */ void yypush_buffer_state (YY_BUFFER_STATE new_buffer ) { if (new_buffer == NULL) return; if ( include_stack_ptr >= MAX_INCLUDE_DEPTH ) { fprintf( stderr, "Includes nested too deeply" ); exit( 1 ); } include_stack[include_stack_ptr++] = YY_CURRENT_BUFFER; yy_switch_to_buffer(new_buffer); BEGIN(INITIAL); } /** Removes and deletes the top of the stack, if present. * The next element becomes the new top. * */ void yypop_buffer_state (void) { if (!YY_CURRENT_BUFFER) return; if ( --include_stack_ptr < 0 ) { fprintf( stderr, "error in flex compat code\n" ); exit( 1 ); } yy_delete_buffer(YY_CURRENT_BUFFER ); yy_switch_to_buffer(include_stack[include_stack_ptr]); } #endif void my_yypush_buffer_state(FILE *f) { /* Since we do not have YY_BUF_SIZE outside of the flex generated file.*/ yypush_buffer_state(yy_create_buffer(f, YY_BUF_SIZE)); } drbd-utils-8.9.6/user/v83/drbdadm_adjust.c0000644000175000017500000003247612466702074020240 0ustar apoikosapoikos/* drbdadm_adjust.c This file is part of DRBD by Philipp Reisner and Lars Ellenberg. Copyright (C) 2003-2008, LINBIT Information Technologies GmbH. Copyright (C) 2003-2008, Philipp Reisner . Copyright (C) 2003-2008, Lars Ellenberg . drbd is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. drbd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with drbd; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include "drbdadm.h" #include "drbdtool_common.h" #include "drbdadm_parser.h" /* drbdsetup show might complain that the device minor does not exist at all. Redirect stderr to /dev/null therefore. */ static FILE *m_popen(int *pid,char** argv) { int mpid; int pipes[2]; int dev_null; if(pipe(pipes)) { perror("Creation of pipes failed"); exit(E_EXEC_ERROR); } dev_null = open("/dev/null", O_WRONLY); if (dev_null == -1) { perror("Opening /dev/null failed"); exit(E_EXEC_ERROR); } mpid = fork(); if(mpid == -1) { fprintf(stderr,"Can not fork"); exit(E_EXEC_ERROR); } if(mpid == 0) { close(pipes[0]); // close reading end dup2(pipes[1], fileno(stdout)); close(pipes[1]); dup2(dev_null, fileno(stderr)); close(dev_null); execvp(argv[0],argv); fprintf(stderr,"Can not exec"); exit(E_EXEC_ERROR); } close(pipes[1]); // close writing end close(dev_null); *pid=mpid; return fdopen(pipes[0],"r"); } /* option value equal? */ static int ov_eq(char* val1, char* val2) { unsigned long long v1,v2; if(val1 == NULL && val2 == NULL) return 1; if(val1 == NULL || val2 == NULL) return 0; if(new_strtoll(val1,0,&v1) == MSE_OK && new_strtoll(val2,0,&v2) == MSE_OK) return v1 == v2; return !strcmp(val1,val2); } static int opts_equal(struct d_option* conf, struct d_option* running) { struct d_option* opt; while(running) { if((opt=find_opt(conf,running->name))) { if(!ov_eq(running->value,opt->value)) { /* printf("Value of '%s' differs: r=%s c=%s\n", opt->name,running->value,opt->value); */ return 0; } opt->mentioned=1; } else { if(!running->is_default) { /*printf("Only in running config %s: %s\n", running->name,running->value);*/ return 0; } } running=running->next; } while(conf) { if(conf->mentioned==0) { /*printf("Only in config file %s: %s\n", conf->name,conf->value);*/ return 0; } conf=conf->next; } return 1; } static int addr_equal(struct d_resource* conf, struct d_resource* running) { int equal; if (conf->peer == NULL && running->peer == NULL) return 1; if (running->peer == NULL) return 0; equal = !strcmp(conf->me->address, running->me->address) && !strcmp(conf->me->port, running->me->port) && !strcmp(conf->me->address_family, running->me->address_family); if(conf->me->proxy) equal = equal && !strcmp(conf->me->proxy->inside_addr, running->peer->address) && !strcmp(conf->me->proxy->inside_port, running->peer->port) && !strcmp(conf->me->proxy->inside_af, running->peer->address_family); else equal = equal && conf->peer && !strcmp(conf->peer->address, running->peer->address) && !strcmp(conf->peer->port, running->peer->port) && !strcmp(conf->peer->address_family, running->peer->address_family); return equal; } static int proto_equal(struct d_resource* conf, struct d_resource* running) { if (conf->protocol == NULL && running->protocol == NULL) return 1; if (conf->protocol == NULL || running->protocol == NULL) return 0; return !strcmp(conf->protocol, running->protocol); } /* Are both internal, or are both not internal. */ static int int_eq(char* m_conf, char* m_running) { return !strcmp(m_conf,"internal") == !strcmp(m_running,"internal"); } static int disk_equal(struct d_host_info* conf, struct d_host_info* running) { int eq = 1; if (conf->disk == NULL && running->disk == NULL) return 1; if (conf->disk == NULL || running->disk == NULL) return 0; eq &= !strcmp(conf->disk,running->disk); eq &= int_eq(conf->meta_disk,running->meta_disk); if(!strcmp(conf->meta_disk,"internal")) return eq; eq &= !strcmp(conf->meta_disk,running->meta_disk); return eq; } /* NULL terminated */ static void find_option_in_resources(char *name, struct d_option *list, struct d_option **opt, ...) { va_list va; va_start(va, opt); /* We need to keep setting *opt to NULL, even if a list == NULL. */ while (list || opt) { while (list) { if (strcmp(list->name, name) == 0) break; list = list->next; } *opt = list; list = va_arg(va, struct d_option*); opt = va_arg(va, struct d_option**); } } static int do_proxy_reconf(struct d_resource *res, const char *cmd) { int rv; char *argv[4] = { drbd_proxy_ctl, "-c", (char*)cmd, NULL }; rv = m_system_ex(argv, SLEEPS_SHORT, res->name); return rv; } #define MAX_PLUGINS (10) #define MAX_PLUGIN_NAME (16) /* The new name is appended to the alist. */ int _is_plugin_in_list(char *string, char slist[MAX_PLUGINS][MAX_PLUGIN_NAME], char alist[MAX_PLUGINS][MAX_PLUGIN_NAME], int list_len) { int word_len, i; char *copy; for(word_len=0; string[word_len]; word_len++) if (isspace(string[word_len])) break; if (word_len+1 >= MAX_PLUGIN_NAME) { fprintf(stderr, "Wrong proxy plugin name %*.*s", word_len, word_len, string); exit(E_CONFIG_INVALID); } copy = alist[list_len]; strncpy(copy, string, word_len); copy[word_len] = 0; for(i=0; i= MAX_PLUGINS) { fprintf(stderr, "Too many proxy plugins."); exit(E_CONFIG_INVALID); } return 0; } static int proxy_reconf(struct d_resource *res, struct d_resource *running) { int reconn = 0; struct d_option* res_o, *run_o; unsigned long long v1, v2, minimum; char *plugin_changes[MAX_PLUGINS], *cp, *conn_name; /* It's less memory usage when we're storing char[]. malloc overhead for * the few bytes + pointers is much more. */ char p_res[MAX_PLUGINS][MAX_PLUGIN_NAME], p_run[MAX_PLUGINS][MAX_PLUGIN_NAME]; int used, i, re_do; reconn = 0; find_option_in_resources("memlimit", res->proxy_options, &res_o, running->proxy_options, &run_o, NULL, NULL); v1 = res_o ? m_strtoll(res_o->value, 1) : 0; v2 = run_o ? m_strtoll(run_o->value, 1) : 0; minimum = v1 < v2 ? v1 : v2; /* We allow an Ñ” [epsilon] of 2%, so that small (rounding) deviations do * not cause the connection to be re-established. */ if (res_o && (!run_o || abs(v1-v2)/(float)minimum > 0.02)) { redo_whole_conn: /* As the memory is in use while the connection is allocated we have to * completely destroy and rebuild the connection. */ schedule_dcmd( do_proxy_conn_down, res, NULL, 0); schedule_dcmd( do_proxy_conn_up, res, NULL, 1); schedule_dcmd( do_proxy_conn_plugins, res, NULL, 2); /* With connection cleanup and reopen everything is rebuild anyway, and * DRBD will get a reconnect too. */ return 0; } res_o = res->proxy_plugins; run_o = running->proxy_plugins; used = 0; conn_name = proxy_connection_name(res); for(i=0; i= sizeof(plugin_changes)-1) { fprintf(stderr, "Too many proxy plugin changes"); exit(E_CONFIG_INVALID); } /* Now we can be sure that we can store another pointer. */ if (!res_o) { if (run_o) { /* More plugins running than configured - just stop here. */ m_asprintf(&cp, "set plugin %s %d end", conn_name, i); plugin_changes[used++] = cp; } else { /* Both at the end? ok, quit loop */ } break; } /* res_o != NULL. */ if (!run_o) { p_run[i][0] = 0; if (_is_plugin_in_list(res_o->name, p_run, p_res, i)) { /* Current plugin was already active, just at another position. * Redo the whole connection. */ goto redo_whole_conn; } /* More configured than running - just add it, if it's not already * somewhere else. */ m_asprintf(&cp, "set plugin %s %d %s", conn_name, i, res_o->name); plugin_changes[used++] = cp; } else { /* If we get here, both lists have been filled in parallel, so we * can simply use the common counter. */ re_do = _is_plugin_in_list(res_o->name, p_run, p_res, i) || _is_plugin_in_list(run_o->name, p_res, p_run, i); if (re_do) { /* Plugin(s) were moved, not simple reconfigured. * Re-do the whole connection. */ goto redo_whole_conn; } /* TODO: We don't (yet) account for possible different ordering of * the parameters to the plugin. * plugin A 1 B 2 * should be treated as equal to * plugin B 2 A 1. */ if (strcmp(run_o->name, res_o->name) != 0) { /* Either a different plugin, or just different settings * - plugin can be overwritten. */ m_asprintf(&cp, "set plugin %s %d %s", conn_name, i, res_o->name); plugin_changes[used++] = cp; } } if (res_o) res_o = res_o->next; if (run_o) run_o = run_o->next; } /* change only a few plugin settings. */ for(i=0; iname); err = stat("/dev/drbd/by-res", &sbuf); if (err) /* probably no udev rules in use */ return 0; err = stat(link_name, &sbuf); if (err) /* resource link cannot be stat()ed. */ return 1; /* double check device information */ if (!S_ISBLK(sbuf.st_mode)) return 1; if (major(sbuf.st_rdev) != DRBD_MAJOR) return 1; if (minor(sbuf.st_rdev) != res->me->device_minor) return 1; /* Link exists, and is expected block major:minor. * Do nothing. */ return 0; } /* * CAUTION this modifies global static char * config_file! */ int adm_adjust(struct d_resource* res,char* unused __attribute((unused))) { char* argv[20]; int pid,argc, i; struct d_resource* running; int do_attach=0,do_connect=0,do_syncer=0; int have_disk=0,have_net=0,can_do_proxy=1; char config_file_dummy[250], *conn_name, show_conn[128]; /* disable check_uniq, so it won't interfere * with parsing of drbdsetup show output */ config_valid = 2; /* setup error reporting context for the parsing routines */ line = 1; sprintf(config_file_dummy,"drbdsetup %u show", res->me->device_minor); config_file = config_file_dummy; argc=0; argv[argc++]=drbdsetup; argv[argc++]=res->me->device; argv[argc++]="show"; argv[argc++]=0; /* actually parse drbdsetup show output */ yyin = m_popen(&pid,argv); running = parse_resource(res->name, IgnDiscardMyData); fclose(yyin); waitpid(pid,0,0); /* Sets "me" and "peer" pointer */ post_parse(running, 0); set_peer_in_resource(running, 0); /* Parse proxy settings, if this host has a proxy definition */ if (res->me->proxy) { line = 1; conn_name = proxy_connection_name(res); i=snprintf(show_conn, sizeof(show_conn), "show proxy-settings %s", conn_name); if (i>= sizeof(show_conn)-1) { fprintf(stderr,"connection name too long"); exit(E_THINKO); } sprintf(config_file_dummy,"drbd-proxy-ctl -c '%s'", show_conn); config_file = config_file_dummy; argc=0; argv[argc++]=drbd_proxy_ctl; argv[argc++]="-c"; argv[argc++]=show_conn; argv[argc++]=0; /* actually parse "drbd-proxy-ctl show" output */ yyin = m_popen(&pid,argv); can_do_proxy = !parse_proxy_settings(running, PARSER_CHECK_PROXY_KEYWORD | PARSER_STOP_IF_INVALID); fclose(yyin); waitpid(pid,0,0); } do_attach = !opts_equal(res->disk_options, running->disk_options); if(running->me) { do_attach |= (res->me->device_minor != running->me->device_minor); do_attach |= !disk_equal(res->me, running->me); have_disk = (running->me->disk != NULL); } else do_attach |= 1; do_connect = !opts_equal(res->net_options, running->net_options); do_connect |= !addr_equal(res,running); do_connect |= !proto_equal(res,running); /* No adjust support for drbd proxy version 1. */ if (res->me->proxy && can_do_proxy) do_connect |= proxy_reconf(res,running); have_net = (running->protocol != NULL); do_syncer = !opts_equal(res->sync_options, running->sync_options); /* Special case: nothing changed, but the resource name. * Trigger a no-op syncer request, which will cause a KOBJ_CHANGE * to be broadcast, so udev may pick up the resource name change * and update its symlinks. */ if (!(do_attach || do_syncer || do_connect)) do_syncer = need_trigger_kobj_change(running); if(do_attach) { if(have_disk) schedule_dcmd(adm_generic_s,res,"detach",0); schedule_dcmd(adm_attach,res,"attach",0); } if(do_syncer) schedule_dcmd(adm_syncer,res,"syncer",1); if(do_connect) { if (have_net && res->peer) schedule_dcmd(adm_generic_s,res,"disconnect",0); schedule_dcmd(adm_connect,res,"connect",2); } return 0; } drbd-utils-8.9.6/user/v83/drbdadm_main.c0000644000175000017500000023200612523133457017656 0ustar apoikosapoikos/* drbdadm_main.c This file is part of DRBD by Philipp Reisner and Lars Ellenberg. Copyright (C) 2002-2008, LINBIT Information Technologies GmbH. Copyright (C) 2002-2008, Philipp Reisner . Copyright (C) 2002-2008, Lars Ellenberg . drbd is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. drbd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with drbd; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "linux/drbd_limits.h" #include "drbdtool_common.h" #include "drbdadm.h" #include "shared_main.h" #define MAX_ARGS 40 static int indent = 0; #define INDENT_WIDTH 4 #define BFMT "%s;\n" #define IPV4FMT "%-16s %s %s:%s;\n" #define IPV6FMT "%-16s %s [%s]:%s;\n" #define MDISK "%-16s %s [%s];\n" #define FMDISK "%-16s %s;\n" #define printI(fmt, args... ) printf("%*s" fmt,INDENT_WIDTH * indent,"" , ## args ) #define printA(name, val ) \ printf("%*s%*s %3s;\n", \ INDENT_WIDTH * indent,"" , \ -24+INDENT_WIDTH * indent, \ name, val ) char *progname; struct adm_cmd { const char *name; int (*function) (struct d_resource *, const char *); /* which level this command is for. * 0: don't show this command, ever * 1: normal administrative commands, shown in normal help * 2-4: shown on "drbdadm hidden-commands" * 2: useful for shell scripts * 3: callbacks potentially called from kernel module on certain events * 4: advanced, experts and developers only */ unsigned int show_in_usage:3; /* if set, command requires an explicit resource name */ unsigned int res_name_required:1; /* error out if the ip specified is not available/active now */ unsigned int verify_ips:1; /* if set, use the "cache" in /var/lib/drbd to figure out * which config file to use. * This is necessary for handlers (callbacks from kernel) to work * when using "drbdadm -c /some/other/config/file" */ unsigned int use_cached_config_file:1; unsigned int need_peer:1; unsigned int is_proxy_cmd:1; unsigned int uc_dialog:1; /* May show usage count dialog */ unsigned int test_config:1; /* Allow -t option */ }; struct deferred_cmd { int (*function) (struct d_resource *, const char *); const char *arg; struct d_resource *res; struct deferred_cmd *next; }; struct option admopt[] = { {"stacked", no_argument, 0, 'S'}, {"dry-run", no_argument, 0, 'd'}, {"verbose", no_argument, 0, 'v'}, {"config-file", required_argument, 0, 'c'}, {"config-to-test", required_argument, 0, 't'}, {"drbdsetup", required_argument, 0, 's'}, {"drbdmeta", required_argument, 0, 'm'}, {"drbd-proxy-ctl", required_argument, 0, 'p'}, {"sh-varname", required_argument, 0, 'n'}, {"force", no_argument, 0, 'f'}, {"peer", required_argument, 0, 'P'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0} }; extern void my_parse(); extern int yydebug; extern FILE *yyin; int adm_attach(struct d_resource *, const char *); int adm_connect(struct d_resource *, const char *); int adm_generic_s(struct d_resource *, const char *); int adm_status_xml(struct d_resource *, const char *); int adm_generic_l(struct d_resource *, const char *); int adm_resize(struct d_resource *, const char *); int adm_syncer(struct d_resource *, const char *); static int adm_up(struct d_resource *, const char *); extern int adm_adjust(struct d_resource *, const char *); static int adm_dump(struct d_resource *, const char *); static int adm_dump_xml(struct d_resource *, const char *); static int adm_wait_c(struct d_resource *, const char *); static int adm_wait_ci(struct d_resource *, const char *); static int adm_proxy_up(struct d_resource *, const char *); static int adm_proxy_down(struct d_resource *, const char *); static int sh_nop(struct d_resource *, const char *); static int sh_resources(struct d_resource *, const char *); static int sh_resource(struct d_resource *, const char *); static int sh_mod_parms(struct d_resource *, const char *); static int sh_dev(struct d_resource *, const char *); static int sh_udev(struct d_resource *, const char *); static int sh_minor(struct d_resource *, const char *); static int sh_ip(struct d_resource *, const char *); static int sh_lres(struct d_resource *, const char *); static int sh_ll_dev(struct d_resource *, const char *); static int sh_md_dev(struct d_resource *, const char *); static int sh_md_idx(struct d_resource *, const char *); static int sh_b_pri(struct d_resource *, const char *); static int sh_status(struct d_resource *, const char *); static int admm_generic(struct d_resource *, const char *); static int adm_khelper(struct d_resource *, const char *); static int adm_generic_b(struct d_resource *, const char *); static int hidden_cmds(struct d_resource *, const char *); static int adm_outdate(struct d_resource *, const char *); static int adm_chk_resize(struct d_resource *res, const char *cmd); static void dump_options(char *name, struct d_option *opts); static char *get_opt_val(struct d_option *, const char *, char *); static void register_config_file(struct d_resource *res, const char *cfname); char ss_buffer[1024]; struct utsname nodeinfo; int line = 1; int fline; char *config_file = NULL; char *config_save = NULL; char *config_test = NULL; struct d_resource *config = NULL; struct d_resource *common = NULL; struct ifreq *ifreq_list = NULL; int is_drbd_top; int nr_resources; int nr_stacked; int nr_normal; int nr_ignore; int highest_minor; int config_from_stdin = 0; int config_valid = 1; int no_tty; int dry_run = 0; int verbose = 0; int adjust_with_progress = 0; int do_verify_ips = 0; int do_register_minor = 1; /* whether drbdadm was called with "all" instead of resource name(s) */ int all_resources = 0; char *drbdsetup = NULL; char *drbdmeta = NULL; char *drbd_proxy_ctl; char *sh_varname = NULL; char *setup_opts[10]; char *connect_to_host = NULL; int soi = 0; struct deferred_cmd *deferred_cmds[3] = { NULL, NULL, NULL }; struct deferred_cmd *deferred_cmds_tail[3] = { NULL, NULL, NULL }; /* DRBD adm_cmd flags shortcuts, * to avoid merge conflicts and unreadable diffs * when we add the next flag */ #define DRBD_acf1_default \ .show_in_usage = 1, \ .res_name_required = 1, \ .verify_ips = 0, \ .uc_dialog = 1, \ #define DRBD_acf1_connect \ .show_in_usage = 1, \ .res_name_required = 1, \ .verify_ips = 1, \ .need_peer = 1, \ .uc_dialog = 1, \ #define DRBD_acf1_defnet \ .show_in_usage = 1, \ .res_name_required = 1, \ .verify_ips = 1, \ .uc_dialog = 1, \ #define DRBD_acf3_handler \ .show_in_usage = 3, \ .res_name_required = 1, \ .verify_ips = 0, \ .use_cached_config_file = 1, \ #define DRBD_acf4_advanced \ .show_in_usage = 4, \ .res_name_required = 1, \ .verify_ips = 0, \ .uc_dialog = 1, \ #define DRBD_acf1_dump \ .show_in_usage = 1, \ .res_name_required = 1, \ .verify_ips = 1, \ .uc_dialog = 1, \ .test_config = 1, \ #define DRBD_acf2_shell \ .show_in_usage = 2, \ .res_name_required = 1, \ .verify_ips = 0, \ #define DRBD_acf2_proxy \ .show_in_usage = 2, \ .res_name_required = 1, \ .verify_ips = 0, \ .need_peer = 1, \ .is_proxy_cmd = 1, \ #define DRBD_acf2_hook \ .show_in_usage = 2, \ .res_name_required = 1, \ .verify_ips = 0, \ .use_cached_config_file = 1, \ #define DRBD_acf2_gen_shell \ .show_in_usage = 2, \ .res_name_required = 0, \ .verify_ips = 0, \ struct adm_cmd cmds[] = { /* name, function, flags * sort order: * - normal config commands, * - normal meta data manipulation * - sh-* * - handler * - advanced ***/ {"attach", adm_attach, DRBD_acf1_default}, {"detach", adm_generic_l, DRBD_acf1_default}, {"connect", adm_connect, DRBD_acf1_connect}, {"disconnect", adm_generic_s, DRBD_acf1_default}, {"up", adm_up, DRBD_acf1_connect}, {"down", adm_generic_l, DRBD_acf1_default}, {"primary", adm_generic_l, DRBD_acf1_default}, {"secondary", adm_generic_l, DRBD_acf1_default}, {"invalidate", adm_generic_b, DRBD_acf1_default}, {"invalidate-remote", adm_generic_l, DRBD_acf1_defnet}, {"outdate", adm_outdate, DRBD_acf1_default}, {"resize", adm_resize, DRBD_acf1_defnet}, {"syncer", adm_syncer, DRBD_acf1_defnet}, {"verify", adm_generic_s, DRBD_acf1_defnet}, {"pause-sync", adm_generic_s, DRBD_acf1_defnet}, {"resume-sync", adm_generic_s, DRBD_acf1_defnet}, {"adjust", adm_adjust, DRBD_acf1_connect}, {"wait-connect", adm_wait_c, DRBD_acf1_defnet}, {"wait-con-int", adm_wait_ci, .show_in_usage = 1,.verify_ips = 1,}, {"status", adm_status_xml, DRBD_acf2_gen_shell}, {"role", adm_generic_s, DRBD_acf1_default}, {"cstate", adm_generic_s, DRBD_acf1_default}, {"dstate", adm_generic_b, DRBD_acf1_default}, {"dump", adm_dump, DRBD_acf1_dump}, {"dump-xml", adm_dump_xml, DRBD_acf1_dump}, {"create-md", adm_create_md, DRBD_acf1_default}, {"show-gi", adm_generic_b, DRBD_acf1_default}, {"get-gi", adm_generic_b, DRBD_acf1_default}, {"dump-md", admm_generic, DRBD_acf1_default}, {"wipe-md", admm_generic, DRBD_acf1_default}, {"hidden-commands", hidden_cmds,.show_in_usage = 1,}, {"sh-nop", sh_nop, DRBD_acf2_gen_shell .uc_dialog = 1, .test_config = 1}, {"sh-resources", sh_resources, DRBD_acf2_gen_shell}, {"sh-resource", sh_resource, DRBD_acf2_shell}, {"sh-mod-parms", sh_mod_parms, DRBD_acf2_gen_shell}, {"sh-dev", sh_dev, DRBD_acf2_shell}, {"sh-udev", sh_udev, DRBD_acf2_hook}, {"sh-minor", sh_minor, DRBD_acf2_shell}, {"sh-ll-dev", sh_ll_dev, DRBD_acf2_shell}, {"sh-md-dev", sh_md_dev, DRBD_acf2_shell}, {"sh-md-idx", sh_md_idx, DRBD_acf2_shell}, {"sh-ip", sh_ip, DRBD_acf2_shell}, {"sh-lr-of", sh_lres, DRBD_acf2_shell}, {"sh-b-pri", sh_b_pri, DRBD_acf2_shell}, {"sh-status", sh_status, DRBD_acf2_gen_shell}, {"proxy-up", adm_proxy_up, DRBD_acf2_proxy}, {"proxy-down", adm_proxy_down, DRBD_acf2_proxy}, {"before-resync-target", adm_khelper, DRBD_acf3_handler}, {"after-resync-target", adm_khelper, DRBD_acf3_handler}, {"before-resync-source", adm_khelper, DRBD_acf3_handler}, {"pri-on-incon-degr", adm_khelper, DRBD_acf3_handler}, {"pri-lost-after-sb", adm_khelper, DRBD_acf3_handler}, {"fence-peer", adm_khelper, DRBD_acf3_handler}, {"local-io-error", adm_khelper, DRBD_acf3_handler}, {"pri-lost", adm_khelper, DRBD_acf3_handler}, {"initial-split-brain", adm_khelper, DRBD_acf3_handler}, {"split-brain", adm_khelper, DRBD_acf3_handler}, {"out-of-sync", adm_khelper, DRBD_acf3_handler}, {"suspend-io", adm_generic_s, DRBD_acf4_advanced}, {"resume-io", adm_generic_s, DRBD_acf4_advanced}, {"set-gi", admm_generic, DRBD_acf4_advanced}, {"new-current-uuid", adm_generic_s, DRBD_acf4_advanced}, {"check-resize", adm_chk_resize, DRBD_acf4_advanced}, }; void schedule_dcmd(int (*function) (struct d_resource *, const char *), struct d_resource *res, char *arg, int order) { struct deferred_cmd *d, *t; d = calloc(1, sizeof(struct deferred_cmd)); if (d == NULL) { perror("calloc"); exit(E_EXEC_ERROR); } d->function = function; d->res = res; d->arg = arg; /* first to come is head */ if (!deferred_cmds[order]) deferred_cmds[order] = d; /* link it in at tail */ t = deferred_cmds_tail[order]; if (t) t->next = d; /* advance tail */ deferred_cmds_tail[order] = d; } static void _adm_generic(struct d_resource *res, const char *cmd, int flags, pid_t *pid, int *fd, int *ex); /* Returns non-zero if the resource is down. */ static int test_if_resource_is_down(struct d_resource *res) { char buf[1024]; int rr, s = 0; int fd; pid_t pid; int old_verbose = verbose; if (dry_run) { fprintf(stderr, "Logic bug: should not be dry-running here.\n"); exit(E_THINKO); } if (verbose == 1) verbose = 0; _adm_generic(res, "role", SLEEPS_SHORT | RETURN_STDOUT_FD | SUPRESS_STDERR, &pid, &fd, NULL); verbose = old_verbose; if (fd < 0) { fprintf(stderr, "Strange: got negative fd.\n"); exit(E_THINKO); } while (1) { rr = read(fd, buf + s, sizeof(buf) - s); if (rr <= 0) break; s += rr; } close(fd); waitpid(pid, NULL, 0); /* Reap the child process, do not leave a zombie around. */ alarm(0); if (s == 0 || strncmp(buf, "Unconfigured", strlen("Unconfigured")) == 0) return 1; return 0; } enum do_register { SAME_ANYWAYS, DO_REGISTER }; enum do_register if_conf_differs_confirm_or_abort(struct d_resource *res) { int minor = res->me->device_minor; char *f; /* if the resource was down, * just register the new config file */ if (test_if_resource_is_down(res)) { unregister_minor(minor); return DO_REGISTER; } f = lookup_minor(minor); /* if there was nothing registered before, * there is nothing to compare to */ if (!f) return DO_REGISTER; /* no need to register the same thing again */ if (strcmp(f, config_save) == 0) return SAME_ANYWAYS; fprintf(stderr, "Warning: resource %s\n" "last used config file: %s\n" " current config file: %s\n", res->name, f, config_save); /* implicitly force if we don't have a tty */ if (no_tty) force = 1; if (!confirmed("Do you want to proceed " "and register the current config file?")) { printf("Operation canceled.\n"); exit(E_USAGE); } return DO_REGISTER; } static void register_config_file(struct d_resource *res, const char *cfname) { int minor = res->me->device_minor; if (test_if_resource_is_down(res)) unregister_minor(minor); else register_minor(minor, cfname); } enum on_error { KEEP_RUNNING, EXIT_ON_FAIL }; int call_cmd_fn(int (*function) (struct d_resource *, const char *), const char *fn_name, struct d_resource *res, enum on_error on_error) { int rv; int really_register = do_register_minor && DO_REGISTER == if_conf_differs_confirm_or_abort(res) && /* adm_up and adm_adjust only * "schedule" the commands, don't register yet! */ function != adm_up && function != adm_adjust; rv = function(res, fn_name); if (rv >= 20) { fprintf(stderr, "%s %s %s: exited with code %d\n", progname, fn_name, res->name, rv); if (on_error == EXIT_ON_FAIL) exit(rv); } if (rv == 0 && really_register) register_config_file(res, config_save); return rv; } int call_cmd(struct adm_cmd *cmd, struct d_resource *res, enum on_error on_error) { if (!res->peer) set_peer_in_resource(res, cmd->need_peer); return call_cmd_fn(cmd->function, cmd->name, res, on_error); } int _run_dcmds(int order) { struct deferred_cmd *d = deferred_cmds[order]; struct deferred_cmd *t; int r = 0; int rv = 0; while (d) { r = call_cmd_fn(d->function, d->arg, d->res, KEEP_RUNNING); t = d->next; free(d); d = t; if (r > rv) rv = r; } return rv; } int run_dcmds(void) { return _run_dcmds(0) || _run_dcmds(1) || _run_dcmds(2); } /*** These functions are used to the print the config ***/ static void dump_options2(char *name, struct d_option *opts, void(*within)(void*), void *ctx) { if (!opts && !(within && ctx)) return; printI("%s {\n", name); ++indent; while (opts) { if (opts->value) printA(opts->name, opts->is_escaped ? opts->value : esc(opts-> value)); else printI(BFMT, opts->name); opts = opts->next; } if (within) within(ctx); --indent; printI("}\n"); } static void dump_options(char *name, struct d_option *opts) { dump_options2(name, opts, NULL, NULL); } void dump_proxy_plugins(void *ctx) { struct d_option *opt = ctx; dump_options("plugin", opt); } static void dump_global_info() { if (!global_options.minor_count && !global_options.disable_ip_verification && global_options.dialog_refresh == 1) return; printI("global {\n"); ++indent; if (global_options.disable_ip_verification) printI("disable-ip-verification;\n"); if (global_options.minor_count) printI("minor-count %i;\n", global_options.minor_count); if (global_options.dialog_refresh != 1) printI("dialog-refresh %i;\n", global_options.dialog_refresh); --indent; printI("}\n\n"); } static void fake_startup_options(struct d_resource *res); static void dump_common_info() { if (!common) return; printI("common {\n"); ++indent; if (common->protocol) printA("protocol", common->protocol); fake_startup_options(common); dump_options("net", common->net_options); dump_options("disk", common->disk_options); dump_options("syncer", common->sync_options); dump_options("startup", common->startup_options); dump_options2("proxy", common->proxy_options, dump_proxy_plugins, common->proxy_plugins); dump_options("handlers", common->handlers); --indent; printf("}\n\n"); } static void dump_address(char *name, char *addr, char *port, char *af) { if (!strcmp(af, "ipv6")) printI(IPV6FMT, name, af, addr, port); else printI(IPV4FMT, name, af, addr, port); } static void dump_proxy_info(struct d_proxy_info *pi) { printI("proxy on %s {\n", names_to_str(pi->on_hosts)); ++indent; dump_address("inside", pi->inside_addr, pi->inside_port, pi->inside_af); dump_address("outside", pi->outside_addr, pi->outside_port, pi->outside_af); --indent; printI("}\n"); } static void dump_host_info(struct d_host_info *hi) { if (!hi) { printI(" # No host section data available.\n"); return; } if (hi->lower) { printI("stacked-on-top-of %s {\n", esc(hi->lower->name)); ++indent; printI("# on %s \n", names_to_str(hi->on_hosts)); } else if (hi->by_address) { if (!strcmp(hi->address_family, "ipv6")) printI("floating ipv6 [%s]:%s {\n", hi->address, hi->port); else printI("floating %s %s:%s {\n", hi->address_family, hi->address, hi->port); ++indent; } else { printI("on %s {\n", names_to_str(hi->on_hosts)); ++indent; } printI("device%*s", -19 + INDENT_WIDTH * indent, ""); if (hi->device) printf("%s ", esc(hi->device)); printf("minor %d;\n", hi->device_minor); if (!hi->lower) printA("disk", esc(hi->disk)); if (!hi->by_address) dump_address("address", hi->address, hi->port, hi->address_family); if (!hi->lower) { if (!strncmp(hi->meta_index, "flex", 4)) printI(FMDISK, "flexible-meta-disk", esc(hi->meta_disk)); else if (!strcmp(hi->meta_index, "internal")) printA("meta-disk", "internal"); else printI(MDISK, "meta-disk", esc(hi->meta_disk), hi->meta_index); } if (hi->proxy) dump_proxy_info(hi->proxy); --indent; printI("}\n"); } static void dump_options_xml2(char *name, struct d_option *opts, void(*within)(void*), void *ctx) { if (!opts && !(within && ctx)) return; printI("
\n", name); ++indent; while (opts) { if (opts->value) printI("
\n"); } static void dump_options_xml(char *name, struct d_option *opts) { dump_options_xml2(name, opts, NULL, NULL); } void dump_proxy_plugins_xml(void *ctx) { struct d_option *opt = ctx; dump_options_xml("plugin", opt); } static void dump_global_info_xml() { if (!global_options.minor_count && !global_options.disable_ip_verification && global_options.dialog_refresh == 1) return; printI("\n"); ++indent; if (global_options.disable_ip_verification) printI("\n"); if (global_options.minor_count) printI("\n", global_options.minor_count); if (global_options.dialog_refresh != 1) printI("\n", global_options.dialog_refresh); --indent; printI("\n"); } static void dump_common_info_xml() { if (!common) return; printI("protocol) printf(" protocol=\"%s\"", common->protocol); printf(">\n"); ++indent; fake_startup_options(common); dump_options_xml("net", common->net_options); dump_options_xml("disk", common->disk_options); dump_options_xml("syncer", common->sync_options); dump_options_xml("startup", common->startup_options); dump_options2("proxy", common->proxy_options, dump_proxy_plugins, common->proxy_plugins); dump_options_xml("handlers", common->handlers); --indent; printI("\n"); } static void dump_proxy_info_xml(struct d_proxy_info *pi) { printI("\n", names_to_str(pi->on_hosts)); ++indent; printI("%s\n", pi->inside_af, pi->inside_port, pi->inside_addr); printI("%s\n", pi->outside_af, pi->outside_port, pi->outside_addr); --indent; printI("\n"); } static void dump_host_info_xml(struct d_host_info *hi) { if (!hi) { printI("\n"); return; } if (hi->by_address) printI("\n"); else printI("\n", names_to_str(hi->on_hosts)); ++indent; printI("%s\n", hi->device_minor, esc_xml(hi->device)); printI("%s\n", esc_xml(hi->disk)); printI("
%s
\n", hi->address_family, hi->port, hi->address); if (!strncmp(hi->meta_index, "flex", 4)) printI("%s\n", esc_xml(hi->meta_disk)); else if (!strcmp(hi->meta_index, "internal")) printI("internal\n"); else { printI("%s\n", hi->meta_index, esc_xml(hi->meta_disk)); } if (hi->proxy) dump_proxy_info_xml(hi->proxy); --indent; printI("
\n"); } static void fake_startup_options(struct d_resource *res) { struct d_option *opt; char *val; if (res->stacked_timeouts) { opt = new_opt(strdup("stacked-timeouts"), NULL); res->startup_options = APPEND(res->startup_options, opt); } if (res->become_primary_on) { val = strdup(names_to_str(res->become_primary_on)); opt = new_opt(strdup("become-primary-on"), val); opt->is_escaped = 1; res->startup_options = APPEND(res->startup_options, opt); } } static int adm_dump(struct d_resource *res, const char *unused __attribute((unused))) { struct d_host_info *host; printI("# resource %s on %s: %s, %s\n", esc(res->name), nodeinfo.nodename, res->ignore ? "ignored" : "not ignored", res->stacked ? "stacked" : "not stacked"); printI("resource %s {\n", esc(res->name)); ++indent; if (res->protocol) printA("protocol", res->protocol); for (host = res->all_hosts; host; host = host->next) dump_host_info(host); fake_startup_options(res); dump_options("net", res->net_options); dump_options("disk", res->disk_options); dump_options("syncer", res->sync_options); dump_options("startup", res->startup_options); dump_options2("proxy", res->proxy_options, dump_proxy_plugins, res->proxy_plugins); dump_options("handlers", res->handlers); --indent; printf("}\n\n"); return 0; } static int adm_dump_xml(struct d_resource *res, const char *unused __attribute((unused))) { struct d_host_info *host; printI("name)); if (res->protocol) printf(" protocol=\"%s\"", res->protocol); printf(">\n"); ++indent; // else if (common && common->protocol) printA("# common protocol", common->protocol); for (host = res->all_hosts; host; host = host->next) dump_host_info_xml(host); fake_startup_options(res); dump_options_xml("net", res->net_options); dump_options_xml("disk", res->disk_options); dump_options_xml("syncer", res->sync_options); dump_options_xml("startup", res->startup_options); dump_options_xml2("proxy", res->proxy_options, dump_proxy_plugins_xml, res->proxy_plugins); dump_options_xml("handlers", res->handlers); --indent; printI("\n"); return 0; } static int sh_nop(struct d_resource *ignored __attribute((unused)), const char *unused __attribute((unused))) { return 0; } static int sh_resources(struct d_resource *ignored __attribute((unused)), const char *unused __attribute((unused))) { struct d_resource *res, *t; int first = 1; for_each_resource(res, t, config) { if (res->ignore) continue; if (is_drbd_top != res->stacked) continue; printf(first ? "%s" : " %s", esc(res->name)); first = 0; } if (!first) printf("\n"); return 0; } static int sh_resource(struct d_resource *res, const char *unused __attribute((unused))) { printf("%s\n", res->name); return 0; } static int sh_dev(struct d_resource *res, const char *unused __attribute((unused))) { printf("%s\n", res->me->device); return 0; } static int sh_udev(struct d_resource *res, const char *unused __attribute((unused))) { /* No shell escape necessary. Udev does not handle it anyways... */ printf("RESOURCE=%s\n", res->name); if (!strncmp(res->me->device, "/dev/drbd", 9)) printf("DEVICE=%s\n", res->me->device + 5); else printf("DEVICE=drbd%u\n", res->me->device_minor); if (!strncmp(res->me->disk, "/dev/", 5)) printf("DISK=%s\n", res->me->disk + 5); else printf("DISK=%s\n", res->me->disk); return 0; } static int sh_minor(struct d_resource *res, const char *unused __attribute((unused))) { printf("%d\n", res->me->device_minor); return 0; } static int sh_ip(struct d_resource *res, const char *unused __attribute((unused))) { printf("%s\n", res->me->address); return 0; } static int sh_lres(struct d_resource *res, const char *unused __attribute((unused))) { if (!is_drbd_top) { fprintf(stderr, "sh-lower-resource only available in stacked mode\n"); exit(E_USAGE); } if (!res->stacked) { fprintf(stderr, "'%s' is not stacked on this host (%s)\n", res->name, nodeinfo.nodename); exit(E_USAGE); } printf("%s\n", res->me->lower->name); return 0; } static int sh_ll_dev(struct d_resource *res, const char *unused __attribute((unused))) { printf("%s\n", res->me->disk); return 0; } static int sh_md_dev(struct d_resource *res, const char *unused __attribute((unused))) { char *r; if (strcmp("internal", res->me->meta_disk) == 0) r = res->me->disk; else r = res->me->meta_disk; printf("%s\n", r); return 0; } static int sh_md_idx(struct d_resource *res, const char *unused __attribute((unused))) { printf("%s\n", res->me->meta_index); return 0; } static int sh_b_pri(struct d_resource *res, const char *unused __attribute((unused))) { int i, rv; if (name_in_names(nodeinfo.nodename, res->become_primary_on) || name_in_names("both", res->become_primary_on)) { /* Opon connect resync starts, and both sides become primary at the same time. One's try might be declined since an other state transition happens. Retry. */ for (i = 0; i < 5; i++) { rv = adm_generic_s(res, "primary"); if (rv == 0) return rv; sleep(1); } return rv; } return 0; } static int sh_mod_parms(struct d_resource *res __attribute((unused)), const char *unused __attribute((unused))) { int mc = global_options.minor_count; if (mc == 0) { mc = highest_minor + 11; if (mc > DRBD_MINOR_COUNT_MAX) mc = DRBD_MINOR_COUNT_MAX; if (mc < DRBD_MINOR_COUNT_DEF) mc = DRBD_MINOR_COUNT_DEF; } printf("minor_count=%d\n", mc); return 0; } static void free_host_info(struct d_host_info *hi) { if (!hi) return; free_names(hi->on_hosts); free(hi->device); free(hi->disk); free(hi->address); free(hi->address_family); free(hi->port); free(hi->meta_disk); free(hi->meta_index); } static void free_options(struct d_option *opts) { struct d_option *f; while (opts) { free(opts->name); free(opts->value); f = opts; opts = opts->next; free(f); } } static void free_config(struct d_resource *res) { struct d_resource *f, *t; struct d_host_info *host; for_each_resource(f, t, res) { free(f->name); free(f->protocol); free(f->device); free(f->disk); free(f->meta_disk); free(f->meta_index); for (host = f->all_hosts; host; host = host->next) free_host_info(host); free_options(f->net_options); free_options(f->disk_options); free_options(f->sync_options); free_options(f->startup_options); free_options(f->proxy_options); free_options(f->handlers); free(f); } if (common) { free_options(common->net_options); free_options(common->disk_options); free_options(common->sync_options); free_options(common->startup_options); free_options(common->proxy_options); free_options(common->handlers); free(common); } if (ifreq_list) free(ifreq_list); } static void expand_opts(struct d_option *co, struct d_option **opts) { struct d_option *no; while (co) { if (!find_opt(*opts, co->name)) { // prepend new item to opts no = new_opt(strdup(co->name), co->value ? strdup(co->value) : NULL); no->next = *opts; *opts = no; } co = co->next; } } static void expand_common(void) { struct d_resource *res, *tmp; struct d_host_info *h; for_each_resource(res, tmp, config) { for (h = res->all_hosts; h; h = h->next) { if (!h->device) m_asprintf(&h->device, "/dev/drbd%u", h->device_minor); } } if (!common) return; for_each_resource(res, tmp, config) { expand_opts(common->net_options, &res->net_options); expand_opts(common->disk_options, &res->disk_options); expand_opts(common->sync_options, &res->sync_options); expand_opts(common->startup_options, &res->startup_options); expand_opts(common->proxy_options, &res->proxy_options); expand_opts(common->handlers, &res->handlers); if (common->protocol && !res->protocol) res->protocol = strdup(common->protocol); if (common->stacked_timeouts) res->stacked_timeouts = 1; if (!res->become_primary_on) res->become_primary_on = common->become_primary_on; if (common->proxy_plugins && !res->proxy_plugins) expand_opts(common->proxy_plugins, &res->proxy_plugins); } } static void find_drbdcmd(char **cmd, char **pathes) { char **path; path = pathes; while (*path) { if (access(*path, X_OK) == 0) { *cmd = *path; return; } path++; } fprintf(stderr, "Can not find command (drbdsetup/drbdmeta)\n"); exit(E_EXEC_ERROR); } #define NA(ARGC) \ ({ if((ARGC) >= MAX_ARGS) { fprintf(stderr,"MAX_ARGS too small\n"); \ exit(E_THINKO); \ } \ (ARGC)++; \ }) #define make_options(OPT) \ while(OPT) { \ if(OPT->value) { \ ssprintf(argv[NA(argc)],"--%s=%s",OPT->name,OPT->value); \ } else { \ ssprintf(argv[NA(argc)],"--%s",OPT->name); \ } \ OPT=OPT->next; \ } #define make_address(ADDR, PORT, AF) \ if (!strcmp(AF, "ipv6")) { \ ssprintf(argv[NA(argc)],"%s:[%s]:%s", AF, ADDR, PORT); \ } else { \ ssprintf(argv[NA(argc)],"%s:%s:%s", AF, ADDR, PORT); \ } int adm_attach(struct d_resource *res, const char *unused __attribute((unused))) { char *argv[MAX_ARGS]; struct d_option *opt; int argc = 0; argv[NA(argc)] = drbdsetup; ssprintf(argv[NA(argc)], "%d", res->me->device_minor); argv[NA(argc)] = "disk"; argv[NA(argc)] = res->me->disk; if (!strcmp(res->me->meta_disk, "internal")) { argv[NA(argc)] = res->me->disk; } else { argv[NA(argc)] = res->me->meta_disk; } argv[NA(argc)] = res->me->meta_index; argv[NA(argc)] = "--set-defaults"; argv[NA(argc)] = "--create-device"; opt = res->disk_options; make_options(opt); argv[NA(argc)] = 0; return m_system_ex(argv, SLEEPS_LONG, res->name); } struct d_option *find_opt(struct d_option *base, char *name) { while (base) { if (!strcmp(base->name, name)) { return base; } base = base->next; } return 0; } int adm_resize(struct d_resource *res, const char *cmd) { char *argv[MAX_ARGS]; struct d_option *opt; int i, argc = 0; int silent; int ex; argv[NA(argc)] = drbdsetup; ssprintf(argv[NA(argc)], "%d", res->me->device_minor); argv[NA(argc)] = "resize"; opt = find_opt(res->disk_options, "size"); if (opt) ssprintf(argv[NA(argc)], "--%s=%s", opt->name, opt->value); for (i = 0; i < soi; i++) argv[NA(argc)] = setup_opts[i]; argv[NA(argc)] = 0; /* if this is not "resize", but "check-resize", be silent! */ silent = strcmp(cmd, "resize") ? SUPRESS_STDERR : 0; ex = m_system_ex(argv, SLEEPS_SHORT | silent, res->name); if (ex) return ex; /* Record last-known bdev info. * Unfortunately drbdsetup did not have enough information * when doing the "resize", and in theory, _our_ information * about the backing device may even be wrong. * Call drbdsetup again, tell it to ask the kernel for * current config, and update the last known bdev info * according to that. */ /* argv[0] = drbdsetup; * argv[1] = minor; */ argv[2] = "check-resize"; argv[3] = NULL; /* ignore exit code */ m_system_ex(argv, SLEEPS_SHORT | silent, res->name); return 0; } int _admm_generic(struct d_resource *res, const char *cmd, int flags) { char *argv[MAX_ARGS]; int argc = 0, i; argv[NA(argc)] = drbdmeta; ssprintf(argv[NA(argc)], "%d", res->me->device_minor); argv[NA(argc)] = "v08"; if (!strcmp(res->me->meta_disk, "internal")) { argv[NA(argc)] = res->me->disk; } else { argv[NA(argc)] = res->me->meta_disk; } if (!strcmp(res->me->meta_index, "flexible")) { if (!strcmp(res->me->meta_disk, "internal")) { argv[NA(argc)] = "flex-internal"; } else { argv[NA(argc)] = "flex-external"; } } else { argv[NA(argc)] = res->me->meta_index; } argv[NA(argc)] = (char *)cmd; for (i = 0; i < soi; i++) { argv[NA(argc)] = setup_opts[i]; } argv[NA(argc)] = 0; return m_system_ex(argv, flags, res->name); } static int admm_generic(struct d_resource *res, const char *cmd) { return _admm_generic(res, cmd, SLEEPS_VERY_LONG); } static void _adm_generic(struct d_resource *res, const char *cmd, int flags, pid_t *pid, int *fd, int *ex) { char *argv[MAX_ARGS]; int argc = 0, i; argv[NA(argc)] = drbdsetup; ssprintf(argv[NA(argc)], "%d", res->me->device_minor); argv[NA(argc)] = (char *)cmd; for (i = 0; i < soi; i++) { argv[NA(argc)] = setup_opts[i]; } argv[NA(argc)] = 0; setenv("DRBD_RESOURCE", res->name, 1); m__system(argv, flags, res->name, pid, fd, ex); } static int adm_generic(struct d_resource *res, const char *cmd, int flags) { int ex; _adm_generic(res, cmd, flags, NULL, NULL, &ex); return ex; } int adm_generic_s(struct d_resource *res, const char *cmd) { return adm_generic(res, cmd, SLEEPS_SHORT); } int adm_status_xml(struct d_resource *res, const char *cmd) { struct d_resource *r, *t; int rv = 0; if (!dry_run) { printf("\n", PACKAGE_VERSION, API_VERSION); printf("\n", config_save); } for_each_resource(r, t, res) { if (r->ignore) continue; rv = adm_generic(r, cmd, SLEEPS_SHORT); if (rv) break; } if (!dry_run) printf("\n\n"); return rv; } int sh_status(struct d_resource *res, const char *cmd) { struct d_resource *r, *t; int rv = 0; if (!dry_run) { printf("_drbd_version=%s\n_drbd_api=%u\n", shell_escape(PACKAGE_VERSION), API_VERSION); printf("_config_file=%s\n\n", shell_escape(config_save)); } for_each_resource(r, t, res) { if (r->ignore) continue; printf("_stacked_on=%s\n", r->stacked && r->me->lower ? shell_escape(r->me->lower->name) : ""); printf("_stacked_on_device=%s\n", r->stacked && r->me->lower ? shell_escape(r->me->lower->me->device) : ""); if (r->stacked && r->me->lower) printf("_stacked_on_minor=%d\n", r->me->lower->me->device_minor); else printf("_stacked_on_minor=\n"); rv = adm_generic(r, cmd, SLEEPS_SHORT); if (rv) break; } return rv; } int adm_generic_l(struct d_resource *res, const char *cmd) { return adm_generic(res, cmd, SLEEPS_LONG); } static int adm_outdate(struct d_resource *res, const char *cmd) { int rv; rv = adm_generic(res, cmd, SLEEPS_SHORT | SUPRESS_STDERR); /* special cases for outdate: * 17: drbdsetup outdate, but is primary and thus cannot be outdated. * 5: drbdsetup outdate, and is inconsistent or worse anyways. */ if (rv == 17) return rv; if (rv == 5) { /* That might mean it is diskless. */ rv = admm_generic(res, cmd); if (rv) rv = 5; return rv; } if (rv || dry_run) { rv = admm_generic(res, cmd); } return rv; } /* shell equivalent: * ( drbdsetup resize && drbdsetup check-resize ) || drbdmeta check-resize */ static int adm_chk_resize(struct d_resource *res, const char *cmd) { /* drbdsetup resize && drbdsetup check-resize */ int ex = adm_resize(res, cmd); if (ex == 0) return 0; /* try drbdmeta check-resize */ return admm_generic(res, cmd); } static int adm_generic_b(struct d_resource *res, const char *cmd) { char buffer[4096]; int fd, status, rv = 0, rr, s = 0; pid_t pid; _adm_generic(res, cmd, SLEEPS_SHORT | RETURN_STDERR_FD, &pid, &fd, NULL); if (!dry_run) { if (fd < 0) { fprintf(stderr, "Strange: got negative fd.\n"); exit(E_THINKO); } while (1) { rr = read(fd, buffer + s, 4096 - s); if (rr <= 0) break; s += rr; } close(fd); rr = waitpid(pid, &status, 0); alarm(0); if (WIFEXITED(status)) rv = WEXITSTATUS(status); if (alarm_raised) { rv = 0x100; } } /* see drbdsetup.c, print_config_error(): * 11: some unspecific state change error * 17: SS_NO_UP_TO_DATE_DISK * In both cases, we don't need to retry with drbdmeta, * it would fail anyways with "Device is configured!" */ if (rv == 11 || rv == 17) { /* Some state transition error, report it ... */ rr = write(fileno(stderr), buffer, s); return rv; } if (rv || dry_run) { /* On other errors rv = 10 .. no minor allocated rv = 20 .. module not loaded rv = 16 .. we are diskless here retry with drbdmeta. */ rv = admm_generic(res, cmd); } return rv; } static int adm_khelper(struct d_resource *res, const char *cmd) { int rv = 0; char *sh_cmd; char minor_string[8]; char *argv[] = { "/bin/sh", "-c", NULL, NULL }; if (!res->peer) { /* Since 8.3.2 we get DRBD_PEER_AF and DRBD_PEER_ADDRESS from the kernel. If we do not know the peer by now, use these to find the peer. */ struct d_host_info *host; char *peer_address = getenv("DRBD_PEER_ADDRESS"); char *peer_af = getenv("DRBD_PEER_AF"); if (peer_address && peer_af) { for (host = res->all_hosts; host; host = host->next) { if (!strcmp(host->address_family, peer_af) && !strcmp(host->address, peer_address)) { res->peer = host; break; } } } } if (res->peer) { setenv("DRBD_PEER_AF", res->peer->address_family, 1); /* since 8.3.0 */ setenv("DRBD_PEER_ADDRESS", res->peer->address, 1); /* since 8.3.0 */ setenv("DRBD_PEER", res->peer->on_hosts->name, 1); /* deprecated */ setenv("DRBD_PEERS", names_to_str(res->peer->on_hosts), 1); /* since 8.3.0, but not usable when using a config with "floating" statements. */ } snprintf(minor_string, sizeof(minor_string), "%u", res->me->device_minor); setenv("DRBD_RESOURCE", res->name, 1); setenv("DRBD_MINOR", minor_string, 1); setenv("DRBD_CONF", config_save, 1); if ((sh_cmd = get_opt_val(res->handlers, cmd, NULL))) { argv[2] = sh_cmd; rv = m_system_ex(argv, SLEEPS_VERY_LONG, res->name); } return rv; } // need to convert discard-node-nodename to discard-local or discard-remote. void convert_discard_opt(struct d_resource *res) { struct d_option *opt; if (res == NULL) return; if ((opt = find_opt(res->net_options, "after-sb-0pri"))) { if (!strncmp(opt->value, "discard-node-", 13)) { if (!strcmp(nodeinfo.nodename, opt->value + 13)) { free(opt->value); opt->value = strdup("discard-local"); } else { free(opt->value); opt->value = strdup("discard-remote"); } } } } int adm_connect(struct d_resource *res, const char *unused __attribute((unused))) { char *argv[MAX_ARGS]; struct d_option *opt; int i; int argc = 0; argv[NA(argc)] = drbdsetup; ssprintf(argv[NA(argc)], "%d", res->me->device_minor); argv[NA(argc)] = "net"; make_address(res->me->address, res->me->port, res->me->address_family); if (res->me->proxy) { make_address(res->me->proxy->inside_addr, res->me->proxy->inside_port, res->me->proxy->inside_af); } else if (res->peer) { make_address(res->peer->address, res->peer->port, res->peer->address_family); } else if (dry_run > 1) { argv[NA(argc)] = "N/A"; } else { fprintf(stderr, "resource %s: cannot change network config without knowing my peer.\n", res->name); return dry_run ? 0 : 20; } argv[NA(argc)] = res->protocol; argv[NA(argc)] = "--set-defaults"; argv[NA(argc)] = "--create-device"; opt = res->net_options; make_options(opt); for (i = 0; i < soi; i++) { argv[NA(argc)] = setup_opts[i]; } argv[NA(argc)] = 0; return m_system_ex(argv, SLEEPS_SHORT, res->name); } struct d_resource *res_by_name(const char *name); struct d_option *del_opt(struct d_option *base, struct d_option *item) { struct d_option *i; if (base == item) { base = item->next; free(item->name); free(item->value); free(item); return base; } for (i = base; i; i = i->next) { if (i->next == item) { i->next = item->next; free(item->name); free(item->value); free(item); return base; } } return base; } // Need to convert after from resourcename to minor_number. void convert_after_option(struct d_resource *res) { struct d_option *opt, *next; struct d_resource *depends_on_res; if (res == NULL) return; opt = res->sync_options; while ((opt = find_opt(opt, "after"))) { next = opt->next; depends_on_res = res_by_name(opt->value); if (!depends_on_res || depends_on_res->ignore) { res->sync_options = del_opt(res->sync_options, opt); } else { free(opt->value); m_asprintf(&opt->value, "%d", depends_on_res->me->device_minor); } opt = next; } } char *proxy_connection_name(struct d_resource *res) { static char conn_name[128]; int counter; counter = snprintf(conn_name, sizeof(conn_name), "%s-%s-%s", names_to_str_c(res->me->proxy->on_hosts, '_'), res->name, names_to_str_c(res->peer->proxy->on_hosts, '_')); if (counter >= sizeof(conn_name)-3) { fprintf(stderr, "The connection name in resource %s got too long.\n", res->name); exit(E_CONFIG_INVALID); } return conn_name; } int do_proxy_conn_up(struct d_resource *res, const char *conn_name) { char *argv[4] = { drbd_proxy_ctl, "-c", NULL, NULL }; int rv; if (!conn_name) conn_name = proxy_connection_name(res); ssprintf(argv[2], "add connection %s %s:%s %s:%s %s:%s %s:%s", conn_name, res->me->proxy->inside_addr, res->me->proxy->inside_port, res->peer->proxy->outside_addr, res->peer->proxy->outside_port, res->me->proxy->outside_addr, res->me->proxy->outside_port, res->me->address, res->me->port); rv = m_system_ex(argv, SLEEPS_SHORT, res->name); return rv; } int do_proxy_conn_plugins(struct d_resource *res, const char *conn_name) { char *argv[MAX_ARGS]; int argc = 0; struct d_option *opt; int counter; if (!conn_name) conn_name = proxy_connection_name(res); argc = 0; argv[NA(argc)] = drbd_proxy_ctl; opt = res->proxy_options; while (opt) { argv[NA(argc)] = "-c"; ssprintf(argv[NA(argc)], "set %s %s %s", opt->name, conn_name, opt->value); opt = opt->next; } counter = 0; opt = res->proxy_plugins; /* Don't send the "set plugin ... END" line if no plugins are defined * - that's incompatible with the drbd proxy version 1. */ if (opt) { while (1) { argv[NA(argc)] = "-c"; ssprintf(argv[NA(argc)], "set plugin %s %d %s", conn_name, counter, opt ? opt->name : "END"); if (!opt) break; opt = opt->next; counter ++; } } argv[NA(argc)] = 0; if (argc > 2) return m_system_ex(argv, SLEEPS_SHORT, res->name); return 0; } int do_proxy_conn_down(struct d_resource *res, const char *conn_name) { char *argv[4] = { drbd_proxy_ctl, "-c", NULL, NULL}; int rv; if (!conn_name) conn_name = proxy_connection_name(res); ssprintf(argv[2], "del connection %s", conn_name); rv = m_system_ex(argv, SLEEPS_SHORT, res->name); return rv; } static int check_proxy(struct d_resource *res, int do_up) { int rv; if (!res->me->proxy) { if (all_resources) return 0; fprintf(stderr, "There is no proxy config for host %s in resource %s.\n", nodeinfo.nodename, res->name); exit(E_CONFIG_INVALID); } if (!name_in_names(nodeinfo.nodename, res->me->proxy->on_hosts)) { if (all_resources) return 0; fprintf(stderr, "The proxy config in resource %s is not for %s.\n", res->name, nodeinfo.nodename); exit(E_CONFIG_INVALID); } if (!res->peer) { fprintf(stderr, "Cannot determine the peer in resource %s.\n", res->name); exit(E_CONFIG_INVALID); } if (!res->peer->proxy) { fprintf(stderr, "There is no proxy config for the peer in resource %s.\n", res->name); if (all_resources) return 0; exit(E_CONFIG_INVALID); } if (do_up) { rv = do_proxy_conn_up(res, NULL); if (!rv) rv = do_proxy_conn_plugins(res, NULL); } else rv = do_proxy_conn_down(res, NULL); return rv; } static int adm_proxy_up(struct d_resource *res, const char *unused __attribute((unused))) { return check_proxy(res, 1); } static int adm_proxy_down(struct d_resource *res, const char *unused __attribute((unused))) { return check_proxy(res, 0); } int adm_syncer(struct d_resource *res, const char *unused __attribute((unused))) { char *argv[MAX_ARGS]; struct d_option *opt; int i, argc = 0; argv[NA(argc)] = drbdsetup; ssprintf(argv[NA(argc)], "%d", res->me->device_minor); argv[NA(argc)] = "syncer"; argv[NA(argc)] = "--set-defaults"; argv[NA(argc)] = "--create-device"; opt = res->sync_options; make_options(opt); for (i = 0; i < soi; i++) { argv[NA(argc)] = setup_opts[i]; } argv[NA(argc)] = 0; return m_system_ex(argv, SLEEPS_SHORT, res->name); } static int adm_up(struct d_resource *res, const char *unused __attribute((unused))) { schedule_dcmd(adm_attach, res, "attach", 0); schedule_dcmd(adm_syncer, res, "syncer", 1); schedule_dcmd(adm_connect, res, "connect", 2); return 0; } /* The stacked-timeouts switch in the startup sections allows us to enforce the use of the specified timeouts instead the use of a sane value. Should only be used if the third node should never become primary. */ static int adm_wait_c(struct d_resource *res, const char *unused __attribute((unused))) { char *argv[MAX_ARGS]; struct d_option *opt; int argc = 0, rv; argv[NA(argc)] = drbdsetup; ssprintf(argv[NA(argc)], "%d", res->me->device_minor); argv[NA(argc)] = "wait-connect"; if (is_drbd_top && !res->stacked_timeouts) { unsigned long timeout = 20; if ((opt = find_opt(res->net_options, "connect-int"))) { timeout = strtoul(opt->value, NULL, 10); // one connect-interval? two? timeout *= 2; } argv[argc++] = "-t"; ssprintf(argv[argc], "%lu", timeout); argc++; } else { opt = res->startup_options; make_options(opt); } argv[NA(argc)] = 0; rv = m_system_ex(argv, SLEEPS_FOREVER, res->name); return rv; } struct d_resource *res_by_minor(const char *id) { struct d_resource *res, *t; unsigned int mm; mm = minor_by_id(id); if (mm == -1U) return NULL; for_each_resource(res, t, config) { if (res->ignore) continue; if (mm == res->me->device_minor) { is_drbd_top = res->stacked; return res; } } return NULL; } struct d_resource *res_by_name(const char *name) { struct d_resource *res, *t; for_each_resource(res, t, config) { if (strcmp(name, res->name) == 0) return res; } return NULL; } /* In case a child exited, or exits, its return code is stored as negative number in the pids[i] array */ static int childs_running(pid_t * pids, int opts) { int i = 0, wr, rv = 0, status; for (i = 0; i < nr_resources; i++) { if (pids[i] <= 0) continue; wr = waitpid(pids[i], &status, opts); if (wr == -1) { // Wait error. if (errno == ECHILD) { printf("No exit code for %d\n", pids[i]); pids[i] = 0; // Child exited before ? continue; } perror("waitpid"); exit(E_EXEC_ERROR); } if (wr == 0) rv = 1; // Child still running. if (wr > 0) { pids[i] = 0; if (WIFEXITED(status)) pids[i] = -WEXITSTATUS(status); if (WIFSIGNALED(status)) pids[i] = -1000; } } return rv; } static void kill_childs(pid_t * pids) { int i; for (i = 0; i < nr_resources; i++) { if (pids[i] <= 0) continue; kill(pids[i], SIGINT); } } /* returns: -1 ... all childs terminated 0 ... timeout expired 1 ... a string was read */ int gets_timeout(pid_t * pids, char *s, int size, int timeout) { int pr, rr, n = 0; struct pollfd pfd; if (s) { pfd.fd = fileno(stdin); pfd.events = POLLIN | POLLHUP | POLLERR | POLLNVAL; n = 1; } if (!childs_running(pids, WNOHANG)) { pr = -1; goto out; } do { pr = poll(&pfd, n, timeout); if (pr == -1) { // Poll error. if (errno == EINTR) { if (childs_running(pids, WNOHANG)) continue; goto out; // pr = -1 here. } perror("poll"); exit(E_EXEC_ERROR); } } while (pr == -1); if (pr == 1) { // Input available. rr = read(fileno(stdin), s, size - 1); if (rr == -1) { perror("read"); exit(E_EXEC_ERROR); } s[rr] = 0; } out: return pr; } static char *get_opt_val(struct d_option *base, const char *name, char *def) { while (base) { if (!strcmp(base->name, name)) { return base->value; } base = base->next; } return def; } static int check_exit_codes(pid_t * pids) { struct d_resource *res, *t; int i = 0, rv = 0; for_each_resource(res, t, config) { if (res->ignore) continue; if (is_drbd_top != res->stacked) continue; if (pids[i] == -5 || pids[i] == -1000) { pids[i] = 0; } if (pids[i] == -20) rv = 20; i++; } return rv; } static int adm_wait_ci(struct d_resource *ignored __attribute((unused)), const char *unused __attribute((unused))) { struct d_resource *res, *t; char *argv[20], answer[40]; pid_t *pids; struct d_option *opt; int rr, wtime, argc, i = 0; time_t start; int saved_stdin, saved_stdout, fd; struct sigaction so, sa; saved_stdin = -1; saved_stdout = -1; if (no_tty) { fprintf(stderr, "WARN: stdin/stdout is not a TTY; using /dev/console"); fprintf(stdout, "WARN: stdin/stdout is not a TTY; using /dev/console"); saved_stdin = dup(fileno(stdin)); if (saved_stdin == -1) perror("dup(stdin)"); saved_stdout = dup(fileno(stdout)); if (saved_stdin == -1) perror("dup(stdout)"); fd = open("/dev/console", O_RDONLY); if (fd == -1) perror("open('/dev/console, O_RDONLY)"); dup2(fd, fileno(stdin)); fd = open("/dev/console", O_WRONLY); if (fd == -1) perror("open('/dev/console, O_WRONLY)"); dup2(fd, fileno(stdout)); } sa.sa_handler = chld_sig_hand; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_NOCLDSTOP; sigaction(SIGCHLD, &sa, &so); pids = alloca(nr_resources * sizeof(pid_t)); /* alloca can not fail, it can "only" overflow the stack :) * but it needs to be initialized anyways! */ memset(pids, 0, nr_resources * sizeof(pid_t)); for_each_resource(res, t, config) { if (res->ignore) continue; if (is_drbd_top != res->stacked) continue; argc = 0; argv[NA(argc)] = drbdsetup; ssprintf(argv[NA(argc)], "%d", res->me->device_minor); argv[NA(argc)] = "wait-connect"; opt = res->startup_options; make_options(opt); argv[NA(argc)] = 0; m__system(argv, RETURN_PID, res->name, &pids[i++], NULL, NULL); } wtime = global_options.dialog_refresh ? : -1; start = time(0); for (i = 0; i < 10; i++) { // no string, but timeout rr = gets_timeout(pids, 0, 0, 1 * 1000); if (rr < 0) break; putchar('.'); fflush(stdout); check_exit_codes(pids); } if (rr == 0) { /* track a "yes", as well as ctrl-d and ctrl-c, * in case our tty is stuck in "raw" mode, and * we get it one character a time (-icanon) */ char yes_string[] = "yes\n"; char *yes_expect = yes_string; int ctrl_c_count = 0; int ctrl_d_count = 0; /* Just in case, if plymouth or usplash is running, * tell them to step aside. * Also try to force canonical tty mode. */ if (system("exec > /dev/null 2>&1; plymouth quit ; usplash_write QUIT ; " "stty echo icanon icrnl")) /* Ignore return value. Cannot do anything about it anyways. */; printf ("\n***************************************************************\n" " DRBD's startup script waits for the peer node(s) to appear.\n" " - In case this node was already a degraded cluster before the\n" " reboot the timeout is %s seconds. [degr-wfc-timeout]\n" " - If the peer was available before the reboot the timeout will\n" " expire after %s seconds. [wfc-timeout]\n" " (These values are for resource '%s'; 0 sec -> wait forever)\n", get_opt_val(config->startup_options, "degr-wfc-timeout", "0"), get_opt_val(config->startup_options, "wfc-timeout", "0"), config->name); printf(" To abort waiting enter 'yes' [ -- ]:"); do { printf("\e[s\e[31G[%4d]:\e[u", (int)(time(0) - start)); // Redraw sec. fflush(stdout); rr = gets_timeout(pids, answer, 40, wtime * 1000); check_exit_codes(pids); if (rr != 1) continue; /* If our tty is in "sane" or "canonical" mode, * we get whole lines. * If it still is in "raw" mode, even though we * tried to set ICANON above, possibly some other * "boot splash thingy" is in operation. * We may be lucky to get single characters. * If a sysadmin sees things stuck during boot, * I expect that ctrl-c or ctrl-d will be one * of the first things that are tried. * In raw mode, we get these characters directly. * But I want them to try that three times ;) */ if (answer[0] && answer[1] == 0) { if (answer[0] == '\3') ++ctrl_c_count; if (answer[0] == '\4') ++ctrl_d_count; if (yes_expect && answer[0] == *yes_expect) ++yes_expect; else if (answer[0] == '\n') yes_expect = yes_string; else yes_expect = NULL; } if (!strcmp(answer, "yes\n") || (yes_expect && *yes_expect == '\0') || ctrl_c_count >= 3 || ctrl_d_count >= 3) { kill_childs(pids); childs_running(pids, 0); check_exit_codes(pids); break; } printf(" To abort waiting enter 'yes' [ -- ]:"); } while (rr != -1); printf("\n"); } if (saved_stdin != -1) { dup2(saved_stdin, fileno(stdin)); dup2(saved_stdout, fileno(stdout)); } return 0; } static void print_cmds(int level) { size_t i; int j = 0; for (i = 0; i < ARRAY_SIZE(cmds); i++) { if (cmds[i].show_in_usage != level) continue; if (j++ % 2) { printf("%-35s\n", cmds[i].name); } else { printf(" %-35s", cmds[i].name); } } if (j % 2) printf("\n"); } static int hidden_cmds(struct d_resource *ignored __attribute((unused)), const char *ignored2 __attribute((unused))) { printf("\nThese additional commands might be useful for writing\n" "nifty shell scripts around drbdadm:\n\n"); print_cmds(2); printf("\nThese commands are used by the kernel part of DRBD to\n" "invoke user mode helper programs:\n\n"); print_cmds(3); printf ("\nThese commands ought to be used by experts and developers:\n\n"); print_cmds(4); printf("\n"); exit(0); } void print_usage_and_exit(const char *addinfo) { struct option *opt; printf("\nUSAGE: %s [OPTION...] [-- DRBDSETUP-OPTION...] COMMAND " "{all|RESOURCE...}\n\n" "OPTIONS:\n", progname); opt = admopt; while (opt->name) { if (opt->has_arg == required_argument) printf(" {--%s|-%c} val\n", opt->name, opt->val); else printf(" {--%s|-%c}\n", opt->name, opt->val); opt++; } printf("\nCOMMANDS:\n"); print_cmds(1); printf("\nVersion: " PACKAGE_VERSION " (api:%d)\n%s\n", API_VERSION, drbd_buildtag()); if (addinfo) printf("\n%s\n", addinfo); exit(E_USAGE); } void verify_ips(struct d_resource *res) { if (global_options.disable_ip_verification) return; if (dry_run == 1 || do_verify_ips == 0) return; if (res->ignore) return; if (res->stacked && !is_drbd_top) return; if (!have_ip(res->me->address_family, res->me->address)) { ENTRY e, *ep; e.key = e.data = ep = NULL; m_asprintf(&e.key, "%s:%s", res->me->address, res->me->port); hsearch_r(e, FIND, &ep, &global_htable); fprintf(stderr, "%s: in resource %s, on %s:\n\t" "IP %s not found on this host.\n", ep ? (char *)ep->data : res->config_file, res->name, names_to_str(res->me->on_hosts), res->me->address); if (INVALID_IP_IS_INVALID_CONF) config_valid = 0; } } static char *conf_file[] = { DRBD_CONFIG_DIR "/drbd-83.conf", DRBD_CONFIG_DIR "/drbd-82.conf", DRBD_CONFIG_DIR "/drbd-08.conf", DRBD_CONFIG_DIR "/drbd.conf", 0 }; int sanity_check_abs_cmd(char *cmd_name) { struct stat sb; if (stat(cmd_name, &sb)) { /* If stat fails, just ignore this sanity check, * we are still iterating over $PATH probably. */ return 0; } if (!(sb.st_mode & S_ISUID) || sb.st_mode & S_IXOTH || sb.st_gid == 0) { static int did_header = 0; if (!did_header) fprintf(stderr, "WARN:\n" " You are using the 'drbd-peer-outdater' as fence-peer program.\n" " If you use that mechanism the dopd heartbeat plugin program needs\n" " to be able to call drbdsetup and drbdmeta with root privileges.\n\n" " You need to fix this with these commands:\n"); did_header = 1; fprintf(stderr, " chgrp haclient %s\n" " chmod o-x %s\n" " chmod u+s %s\n\n", cmd_name, cmd_name, cmd_name); } return 1; } void sanity_check_cmd(char *cmd_name) { char *path, *pp, *c; char abs_path[100]; if (strchr(cmd_name, '/')) { sanity_check_abs_cmd(cmd_name); } else { path = pp = c = strdup(getenv("PATH")); while (1) { c = strchr(pp, ':'); if (c) *c = 0; snprintf(abs_path, 100, "%s/%s", pp, cmd_name); if (sanity_check_abs_cmd(abs_path)) break; if (!c) break; c++; if (!*c) break; pp = c; } free(path); } } /* if the config file is not readable by haclient, * dopd cannot work. * NOTE: we assume that any gid != 0 will be the group dopd will run as, * typically haclient. */ void sanity_check_conf(char *c) { struct stat sb; /* if we cannot stat the config file, * we have other things to worry about. */ if (stat(c, &sb)) return; /* permissions are funny: if it is world readable, * but not group readable, and it belongs to my group, * I am denied access. * For the file to be readable by dopd (hacluster:haclient), * it is not enough to be world readable. */ /* ok if world readable, and NOT group haclient (see NOTE above) */ if (sb.st_mode & S_IROTH && sb.st_gid == 0) return; /* ok if group readable, and group haclient (see NOTE above) */ if (sb.st_mode & S_IRGRP && sb.st_gid != 0) return; fprintf(stderr, "WARN:\n" " You are using the 'drbd-peer-outdater' as fence-peer program.\n" " If you use that mechanism the dopd heartbeat plugin program needs\n" " to be able to read the drbd.config file.\n\n" " You need to fix this with these commands:\n" " chgrp haclient %s\n" " chmod g+r %s\n\n", c, c); } void sanity_check_perm() { static int checked = 0; if (checked) return; sanity_check_cmd(drbdsetup); sanity_check_cmd(drbdmeta); sanity_check_conf(config_file); checked = 1; } void validate_resource(struct d_resource *res) { struct d_option *opt, *next; struct d_name *bpo; if (!res->protocol) { if (!common || !common->protocol) { fprintf(stderr, "%s:%d: in resource %s:\n\tprotocol definition missing.\n", res->config_file, res->start_line, res->name); config_valid = 0; } /* else: * may not have been expanded yet for "dump" subcommand */ } else { res->protocol[0] = toupper(res->protocol[0]); } /* there may be more than one "after" statement, * see commit 89cd0585 */ opt = res->sync_options; while ((opt = find_opt(opt, "after"))) { next = opt->next; if (res_by_name(opt->value) == NULL) { fprintf(stderr, "%s:%d: in resource %s:\n\tresource '%s' mentioned in " "'after' option is not known.\n", res->config_file, res->start_line, res->name, opt->value); /* Non-fatal if run from some script. * When deleting resources, it is an easily made * oversight to leave references to the deleted * resources in sync-after statements. Don't fail on * every pacemaker-induced action, as it would * ultimately lead to all nodes committing suicide. */ if (no_tty) res->sync_options = del_opt(res->sync_options, opt); else config_valid = 0; } opt = next; } if (res->ignore) return; if (!res->me) { fprintf(stderr, "%s:%d: in resource %s:\n\tmissing section 'on %s { ... }'.\n", res->config_file, res->start_line, res->name, nodeinfo.nodename); config_valid = 0; } // need to verify that in the discard-node-nodename options only known // nodenames are mentioned. if ((opt = find_opt(res->net_options, "after-sb-0pri"))) { if (!strncmp(opt->value, "discard-node-", 13)) { if (res->peer && !name_in_names(opt->value + 13, res->peer->on_hosts) && !name_in_names(opt->value + 13, res->me->on_hosts)) { fprintf(stderr, "%s:%d: in resource %s:\n\t" "the nodename in the '%s' option is " "not known.\n\t" "valid nodenames are: '%s %s'.\n", res->config_file, res->start_line, res->name, opt->value, names_to_str(res->me->on_hosts), names_to_str(res->peer->on_hosts)); config_valid = 0; } } } if ((opt = find_opt(res->handlers, "fence-peer"))) { if (strstr(opt->value, "drbd-peer-outdater")) sanity_check_perm(); } opt = find_opt(res->net_options, "allow-two-primaries"); if (name_in_names("both", res->become_primary_on) && opt == NULL) { fprintf(stderr, "%s:%d: in resource %s:\n" "become-primary-on is set to both, but allow-two-primaries " "is not set.\n", res->config_file, res->start_line, res->name); config_valid = 0; } if (!res->peer) set_peer_in_resource(res, 0); if (res->peer && ((res->me->proxy == NULL) != (res->peer->proxy == NULL))) { fprintf(stderr, "%s:%d: in resource %s:\n\t" "Either both 'on' sections must contain a proxy subsection, or none.\n", res->config_file, res->start_line, res->name); config_valid = 0; } for (bpo = res->become_primary_on; bpo; bpo = bpo->next) { if (res->peer && !name_in_names(bpo->name, res->me->on_hosts) && !name_in_names(bpo->name, res->peer->on_hosts) && strcmp(bpo->name, "both")) { fprintf(stderr, "%s:%d: in resource %s:\n\t" "become-primary-on contains '%s', which is not named with the 'on' sections.\n", res->config_file, res->start_line, res->name, bpo->name); config_valid = 0; } } } static void global_validate_maybe_expand_die_if_invalid(int expand) { struct d_resource *res, *tmp; for_each_resource(res, tmp, config) { validate_resource(res); if (!config_valid) exit(E_CONFIG_INVALID); if (expand) { convert_after_option(res); convert_discard_opt(res); } } } /* * returns a pointer to an malloced area that contains * an absolute, canonical, version of path. * aborts if any allocation or syscall fails. * return value should be free()d, once no longer needed. */ char *canonify_path(char *path) { int cwd_fd = -1; char *last_slash; char *tmp; char *that_wd; char *abs_path; if (!path || !path[0]) { fprintf(stderr, "cannot canonify an empty path\n"); exit(E_USAGE); } tmp = strdupa(path); last_slash = strrchr(tmp, '/'); if (last_slash) { *last_slash++ = '\0'; cwd_fd = open(".", O_RDONLY | O_CLOEXEC); if (cwd_fd < 0) { fprintf(stderr, "open(\".\") failed: %m\n"); exit(E_USAGE); } if (chdir(tmp)) { fprintf(stderr, "chdir(\"%s\") failed: %m\n", tmp); exit(E_USAGE); } } else { last_slash = tmp; } that_wd = getcwd(NULL, 0); if (!that_wd) { fprintf(stderr, "getcwd() failed: %m\n"); exit(E_USAGE); } if (!strcmp("/", that_wd)) m_asprintf(&abs_path, "/%s", last_slash); else m_asprintf(&abs_path, "%s/%s", that_wd, last_slash); free(that_wd); if (cwd_fd >= 0) { if (fchdir(cwd_fd) < 0) { fprintf(stderr, "fchdir() failed: %m\n"); exit(E_USAGE); } close(cwd_fd); } return abs_path; } void assign_command_names_from_argv0(char **argv) { /* in case drbdadm is called with an absolute or relative pathname * look for the drbdsetup binary in the same location, * otherwise, just let execvp sort it out... */ if ((progname = strrchr(argv[0], '/')) == 0) { progname = argv[0]; drbdsetup = strdup("drbdsetup-83"); drbdmeta = strdup("drbdmeta"); drbd_proxy_ctl = strdup("drbd-proxy-ctl"); } else { struct cmd_helper { char *name; char **var; }; struct cmd_helper helpers[] = { {"drbdsetup-83", &drbdsetup}, {"drbdmeta", &drbdmeta}, {"drbd-proxy-ctl", &drbd_proxy_ctl}, {NULL, NULL} }; size_t len_dir, l; struct cmd_helper *c; ++progname; len_dir = progname - argv[0]; for (c = helpers; c->name; ++c) { l = len_dir + strlen(c->name) + 1; *(c->var) = malloc(l); if (*(c->var)) { strncpy(*(c->var), argv[0], len_dir); strcpy(*(c->var) + len_dir, c->name); } } /* for pretty printing, truncate to basename */ argv[0] = progname; } } int parse_options(int argc, char **argv) { opterr = 1; optind = 0; while (1) { int c; c = getopt_long(argc, argv, make_optstring(admopt), admopt, 0); if (c == -1) break; switch (c) { case 'S': is_drbd_top = 1; break; case 'v': verbose++; break; case 'd': dry_run++; break; case 'c': if (!strcmp(optarg, "-")) { yyin = stdin; if (asprintf(&config_file, "STDIN") < 0) { fprintf(stderr, "asprintf(config_file): %m\n"); return 20; } config_from_stdin = 1; } else { yyin = fopen(optarg, "r"); if (!yyin) { fprintf(stderr, "Can not open '%s'.\n.", optarg); exit(E_EXEC_ERROR); } if (asprintf(&config_file, "%s", optarg) < 0) { fprintf(stderr, "asprintf(config_file): %m\n"); return 20; } } break; case 't': config_test = optarg; break; case 's': { char *pathes[2]; pathes[0] = optarg; pathes[1] = 0; find_drbdcmd(&drbdsetup, pathes); } break; case 'm': { char *pathes[2]; pathes[0] = optarg; pathes[1] = 0; find_drbdcmd(&drbdmeta, pathes); } break; case 'p': { char *pathes[2]; pathes[0] = optarg; pathes[1] = 0; find_drbdcmd(&drbd_proxy_ctl, pathes); } break; case 'n': { char *c; int shell_var_name_ok = 1; for (c = optarg; *c && shell_var_name_ok; c++) { switch (*c) { case 'a'...'z': case 'A'...'Z': case '0'...'9': case '_': break; default: shell_var_name_ok = 0; } } if (shell_var_name_ok) sh_varname = optarg; else fprintf(stderr, "ignored --sh-varname=%s: " "contains suspect characters, allowed set is [a-zA-Z0-9_]\n", optarg); } break; case 'f': force = 1; break; case 'V': printf("DRBDADM_BUILDTAG=%s\n", shell_escape(drbd_buildtag())); printf("DRBDADM_API_VERSION=%u\n", API_VERSION); printf("DRBD_KERNEL_VERSION_CODE=0x%06x\n", version_code_kernel()); printf("DRBDADM_VERSION_CODE=0x%06x\n", version_code_userland()); printf("DRBDADM_VERSION=%s\n", shell_escape(PACKAGE_VERSION)); exit(0); break; case 'P': connect_to_host = optarg; break; case '?': /* commented out, since opterr=1 * fprintf(stderr,"Unknown option %s\n",argv[optind-1]); */ fprintf(stderr, "try '%s help'\n", progname); return 20; break; } } return 0; } struct adm_cmd *find_cmd(char *cmdname) { struct adm_cmd *cmd = NULL; unsigned int i; if (!strcmp("hidden-commands", cmdname)) { // before parsing the configuration file... hidden_cmds(NULL, NULL); exit(0); } if (!strncmp("help", cmdname, 5)) print_usage_and_exit(0); /* R_PRIMARY / R_SECONDARY is not a state, but a role. Whatever that * means, actually. But anyways, we decided to start using _role_ as * the terminus of choice, and deprecate "state". */ substitute_deprecated_cmd(&cmdname, "state", "role"); /* "outdate-peer" got renamed to fence-peer, * it is not required to actually outdate the peer, * depending on situation it may be sufficient to power-reset it * or do some other fencing action, or even call out to "meatware". * The name of the handler should not imply something that is not done. */ substitute_deprecated_cmd(&cmdname, "outdate-peer", "fence-peer"); for (i = 0; i < ARRAY_SIZE(cmds); i++) { if (!strcmp(cmds[i].name, cmdname)) { cmd = cmds + i; break; } } return cmd; } char *config_file_from_arg(char *arg) { char *f; int minor = minor_by_id(arg); if (minor < 0) { /* this is expected, if someone wants to test the configured * handlers from the command line, using resource names */ fprintf(stderr, "Couldn't find minor from id %s, " "expecting minor- as id. " "Trying default config files.\n", arg); return NULL; } f = lookup_minor(minor); if (!f) { fprintf(stderr, "Don't know which config file belongs to minor %d, " "trying default ones...\n", minor); } else { yyin = fopen(f, "r"); if (yyin == NULL) { fprintf(stderr, "Couldn't open file %s for reading, reason: %m\n" "trying default config file...\n", config_file); } } return f; } void assign_default_config_file(void) { int i; for (i = 0; conf_file[i]; i++) { yyin = fopen(conf_file[i], "r"); if (yyin) { config_file = conf_file[i]; break; } } if (!config_file) { fprintf(stderr, "Can not open '%s': %m\n", conf_file[i - 1]); exit(E_CONFIG_INVALID); } } void count_resources_or_die(void) { int m, mc = global_options.minor_count; struct d_resource *res, *tmp; highest_minor = 0; for_each_resource(res, tmp, config) { if (res->ignore) continue; m = res->me->device_minor; if (m > highest_minor) highest_minor = m; nr_resources++; if (res->stacked) nr_stacked++; else if (res->ignore) nr_ignore++; else nr_normal++; } // Just for the case that minor_of_res() returned 0 for all devices. if (nr_resources > (highest_minor + 1)) highest_minor = nr_resources - 1; if (mc && mc < (highest_minor + 1)) { fprintf(stderr, "The highest minor you have in your config is %d" "but a minor_count of %d in your config!\n", highest_minor, mc); exit(E_USAGE); } } void die_if_no_resources(void) { if (!is_drbd_top && nr_ignore > 0 && nr_normal == 0) { fprintf(stderr, "WARN: no normal resources defined for this host (%s)!?\n" "Misspelled name of the local machine with the 'on' keyword ?\n", nodeinfo.nodename); exit(E_USAGE); } if (!is_drbd_top && nr_normal == 0) { fprintf(stderr, "WARN: no normal resources defined for this host (%s)!?\n", nodeinfo.nodename); exit(E_USAGE); } if (is_drbd_top && nr_stacked == 0) { fprintf(stderr, "WARN: nothing stacked for this host (%s), " "nothing to do in stacked mode!\n", nodeinfo.nodename); exit(E_USAGE); } } void print_dump_xml_header(void) { printf("\n", config_save); ++indent; dump_global_info_xml(); dump_common_info_xml(); } void print_dump_header(void) { printf("# %s\n", config_save); dump_global_info(); dump_common_info(); } int main(int argc, char **argv) { size_t i; int rv = 0, r; struct adm_cmd *cmd = NULL; struct d_resource *res, *tmp; char *env_drbd_nodename = NULL; int is_dump_xml; int is_dump; initialize_err(); yyin = NULL; uname(&nodeinfo); /* FIXME maybe fold to lower case ? */ no_tty = (!isatty(fileno(stdin)) || !isatty(fileno(stdout))); env_drbd_nodename = getenv("__DRBD_NODE__"); if (env_drbd_nodename && *env_drbd_nodename) { strncpy(nodeinfo.nodename, env_drbd_nodename, sizeof(nodeinfo.nodename) - 1); nodeinfo.nodename[sizeof(nodeinfo.nodename) - 1] = 0; fprintf(stderr, "\n" " found __DRBD_NODE__ in environment\n" " PRETENDING that I am >>%s<<\n\n", nodeinfo.nodename); } assign_command_names_from_argv0(argv); if (argc == 1) print_usage_and_exit("missing arguments"); // arguments missing. if (drbdsetup == NULL || drbdmeta == NULL || drbd_proxy_ctl == NULL) { fprintf(stderr, "could not strdup argv[0].\n"); exit(E_EXEC_ERROR); } if (!getenv("DRBD_DONT_WARN_ON_VERSION_MISMATCH")) warn_on_version_mismatch(); rv = parse_options(argc, argv); if (rv) return rv; /* store everything before the command name as pass through option/argument */ while (optind < argc) { cmd = find_cmd(argv[optind]); if (cmd) break; setup_opts[soi++] = argv[optind++]; } if (optind == argc) print_usage_and_exit(0); if (cmd == NULL) { fprintf(stderr, "Unknown command '%s'.\n", argv[optind]); exit(E_USAGE); } if (config_test && !cmd->test_config) { fprintf(stderr, "The --config-to-test (-t) option is only allowed " "with the dump and sh-nop commands\n"); exit(E_USAGE); } do_verify_ips = cmd->verify_ips; optind++; is_dump_xml = (cmd->function == adm_dump_xml); is_dump = (is_dump_xml || cmd->function == adm_dump); /* remaining argv are expected to be resource names * optind == argc: no resourcenames given. * optind + 1 == argc: exactly one resource name (or "all") given * optind + 1 < argc: multiple resource names given. */ if (optind == argc) { if (is_dump) all_resources = 1; else if (cmd->res_name_required) print_usage_and_exit("missing resourcename arguments"); } else if (optind + 1 < argc) { if (!cmd->res_name_required) fprintf(stderr, "this command will ignore resource names!\n"); else if (cmd->use_cached_config_file) fprintf(stderr, "You should not use this command with multiple resources!\n"); } if (!config_file && cmd->use_cached_config_file) config_file = config_file_from_arg(argv[optind]); if (!config_file) /* may exit if no config file can be used! */ assign_default_config_file(); /* for error-reporting reasons config_file may be re-assigned by adm_adjust, * we need the current value for register_minor, though. * save that. */ if (config_from_stdin) config_save = config_file; else config_save = canonify_path(config_file); my_parse(); if (config_test) { char *saved_config_file = config_file; char *saved_config_save = config_save; config_file = config_test; config_save = canonify_path(config_test); fclose(yyin); yyin = fopen(config_test, "r"); if (!yyin) { fprintf(stderr, "Can not open '%s'.\n.", config_test); exit(E_EXEC_ERROR); } my_parse(); config_file = saved_config_file; config_save = saved_config_save; } if (!config_valid) exit(E_CONFIG_INVALID); post_parse(config, cmd->is_proxy_cmd ? MATCH_ON_PROXY : 0); if (!is_dump || dry_run || verbose) expand_common(); if (is_dump || dry_run || config_from_stdin) do_register_minor = 0; count_resources_or_die(); if (cmd->uc_dialog) uc_node(global_options.usage_count); if (cmd->res_name_required) { if (config == NULL) { fprintf(stderr, "no resources defined!\n"); exit(E_USAGE); } global_validate_maybe_expand_die_if_invalid(!is_dump); if (optind == argc || !strcmp(argv[optind], "all")) { /* either no resource arguments at all, * but command is dump / dump-xml, so implicit "all", * or an explicit "all" argument is given */ all_resources = 1; if (!is_dump || !force) die_if_no_resources(); /* verify ips first, for all of them */ for_each_resource(res, tmp, config) { verify_ips(res); } if (!config_valid) exit(E_CONFIG_INVALID); if (is_dump_xml) print_dump_xml_header(); else if (is_dump) print_dump_header(); for_each_resource(res, tmp, config) { if (!is_dump && res->ignore) continue; if (!is_dump && is_drbd_top != res->stacked) continue; int r = call_cmd(cmd, res, EXIT_ON_FAIL); /* does exit for r >= 20! */ /* this super positioning of return values is soo ugly * anyone any better idea? */ if (r > rv) rv = r; } if (is_dump_xml) { --indent; printf("\n"); } } else { /* explicit list of resources to work on */ for (i = optind; (int)i < argc; i++) { res = res_by_name(argv[i]); if (!res) res = res_by_minor(argv[i]); if (!res) { fprintf(stderr, "'%s' not defined in your config.\n", argv[i]); exit(E_USAGE); } if (res->ignore && !is_dump) { fprintf(stderr, "'%s' ignored, since this host (%s) is not mentioned with an 'on' keyword.\n", res->name, nodeinfo.nodename); rv = E_USAGE; continue; } if (is_drbd_top != res->stacked && !is_dump) { fprintf(stderr, "'%s' is a %s resource, and not available in %s mode.\n", res->name, res-> stacked ? "stacked" : "normal", is_drbd_top ? "stacked" : "normal"); rv = E_USAGE; continue; } verify_ips(res); if (!is_dump && !config_valid) exit(E_CONFIG_INVALID); r = call_cmd(cmd, res, EXIT_ON_FAIL); /* does exit for rv >= 20! */ if (r > rv) rv = r; } } } else { // Commands which do not need a resource name /* no call_cmd, as that implies register_minor, * which does not make sense for resource independent commands */ rv = cmd->function(config, cmd->name); if (rv >= 10) { /* why do we special case the "generic sh-*" commands? */ fprintf(stderr, "command %s exited with code %d\n", cmd->name, rv); exit(rv); } } /* do we really have to bitor the exit code? * it is even only a Boolean value in this case! */ r = run_dcmds(); if (r > rv) rv = r; free_config(config); return rv; } void yyerror(char *text) { fprintf(stderr, "%s:%d: %s\n", config_file, line, text); exit(E_SYNTAX); } drbd-utils-8.9.6/user/v83/Makefile.in0000644000175000017500000000655412634271674017174 0ustar apoikosapoikos# Makefile for drbd.o # # This file is part of DRBD by Philipp Reisner and Lars Ellenberg. # # drbd is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # drbd is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with drbd; see the file COPYING. If not, write to # the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. # VPATH = ../shared # variables set by configure DISTRO = @DISTRO@ prefix = @prefix@ exec_prefix = @exec_prefix@ localstatedir = @localstatedir@ datarootdir = @datarootdir@ datadir = @datadir@ sbindir = @sbindir@ sysconfdir = @sysconfdir@ BASH_COMPLETION_SUFFIX = @BASH_COMPLETION_SUFFIX@ UDEV_RULE_SUFFIX = @UDEV_RULE_SUFFIX@ INITDIR = @INITDIR@ LIBDIR = @prefix@/lib/@PACKAGE_TARNAME@ CC = @CC@ CFLAGS = @CFLAGS@ LDFLAGS = @LDFLAGS@ LN_S = @LN_S@ # features enabled or disabled by configure WITH_83_SUPPORT = @WITH_83_SUPPORT@ WITH_UDEV = @WITH_UDEV@ WITH_XEN = @WITH_XEN@ WITH_PACEMAKER = @WITH_PACEMAKER@ WITH_RGMANAGER = @WITH_RGMANAGER@ WITH_BASHCOMPLETION = @WITH_BASHCOMPLETION@ # variables meant to be overridden from the make command line DESTDIR ?= / CFLAGS += -Wall -I. -I../shared drbdadm-obj = drbdadm_scanner.o drbdadm_parser.o drbdadm_main.o \ drbdadm_adjust.o drbdtool_common.o drbdadm_usage_cnt.o \ drbd_buildtag.o drbdadm_minor_table.o shared_tool.o \ shared_main.o shared_parser.o drbdsetup-obj = drbdsetup.o drbdtool_common.o drbd_buildtag.o \ drbd_strings.o shared_tool.o all-obj := $(drbdadm-obj) $(drbdsetup-obj) all: tools ../shared_prereqs.mk: ; include ../shared_prereqs.mk ifeq ($(WITH_83_SUPPORT),yes) tools: drbdadm-83 drbdsetup-83 else tools: endif .PHONY: drbdadm drbdsetup drbdadm drbdsetup: echo >&2 "You meant to ask for $@-83" ; exit 1 drbdadm-83: $(drbdadm-obj) $(LINK.c) $(LDFLAGS) -o $@ $^ drbdadm_scanner.c: drbdadm_scanner.fl drbdadm_parser.h flex -s -odrbdadm_scanner.c drbdadm_scanner.fl drbdsetup-83: $(drbdsetup-obj) $(LINK.c) $(LDFLAGS) -o $@ $^ clean: rm -f drbdadm_scanner.c rm -f drbdsetup-83 drbdadm-83 $(all-obj) rm -f *~ distclean: clean rm -f $(all-dep) install: ifeq ($(WITH_83_SUPPORT),yes) install -d $(DESTDIR)$(localstatedir)/lib/drbd install -d $(DESTDIR)$(localstatedir)/lock install -d $(DESTDIR)/lib/drbd/ if getent group haclient > /dev/null 2> /dev/null ; then \ install -g haclient -m 4750 drbdsetup-83 $(DESTDIR)/lib/drbd/ ; \ install -m 755 drbdadm-83 $(DESTDIR)/lib/drbd/ ; \ else \ install -m 755 drbdsetup-83 $(DESTDIR)/lib/drbd/ ; \ install -m 755 drbdadm-83 $(DESTDIR)/lib/drbd/ ; \ fi endif uninstall: rm -f $(DESTDIR)/lib/drbd/drbdsetup-83 rm -f $(DESTDIR)/lib/drbd/drbdadm-83 .PHONY: install uninstall clean distclean ../../configure: @echo "please (re-)run ./autogen.sh with appropriate arguments"; exit 1 ../../config.status: ../../configure @echo "please (re-)run ./configure with appropriate arguments"; exit 1 Makefile.in: ; Makefile: Makefile.in ../../config.status cd ../.. && ./config.status user/v83/Makefile drbd-utils-8.9.6/user/v83/drbdadm_minor_table.c0000644000175000017500000001030212466702074021221 0ustar apoikosapoikos/* drbdadm_minor_table.c This file is part of DRBD by Philipp Reisner and Lars Ellenberg. It was written by Johannes Thoma Copyright (C) 2002-2008, LINBIT Information Technologies GmbH. Copyright (C) 2002-2008, Philipp Reisner . Copyright (C) 2002-2008, Lars Ellenberg . drbd is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. drbd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with drbd; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ /* This keeps track of which DRBD minor was configured in which * config file. This is required to have alternative config files * (-c switch) and userland event handlers. */ #include #include #include #include #include #include #include #include #include #include "config.h" #define MAX_MINOR 256 #define MAX_REGISTER_PATH_LEN 1024 /* buf has to be big enough to hold that path. * it is assumed that sprintf cannot fail :-] */ void linkname_from_minor(char *buf, int minor) { sprintf(buf, "%s/drbd-minor-%d.conf", DRBD_LIB_DIR, minor); } int unregister_minor(int minor) { char buf[255]; if (minor >= MAX_MINOR || minor < 0) { fprintf(stderr, "unregister_minor: minor too big (%d).\n", minor); return -1; } linkname_from_minor(buf, minor); if (unlink(buf) < 0) { if (errno != ENOENT) { perror("unlink"); return -1; } } return 0; } int register_minor(int minor, const char *path) { char buf[255]; struct stat stat_buf; int err = -1; if (minor >= MAX_MINOR || minor < 0) { fprintf(stderr, "register_minor: minor too big (%d).\n", minor); return -1; } linkname_from_minor(buf, minor); if (!path || !path[0]) fprintf(stderr, "Cannot register an empty path.\n"); else if (path[0] != '/') fprintf(stderr, "Absolute path expected, " "won't register relative path (%s).\n", path); else if (strlen(path) >= MAX_REGISTER_PATH_LEN) fprintf(stderr, "path (%s):\ntoo long to be registered, " "max path len supported: %u\n", path, MAX_REGISTER_PATH_LEN-1); else if (stat(path, &stat_buf) < 0) fprintf(stderr, "stat(%s): %m\n", path); else if (unlink(buf) < 0 && errno != ENOENT) fprintf(stderr, "unlink(%s): %m\n", buf); else if (symlink(path, buf) < 0) fprintf(stderr, "symlink(%s, %s): %m\n", path, buf); else /* it did work out after all! */ err = 0; return err; } /* This returns a static buffer containing the real * configuration file known to be used last for this minor. * If you need the return value longer, stuff it away with strdup. */ char *lookup_minor(int minor) { static char buf[255]; static char resolved_path[MAX_REGISTER_PATH_LEN+1]; struct stat stat_buf; ssize_t len; if (minor >= MAX_MINOR || minor < 0) { fprintf(stderr, "register_minor: minor too big (%d).\n", minor); return NULL; } linkname_from_minor(buf, minor); if (stat(buf, &stat_buf) < 0) { if (errno != ENOENT) fprintf(stderr, "stat(%s): %m\n", buf); return NULL; } len = readlink(buf, resolved_path, sizeof(resolved_path)-1); if (len < 0) { perror("readlink"); return NULL; } if (len >= MAX_REGISTER_PATH_LEN) fprintf(stderr, "readlink(%s): result has probably been truncated\n", buf); resolved_path[len] = '\0'; return resolved_path; } #ifdef TEST int main(int argc, char ** argv) { register_minor(1, "/etc/drbd-xy.conf"); register_minor(15, "/etc/drbd-82.conf"); register_minor(14, "/../../../../../../etc/drbd-82.conf"); printf("Minor 1 is %s.\n", lookup_minor(1)); printf("Minor 2 is %s.\n", lookup_minor(2)); printf("Minor 14 is %s.\n", lookup_minor(14)); printf("Minor 15 is %s.\n", lookup_minor(15)); return 0; } #endif drbd-utils-8.9.6/user/v83/drbdadm.h0000644000175000017500000001456212477305373016672 0ustar apoikosapoikos#ifndef DRBDADM_H #define DRBDADM_H #include #include #include #include #include #include #include #ifndef O_CLOEXEC #warning "O_CLOEXEC undefined, redefining to 0" #define O_CLOEXEC 0 #endif #include "config.h" #include "shared_main.h" struct d_name { char *name; struct d_name *next; }; struct d_proxy_info { struct d_name *on_hosts; char* inside_addr; char* inside_port; char* inside_af; char* outside_addr; char* outside_port; char* outside_af; }; struct d_host_info { struct d_name *on_hosts; char* device; unsigned device_minor; char* disk; char* address; char* port; char* meta_disk; char* address_family; int meta_major; int meta_minor; char* meta_index; struct d_proxy_info *proxy; struct d_host_info* next; struct d_resource* lower; /* for device stacking */ char *lower_name; /* for device stacking, before bind_stacked_res() */ int config_line; unsigned int by_address:1; /* Match to machines by address, not by names (=on_hosts) */ }; struct d_option { char* name; char* value; struct d_option* next; unsigned int mentioned :1 ; // for the adjust command. unsigned int is_default :1 ; // for the adjust command. unsigned int is_escaped :1 ; }; struct d_resource { char* name; char* protocol; /* these get propagated to host_info sections later. */ char* device; unsigned device_minor; char* disk; char* meta_disk; char* meta_index; struct d_host_info* me; struct d_host_info* peer; struct d_host_info* all_hosts; struct d_option* net_options; struct d_option* disk_options; struct d_option* sync_options; struct d_option* startup_options; struct d_option* handlers; struct d_option* proxy_options; struct d_option* proxy_plugins; struct d_resource* next; struct d_name *become_primary_on; char *config_file; /* The config file this resource is define in.*/ int start_line; unsigned int stacked_timeouts:1; unsigned int ignore:1; unsigned int stacked:1; /* Stacked on this node */ unsigned int stacked_on_one:1; /* Stacked either on me or on peer */ }; extern char *canonify_path(char *path); extern int adm_attach(struct d_resource* ,const char* ); extern int adm_connect(struct d_resource* ,const char* ); extern int adm_resize(struct d_resource* ,const char* ); extern int adm_syncer(struct d_resource* ,const char* ); extern int adm_generic_s(struct d_resource* ,const char* ); extern int _admm_generic(struct d_resource* ,const char*, int flags); extern struct d_option* find_opt(struct d_option*,char*); extern void validate_resource(struct d_resource *); extern void schedule_dcmd( int (* function)(struct d_resource*,const char* ), struct d_resource* res, char* arg, int order); extern int version_code_kernel(void); extern int version_code_userland(void); extern void warn_on_version_mismatch(void); extern void uc_node(enum usage_count_type type); extern int adm_create_md(struct d_resource* res ,const char* cmd); extern void convert_discard_opt(struct d_resource* res); extern void convert_after_option(struct d_resource* res); extern int have_ip(const char *af, const char *ip); /* See drbdadm_minor_table.c */ extern int register_minor(int minor, const char *path); extern int unregister_minor(int minor); extern char *lookup_minor(int minor); enum pr_flags { NoneHAllowed = 4, IgnDiscardMyData = 8 }; extern struct d_resource* parse_resource(char*, enum pr_flags); extern void post_parse(struct d_resource *config, enum pp_flags); extern struct d_option *new_opt(char *name, char *value); extern int name_in_names(char *name, struct d_name *names); extern char *_names_to_str(char* buffer, struct d_name *names); extern char *_names_to_str_c(char* buffer, struct d_name *names, char c); #define NAMES_STR_SIZE 255 #define names_to_str(N) _names_to_str(alloca(NAMES_STR_SIZE+1), N) #define names_to_str_c(N, C) _names_to_str_c(alloca(NAMES_STR_SIZE+1), N, C) extern void free_names(struct d_name *names); extern void set_me_in_resource(struct d_resource* res, int match_on_proxy); extern void set_peer_in_resource(struct d_resource* res, int peer_required); extern void set_on_hosts_in_res(struct d_resource *res); extern void set_disk_in_res(struct d_resource *res); extern char *proxy_connection_name(struct d_resource *res); int parse_proxy_settings(struct d_resource *res, int check_proxy_token); /* conn_name is optional and mostly for compatibility with dcmd */ int do_proxy_conn_up(struct d_resource *res, const char *conn_name); int do_proxy_conn_down(struct d_resource *res, const char *conn_name); int do_proxy_conn_plugins(struct d_resource *res, const char *conn_name); extern char *config_file; extern char *config_save; extern int config_valid; extern struct d_resource* config; extern struct d_resource* common; extern int line, fline; extern struct hsearch_data global_htable; extern int no_tty; extern int dry_run; extern int verbose; extern char* drbdsetup; extern char* drbd_proxy_ctl; extern char ss_buffer[1024]; extern struct utsname nodeinfo; extern char* setup_opts[10]; extern char* connect_to_host; extern int soi; /* ssprintf() places the result of the printf in the current stack frame and sets ptr to the resulting string. If the current stack frame is destroyed (=function returns), the allocated memory is freed automatically */ /* // This is the nicer version, that does not need the ss_buffer. // But it only works with very new glibcs. #define ssprintf(...) \ ({ int _ss_size = snprintf(0, 0, ##__VA_ARGS__); \ char *_ss_ret = __builtin_alloca(_ss_size+1); \ snprintf(_ss_ret, _ss_size+1, ##__VA_ARGS__); \ _ss_ret; }) */ #define ssprintf(ptr,...) \ ptr=strcpy(alloca(snprintf(ss_buffer,sizeof(ss_buffer),##__VA_ARGS__)+1),ss_buffer) /* CAUTION: arguments may not have side effects! */ #define for_each_resource(res,tmp,config) \ for (res = (config); res && (tmp = res->next, 1); res = tmp) #endif #define APPEND(LIST,ITEM) ({ \ typeof((LIST)) _l = (LIST); \ typeof((ITEM)) _i = (ITEM); \ typeof((ITEM)) _t; \ _i->next = NULL; \ if (_l == NULL) { _l = _i; } \ else { \ for (_t = _l; _t->next; _t = _t->next); \ _t->next = _i; \ }; \ _l; \ }) #define PARSER_CHECK_PROXY_KEYWORD (1) #define PARSER_STOP_IF_INVALID (2) drbd-utils-8.9.6/user/v83/unaligned.h0000644000175000017500000000336712466702074017241 0ustar apoikosapoikos#ifndef UNALIGNED_H #define UNALIGNED_H #include #if defined(__i386__) || defined(__x86_64__) #define UNALIGNED_ACCESS_SUPPORTED #endif #ifndef UNALIGNED_ACCESS_SUPPORTED #warning "Assuming that your architecture can not do unaligned memory accesses." #warning "Enabling extra code for unaligned memory accesses." #endif #ifdef UNALIGNED_ACCESS_SUPPORTED /* On some architectures the hardware (or microcode) does it */ #define get_unaligned(ptr) *(ptr) #define put_unaligned(val, ptr) *(ptr) = (val) #else /* on some architectures we have to do it in program code */ /* Better not use memcpy(). gcc generates broken code an ARM at higher optimisation levels */ #define __bad_unaligned_access_size() ({ \ fprintf(stderr, "bad unaligned access. abort()\n"); \ abort(); \ }) #define get_unaligned(ptr) ((typeof(*(ptr)))({ \ typeof(*(ptr)) v; \ unsigned char *s = (unsigned char*)(ptr); \ unsigned char *d = (unsigned char*)&v; \ switch (sizeof(v)) { \ case 8: *d++ = *s++; \ *d++ = *s++; \ *d++ = *s++; \ *d++ = *s++; \ case 4: *d++ = *s++; \ *d++ = *s++; \ case 2: *d++ = *s++; \ case 1: *d++ = *s++; \ break; \ default: \ __bad_unaligned_access_size(); \ break; \ } \ v; })) #define put_unaligned(val, ptr) ({ \ typeof(*(ptr)) v = (val); \ unsigned char *d = (unsigned char*)(ptr); \ unsigned char *s = (unsigned char*)&v; \ switch (sizeof(v)) { \ case 8: *d++ = *s++; \ *d++ = *s++; \ *d++ = *s++; \ *d++ = *s++; \ case 4: *d++ = *s++; \ *d++ = *s++; \ case 2: *d++ = *s++; \ case 1: *d++ = *s++; \ break; \ default: \ __bad_unaligned_access_size(); \ break; \ } \ (void)0; }) #endif #endif drbd-utils-8.9.6/user/v83/drbdadm_parser.c0000644000175000017500000012323612466702074020235 0ustar apoikosapoikos/* * drbdadm_parser.c a hand crafted parser This file is part of DRBD by Philipp Reisner and Lars Ellenberg. Copyright (C) 2006-2008, LINBIT Information Technologies GmbH Copyright (C) 2006-2008, Philipp Reisner Copyright (C) 2006-2008, Lars Ellenberg drbd is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. drbd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with drbd; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include "drbdadm.h" #include "linux/drbd_limits.h" #include "drbdtool_common.h" #include "drbdadm_parser.h" #include "shared_parser.h" YYSTYPE yylval; ///////////////////// static int c_section_start; void my_parse(void); struct d_name *names_from_str(char* str) { struct d_name *names; names = malloc(sizeof(struct d_name)); names->next = NULL; names->name = strdup(str); return names; } char *_names_to_str_c(char* buffer, struct d_name *names, char c) { int n = 0; if (!names) return buffer; while (1) { n += snprintf(buffer + n, NAMES_STR_SIZE - n, "%s", names->name); names = names->next; if (!names) return buffer; n += snprintf(buffer + n, NAMES_STR_SIZE - n, "%c", c); } } char *_names_to_str(char* buffer, struct d_name *names) { return _names_to_str_c(buffer, names, ' '); } int name_in_names(char *name, struct d_name *names) { while (names) { if (!strcmp(names->name, name)) return 1; names = names->next; } return 0; } void free_names(struct d_name *names) { struct d_name *nf; while (names) { nf = names->next; free(names->name); free(names); names = nf; } } static void append_names(struct d_name **head, struct d_name ***last, struct d_name *to_copy) { struct d_name *new; while (to_copy) { new = malloc(sizeof(struct d_name)); if (!*head) *head = new; new->name = strdup(to_copy->name); new->next = NULL; if (*last) **last = new; *last = &new->next; to_copy = to_copy->next; } } struct d_name *concat_names(struct d_name *to_copy1, struct d_name *to_copy2) { struct d_name *head = NULL, **last = NULL; append_names(&head, &last, to_copy1); append_names(&head, &last, to_copy2); return head; } void m_strtoll_range(const char *s, char def_unit, const char *name, unsigned long long min, unsigned long long max) { unsigned long long r = m_strtoll(s, def_unit); char unit[] = { def_unit > '1' ? def_unit : 0, 0 }; if (min > r || r > max) { fprintf(stderr, "%s:%d: %s %s => %llu%s out of range [%llu..%llu]%s.\n", config_file, fline, name, s, r, unit, min, max, unit); if (config_valid <= 1) { config_valid = 0; return; } } if (DEBUG_RANGE_CHECK) { fprintf(stderr, "%s:%d: %s %s => %llu%s in range [%llu..%llu]%s.\n", config_file, fline, name, s, r, unit, min, max, unit); } } void range_check(const enum range_checks what, const char *name, const char *value) { switch (what) { case R_NO_CHECK: break; default: fprintf(stderr, "%s:%d: unknown range for %s => %s\n", config_file, fline, name, value); break; case R_MINOR_COUNT: m_strtoll_range(value, 1, name, DRBD_MINOR_COUNT_MIN, DRBD_MINOR_COUNT_MAX); break; case R_DIALOG_REFRESH: m_strtoll_range(value, 1, name, DRBD_DIALOG_REFRESH_MIN, DRBD_DIALOG_REFRESH_MAX); break; case R_DISK_SIZE: m_strtoll_range(value, 's', name, DRBD_DISK_SIZE_SECT_MIN, DRBD_DISK_SIZE_SECT_MAX); break; case R_TIMEOUT: m_strtoll_range(value, 1, name, DRBD_TIMEOUT_MIN, DRBD_TIMEOUT_MAX); break; case R_CONNECT_INT: m_strtoll_range(value, 1, name, DRBD_CONNECT_INT_MIN, DRBD_CONNECT_INT_MAX); break; case R_PING_INT: m_strtoll_range(value, 1, name, DRBD_PING_INT_MIN, DRBD_PING_INT_MAX); break; case R_MAX_BUFFERS: m_strtoll_range(value, 1, name, DRBD_MAX_BUFFERS_MIN, DRBD_MAX_BUFFERS_MAX); break; case R_MAX_EPOCH_SIZE: m_strtoll_range(value, 1, name, DRBD_MAX_EPOCH_SIZE_MIN, DRBD_MAX_EPOCH_SIZE_MAX); break; case R_SNDBUF_SIZE: m_strtoll_range(value, 1, name, DRBD_SNDBUF_SIZE_MIN, DRBD_SNDBUF_SIZE_MAX); break; case R_RCVBUF_SIZE: m_strtoll_range(value, 1, name, DRBD_RCVBUF_SIZE_MIN, DRBD_RCVBUF_SIZE_MAX); break; case R_KO_COUNT: m_strtoll_range(value, 1, name, DRBD_KO_COUNT_MIN, DRBD_KO_COUNT_MAX); break; case R_RATE: m_strtoll_range(value, 'K', name, DRBD_RATE_MIN, DRBD_RATE_MAX); break; case R_AL_EXTENTS: m_strtoll_range(value, 1, name, DRBD_AL_EXTENTS_MIN, DRBD_AL_EXTENTS_MAX); break; case R_PORT: m_strtoll_range(value, 1, name, DRBD_PORT_MIN, DRBD_PORT_MAX); break; /* FIXME not yet implemented! case R_META_IDX: m_strtoll_range(value, 1, name, DRBD_META_IDX_MIN, DRBD_META_IDX_MAX); break; */ case R_WFC_TIMEOUT: m_strtoll_range(value, 1, name, DRBD_WFC_TIMEOUT_MIN, DRBD_WFC_TIMEOUT_MAX); break; case R_DEGR_WFC_TIMEOUT: m_strtoll_range(value, 1, name, DRBD_DEGR_WFC_TIMEOUT_MIN, DRBD_DEGR_WFC_TIMEOUT_MAX); break; case R_OUTDATED_WFC_TIMEOUT: m_strtoll_range(value, 1, name, DRBD_OUTDATED_WFC_TIMEOUT_MIN, DRBD_OUTDATED_WFC_TIMEOUT_MAX); break; case R_C_PLAN_AHEAD: m_strtoll_range(value, 1, name, DRBD_C_PLAN_AHEAD_MIN, DRBD_C_PLAN_AHEAD_MAX); break; case R_C_DELAY_TARGET: m_strtoll_range(value, 1, name, DRBD_C_DELAY_TARGET_MIN, DRBD_C_DELAY_TARGET_MAX); break; case R_C_FILL_TARGET: m_strtoll_range(value, 's', name, DRBD_C_FILL_TARGET_MIN, DRBD_C_FILL_TARGET_MAX); break; case R_C_MAX_RATE: m_strtoll_range(value, 'k', name, DRBD_C_MAX_RATE_MIN, DRBD_C_MAX_RATE_MAX); break; case R_C_MIN_RATE: m_strtoll_range(value, 'k', name, DRBD_C_MIN_RATE_MIN, DRBD_C_MIN_RATE_MAX); break; case R_CONG_FILL: m_strtoll_range(value, 's', name, DRBD_CONG_FILL_MIN, DRBD_CONG_FILL_MAX); break; case R_CONG_EXTENTS: m_strtoll_range(value, 1, name, DRBD_CONG_EXTENTS_MIN, DRBD_CONG_EXTENTS_MAX); break; } } struct d_option *new_opt(char *name, char *value) { struct d_option *cn = malloc(sizeof(struct d_option)); /* fprintf(stderr,"%s:%d: %s = %s\n",config_file,line,name,value); */ cn->name = name; cn->value = value; cn->mentioned = 0; cn->is_default = 0; cn->is_escaped = 0; return cn; } static void derror(struct d_host_info *host, struct d_resource *res, char *text) { config_valid = 0; fprintf(stderr, "%s:%d: in resource %s, on %s { ... }:" " '%s' keyword missing.\n", config_file, c_section_start, res->name, names_to_str(host->on_hosts), text); } void pdperror(char *text) { config_valid = 0; fprintf(stderr, "%s:%d: in proxy plugin section: %s.\n", config_file, line, text); exit(E_CONFIG_INVALID); } static void pperror(struct d_host_info *host, struct d_proxy_info *proxy, char *text) { config_valid = 0; fprintf(stderr, "%s:%d: in section: on %s { proxy on %s { ... } }:" " '%s' keyword missing.\n", config_file, c_section_start, names_to_str(host->on_hosts), names_to_str(proxy->on_hosts), text); } #define typecheck(type,x) \ ({ type __dummy; \ typeof(x) __dummy2; \ (void)(&__dummy == &__dummy2); \ 1; \ }) #define for_each_host(h_,hosts_) \ for ( ({ typecheck(struct d_name*, h_); \ h_ = hosts_; }); \ h_; h_ = h_->next) /* * for check_uniq: check uniqueness of * resource names, ip:port, node:disk and node:device combinations * as well as resource:section ... * hash table to test for uniqueness of these values... * 256 (max minors) * *( * 2 (host sections) * 4 (res ip:port node:disk node:device) * + 4 (other sections) * + some more, * if we want to check for scoped uniqueness of *every* option * ) * since nobody (?) will actually use more than a dozen minors, * this should be more than enough. */ struct hsearch_data global_htable; void check_uniq_init(void) { memset(&global_htable, 0, sizeof(global_htable)); if (!hcreate_r(256 * ((2 * 4) + 4), &global_htable)) { fprintf(stderr, "Insufficient memory.\n"); exit(E_EXEC_ERROR); }; } /* some settings need only be unique within one resource definition. * we need currently about 8 + (number of host) * 8 entries, * 200 should be much more than enough. */ struct hsearch_data per_resource_htable; void check_upr_init(void) { static int created = 0; if (config_valid >= 2) return; if (created) hdestroy_r(&per_resource_htable); memset(&per_resource_htable, 0, sizeof(per_resource_htable)); if (!hcreate_r(256, &per_resource_htable)) { fprintf(stderr, "Insufficient memory.\n"); exit(E_EXEC_ERROR); }; created = 1; } /* FIXME * strictly speaking we don't need to check for uniqueness of disk and device names, * but for uniqueness of their major:minor numbers ;-) */ int vcheck_uniq(struct hsearch_data *ht, const char *what, const char *fmt, va_list ap) { int rv; ENTRY e, *ep; e.key = e.data = ep = NULL; /* if we are done parsing the config file, * switch off this paranoia */ if (config_valid >= 2) return 1; rv = vasprintf(&e.key, fmt, ap); if (rv < 0) { perror("vasprintf"); exit(E_THINKO); } if (EXIT_ON_CONFLICT && !what) { fprintf(stderr, "Oops, unset argument in %s:%d.\n", __FILE__, __LINE__); exit(E_THINKO); } m_asprintf((char **)&e.data, "%s:%u", config_file, fline); hsearch_r(e, FIND, &ep, ht); //fprintf(stderr, "FIND %s: %p\n", e.key, ep); if (ep) { if (what) { fprintf(stderr, "%s: conflicting use of %s '%s' ...\n" "%s: %s '%s' first used here.\n", (char *)e.data, what, ep->key, (char *)ep->data, what, ep->key); } free(e.key); free(e.data); config_valid = 0; } else { //fprintf(stderr, "ENTER %s\t=>\t%s\n", e.key, (char *)e.data); hsearch_r(e, ENTER, &ep, ht); if (!ep) { fprintf(stderr, "hash table entry (%s => %s) failed\n", e.key, (char *)e.data); exit(E_THINKO); } ep = NULL; } if (EXIT_ON_CONFLICT && ep) exit(E_CONFIG_INVALID); return !ep; } void check_meta_disk(struct d_host_info *host) { struct d_name *h; if (strcmp(host->meta_disk, "internal") != 0) { /* external */ if (host->meta_index == NULL) { fprintf(stderr, "%s:%d: expected 'meta-disk = %s [index]'.\n", config_file, fline, host->meta_disk); } /* index either some number, or "flexible" */ for_each_host(h, host->on_hosts) check_uniq("meta-disk", "%s:%s[%s]", h->name, host->meta_disk, host->meta_index); } else if (host->meta_index) { /* internal */ if (strcmp(host->meta_index, "flexible") != 0) { /* internal, not flexible, but index given: no sir! */ fprintf(stderr, "%s:%d: no index allowed with 'meta-disk = internal'.\n", config_file, fline); } /* else internal, flexible: fine */ } else { /* internal, not flexible */ host->meta_index = strdup("internal"); } } static void pe_expected(const char *exp) { const char *s = yytext; fprintf(stderr, "%s:%u: Parse error: '%s' expected,\n\t" "but got '%.20s%s'\n", config_file, line, exp, s, strlen(s) > 20 ? "..." : ""); exit(E_CONFIG_INVALID); } static void check_string_error(int got) { const char *msg; switch(got) { case TK_ERR_STRING_TOO_LONG: msg = "Token too long"; break; case TK_ERR_DQSTRING_TOO_LONG: msg = "Double quoted string too long"; break; case TK_ERR_DQSTRING: msg = "Unterminated double quoted string\n we don't allow embedded newlines\n "; break; default: return; } fprintf(stderr,"%s:%u: %s >>>%.20s...<<<\n", config_file, line, msg, yytext); exit(E_CONFIG_INVALID); } static void pe_expected_got(const char *exp, int got) { static char tmp[2] = "\0"; const char *s = yytext; if (exp[0] == '\'' && exp[1] && exp[2] == '\'' && exp[3] == 0) { tmp[0] = exp[1]; } fprintf(stderr, "%s:%u: Parse error: '%s' expected,\n\t" "but got '%.20s%s' (TK %d)\n", config_file, line, tmp[0] ? tmp : exp, s, strlen(s) > 20 ? "..." : "", got); exit(E_CONFIG_INVALID); } #define EXP(TOKEN1) \ ({ \ int token; \ token = yylex(); \ if (token != TOKEN1) { \ if (TOKEN1 == TK_STRING) \ check_string_error(token); \ pe_expected_got( #TOKEN1, token); \ } \ token; \ }) static void expect_STRING_or_INT(void) { int token = yylex(); switch(token) { case TK_INTEGER: case TK_STRING: break; case TK_ON: yylval.txt = strdup(yytext); break; default: check_string_error(token); pe_expected_got("TK_STRING | TK_INTEGER", token); } } static void parse_global(void) { fline = line; check_uniq("global section", "global"); if (config) { fprintf(stderr, "%s:%u: You should put the global {} section\n\t" "in front of any resource {} section\n", config_file, line); } EXP('{'); while (1) { int token = yylex(); fline = line; switch (token) { case TK_DISABLE_IP_VERIFICATION: global_options.disable_ip_verification = 1; break; case TK_MINOR_COUNT: EXP(TK_INTEGER); range_check(R_MINOR_COUNT, "minor-count", yylval.txt); global_options.minor_count = atoi(yylval.txt); break; case TK_DIALOG_REFRESH: EXP(TK_INTEGER); range_check(R_DIALOG_REFRESH, "dialog-refresh", yylval.txt); global_options.dialog_refresh = atoi(yylval.txt); break; case TK_USAGE_COUNT: switch (yylex()) { case TK_YES: global_options.usage_count = UC_YES; break; case TK_NO: global_options.usage_count = UC_NO; break; case TK_ASK: global_options.usage_count = UC_ASK; break; default: pe_expected("yes | no | ask"); } break; case '}': return; default: pe_expected("dialog-refresh | minor-count | " "disable-ip-verification"); } EXP(';'); } } static void check_and_change_deprecated_alias(char **name, int token_option) { if (token_option == TK_HANDLER_OPTION) { if (!strcmp(*name, "outdate-peer")) { /* fprintf(stder, "config file:line: name is deprecated ...\n") */ free(*name); *name = strdup("fence-peer"); } } } static struct d_option *parse_options_d(int token_switch, int token_option, int token_delegate, void (*delegate)(void*), void *ctx) { char *opt_name; int token, token_group; enum range_checks rc; struct d_option *options = NULL, *ro = NULL; c_section_start = line; fline = line; while (1) { token_group = yylex(); /* Keep the higher bits in token_option, remove them from token. */ token = REMOVE_GROUP_FROM_TOKEN(token_group); fline = line; if (token == token_switch) { options = APPEND(options, new_opt(yylval.txt, NULL)); } else if (token == token_option || GET_TOKEN_GROUP(token_option & token_group)) { opt_name = yylval.txt; check_and_change_deprecated_alias(&opt_name, token_option); rc = yylval.rc; expect_STRING_or_INT(); range_check(rc, opt_name, yylval.txt); ro = new_opt(opt_name, yylval.txt); options = APPEND(options, ro); } else if (token == token_delegate || GET_TOKEN_GROUP(token_delegate & token_group)) { delegate(ctx); continue; } else if (token == TK_DEPRECATED_OPTION) { /* fprintf(stderr, "Warn: Ignoring deprecated option '%s'\n", yylval.txt); */ expect_STRING_or_INT(); } else if (token == '}') { return options; } else { pe_expected("an option keyword"); } switch (yylex()) { case TK__IS_DEFAULT: ro->is_default = 1; EXP(';'); break; case ';': break; default: pe_expected("_is_default | ;"); } } } static struct d_option *parse_options(int token_switch, int token_option) { return parse_options_d(token_switch, token_option, 0, NULL, NULL); } static void __parse_address(char** addr, char** port, char** af) { switch(yylex()) { case TK_SCI: /* 'ssocks' was names 'sci' before. */ if (af) *af = strdup("ssocks"); EXP(TK_IPADDR); break; case TK_SSOCKS: case TK_SDP: case TK_IPV4: if (af) *af = yylval.txt; EXP(TK_IPADDR); break; case TK_IPV6: if (af) *af = yylval.txt; EXP('['); EXP(TK_IPADDR6); break; case TK_IPADDR: if (af) *af = strdup("ipv4"); break; /* case '[': // Do not foster people's laziness ;) EXP(TK_IPADDR6); *af = strdup("ipv6"); break; */ default: pe_expected("ssocks | sdp | ipv4 | ipv6 | "); } if (addr) *addr = yylval.txt; if (af && !strcmp(*af, "ipv6")) EXP(']'); EXP(':'); EXP(TK_INTEGER); if (port) *port = yylval.txt; range_check(R_PORT, "port", yylval.txt); } static void parse_address(struct d_name *on_hosts, char** addr, char** port, char** af) { struct d_name *h; __parse_address(addr, port, af); if (addr_scope_local(*addr)) for_each_host(h, on_hosts) check_uniq("IP", "%s:%s:%s", h->name, *addr, *port); else check_uniq("IP", "%s:%s", *addr, *port); EXP(';'); } static void parse_hosts(struct d_name **pnp, char delimeter) { char errstr[20]; struct d_name *name; int hosts = 0; int token; while (1) { token = yylex(); switch (token) { case TK_STRING: name = malloc(sizeof(struct d_name)); name->name = yylval.txt; name->next = NULL; *pnp = name; pnp = &name->next; hosts++; break; default: if (token == delimeter) { if (!hosts) pe_expected_got("TK_STRING", token); return; } else { sprintf(errstr, "TK_STRING | '%c'", delimeter); pe_expected_got(errstr, token); } } } } static void parse_proxy_section(struct d_host_info *host) { struct d_proxy_info *proxy; proxy=calloc(1,sizeof(struct d_proxy_info)); host->proxy = proxy; EXP(TK_ON); parse_hosts(&proxy->on_hosts, '{'); while (1) { switch (yylex()) { case TK_INSIDE: parse_address(proxy->on_hosts, &proxy->inside_addr, &proxy->inside_port, &proxy->inside_af); break; case TK_OUTSIDE: parse_address(proxy->on_hosts, &proxy->outside_addr, &proxy->outside_port, &proxy->outside_af); break; case '}': goto break_loop; default: pe_expected("inside | outside"); } } break_loop: if (!proxy->inside_addr) pperror(host, proxy, "inside"); if (!proxy->outside_addr) pperror(host, proxy, "outside"); return; } static void parse_meta_disk(char **disk, char** index) { EXP(TK_STRING); *disk = yylval.txt; if (strcmp("internal", yylval.txt)) { EXP('['); EXP(TK_INTEGER); *index = yylval.txt; EXP(']'); EXP(';'); } else { EXP(';'); } } static void check_minor_nonsense(const char *devname, const int explicit_minor) { if (!devname) return; /* if devname is set, it starts with /dev/drbd */ if (only_digits(devname + 9)) { int m = strtol(devname + 9, NULL, 10); if (m == explicit_minor) return; fprintf(stderr, "%s:%d: explicit minor number must match with device name\n" "\tTry \"device /dev/drbd%u minor %u;\",\n" "\tor leave off either device name or explicit minor.\n" "\tArbitrary device names must start with /dev/drbd_\n" "\tmind the '_'! (/dev/ is optional, but drbd_ is required)\n", config_file, fline, explicit_minor, explicit_minor); config_valid = 0; return; } else if (devname[9] == '_') return; fprintf(stderr, "%s:%d: arbitrary device name must start with /dev/drbd_\n" "\tmind the '_'! (/dev/ is optional, but drbd_ is required)\n", config_file, fline); config_valid = 0; return; } static void parse_device(struct d_name* on_hosts, unsigned *minor, char **device) { struct d_name *h; int m; switch (yylex()) { case TK_STRING: if (!strncmp("drbd", yylval.txt, 4)) { m_asprintf(device, "/dev/%s", yylval.txt); free(yylval.txt); } else *device = yylval.txt; if (strncmp("/dev/drbd", *device, 9)) { fprintf(stderr, "%s:%d: device name must start with /dev/drbd\n" "\t(/dev/ is optional, but drbd is required)\n", config_file, fline); config_valid = 0; /* no goto out yet, * as that would additionally throw a parse error */ } switch (yylex()) { default: pe_expected("minor | ;"); /* fall through */ case ';': m = dt_minor_of_dev(*device); if (m < 0) { fprintf(stderr, "%s:%d: no minor given nor device name contains a minor number\n", config_file, fline); config_valid = 0; } *minor = m; goto out; case TK_MINOR: ; /* double fall through */ } case TK_MINOR: EXP(TK_INTEGER); *minor = atoi(yylval.txt); EXP(';'); /* if both device name and minor number are explicitly given, * force /dev/drbd or /dev/drbd_ */ check_minor_nonsense(*device, *minor); } out: for_each_host(h, on_hosts) { check_uniq("device-minor", "device-minor:%s:%u", h->name, *minor); if (*device) check_uniq("device", "device:%s:%s", h->name, *device); } } enum parse_host_section_flags { REQUIRE_ALL = 1, BY_ADDRESS = 2, }; static void parse_host_section(struct d_resource *res, struct d_name* on_hosts, enum parse_host_section_flags flags) { struct d_host_info *host; struct d_name *h; int in_braces = 1; c_section_start = line; fline = line; host=calloc(1,sizeof(struct d_host_info)); host->on_hosts = on_hosts; host->config_line = c_section_start; host->device_minor = -1; if (flags & BY_ADDRESS) { /* floating
{} */ char *fake_uname = NULL; int token; host->by_address = 1; __parse_address(&host->address, &host->port, &host->address_family); check_uniq("IP", "%s:%s", host->address, host->port); if (!strcmp(host->address_family, "ipv6")) m_asprintf(&fake_uname, "ipv6 [%s]:%s", host->address, host->port); else m_asprintf(&fake_uname, "%s:%s", host->address, host->port); on_hosts = names_from_str(fake_uname); host->on_hosts = on_hosts; token = yylex(); switch(token) { case '{': break; case ';': in_braces = 0; break; default: pe_expected_got("{ | ;", token); } } for_each_host(h, on_hosts) check_upr("host section", "%s: on %s", res->name, h->name); res->all_hosts = APPEND(res->all_hosts, host); while (in_braces) { int token = yylex(); fline = line; switch (token) { case TK_DISK: for_each_host(h, on_hosts) check_upr("disk statement", "%s:%s:disk", res->name, h->name); EXP(TK_STRING); host->disk = yylval.txt; for_each_host(h, on_hosts) check_uniq("disk", "disk:%s:%s", h->name, yylval.txt); EXP(';'); break; case TK_DEVICE: for_each_host(h, on_hosts) check_upr("device statement", "%s:%s:device", res->name, h->name); parse_device(on_hosts, &host->device_minor, &host->device); break; case TK_ADDRESS: if (host->by_address) { fprintf(stderr, "%s:%d: address statement not allowed for floating {} host sections\n", config_file, fline); config_valid = 0; exit(E_CONFIG_INVALID); } for_each_host(h, on_hosts) check_upr("address statement", "%s:%s:address", res->name, h->name); parse_address(on_hosts, &host->address, &host->port, &host->address_family); range_check(R_PORT, "port", host->port); break; case TK_META_DISK: for_each_host(h, on_hosts) check_upr("meta-disk statement", "%s:%s:meta-disk", res->name, h->name); parse_meta_disk(&host->meta_disk, &host->meta_index); check_meta_disk(host); break; case TK_FLEX_META_DISK: for_each_host(h, on_hosts) check_upr("meta-disk statement", "%s:%s:meta-disk", res->name, h->name); EXP(TK_STRING); host->meta_disk = yylval.txt; if (strcmp("internal", yylval.txt)) { host->meta_index = strdup("flexible"); } check_meta_disk(host); EXP(';'); break; case TK_PROXY: parse_proxy_section(host); break; case '}': in_braces = 0; break; default: pe_expected("disk | device | address | meta-disk " "| flexible-meta-disk"); } } /* Inherit device, disk, meta_disk and meta_index from the resource. */ if(!host->disk && res->disk) { host->disk = strdup(res->disk); for_each_host(h, on_hosts) check_uniq("disk", "disk:%s:%s", h->name, host->disk); } if(!host->device && res->device) { host->device = strdup(res->device); } if (host->device_minor == -1U && res->device_minor != -1U) { host->device_minor = res->device_minor; for_each_host(h, on_hosts) check_uniq("device-minor", "device-minor:%s:%d", h->name, host->device_minor); } if(!host->meta_disk && res->meta_disk) { host->meta_disk = strdup(res->meta_disk); if(res->meta_index) host->meta_index = strdup(res->meta_index); check_meta_disk(host); } if (!(flags & REQUIRE_ALL)) return; if (!host->device && host->device_minor == -1U) derror(host, res, "device"); if (!host->disk) derror(host, res, "disk"); if (!host->address) derror(host, res, "address"); if (!host->meta_disk) derror(host, res, "meta-disk"); } void parse_skip() { int level; int token; fline = line; token = yylex(); switch (token) { case TK_STRING: EXP('{'); break; case '{': break; default: check_string_error(token); pe_expected("[ some_text ] {"); } level = 1; while (level) { switch (yylex()) { case '{': /* if you really want to, you can wrap this with a GB size config file :) */ level++; break; case '}': level--; break; case 0: fprintf(stderr, "%s:%u: reached eof " "while parsing this skip block.\n", config_file, fline); exit(E_CONFIG_INVALID); } } while (level) ; } static void parse_stacked_section(struct d_resource* res) { struct d_host_info *host; struct d_name *h; c_section_start = line; fline = line; host=calloc(1,sizeof(struct d_host_info)); host->device_minor = -1; res->all_hosts = APPEND(res->all_hosts, host); EXP(TK_STRING); check_uniq("stacked-on-top-of", "stacked:%s", yylval.txt); host->lower_name = yylval.txt; m_asprintf(&host->meta_disk, "%s", "internal"); m_asprintf(&host->meta_index, "%s", "internal"); EXP('{'); while (1) { switch(yylex()) { case TK_DEVICE: for_each_host(h, host->on_hosts) check_upr("device statement", "%s:%s:device", res->name, h->name); parse_device(host->on_hosts, &host->device_minor, &host->device); break; case TK_ADDRESS: for_each_host(h, host->on_hosts) check_upr("address statement", "%s:%s:address", res->name, h->name); parse_address(NULL, &host->address, &host->port, &host->address_family); range_check(R_PORT, "port", yylval.txt); break; case TK_PROXY: parse_proxy_section(host); break; case '}': goto break_loop; default: pe_expected("device | address | proxy"); } } break_loop: res->stacked_on_one = 1; /* inherit device */ if (!host->device && res->device) { host->device = strdup(res->device); for_each_host(h, host->on_hosts) { if (host->device) check_uniq("device", "device:%s:%s", h->name, host->device); } } if (host->device_minor == -1U && res->device_minor != -1U) { host->device_minor = res->device_minor; for_each_host(h, host->on_hosts) check_uniq("device-minor", "device-minor:%s:%d", h->name, host->device_minor); } if (!host->device && host->device_minor == -1U) derror(host, res, "device"); if (!host->address) derror(host,res,"address"); if (!host->meta_disk) derror(host,res,"meta-disk"); } void startup_delegate(void *ctx) { struct d_resource *res = (struct d_resource *)ctx; if (!strcmp(yytext, "become-primary-on")) { parse_hosts(&res->become_primary_on, ';'); } else if (!strcmp(yytext, "stacked-timeouts")) { res->stacked_timeouts = 1; EXP(';'); } else pe_expected(" | become-primary-on | stacked-timeouts"); } void net_delegate(void *ctx) { enum pr_flags flags = (enum pr_flags)ctx; if (!strcmp(yytext, "discard-my-data") && flags & IgnDiscardMyData) EXP(';'); else pe_expected("an option keyword"); } void set_me_in_resource(struct d_resource* res, int match_on_proxy) { struct d_host_info *host; /* Determine the local host section */ for (host = res->all_hosts; host; host=host->next) { /* do we match this host? */ if (match_on_proxy) { if (!host->proxy || !name_in_names(nodeinfo.nodename, host->proxy->on_hosts)) continue; } else if (host->by_address) { if (!have_ip(host->address_family, host->address) && /* for debugging only, e.g. __DRBD_NODE__=10.0.0.1 */ strcmp(nodeinfo.nodename, host->address)) continue; } else if (host->lower) { if (!host->lower->me) continue; } else if (!host->on_hosts) { /* huh? a resource without hosts to run on?! */ continue; } else { if (!name_in_names(nodeinfo.nodename, host->on_hosts) && strcmp("_this_host", host->on_hosts->name)) continue; } /* we matched. */ if (res->ignore) { config_valid = 0; fprintf(stderr, "%s:%d: in resource %s, %s %s { ... }:\n" "\tYou cannot ignore and define at the same time.\n", res->config_file, host->config_line, res->name, host->lower ? "stacked-on-top-of" : "on", host->lower ? host->lower->name : names_to_str(host->on_hosts)); } if (res->me) { config_valid = 0; fprintf(stderr, "%s:%d: in resource %s, %s %s { ... } ... %s %s { ... }:\n" "\tThere are multiple host sections for this node.\n", res->config_file, host->config_line, res->name, res->me->lower ? "stacked-on-top-of" : "on", res->me->lower ? res->me->lower->name : names_to_str(res->me->on_hosts), host->lower ? "stacked-on-top-of" : "on", host->lower ? host->lower->name : names_to_str(host->on_hosts)); } res->me = host; if (host->lower) res->stacked = 1; } /* If there is no me, implicitly ignore that resource */ if (!res->me) { res->ignore = 1; return; } } void set_peer_in_resource(struct d_resource* res, int peer_required) { struct d_host_info *host = NULL; if (res->ignore) return; /* me must be already set */ if (!res->me) { /* should have been implicitly ignored. */ fprintf(stderr, "%s:%d: in resource %s:\n" "\tcannot determine the peer, don't even know myself!\n", res->config_file, res->start_line, res->name); exit(E_THINKO); } /* only one host section? */ if (!res->all_hosts->next) { if (peer_required) { fprintf(stderr, "%s:%d: in resource %s:\n" "\tMissing section 'on { ... }'.\n", res->config_file, res->start_line, res->name); config_valid = 0; } return; } /* short cut for exactly two host sections. * silently ignore any --peer connect_to_host option. */ if (res->all_hosts->next->next == NULL) { res->peer = res->all_hosts == res->me ? res->all_hosts->next : res->all_hosts; if (dry_run > 1 && connect_to_host) fprintf(stderr, "%s:%d: in resource %s:\n" "\tIgnoring --peer '%s': there are only two host sections.\n", res->config_file, res->start_line, res->name, connect_to_host); return; } /* Multiple peer hosts to choose from. * we need some help! */ if (!connect_to_host) { if (peer_required) { fprintf(stderr, "%s:%d: in resource %s:\n" "\tThere are multiple host sections for the peer node.\n" "\tUse the --peer option to select which peer section to use.\n", res->config_file, res->start_line, res->name); config_valid = 0; } return; } for (host = res->all_hosts; host; host=host->next) { if (host->by_address && strcmp(connect_to_host, host->address)) continue; if (host->proxy && !name_in_names(nodeinfo.nodename, host->proxy->on_hosts)) continue; if (!name_in_names(connect_to_host, host->on_hosts)) continue; if (host == res->me) { fprintf(stderr, "%s:%d: in resource %s\n" "\tInvoked with --peer '%s', but that matches myself!\n", res->config_file, res->start_line, res->name, connect_to_host); res->peer = NULL; break; } if (res->peer) { fprintf(stderr, "%s:%d: in resource %s:\n" "\tInvoked with --peer '%s', but that matches multiple times!\n", res->config_file, res->start_line, res->name, connect_to_host); res->peer = NULL; break; } res->peer = host; } if (peer_required && !res->peer) { config_valid = 0; if (!host) fprintf(stderr, "%s:%d: in resource %s:\n" "\tNo host ('on' or 'floating') section matches --peer '%s'\n", res->config_file, res->start_line, res->name, connect_to_host); } } void set_on_hosts_in_res(struct d_resource *res) { struct d_resource *l_res, *tmp; struct d_host_info *host, *host2; struct d_name *h, **last; for (host = res->all_hosts; host; host=host->next) { if (host->lower_name) { for_each_resource(l_res, tmp, config) { if (!strcmp(l_res->name, host->lower_name)) break; } if (l_res == NULL) { fprintf(stderr, "%s:%d: in resource %s, " "referenced resource '%s' not defined.\n", res->config_file, res->start_line, res->name, host->lower_name); config_valid = 0; continue; } /* Simple: host->on_hosts = concat_names(l_res->me->on_hosts, l_res->peer->on_hosts); */ last = NULL; for (host2 = l_res->all_hosts; host2; host2 = host2->next) if (!host2->lower_name) { append_names(&host->on_hosts, &last, host2->on_hosts); for_each_host(h, host2->on_hosts) { check_uniq("device-minor", "device-minor:%s:%u", h->name, host->device_minor); if (host->device) check_uniq("device", "device:%s:%s", h->name, host->device); } } host->lower = l_res; /* */ if (addr_scope_local(host->address)) for_each_host(h, host->on_hosts) check_uniq("IP", "%s:%s:%s", h->name, host->address, host->port); } } } void set_disk_in_res(struct d_resource *res) { struct d_host_info *host; if (res->ignore) return; for (host = res->all_hosts; host; host=host->next) { if (host->lower) { if (res->stacked && host->lower->stacked) { fprintf(stderr, "%s:%d: in resource %s, stacked-on-top-of %s { ... }:\n" "\tFIXME. I won't stack stacked resources.\n", res->config_file, res->start_line, res->name, host->lower_name); config_valid = 0; } if (host->lower->ignore) continue; if (host->lower->me->device) m_asprintf(&host->disk, "%s", host->lower->me->device); else m_asprintf(&host->disk, "/dev/drbd%u", host->lower->me->device_minor); if (!host->disk) derror(host,res,"disk"); } } } void proxy_delegate(void *ctx) { struct d_resource *res = (struct d_resource *)ctx; int token; struct d_option *options, *opt; struct d_name *line, *word, **pnp; opt = NULL; token = yylex(); if (token != '{') { fprintf(stderr, "%s:%d: expected \"{\" after \"proxy\" keyword\n", config_file, fline); exit(E_CONFIG_INVALID); } options = NULL; while (1) { pnp = &line; while (1) { token = yylex(); if (token == ';') break; if (token == '}') { if (pnp == &line) goto out; fprintf(stderr, "%s:%d: Missing \";\" before \"}\"\n", config_file, fline); exit(E_CONFIG_INVALID); } word = malloc(sizeof(struct d_name)); if (!word) pdperror("out of memory."); word->name = yylval.txt; word->next = NULL; *pnp = word; pnp = &word->next; } opt = calloc(1, sizeof(struct d_option)); if (!opt) pdperror("out of memory."); opt->name = strdup(names_to_str(line)); options = APPEND(options, opt); free_names(line); } out: res->proxy_plugins = options; } int parse_proxy_settings(struct d_resource *res, int flags) { int token; if (flags & PARSER_CHECK_PROXY_KEYWORD) { token = yylex(); if (token != TK_PROXY) { if (flags & PARSER_STOP_IF_INVALID) { yyrestart(yyin); /* flushes flex's buffers */ return 1; } pe_expected_got("proxy", token); } } EXP('{'); res->proxy_options = parse_options_d(TK_PROXY_SWITCH, TK_PROXY_OPTION | TK_PROXY_GROUP, TK_PROXY_DELEGATE, proxy_delegate, res); return 0; } struct d_resource* parse_resource(char* res_name, enum pr_flags flags) { struct d_resource* res; struct d_name *host_names; int token; check_upr_init(); check_uniq("resource section", res_name); res=calloc(1,sizeof(struct d_resource)); res->name = res_name; res->device_minor = -1; res->config_file = config_file; res->start_line = line; while(1) { token = yylex(); fline = line; switch(token) { case TK_PROTOCOL: check_upr("protocol statement","%s: protocol",res->name); EXP(TK_STRING); res->protocol=yylval.txt; EXP(';'); break; case TK_ON: parse_hosts(&host_names, '{'); parse_host_section(res, host_names, REQUIRE_ALL); break; case TK_STACKED: parse_stacked_section(res); break; case TK_IGNORE: if (res->me || res->peer) { fprintf(stderr, "%s:%d: in resource %s, " "'ignore-on' statement must precede any real host section (on ... { ... }).\n", config_file, line, res->name); exit(E_CONFIG_INVALID); } EXP(TK_STRING); fprintf(stderr, "%s:%d: in resource %s, " "WARN: The 'ignore-on' keyword is deprecated.\n", config_file, line, res->name); EXP(';'); break; case TK__THIS_HOST: EXP('{'); host_names = names_from_str("_this_host"); parse_host_section(res, host_names, 0); break; case TK__REMOTE_HOST: EXP('{'); host_names = names_from_str("_remote_host"); parse_host_section(res, host_names, 0); break; case TK_FLOATING: parse_host_section(res, NULL, REQUIRE_ALL + BY_ADDRESS); break; case TK_DISK: switch (token=yylex()) { case TK_STRING: res->disk = yylval.txt; EXP(';'); break; case '{': check_upr("disk section", "%s:disk", res->name); res->disk_options = parse_options(TK_DISK_SWITCH, TK_DISK_OPTION); break; default: check_string_error(token); pe_expected_got( "TK_STRING | {", token); } break; case TK_NET: check_upr("net section", "%s:net", res->name); EXP('{'); res->net_options = parse_options_d(TK_NET_SWITCH, TK_NET_OPTION, TK_NET_DELEGATE, &net_delegate, (void *)flags); break; case TK_SYNCER: check_upr("syncer section", "%s:syncer", res->name); EXP('{'); res->sync_options = parse_options(TK_SYNCER_SWITCH, TK_SYNCER_OPTION); break; case TK_STARTUP: check_upr("startup section", "%s:startup", res->name); EXP('{'); res->startup_options=parse_options_d(TK_STARTUP_SWITCH, TK_STARTUP_OPTION, TK_STARTUP_DELEGATE, &startup_delegate, res); break; case TK_HANDLER: check_upr("handlers section", "%s:handlers", res->name); EXP('{'); res->handlers = parse_options(0, TK_HANDLER_OPTION); break; case TK_PROXY: check_upr("proxy section", "%s:proxy", res->name); parse_proxy_settings(res, 0); break; case TK_DEVICE: check_upr("device statement", "%s:device", res->name); parse_device(NULL, &res->device_minor, &res->device); break; case TK_META_DISK: parse_meta_disk(&res->meta_disk, &res->meta_index); break; case TK_FLEX_META_DISK: EXP(TK_STRING); res->meta_disk = yylval.txt; if (strcmp("internal", yylval.txt)) { res->meta_index = strdup("flexible"); } EXP(';'); break; case '}': case 0: goto exit_loop; default: pe_expected_got("protocol | on | disk | net | syncer |" " startup | handlers |" " ignore-on | stacked-on-top-of",token); } } exit_loop: if (flags == NoneHAllowed && res->all_hosts) { config_valid = 0; fprintf(stderr, "%s:%d: in the %s section, there are no host sections" " allowed.\n", config_file, c_section_start, res->name); } return res; } void post_parse(struct d_resource *config, enum pp_flags flags) { struct d_resource *res,*tmp; for_each_resource(res, tmp, config) if (res->stacked_on_one) set_on_hosts_in_res(res); /* sets on_hosts and host->lower */ /* Needs "on_hosts" and host->lower already set */ for_each_resource(res, tmp, config) if (!res->stacked_on_one) set_me_in_resource(res, flags & MATCH_ON_PROXY); /* Needs host->lower->me already set */ for_each_resource(res, tmp, config) if (res->stacked_on_one) set_me_in_resource(res, flags & MATCH_ON_PROXY); // Needs "me" set already for_each_resource(res, tmp, config) if (res->stacked_on_one) set_disk_in_res(res); } void include_stmt(char *str) { char *last_slash, *tmp; glob_t glob_buf; int cwd_fd; FILE *f; size_t i; int r; /* in order to allow relative paths in include statements we change directory to the location of the current configuration file. */ cwd_fd = open(".", O_RDONLY | O_CLOEXEC); if (cwd_fd < 0) { fprintf(stderr, "open(\".\") failed: %m\n"); exit(E_USAGE); } tmp = strdupa(config_save); last_slash = strrchr(tmp, '/'); if (last_slash) *last_slash = 0; if (chdir(tmp)) { fprintf(stderr, "chdir(\"%s\") failed: %m\n", tmp); exit(E_USAGE); } r = glob(str, 0, NULL, &glob_buf); if (r == 0) { for (i=0; i Copyright (C) 2006-2008, Lars Ellenberg drbd is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. drbd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with drbd; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "drbdadm.h" #include "drbdtool_common.h" #include "drbd_endian.h" #include "linux/drbd.h" /* only use DRBD_MAGIC from here! */ #define HTTP_PORT 80 #define HTTP_HOST "usage.drbd.org" #define HTTP_ADDR "212.69.161.111" #define NODE_ID_FILE DRBD_LIB_DIR"/node_id" #define GIT_HASH_BYTE 20 #define SRCVERSION_BYTE 12 /* actually 11 and a half. */ #define SRCVERSION_PAD (GIT_HASH_BYTE - SRCVERSION_BYTE) #define SVN_STYLE_OD 16 struct vcs_rel { uint32_t svn_revision; char git_hash[GIT_HASH_BYTE]; struct { unsigned major, minor, sublvl; } version; unsigned version_code; }; struct node_info { uint64_t node_uuid; struct vcs_rel rev; }; struct node_info_od { uint32_t magic; struct node_info ni; } __packed; /* For our purpose (finding the revision) SLURP_SIZE is always enough. */ static char* slurp_proc_drbd() { const int SLURP_SIZE = 4096; char* buffer; int rr, fd; fd = open("/proc/drbd",O_RDONLY); if( fd == -1) return 0; buffer = malloc(SLURP_SIZE); if(!buffer) return 0; rr = read(fd, buffer, SLURP_SIZE-1); if( rr == -1) { free(buffer); return 0; } buffer[rr]=0; close(fd); return buffer; } void read_hex(char* dst, char* src, int dst_size, int src_size) { int dst_i, u, src_i=0; for(dst_i=0;dst_i= src_size) break; if(src[src_i] == 0) break; if(++src_i >= src_size) break; } } void vcs_ver_from_str(struct vcs_rel *rel, const char *token) { char *dot; long maj, min, sub; maj = strtol(token, &dot, 10); if (*dot != '.') return; min = strtol(dot+1, &dot, 10); if (*dot != '.') return; sub = strtol(dot+1, &dot, 10); /* don't check on *dot == 0, * we may want to add some extraversion tag sometime if (*dot != 0) return; */ rel->version.major = maj; rel->version.minor = min; rel->version.sublvl = sub; rel->version_code = (maj << 16) + (min << 8) + sub; } void vcs_from_str(struct vcs_rel *rel, const char *text) { char token[80]; int plus=0; enum { begin, f_ver, f_svn, f_rev, f_git, f_srcv } ex = begin; while (sget_token(token, sizeof(token), &text) != EOF) { switch(ex) { case begin: if(!strcmp(token,"version:")) ex = f_ver; if(!strcmp(token,"SVN")) ex = f_svn; if(!strcmp(token,"GIT-hash:")) ex = f_git; if(!strcmp(token,"srcversion:")) ex = f_srcv; break; case f_ver: if(!strcmp(token,"plus")) plus = 1; /* still waiting for version */ else { vcs_ver_from_str(rel, token); ex = begin; } break; case f_svn: if(!strcmp(token,"Revision:")) ex = f_rev; break; case f_rev: rel->svn_revision = atol(token) * 10; if( plus ) rel->svn_revision += 1; memset(rel->git_hash, 0, GIT_HASH_BYTE); return; case f_git: read_hex(rel->git_hash, token, GIT_HASH_BYTE, strlen(token)); rel->svn_revision = 0; return; case f_srcv: memset(rel->git_hash, 0, SRCVERSION_PAD); read_hex(rel->git_hash + SRCVERSION_PAD, token, SRCVERSION_BYTE, strlen(token)); rel->svn_revision = 0; return; } } } static int current_vcs_is_from_proc_drbd; static struct vcs_rel current_vcs_rel; static struct vcs_rel userland_version; static void vcs_get_current(void) { char* version_txt; if (current_vcs_rel.version_code) return; version_txt = slurp_proc_drbd(); if(version_txt) { vcs_from_str(¤t_vcs_rel, version_txt); current_vcs_is_from_proc_drbd = 1; free(version_txt); } else { vcs_from_str(¤t_vcs_rel, drbd_buildtag()); vcs_ver_from_str(¤t_vcs_rel, PACKAGE_VERSION); } } static void vcs_get_userland(void) { if (userland_version.version_code) return; vcs_ver_from_str(&userland_version, PACKAGE_VERSION); } int version_code_kernel(void) { vcs_get_current(); return current_vcs_is_from_proc_drbd ? current_vcs_rel.version_code : 0; } int version_code_userland(void) { vcs_get_userland(); return userland_version.version_code; } static int vcs_eq(struct vcs_rel *rev1, struct vcs_rel *rev2) { if( rev1->svn_revision || rev2->svn_revision ) { return rev1->svn_revision == rev2->svn_revision; } else { return !memcmp(rev1->git_hash,rev2->git_hash,GIT_HASH_BYTE); } } static int vcs_ver_cmp(struct vcs_rel *rev1, struct vcs_rel *rev2) { return rev1->version_code - rev2->version_code; } void warn_on_version_mismatch(void) { char *msg; int cmp; /* get the kernel module version from /proc/drbd */ vcs_get_current(); /* get the userland version from PACKAGE_VERSION */ vcs_get_userland(); cmp = vcs_ver_cmp(&userland_version, ¤t_vcs_rel); /* no message if equal */ if (cmp == 0) return; if (cmp > 0xffff || cmp < -0xffff) /* major version differs! */ msg = "mixing different major numbers will not work!"; else if (cmp < 0) /* userland is older. always warn. */ msg = "you should upgrade your drbd tools!"; else if (cmp & 0xff00) /* userland is newer minor version */ msg = "please don't mix different DRBD series."; else /* userland is newer, but only differ in sublevel. */ msg = "preferably kernel and userland versions should match."; fprintf(stderr, "DRBD module version: %u.%u.%u\n" " userland version: %u.%u.%u\n%s\n", current_vcs_rel.version.major, current_vcs_rel.version.minor, current_vcs_rel.version.sublvl, userland_version.version.major, userland_version.version.minor, userland_version.version.sublvl, msg); } static char *vcs_to_str(struct vcs_rel *rev) { static char buffer[80]; // Not generic, sufficient for the purpose. if( rev->svn_revision ) { snprintf(buffer,80,"nv="U32,rev->svn_revision); } else { int len=20,p; unsigned char *bytes; p = sprintf(buffer,"git="); bytes = (unsigned char*)rev->git_hash; while(len--) p += sprintf(buffer+p,"%02x",*bytes++); } return buffer; } static void write_node_id(struct node_info *ni) { int fd; struct node_info_od on_disk; int size; fd = open(NODE_ID_FILE,O_WRONLY|O_CREAT,S_IRUSR|S_IWUSR); if( fd == -1 && errno == ENOENT) { mkdir(DRBD_LIB_DIR,S_IRWXU); fd = open(NODE_ID_FILE,O_WRONLY|O_CREAT,S_IRUSR|S_IWUSR); } if( fd == -1) { perror("Creation of "NODE_ID_FILE" failed."); exit(20); } if(ni->rev.svn_revision != 0) { // SVN style (old) on_disk.magic = cpu_to_be32(DRBD_MAGIC); on_disk.ni.node_uuid = cpu_to_be64(ni->node_uuid); on_disk.ni.rev.svn_revision = cpu_to_be32(ni->rev.svn_revision); memset(on_disk.ni.rev.git_hash,0,GIT_HASH_BYTE); size = SVN_STYLE_OD; } else { on_disk.magic = cpu_to_be32(DRBD_MAGIC+1); on_disk.ni.node_uuid = cpu_to_be64(ni->node_uuid); on_disk.ni.rev.svn_revision = 0; memcpy(on_disk.ni.rev.git_hash,ni->rev.git_hash,GIT_HASH_BYTE); size = sizeof(on_disk); } if( write(fd,&on_disk, size) != size) { perror("Write to "NODE_ID_FILE" failed."); exit(20); } close(fd); } static int read_node_id(struct node_info *ni) { int rr,fd; struct node_info_od on_disk; fd = open(NODE_ID_FILE,O_RDONLY); if( fd == -1) { return 0; } rr = read(fd,&on_disk, sizeof(on_disk)); if( rr != sizeof(on_disk) && rr != SVN_STYLE_OD ) { close(fd); return 0; } switch(be32_to_cpu(on_disk.magic)) { case DRBD_MAGIC: ni->node_uuid = be64_to_cpu(on_disk.ni.node_uuid); ni->rev.svn_revision = be32_to_cpu(on_disk.ni.rev.svn_revision); memset(ni->rev.git_hash,0,GIT_HASH_BYTE); break; case DRBD_MAGIC+1: ni->node_uuid = be64_to_cpu(on_disk.ni.node_uuid); ni->rev.svn_revision = 0; memcpy(ni->rev.git_hash,on_disk.ni.rev.git_hash,GIT_HASH_BYTE); break; default: return 0; } close(fd); return 1; } /* to interrupt gethostbyname, * we not only need a signal, * but also the long jump: * gethostbyname would otherwise just restart the syscall * and timeout again. */ static jmp_buf timed_out; static void gethostbyname_timeout(int __attribute((unused)) signo) { longjmp(timed_out, 1); } #define DNS_TIMEOUT 3 /* seconds */ #define SOCKET_TIMEOUT 3 /* seconds */ struct hostent *my_gethostbyname(const char *name) { struct sigaction sa; struct sigaction so; struct hostent *h; alarm(0); sa.sa_handler = &gethostbyname_timeout; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sigaction(SIGALRM, &sa, &so); if (!setjmp(timed_out)) { alarm(DNS_TIMEOUT); h = gethostbyname(name); } else /* timed out, longjmp of SIGALRM jumped here */ h = NULL; alarm(0); sigaction(SIGALRM, &so, NULL); return h; } /** * insert_usage_with_socket: * * Return codes: * * 0 - success * 1 - failed to create socket * 2 - unknown server * 3 - cannot connect to server * 5 - other error */ static int make_get_request(char *uri) { struct sockaddr_in server; struct hostent *host_info; unsigned long addr; int sock; char *req_buf; char *http_host = HTTP_HOST; int buf_len = 1024; char buffer[buf_len]; FILE *sockfd; int writeit; struct timeval timeout = { .tv_sec = SOCKET_TIMEOUT }; sock = socket( PF_INET, SOCK_STREAM, 0); if (sock < 0) return 1; setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)); memset (&server, 0, sizeof(server)); /* convert host name to ip */ host_info = my_gethostbyname(http_host); if (host_info == NULL) { /* unknown host, try with ip */ if ((addr = inet_addr( HTTP_ADDR )) != INADDR_NONE) memcpy((char *)&server.sin_addr, &addr, sizeof(addr)); else { close(sock); return 2; } } else { memcpy((char *)&server.sin_addr, host_info->h_addr, host_info->h_length); } ssprintf(req_buf, "GET %s HTTP/1.0\r\n" "Host: "HTTP_HOST"\r\n" "User-Agent: drbdadm/"PACKAGE_VERSION" (%s; %s; %s; %s)\r\n" "\r\n", uri, nodeinfo.sysname, nodeinfo.release, nodeinfo.version, nodeinfo.machine); server.sin_family = AF_INET; server.sin_port = htons(HTTP_PORT); if (connect(sock, (struct sockaddr*)&server, sizeof(server))<0) { /* cannot connect to server */ close(sock); return 3; } if ((sockfd = fdopen(sock, "r+")) == NULL) { close(sock); return 5; } if (fputs(req_buf, sockfd) == EOF) { fclose(sockfd); close(sock); return 5; } writeit = 0; while (fgets(buffer, buf_len, sockfd) != NULL) { /* ignore http headers */ if (writeit == 0) { if (buffer[0] == '\r' || buffer[0] == '\n') writeit = 1; } else { fprintf(stderr,"%s", buffer); } } fclose(sockfd); close(sock); return 0; } static void url_encode(char* in, char* out) { char *h = "0123456789abcdef"; char c; while( (c = *in++) != 0 ) { if( c == '\n' ) break; if( ( 'a' <= c && c <= 'z' ) || ( 'A' <= c && c <= 'Z' ) || ( '0' <= c && c <= '9' ) || c == '-' || c == '_' || c == '.' ) *out++ = c; else if( c == ' ' ) *out++ = '+'; else { *out++ = '%'; *out++ = h[c >> 4]; *out++ = h[c & 0x0f]; } } *out = 0; } /* Ensure that the node is counted on http://usage.drbd.org */ #define ANSWER_SIZE 80 void uc_node(enum usage_count_type type) { struct node_info ni; char *uri; int send = 0; int update = 0; char answer[ANSWER_SIZE]; char n_comment[ANSWER_SIZE*3]; char *r; if( type == UC_NO ) return; if( getuid() != 0 ) return; /* not when running directly from init, * or if stdout is no tty. * you do not want to have the "user information message" * as output from `drbdadm sh-resources all` */ if (getenv("INIT_VERSION")) return; if (no_tty) return; vcs_get_current(); if( ! read_node_id(&ni) ) { get_random_bytes(&ni.node_uuid,sizeof(ni.node_uuid)); ni.rev = current_vcs_rel; send = 1; } else if (current_vcs_is_from_proc_drbd == 0) { /* Avoid flapping between drbd-utils git-hash and * kernel module git-hash. */ send = 0; } else { // read_node_id() was successful if (!vcs_eq(&ni.rev,¤t_vcs_rel)) { ni.rev = current_vcs_rel; update = 1; send = 1; } } if(!send) return; n_comment[0]=0; if (type == UC_ASK ) { fprintf(stderr, "\n" "\t\t--== This is %s of DRBD ==--\n" "Please take part in the global DRBD usage count at http://"HTTP_HOST".\n\n" "The counter works anonymously. It creates a random number to identify\n" "your machine and sends that random number, along with the kernel and\n" "DRBD version, to "HTTP_HOST".\n\n" "The benefits for you are:\n" " * In response to your submission, the server ("HTTP_HOST") will tell you\n" " how many users before you have installed this version (%s).\n" " * With a high counter LINBIT has a strong motivation to\n" " continue funding DRBD's development.\n\n" "http://"HTTP_HOST"/cgi-bin/insert_usage.pl?nu="U64"&%s\n\n" "In case you want to participate but know that this machine is firewalled,\n" "simply issue the query string with your favorite web browser or wget.\n" "You can control all of this by setting 'usage-count' in your drbd.conf.\n\n" "* You may enter a free form comment about your machine, that gets\n" " used on "HTTP_HOST" instead of the big random number.\n" "* If you wish to opt out entirely, simply enter 'no'.\n" "* To count this node without comment, just press [RETURN]\n", update ? "an update" : "a new installation", PACKAGE_VERSION,ni.node_uuid, vcs_to_str(&ni.rev)); r = fgets(answer, ANSWER_SIZE, stdin); if(r && !strcmp(answer,"no\n")) send = 0; url_encode(answer,n_comment); } ssprintf(uri,"http://"HTTP_HOST"/cgi-bin/insert_usage.pl?nu="U64"&%s%s%s", ni.node_uuid, vcs_to_str(&ni.rev), n_comment[0] ? "&nc=" : "", n_comment); if (send) { write_node_id(&ni); fprintf(stderr, "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" " --== Thank you for participating in the global usage survey ==--\n" "The server's response is:\n\n"); make_get_request(uri); if (type == UC_ASK) { fprintf(stderr, "\n" "From now on, drbdadm will contact "HTTP_HOST" only when you update\n" "DRBD or when you use 'drbdadm create-md'. Of course it will continue\n" "to ask you for confirmation as long as 'usage-count' is at its default\n" "value of 'ask'.\n\n" "Just press [RETURN] to continue: "); r = fgets(answer, 9, stdin); } } } /* For our purpose (finding the revision) SLURP_SIZE is always enough. */ char* run_admm_generic(struct d_resource* res ,const char* cmd) { const int SLURP_SIZE = 4096; int rr,pipes[2]; char* buffer; pid_t pid; buffer = malloc(SLURP_SIZE); if(!buffer) return 0; if(pipe(pipes)) return 0; pid = fork(); if(pid == -1) { fprintf(stderr,"Can not fork\n"); exit(E_EXEC_ERROR); } if(pid == 0) { // child close(pipes[0]); // close reading end dup2(pipes[1],1); // 1 = stdout close(pipes[1]); exit(_admm_generic(res,cmd, SLEEPS_VERY_LONG| DONT_REPORT_FAILED)); } close(pipes[1]); // close writing end rr = read(pipes[0], buffer, SLURP_SIZE-1); if( rr == -1) { free(buffer); // FIXME cleanup return 0; } buffer[rr]=0; close(pipes[0]); waitpid(pid,0,0); return buffer; } int adm_create_md(struct d_resource* res ,const char* cmd) { char answer[ANSWER_SIZE]; struct node_info ni; uint64_t device_uuid=0; uint64_t device_size=0; char *uri; int send=0; char *tb; int rv,fd; int soi_tmp; char *setup_opts_0_tmp; char *r; tb = run_admm_generic(res, "read-dev-uuid"); device_uuid = strto_u64(tb,NULL,16); free(tb); rv = _admm_generic(res, cmd, SLEEPS_VERY_LONG); // cmd is "create-md". if(rv || dry_run) return rv; fd = open(res->me->disk,O_RDONLY); if( fd != -1) { device_size = bdev_size(fd); close(fd); } if( read_node_id(&ni) && device_size && !device_uuid) { get_random_bytes(&device_uuid, sizeof(uint64_t)); if( global_options.usage_count == UC_YES ) send = 1; if( global_options.usage_count == UC_ASK ) { fprintf(stderr, "\n" "\t\t--== Creating metadata ==--\n" "As with nodes, we count the total number of devices mirrored by DRBD\n" "at http://"HTTP_HOST".\n\n" "The counter works anonymously. It creates a random number to identify\n" "the device and sends that random number, along with the kernel and\n" "DRBD version, to "HTTP_HOST".\n\n" "http://"HTTP_HOST"/cgi-bin/insert_usage.pl?nu="U64"&ru="U64"&rs="U64"\n\n" "* If you wish to opt out entirely, simply enter 'no'.\n" "* To continue, just press [RETURN]\n", ni.node_uuid,device_uuid,device_size ); r = fgets(answer, ANSWER_SIZE, stdin); if(r && strcmp(answer,"no\n")) send = 1; } } if(!device_uuid) { get_random_bytes(&device_uuid, sizeof(uint64_t)); } if (send) { ssprintf(uri,"http://"HTTP_HOST"/cgi-bin/insert_usage.pl?" "nu="U64"&ru="U64"&rs="U64, ni.node_uuid, device_uuid, device_size); make_get_request(uri); } /* HACK */ soi_tmp = soi; setup_opts_0_tmp = setup_opts[0]; setup_opts[0] = NULL; ssprintf( setup_opts[0], X64(016), device_uuid); soi=1; _admm_generic(res, "write-dev-uuid", SLEEPS_VERY_LONG); setup_opts[0] = setup_opts_0_tmp; soi = soi_tmp; return rv; } drbd-utils-8.9.6/user/v9/0000755000175000017500000000000012654475367015042 5ustar apoikosapoikosdrbd-utils-8.9.6/user/v9/drbdtool_common.h0000644000175000017500000000630412466702074020364 0ustar apoikosapoikos#ifndef DRBDTOOL_COMMON_H #define DRBDTOOL_COMMON_H #include "drbd_endian.h" #include #include #include #include #include "shared_tool.h" #define LANANA_DRBD_MAJOR 147 /* we should get this into linux/major.h */ #ifndef DRBD_MAJOR #define DRBD_MAJOR LANANA_DRBD_MAJOR #elif (DRBD_MAJOR != LANANA_DRBD_MAJOR) # error "FIXME unexpected DRBD_MAJOR" #endif #ifndef __packed #define __packed __attribute__((packed)) #endif #ifndef ARRAY_SIZE #define ARRAY_SIZE(A) (sizeof(A)/sizeof(A[0])) #endif /** * BUILD_BUG_ON - break compile if a condition is true. * @condition: the condition which the compiler should know is false. * * If you have some code which relies on certain constants being equal, or * other compile-time-evaluated condition, you should use BUILD_BUG_ON to * detect if someone changes it. * * The implementation uses gcc's reluctance to create a negative array, but * gcc (as of 4.4) only emits that error for obvious cases (eg. not arguments * to inline functions). So as a fallback we use the optimizer; if it can't * prove the condition is false, it will cause a link error on the undefined * "__build_bug_on_failed". This error message can be harder to track down * though, hence the two different methods. */ #ifndef __OPTIMIZE__ #define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)])) #else extern int __build_bug_on_failed; #define BUILD_BUG_ON(condition) \ do { \ ((void)sizeof(char[1 - 2*!!(condition)])); \ if (condition) __build_bug_on_failed = 1; \ } while(0) #endif /* Flags which used to be in enum mdf_flag before version 09 */ enum mdf_flag_08 { MDF_CONNECTED_IND = 1 << 2, MDF_FULL_SYNC = 1 << 3, MDF_PEER_OUT_DATED = 1 << 5, MDF_FENCING_IND = 1 << 8, }; struct option; extern void dt_release_lockfile(int drbd_fd); extern unsigned long long m_strtoll(const char* s,const char def_unit); extern void dt_print_uuids(const uint64_t* uuid, unsigned int flags); extern void dt_pretty_print_uuids(const uint64_t* uuid, unsigned int flags); void dt_print_v9_uuids(const uint64_t*, unsigned int, unsigned int); void dt_pretty_print_v9_uuids(const uint64_t*, unsigned int, unsigned int); const char *get_hostname(void); #define GIT_HASH_BYTE 20 #define SRCVERSION_BYTE 12 /* actually 11 and a half. */ #define SRCVERSION_PAD (GIT_HASH_BYTE - SRCVERSION_BYTE) #define SVN_STYLE_OD 16 struct version { uint32_t svn_revision; char git_hash[GIT_HASH_BYTE]; struct { unsigned major, minor, sublvl; } version; unsigned version_code; }; enum driver_version_policy { STRICT, FALLBACK_TO_UTILS }; extern const struct version *drbd_driver_version(enum driver_version_policy fallback); extern const struct version *drbd_utils_version(void); extern int version_code_kernel(void); extern int version_code_userland(void); extern int version_equal(const struct version *rev1, const struct version *rev2); extern void config_help_legacy(const char * const tool, const struct version * const driver_version); extern void add_lib_drbd_to_path(void); extern uint32_t crc32c(uint32_t crc, const uint8_t *data, unsigned int length); #endif drbd-utils-8.9.6/user/v9/drbdtool_common.c0000644000175000017500000003300212466702074020352 0ustar apoikosapoikos#define _GNU_SOURCE #define _XOPEN_SOURCE 600 #define _FILE_OFFSET_BITS 64 #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* for BLKGETSIZE64 */ #include #include #include "linux/drbd_config.h" #include "drbdtool_common.h" #include "config.h" static struct version __drbd_driver_version = {}; static struct version __drbd_utils_version = {}; void dt_pretty_print_uuids(const uint64_t* uuid, unsigned int flags) { printf( "\n" " +--< Current data generation UUID >-\n" " | +--< Bitmap's base data generation UUID >-\n" " | | +--< younger history UUID >-\n" " | | | +-< older history >-\n" " V V V V\n"); dt_print_uuids(uuid, flags); printf( " ^ ^ ^ ^ ^ ^ ^\n" " -< Data consistency flag >--+ | | | | | |\n" " -< Data was/is currently up-to-date >--+ | | | | |\n" " -< Node was/is currently primary >--+ | | | |\n" " -< Node was/is currently connected >--+ | | |\n" " -< Node was in the progress of setting all bits in the bitmap >--+ | |\n" " -< The peer's disk was out-dated or inconsistent >--+ |\n" " -< This node was a crashed primary, and has not seen its peer since >--+\n" "\n"); printf("flags:%s %s, %s, %s%s%s\n", (flags & MDF_CRASHED_PRIMARY) ? " crashed" : "", (flags & MDF_PRIMARY_IND) ? "Primary" : "Secondary", (flags & MDF_CONNECTED_IND) ? "Connected" : "StandAlone", (flags & MDF_CONSISTENT) ? ((flags & MDF_WAS_UP_TO_DATE) ? "UpToDate" : "Outdated") : "Inconsistent", (flags & MDF_FULL_SYNC) ? ", need full sync" : "", (flags & MDF_PEER_OUT_DATED) ? ", peer Outdated" : ""); printf("meta-data: %s\n", (flags & MDF_AL_CLEAN) ? "clean" : "need apply-al"); } void dt_print_v9_uuids(const uint64_t* uuid, unsigned int mdf_flags, unsigned int mdf_peer_flags) { int i; printf(X64(016)":"X64(016)":", uuid[UI_CURRENT], uuid[UI_BITMAP]); for ( i=UI_HISTORY_START ; i<=UI_HISTORY_END ; i++ ) { printf(X64(016)":", uuid[i]); } printf("%d:%d:%d:%d:%d:%d", mdf_flags & MDF_CONSISTENT ? 1 : 0, mdf_flags & MDF_WAS_UP_TO_DATE ? 1 : 0, mdf_flags & MDF_PRIMARY_IND ? 1 : 0, mdf_flags & MDF_CRASHED_PRIMARY ? 1 : 0, mdf_flags & MDF_AL_CLEAN ? 1 : 0, mdf_flags & MDF_AL_DISABLED ? 1 : 0); printf(":%d:%d:%d:%d\n", mdf_peer_flags & MDF_PEER_CONNECTED ? 1 : 0, mdf_peer_flags & MDF_PEER_OUTDATED ? 1 : 0, mdf_peer_flags & MDF_PEER_FENCING ? 1 : 0, mdf_peer_flags & MDF_PEER_FULL_SYNC ? 1 : 0); } void dt_pretty_print_v9_uuids(const uint64_t* uuid, unsigned int mdf_flags, unsigned int mdf_peer_flags) { printf( "\n" " +--< Current data generation UUID >-\n" " | +--< Bitmap's base data generation UUID >-\n" " | | +--< younger history UUID >-\n" " | | | +-< older history >-\n" " V V V V\n"); dt_print_v9_uuids(uuid, mdf_flags, mdf_peer_flags); printf( " ^ ^ ^ ^ ^ ^ ^ ^ ^ ^\n" " -< Data consistency flag >--+ | | | | | | | | |\n" " -< Data was/is currently up-to-date >--+ | | | | | | | |\n" " -< Node was/is currently primary >--+ | | | | | | |\n" " -< This node was a crashed primary, and has not seen its peer since >--+ | | | | | |\n" " -< The activity-log was applied, the disk can be attached >--+ | | | | |\n" " -< The activity-log was disabled, peer is completely out of sync >--+ | | | |\n" " -< Node was/is currently connected >--+ | | |\n" " -< The peer's disk was out-dated or inconsistent >--+ | |\n" " -< A fence policy other the dont-care was used >--+ |\n" " -< Node was in the progress of marking all blocks as out of sync >--+\n" "\n"); } const char *get_hostname(void) { static char *s_hostname; if (!s_hostname) { char hostname[HOST_NAME_MAX]; if (gethostname(hostname, sizeof(hostname))) { perror(hostname); exit(20); } s_hostname = strdup(hostname); } return s_hostname; } /* For our purpose (finding the revision) SLURP_SIZE is always enough. */ static char *slurp_proc_drbd() { const int SLURP_SIZE = 4096; char *buffer; int rr, fd; fd = open("/proc/drbd",O_RDONLY); if (fd == -1) return NULL; buffer = malloc(SLURP_SIZE); if(!buffer) goto fail; rr = read(fd, buffer, SLURP_SIZE-1); if (rr == -1) { free(buffer); buffer = NULL; goto fail; } buffer[rr]=0; fail: close(fd); return buffer; } static void read_hex(char *dst, char *src, int dst_size, int src_size) { int dst_i, u, src_i=0; for (dst_i=0; dst_i < dst_size; dst_i++) { if (src[src_i] == 0) break; if (src_size - src_i < 2) { sscanf(src+src_i, "%1x", &u); dst[dst_i] = u << 4; } else { sscanf(src+src_i, "%2x", &u); dst[dst_i] = u; } if (++src_i >= src_size) break; if (src[src_i] == 0) break; if (++src_i >= src_size) break; } } static void version_from_str(struct version *rel, const char *token) { char *dot; long maj, min, sub; maj = strtol(token, &dot, 10); if (*dot != '.') return; min = strtol(dot+1, &dot, 10); if (*dot != '.') return; sub = strtol(dot+1, &dot, 10); /* don't check on *dot == 0, * we may want to add some extraversion tag sometime if (*dot != 0) return; */ rel->version.major = maj; rel->version.minor = min; rel->version.sublvl = sub; rel->version_code = (maj << 16) + (min << 8) + sub; } static void parse_version(struct version *rel, const char *text) { char token[80]; int plus=0; enum { BEGIN, F_VER, F_SVN, F_REV, F_GIT, F_SRCV } ex = BEGIN; while (sget_token(token, sizeof(token), &text) != EOF) { switch(ex) { case BEGIN: if (!strcmp(token, "version:")) ex = F_VER; if (!strcmp(token, "SVN")) ex = F_SVN; if (!strcmp(token, "GIT-hash:")) ex = F_GIT; if (!strcmp(token, "srcversion:")) ex = F_SRCV; break; case F_VER: if (!strcmp(token, "plus")) { plus = 1; /* still waiting for version */ } else { version_from_str(rel, token); ex = BEGIN; } break; case F_SVN: if (!strcmp(token,"Revision:")) ex = F_REV; break; case F_REV: rel->svn_revision = atol(token) * 10; if (plus) rel->svn_revision += 1; memset(rel->git_hash, 0, GIT_HASH_BYTE); return; case F_GIT: read_hex(rel->git_hash, token, GIT_HASH_BYTE, strlen(token)); rel->svn_revision = 0; return; case F_SRCV: memset(rel->git_hash, 0, SRCVERSION_PAD); read_hex(rel->git_hash + SRCVERSION_PAD, token, SRCVERSION_BYTE, strlen(token)); rel->svn_revision = 0; return; } } } const struct version *drbd_driver_version(enum driver_version_policy fallback) { char *version_txt; char *drbd_driver_version_override; if (__drbd_driver_version.version_code) return &__drbd_driver_version; drbd_driver_version_override = getenv("DRBD_DRIVER_VERSION_OVERRIDE"); if (drbd_driver_version_override) { version_from_str(&__drbd_driver_version, drbd_driver_version_override); if (__drbd_driver_version.version_code) return &__drbd_driver_version; } version_txt = slurp_proc_drbd(); if (version_txt) { parse_version(&__drbd_driver_version, version_txt); free(version_txt); return &__drbd_driver_version; } else { FILE *in = popen("modinfo -F version drbd", "r"); if (in) { char buf[32]; int c = fscanf(in, "%30s", buf); pclose(in); if (c == 1) { version_from_str(&__drbd_driver_version, buf); return &__drbd_driver_version; } } } if (fallback == FALLBACK_TO_UTILS) return drbd_utils_version(); return NULL; } const struct version *drbd_utils_version(void) { if (!__drbd_utils_version.version_code) { version_from_str(&__drbd_utils_version, PACKAGE_VERSION); parse_version(&__drbd_utils_version, drbd_buildtag()); } return &__drbd_utils_version; } int version_code_kernel(void) { const struct version *driver_version = drbd_driver_version(STRICT); return driver_version ? driver_version->version_code : 0; } int version_code_userland(void) { const struct version *utils_version = drbd_utils_version(); return utils_version->version_code; } int version_equal(const struct version *rev1, const struct version *rev2) { if( rev1->svn_revision || rev2->svn_revision ) { return rev1->svn_revision == rev2->svn_revision; } else { return !memcmp(rev1->git_hash,rev2->git_hash,GIT_HASH_BYTE); } } void config_help_legacy(const char * const tool, const struct version * const driver_version) { fprintf(stderr, "This %s was build without support for drbd kernel code (%d.%d).\n" "Consider to rebuild your user land tools\n" "and configure --with-%d%d-support ...\n", tool, driver_version->version.major, driver_version->version.minor, driver_version->version.major, driver_version->version.minor); } void add_lib_drbd_to_path(void) { char *new_path = NULL; char *old_path = getenv("PATH"); static const char lib_drbd[]="/lib/drbd"; if (!old_path) setenv("PATH", lib_drbd, 1); else { m_asprintf(&new_path, "%s%s%s", old_path, (*old_path && old_path[strlen(old_path) -1] != ':') ? ":" : "", lib_drbd); setenv("PATH", new_path, 1); } } /* from linux/crypto/crc32.c */ static const uint32_t crc32c_table[256] = { 0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L, 0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL, 0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL, 0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L, 0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL, 0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L, 0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L, 0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL, 0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL, 0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L, 0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L, 0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL, 0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L, 0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL, 0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL, 0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L, 0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L, 0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L, 0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L, 0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L, 0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L, 0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L, 0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L, 0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L, 0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L, 0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L, 0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L, 0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L, 0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L, 0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L, 0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L, 0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L, 0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL, 0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L, 0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L, 0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL, 0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L, 0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL, 0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL, 0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L, 0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L, 0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL, 0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL, 0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L, 0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL, 0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L, 0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L, 0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL, 0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L, 0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL, 0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL, 0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L, 0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL, 0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L, 0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L, 0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL, 0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL, 0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L, 0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L, 0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL, 0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L, 0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL, 0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL, 0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L }; /* * Steps through buffer one byte at at time, calculates reflected * crc using table. */ uint32_t crc32c(uint32_t crc, const uint8_t *data, unsigned int length) { while (length--) crc = crc32c_table[(crc ^ *data++) & 0xFFL] ^ (crc >> 8); return crc; } drbd-utils-8.9.6/user/v9/drbd_nla.h0000644000175000017500000000044012466702074016743 0ustar apoikosapoikos#ifndef __DRBD_NLA_H #define __DRBD_NLA_H extern int drbd_nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla, const struct nla_policy *policy); extern struct nlattr *drbd_nla_find_nested(int maxtype, struct nlattr *nla, int attrtype); #endif /* __DRBD_NLA_H */ drbd-utils-8.9.6/user/v9/drbdsetup.c0000644000175000017500000034256112650365600017175 0ustar apoikosapoikos/* * DRBD setup via genetlink * * This file is part of DRBD by Philipp Reisner and Lars Ellenberg. * * Copyright (C) 2001-2008, LINBIT Information Technologies GmbH. * Copyright (C) 1999-2008, Philipp Reisner . * Copyright (C) 2002-2008, Lars Ellenberg . * * drbd is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * drbd is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with drbd; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #define _GNU_SOURCE #define _XOPEN_SOURCE 600 #define _FILE_OFFSET_BITS 64 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define EXIT_NOMEM 20 #define EXIT_NO_FAMILY 20 #define EXIT_SEND_ERR 20 #define EXIT_RECV_ERR 20 #define EXIT_TIMED_OUT 20 #define EXIT_NOSOCK 30 #define EXIT_THINKO 42 /* * We are not using libnl, * using its API for the few things we want to do * ends up being almost as much lines of code as * coding the necessary bits right here. */ #include "libgenl.h" #include "drbd_nla.h" #include #include #include #include "drbdtool_common.h" #include #include "drbd_strings.h" #include "registry.h" #include "config.h" #include "config_flags.h" #include "wrap_printf.h" #include "drbdsetup_colors.h" char *progname; /* for parsing of messages */ static struct nlattr *global_attrs[128]; /* there is an other table, nested_attr_tb, defined in genl_magic_func.h, * which can be used after _from_attrs, * to check for presence of struct fields. */ #define ntb(t) nested_attr_tb[__nla_type(t)] #ifdef PRINT_NLMSG_LEN /* I'm to lazy to check the maximum possible nlmsg length by hand */ int main(void) { static __u16 nla_attr_minlen[NLA_TYPE_MAX+1] __read_mostly = { [NLA_U8] = sizeof(__u8), [NLA_U16] = sizeof(__u16), [NLA_U32] = sizeof(__u32), [NLA_U64] = sizeof(__u64), [NLA_NESTED] = NLA_HDRLEN, }; int i; int sum_total = 0; #define LEN__(policy) do { \ int sum = 0; \ for (i = 0; i < ARRAY_SIZE(policy); i++) { \ sum += nla_total_size(policy[i].len ?: \ nla_attr_minlen[policy[i].type]); \ \ } \ sum += 4; \ sum_total += sum; \ printf("%-30s %4u [%4u]\n", \ #policy ":", sum, sum_total); \ } while (0) #define LEN_(p) LEN__(p ## _nl_policy) LEN_(disk_conf); LEN_(syncer_conf); LEN_(net_conf); LEN_(set_role_parms); LEN_(resize_parms); LEN_(state_info); LEN_(start_ov_parms); LEN_(new_c_uuid_parms); sum_total += sizeof(struct nlmsghdr) + sizeof(struct genlmsghdr) + sizeof(struct drbd_genlmsghdr); printf("sum total inclusive hdr overhead: %4u\n", sum_total); return 0; } #else #ifndef AF_INET_SDP #define AF_INET_SDP 27 #define PF_INET_SDP AF_INET_SDP #endif #define MULTIPLE_TIMEOUTS (-2) /* pretty print helpers */ static int indent = 0; #define INDENT_WIDTH 4 #define printI(fmt, args... ) printf("%*s" fmt,INDENT_WIDTH * indent,"" , ## args ) enum usage_type { BRIEF, FULL, XML, }; struct drbd_argument { const char* name; __u16 nla_type; int (*convert_function)(struct drbd_argument *, struct msg_buff *, struct drbd_genlmsghdr *dhdr, char *); }; /* Configuration requests typically need a context to operate on. * Possible keys are device minor/volume id (both fit in the drbd_genlmsghdr), * the replication link (aka connection) name, * and/or the replication group (aka resource) name */ enum cfg_ctx_key { /* Only one of these can be present in a command: */ CTX_RESOURCE = 1, CTX_PEER_NODE_ID = 2, CTX_MINOR = 4, CTX_VOLUME = 8, CTX_MY_ADDR = 16, CTX_PEER_ADDR = 32, CTX_ALL = 64, CTX_MULTIPLE_ARGUMENTS = 128, /* To identify a connection, we use (resource_name, peer_node_id) */ CTX_PEER_NODE = CTX_RESOURCE | CTX_PEER_NODE_ID | CTX_MULTIPLE_ARGUMENTS, CTX_PEER_DEVICE = CTX_PEER_NODE | CTX_VOLUME, }; enum cfg_ctx_key ctx_next_arg(enum cfg_ctx_key *key) { enum cfg_ctx_key next_arg; if (*key & CTX_MULTIPLE_ARGUMENTS) { next_arg = *key & ~(*key - 1); /* the lowest set bit */ next_arg &= ~CTX_MULTIPLE_ARGUMENTS; } else next_arg = *key; *key &= ~next_arg; return next_arg; } const char *ctx_arg_string(enum cfg_ctx_key key, enum usage_type ut) { bool xml = (ut == XML); switch(key) { case CTX_RESOURCE: return xml ? "resource" : "{resource}"; case CTX_PEER_NODE_ID: return xml ? "peer_node_id" : "{peer_node_id}"; case CTX_MINOR: return xml ? "minor" : "{minor}"; case CTX_VOLUME: return xml ? "volume" : "{volume}"; case CTX_MY_ADDR: return xml ? "local_addr" : "[local:][{af}:]{local_addr}[:{port}]"; case CTX_PEER_ADDR: return xml ? "remote_addr" : "[peer:][{af}:]{remote_addr}[:{port}]"; case CTX_ALL: return "all"; default: assert(0); } } struct drbd_cmd { const char* cmd; enum cfg_ctx_key ctx_key; int cmd_id; int tla_id; /* top level attribute id */ int (*function)(struct drbd_cmd *, int, char **); struct drbd_argument *drbd_args; int (*show_function)(struct drbd_cmd*, struct genl_info *, void *u_ptr); struct option *options; bool missing_ok; bool warn_on_missing; bool continuous_poll; bool set_defaults; bool lockless; struct context_def *ctx; const char *summary; }; // other functions static int get_af_ssocks(int warn); static void print_command_usage(struct drbd_cmd *cm, enum usage_type); static void print_usage_and_exit(const char* addinfo) __attribute__ ((noreturn)); // command functions static int generic_config_cmd(struct drbd_cmd *cm, int argc, char **argv); static int down_cmd(struct drbd_cmd *cm, int argc, char **argv); static int generic_get_cmd(struct drbd_cmd *cm, int argc, char **argv); static int del_minor_cmd(struct drbd_cmd *cm, int argc, char **argv); static int del_resource_cmd(struct drbd_cmd *cm, int argc, char **argv); static int show_cmd(struct drbd_cmd *cm, int argc, char **argv); static int status_cmd(struct drbd_cmd *cm, int argc, char **argv); static int role_cmd(struct drbd_cmd *cm, int argc, char **argv); static int cstate_cmd(struct drbd_cmd *cm, int argc, char **argv); static int dstate_cmd(struct drbd_cmd *cm, int argc, char **argv); static int check_resize_cmd(struct drbd_cmd *cm, int argc, char **argv); static int show_or_get_gi_cmd(struct drbd_cmd *cm, int argc, char **argv); // sub commands for generic_get_cmd static int print_notifications(struct drbd_cmd *, struct genl_info *, void *); static int wait_for_family(struct drbd_cmd *, struct genl_info *, void *); static int remember_resource(struct drbd_cmd *, struct genl_info *, void *); static int remember_device(struct drbd_cmd *, struct genl_info *, void *); static int remember_connection(struct drbd_cmd *, struct genl_info *, void *); static int remember_peer_device(struct drbd_cmd *, struct genl_info *, void *); #define ADDRESS_STR_MAX 256 static char *address_str(char *buffer, void* address, int addr_len); // convert functions for arguments static int conv_block_dev(struct drbd_argument *ad, struct msg_buff *msg, struct drbd_genlmsghdr *dhdr, char* arg); static int conv_md_idx(struct drbd_argument *ad, struct msg_buff *msg, struct drbd_genlmsghdr *dhdr, char* arg); static int conv_u32(struct drbd_argument *, struct msg_buff *, struct drbd_genlmsghdr *, char *); static int conv_addr(struct drbd_argument *ad, struct msg_buff *msg, struct drbd_genlmsghdr *dhdr, char* arg); struct resources_list { struct resources_list *next; char *name; struct nlattr *res_opts; struct resource_info info; struct resource_statistics statistics; }; static struct resources_list *list_resources(void); static struct resources_list *sort_resources(struct resources_list *); static void free_resources(struct resources_list *); struct devices_list { struct devices_list *next; unsigned minor; struct drbd_cfg_context ctx; struct nlattr *disk_conf_nl; struct disk_conf disk_conf; struct device_info info; struct device_statistics statistics; }; static struct devices_list *list_devices(char *); static void free_devices(struct devices_list *); struct connections_list { struct connections_list *next; struct drbd_cfg_context ctx; struct nlattr *path_list; struct nlattr *net_conf; struct connection_info info; struct connection_statistics statistics; }; static struct connections_list *sort_connections(struct connections_list *); static struct connections_list *list_connections(char *); static void free_connections(struct connections_list *); struct peer_devices_list { struct peer_devices_list *next; struct drbd_cfg_context ctx; struct nlattr *peer_device_conf; struct peer_device_info info; struct peer_device_statistics statistics; struct devices_list *device; int timeout_ms; /* used only by wait_for_family() */ }; static struct peer_devices_list *list_peer_devices(char *); static void free_peer_devices(struct peer_devices_list *); struct option wait_cmds_options[] = { { "wfc-timeout", required_argument, 0, 't' }, { "degr-wfc-timeout", required_argument, 0, 'd'}, { "outdated-wfc-timeout", required_argument, 0, 'o'}, { "wait-after-sb", optional_argument, 0, 'w'}, { } }; struct option events_cmd_options[] = { { "timestamps", no_argument, 0, 'T' }, { "statistics", no_argument, 0, 's' }, { "now", no_argument, 0, 'n' }, { "color", optional_argument, 0, 'c' }, { } }; struct option show_cmd_options[] = { { "show-defaults", no_argument, 0, 'D' }, { } }; static struct option status_cmd_options[] = { { "verbose", no_argument, 0, 'v' }, { "statistics", no_argument, 0, 's' }, { "color", optional_argument, 0, 'c' }, { } }; #define F_CONFIG_CMD generic_config_cmd #define NO_PAYLOAD 0 #define F_NEW_EVENTS_CMD(scmd) DRBD_ADM_GET_INITIAL_STATE, NO_PAYLOAD, generic_get_cmd, \ .show_function = scmd struct drbd_cmd commands[] = { {"primary", CTX_RESOURCE, DRBD_ADM_PRIMARY, DRBD_NLA_SET_ROLE_PARMS, F_CONFIG_CMD, .ctx = &primary_cmd_ctx, .summary = "Change the role of a node in a resource to primary." }, {"secondary", CTX_RESOURCE, DRBD_ADM_SECONDARY, NO_PAYLOAD, F_CONFIG_CMD, .summary = "Change the role of a node in a resource to secondary." }, {"attach", CTX_MINOR, DRBD_ADM_ATTACH, DRBD_NLA_DISK_CONF, F_CONFIG_CMD, .drbd_args = (struct drbd_argument[]) { { "lower_dev", T_backing_dev, conv_block_dev }, { "meta_data_dev", T_meta_dev, conv_block_dev }, { "meta_data_index", T_meta_dev_idx, conv_md_idx }, { } }, .ctx = &attach_cmd_ctx, .summary = "Attach a lower-level device to an existing replicated device." }, {"disk-options", CTX_MINOR, DRBD_ADM_CHG_DISK_OPTS, DRBD_NLA_DISK_CONF, F_CONFIG_CMD, .set_defaults = true, .ctx = &disk_options_ctx, .summary = "Change the disk options of an attached lower-level device." }, {"detach", CTX_MINOR, DRBD_ADM_DETACH, DRBD_NLA_DETACH_PARMS, F_CONFIG_CMD, .ctx = &detach_cmd_ctx, .summary = "Detach the lower-level device of a replicated device." }, {"connect", CTX_PEER_NODE, DRBD_ADM_CONNECT, DRBD_NLA_CONNECT_PARMS, F_CONFIG_CMD, .ctx = &connect_cmd_ctx, .summary = "Attempt to (re)establish a replication link to a peer host." }, {"new-peer", CTX_PEER_NODE, DRBD_ADM_NEW_PEER, DRBD_NLA_NET_CONF, F_CONFIG_CMD, .ctx = &new_peer_cmd_ctx, .summary = "Make a peer host known to a resource." }, {"del-peer", CTX_PEER_NODE, DRBD_ADM_DEL_PEER, DRBD_NLA_DISCONNECT_PARMS, F_CONFIG_CMD, .ctx = &disconnect_cmd_ctx, .summary = "Remove a connection to a peer host." }, {"new-path", CTX_PEER_NODE, DRBD_ADM_NEW_PATH, DRBD_NLA_PATH_PARMS, F_CONFIG_CMD, .drbd_args = (struct drbd_argument[]) { { "local-addr", T_my_addr, conv_addr }, { "remote-addr", T_peer_addr, conv_addr }, { } }, .ctx = &path_cmd_ctx, .summary = "Add a path (endpoint address pair) where a peer host should be reachable." }, {"del-path", CTX_PEER_NODE, DRBD_ADM_DEL_PATH, DRBD_NLA_PATH_PARMS, F_CONFIG_CMD, .drbd_args = (struct drbd_argument[]) { { "local-addr", T_my_addr, conv_addr }, { "remote-addr", T_peer_addr, conv_addr }, { } }, .ctx = &path_cmd_ctx, .summary = "Remove a path (endpoint address pair) from a connection to a peer host." }, {"net-options", CTX_PEER_NODE, DRBD_ADM_CHG_NET_OPTS, DRBD_NLA_NET_CONF, F_CONFIG_CMD, .set_defaults = true, .ctx = &net_options_ctx, .summary = "Change the network options of a connection." }, {"disconnect", CTX_PEER_NODE, DRBD_ADM_DISCONNECT, DRBD_NLA_DISCONNECT_PARMS, F_CONFIG_CMD, .ctx = &disconnect_cmd_ctx, .summary = "Unconnect from a peer host." }, {"resize", CTX_MINOR, DRBD_ADM_RESIZE, DRBD_NLA_RESIZE_PARMS, F_CONFIG_CMD, .ctx = &resize_cmd_ctx, .summary = "Reexamine the lower-level device sizes to resize a replicated device." }, {"resource-options", CTX_RESOURCE, DRBD_ADM_RESOURCE_OPTS, DRBD_NLA_RESOURCE_OPTS, F_CONFIG_CMD, .set_defaults = true, .ctx = &resource_options_ctx, .summary = "Change the resource options of an existing resource." }, {"peer-device-options", CTX_PEER_DEVICE, DRBD_ADM_CHG_PEER_DEVICE_OPTS, DRBD_NLA_PEER_DEVICE_OPTS, F_CONFIG_CMD, .set_defaults = true, .ctx = &peer_device_options_ctx, .summary = "Change peer-device options." }, {"new-current-uuid", CTX_MINOR, DRBD_ADM_NEW_C_UUID, DRBD_NLA_NEW_C_UUID_PARMS, F_CONFIG_CMD, .ctx = &new_current_uuid_cmd_ctx, .summary = "Generate a new current UUID." }, {"invalidate", CTX_MINOR, DRBD_ADM_INVALIDATE, DRBD_NLA_INVALIDATE_PARMS, F_CONFIG_CMD, .ctx = &invalidate_ctx, .summary = "Replace the local data of a volume with that of a peer." }, {"invalidate-remote", CTX_PEER_DEVICE, DRBD_ADM_INVAL_PEER, NO_PAYLOAD, F_CONFIG_CMD, .summary = "Replace a peer's data of a volume with the local data." }, {"pause-sync", CTX_PEER_DEVICE, DRBD_ADM_PAUSE_SYNC, NO_PAYLOAD, F_CONFIG_CMD, .summary = "Stop resynchronizing between a local and a peer device." }, {"resume-sync", CTX_PEER_DEVICE, DRBD_ADM_RESUME_SYNC, NO_PAYLOAD, F_CONFIG_CMD, .summary = "Allow resynchronization to resume on a replicated device." }, {"suspend-io", CTX_MINOR, DRBD_ADM_SUSPEND_IO, NO_PAYLOAD, F_CONFIG_CMD, .summary = "Suspend I/O on a replicated device." }, {"resume-io", CTX_MINOR, DRBD_ADM_RESUME_IO, NO_PAYLOAD, F_CONFIG_CMD, .summary = "Resume I/O on a replicated device." }, {"outdate", CTX_MINOR, DRBD_ADM_OUTDATE, NO_PAYLOAD, F_CONFIG_CMD, .summary = "Mark the data on a lower-level device as outdated." }, {"verify", CTX_PEER_DEVICE, DRBD_ADM_START_OV, DRBD_NLA_START_OV_PARMS, F_CONFIG_CMD, .ctx = &verify_cmd_ctx, .summary = "Verify the data on a lower-level device against a peer device." }, {"down", CTX_RESOURCE | CTX_ALL, DRBD_ADM_DOWN, NO_PAYLOAD, down_cmd, .missing_ok = true, .warn_on_missing = true, .summary = "Take a resource down." }, {"role", CTX_RESOURCE, 0, NO_PAYLOAD, role_cmd, .lockless = true, .summary = "Show the current role of a resource." }, {"cstate", CTX_PEER_NODE, 0, NO_PAYLOAD, cstate_cmd, .lockless = true, .summary = "Show the current state of a connection." }, {"dstate", CTX_MINOR, 0, NO_PAYLOAD, dstate_cmd, .lockless = true, .summary = "Show the current disk state of a lower-level device." }, {"show-gi", CTX_PEER_DEVICE, 0, NO_PAYLOAD, show_or_get_gi_cmd, .lockless = true, .summary = "Show the data generation identifiers for a device on a particular connection, with explanations." }, {"get-gi", CTX_PEER_DEVICE, 0, NO_PAYLOAD, show_or_get_gi_cmd, .lockless = true, .summary = "Show the data generation identifiers for a device on a particular connection." }, {"show", CTX_RESOURCE | CTX_ALL, 0, 0, show_cmd, .options = show_cmd_options, .lockless = true, .summary = "Show the current configuration of a resource, or of all resources." }, {"status", CTX_RESOURCE | CTX_ALL, 0, 0, status_cmd, .options = status_cmd_options, .lockless = true, .summary = "Show the state of a resource, or of all resources." }, {"check-resize", CTX_MINOR, 0, NO_PAYLOAD, check_resize_cmd, .lockless = true, .summary = "Remember the current size of a lower-level device." }, {"events2", CTX_RESOURCE | CTX_ALL, F_NEW_EVENTS_CMD(print_notifications), .options = events_cmd_options, .missing_ok = true, .continuous_poll = true, .lockless = true, .summary = "Show the current state and all state changes of a resource, or of all resources." }, {"wait-sync-volume", CTX_PEER_DEVICE, F_NEW_EVENTS_CMD(wait_for_family), .options = wait_cmds_options, .continuous_poll = true, .lockless = true, .summary = "Wait until resync finished on a volume." }, {"wait-sync-connection", CTX_PEER_NODE, F_NEW_EVENTS_CMD(wait_for_family), .options = wait_cmds_options, .continuous_poll = true, .lockless = true, .summary = "Wait until resync finished on all volumes of a connection." }, {"wait-sync-resource", CTX_RESOURCE, F_NEW_EVENTS_CMD(wait_for_family), .options = wait_cmds_options, .continuous_poll = true, .lockless = true, .summary = "Wait until resync finished on all volumes." }, {"wait-connect-volume", CTX_PEER_DEVICE, F_NEW_EVENTS_CMD(wait_for_family), .options = wait_cmds_options, .continuous_poll = true, .lockless = true, .summary = "Wait until a device on a peer is visible." }, {"wait-connect-connection", CTX_PEER_NODE, F_NEW_EVENTS_CMD(wait_for_family), .options = wait_cmds_options, .continuous_poll = true, .lockless = true, .summary = "Wait until all peer volumes of connection are visible." }, {"wait-connect-resource", CTX_RESOURCE, F_NEW_EVENTS_CMD(wait_for_family), .options = wait_cmds_options, .continuous_poll = true, .lockless = true, .summary = "Wait until all connections are establised." }, {"new-resource", CTX_RESOURCE, DRBD_ADM_NEW_RESOURCE, DRBD_NLA_RESOURCE_OPTS, F_CONFIG_CMD, .drbd_args = (struct drbd_argument[]) { { "node_id", T_node_id, conv_u32 }, { } }, .ctx = &resource_options_ctx, .summary = "Create a new resource." }, {"new-minor", CTX_RESOURCE | CTX_MINOR | CTX_VOLUME | CTX_MULTIPLE_ARGUMENTS, DRBD_ADM_NEW_MINOR, DRBD_NLA_DEVICE_CONF, F_CONFIG_CMD, .ctx = &device_options_ctx, .summary = "Create a new replicated device within a resource." }, {"del-minor", CTX_MINOR, DRBD_ADM_DEL_MINOR, NO_PAYLOAD, del_minor_cmd, .summary = "Remove a replicated device." }, {"del-resource", CTX_RESOURCE, DRBD_ADM_DEL_RESOURCE, NO_PAYLOAD, del_resource_cmd, .summary = "Remove a resource." }, {"forget-peer", CTX_RESOURCE, DRBD_ADM_FORGET_PEER, DRBD_NLA_FORGET_PEER_PARMS, F_CONFIG_CMD, .drbd_args = (struct drbd_argument[]) { { "peer_node_id", T_forget_peer_node_id, conv_u32 }, { } }, .summary = "Completely remove any reference to a unconnected peer from meta-data." }, }; bool show_defaults; bool wait_after_split_brain; #define OTHER_ERROR 900 #define EM(C) [ C - ERR_CODE_BASE ] /* The EM(123) are used for old error messages. */ static const char *error_messages[] = { EM(NO_ERROR) = "No further Information available.", EM(ERR_LOCAL_ADDR) = "Local address(port) already in use.", EM(ERR_PEER_ADDR) = "Remote address(port) already in use.", EM(ERR_OPEN_DISK) = "Can not open backing device.", EM(ERR_OPEN_MD_DISK) = "Can not open meta device.", EM(106) = "Lower device already in use.", EM(ERR_DISK_NOT_BDEV) = "Lower device is not a block device.", EM(ERR_MD_NOT_BDEV) = "Meta device is not a block device.", EM(109) = "Open of lower device failed.", EM(110) = "Open of meta device failed.", EM(ERR_DISK_TOO_SMALL) = "Low.dev. smaller than requested DRBD-dev. size.", EM(ERR_MD_DISK_TOO_SMALL) = "Meta device too small.", EM(113) = "You have to use the disk command first.", EM(ERR_BDCLAIM_DISK) = "Lower device is already claimed. This usually means it is mounted.", EM(ERR_BDCLAIM_MD_DISK) = "Meta device is already claimed. This usually means it is mounted.", EM(ERR_MD_IDX_INVALID) = "Lower device / meta device / index combination invalid.", EM(117) = "Currently we only support devices up to 3.998TB.\n" "(up to 2TB in case you do not have CONFIG_LBD set)\n" "Contact office@linbit.com, if you need more.", EM(ERR_IO_MD_DISK) = "IO error(s) occurred during initial access to meta-data.\n", EM(ERR_MD_UNCLEAN) = "Unclean meta-data found.\nYou need to 'drbdadm apply-al res'\n", EM(ERR_MD_INVALID) = "No valid meta-data signature found.\n\n" "\t==> Use 'drbdadm create-md res' to initialize meta-data area. <==\n", EM(ERR_AUTH_ALG) = "The 'cram-hmac-alg' you specified is not known in " "the kernel. (Maybe you need to modprobe it, or modprobe hmac?)", EM(ERR_AUTH_ALG_ND) = "The 'cram-hmac-alg' you specified is not a digest.", EM(ERR_NOMEM) = "kmalloc() failed. Out of memory?", EM(ERR_DISCARD_IMPOSSIBLE) = "--discard-my-data not allowed when primary.", EM(ERR_DISK_CONFIGURED) = "Device is attached to a disk (use detach first)", EM(ERR_NET_CONFIGURED) = "Device has a net-config (use disconnect first)", EM(ERR_MANDATORY_TAG) = "UnknownMandatoryTag", EM(ERR_MINOR_INVALID) = "Device minor not allocated", EM(128) = "Resulting device state would be invalid", EM(ERR_INTR) = "Interrupted by Signal", EM(ERR_RESIZE_RESYNC) = "Resize not allowed during resync.", EM(ERR_NO_PRIMARY) = "Need one Primary node to resize.", EM(ERR_RESYNC_AFTER) = "The resync-after minor number is invalid", EM(ERR_RESYNC_AFTER_CYCLE) = "This would cause a resync-after dependency cycle", EM(ERR_PAUSE_IS_SET) = "Sync-pause flag is already set", EM(ERR_PAUSE_IS_CLEAR) = "Sync-pause flag is already cleared", EM(136) = "Disk state is lower than outdated", EM(ERR_PACKET_NR) = "Kernel does not know how to handle your request.\n" "Maybe API_VERSION mismatch?", EM(ERR_NO_DISK) = "Device does not have a disk-config", EM(ERR_NOT_PROTO_C) = "Protocol C required", EM(ERR_NOMEM_BITMAP) = "vmalloc() failed. Out of memory?", EM(ERR_INTEGRITY_ALG) = "The 'data-integrity-alg' you specified is not known in " "the kernel. (Maybe you need to modprobe it, or modprobe hmac?)", EM(ERR_INTEGRITY_ALG_ND) = "The 'data-integrity-alg' you specified is not a digest.", EM(ERR_CPU_MASK_PARSE) = "Invalid cpu-mask.", EM(ERR_VERIFY_ALG) = "VERIFYAlgNotAvail", EM(ERR_VERIFY_ALG_ND) = "VERIFYAlgNotDigest", EM(ERR_VERIFY_RUNNING) = "Can not change verify-alg while online verify runs", EM(ERR_DATA_NOT_CURRENT) = "Can only attach to the data we lost last (see kernel log).", EM(ERR_CONNECTED) = "Need to be StandAlone", EM(ERR_CSUMS_ALG) = "CSUMSAlgNotAvail", EM(ERR_CSUMS_ALG_ND) = "CSUMSAlgNotDigest", EM(ERR_CSUMS_RESYNC_RUNNING) = "Can not change csums-alg while resync is in progress", EM(ERR_PERM) = "Permission denied. CAP_SYS_ADMIN necessary", EM(ERR_NEED_APV_93) = "Protocol version 93 required to use --assume-clean", EM(ERR_STONITH_AND_PROT_A) = "Fencing policy resource-and-stonith only with prot B or C allowed", EM(ERR_CONG_NOT_PROTO_A) = "on-congestion policy pull-ahead only with prot A allowed", EM(ERR_PIC_AFTER_DEP) = "Sync-pause flag is already cleared.\n" "Note: Resync pause caused by a local resync-after dependency.", EM(ERR_PIC_PEER_DEP) = "Sync-pause flag is already cleared.\n" "Note: Resync pause caused by the peer node.", EM(ERR_RES_NOT_KNOWN) = "Unknown resource", EM(ERR_RES_IN_USE) = "Resource still in use (delete all minors first)", EM(ERR_MINOR_CONFIGURED) = "Minor still configured (down it first)", EM(ERR_MINOR_OR_VOLUME_EXISTS) = "Minor or volume exists already (delete it first)", EM(ERR_INVALID_REQUEST) = "Invalid configuration request", EM(ERR_NEED_APV_100) = "Prot version 100 required in order to change\n" "these network options while connected", EM(ERR_NEED_ALLOW_TWO_PRI) = "Can not clear allow_two_primaries as long as\n" "there a primaries on both sides", EM(ERR_MD_LAYOUT_CONNECTED) = "DRBD need to be connected for online MD layout change\n", EM(ERR_MD_LAYOUT_TOO_BIG) = "Resulting AL area too big\n", EM(ERR_MD_LAYOUT_TOO_SMALL) = "Resulting AL are too small\n", EM(ERR_MD_LAYOUT_NO_FIT) = "Resulting AL does not fit into available meta data space\n", EM(ERR_IMPLICIT_SHRINK) = "Implicit device shrinking not allowed. See kernel log.\n", EM(ERR_INVALID_PEER_NODE_ID) = "Invalid peer-node-id\n", EM(ERR_CREATE_TRANSPORT) = "Failed to create transport (drbd_transport_xxx module missing?)\n", EM(ERR_LOCAL_AND_PEER_ADDR) = "Combination of local address(port) and remote address(port) already in use\n", }; #define MAX_ERROR (sizeof(error_messages)/sizeof(*error_messages)) const char * error_to_string(int err_no) { const unsigned int idx = err_no - ERR_CODE_BASE; if (idx >= MAX_ERROR) return "Unknown... maybe API_VERSION mismatch?"; return error_messages[idx]; } #undef MAX_ERROR char *cmdname = NULL; /* "drbdsetup" for reporting in usage etc. */ /* * In CTX_MINOR, CTX_RESOURCE, CTX_ALL, objname and minor refer to the object * the command operates on. */ char *objname; unsigned minor = -1U; struct drbd_cfg_context global_ctx; enum cfg_ctx_key context; int lock_fd; struct genl_sock *drbd_sock = NULL; struct genl_family drbd_genl_family = { .name = "drbd", .version = GENL_MAGIC_VERSION, .hdrsize = GENL_MAGIC_FAMILY_HDRSZ, }; #if 0 /* currently unused. */ static bool endpoints_equal(struct drbd_cfg_context *a, struct drbd_cfg_context *b) { return a->ctx_my_addr_len == b->ctx_my_addr_len && a->ctx_peer_addr_len == b->ctx_peer_addr_len && !memcmp(a->ctx_my_addr, b->ctx_my_addr, a->ctx_my_addr_len) && !memcmp(a->ctx_peer_addr, b->ctx_peer_addr, a->ctx_peer_addr_len); } #endif static int conv_block_dev(struct drbd_argument *ad, struct msg_buff *msg, struct drbd_genlmsghdr *dhdr, char* arg) { struct stat sb; int device_fd; if ((device_fd = open(arg,O_RDWR))==-1) { PERROR("Can not open device '%s'", arg); return OTHER_ERROR; } if (fstat(device_fd, &sb)) { PERROR("fstat(%s) failed", arg); return OTHER_ERROR; } if(!S_ISBLK(sb.st_mode)) { fprintf(stderr, "%s is not a block device!\n", arg); return OTHER_ERROR; } close(device_fd); nla_put_string(msg, ad->nla_type, arg); return NO_ERROR; } static int conv_md_idx(struct drbd_argument *ad, struct msg_buff *msg, struct drbd_genlmsghdr *dhdr, char* arg) { int idx; if(!strcmp(arg,"internal")) idx = DRBD_MD_INDEX_FLEX_INT; else if(!strcmp(arg,"flexible")) idx = DRBD_MD_INDEX_FLEX_EXT; else idx = m_strtoll(arg,1); nla_put_u32(msg, ad->nla_type, idx); return NO_ERROR; } static int conv_u32(struct drbd_argument *ad, struct msg_buff *msg, struct drbd_genlmsghdr *dhdr, char* arg) { unsigned int i = m_strtoll(arg, 1); nla_put_u32(msg, ad->nla_type, i); return NO_ERROR; } static void resolv6(const char *name, struct sockaddr_in6 *addr) { struct addrinfo hints, *res, *tmp; int err; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET6; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; err = getaddrinfo(name, 0, &hints, &res); if (err) { fprintf(stderr, "getaddrinfo %s: %s\n", name, gai_strerror(err)); exit(20); } /* Yes, it is a list. We use only the first result. The loop is only * there to document that we know it is a list */ for (tmp = res; tmp; tmp = tmp->ai_next) { memcpy(addr, tmp->ai_addr, sizeof(*addr)); break; } freeaddrinfo(res); if (0) { /* debug output */ char ip[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, &addr->sin6_addr, ip, sizeof(ip)); fprintf(stderr, "%s -> %02x %04x %08x %s %08x\n", name, addr->sin6_family, addr->sin6_port, addr->sin6_flowinfo, ip, addr->sin6_scope_id); } } static unsigned long resolv(const char* name) { unsigned long retval; if((retval = inet_addr(name)) == INADDR_NONE ) { struct hostent *he; he = gethostbyname(name); if (!he) { fprintf(stderr, "can not resolve the hostname: gethostbyname(%s): %s\n", name, hstrerror(h_errno)); exit(20); } retval = ((struct in_addr *)(he->h_addr_list[0]))->s_addr; } return retval; } static void split_ipv6_addr(char **address, int *port) { /* ipv6:[fe80::0234:5678:9abc:def1]:8000; */ char *b = strrchr(*address,']'); if (address[0][0] != '[' || b == NULL || (b[1] != ':' && b[1] != '\0')) { fprintf(stderr, "unexpected ipv6 format: %s\n", *address); exit(20); } *b = 0; *address += 1; /* skip '[' */ if (b[1] == ':') *port = m_strtoll(b+2,1); /* b+2: "]:" */ else *port = 7788; /* will we ever get rid of that default port? */ } static void split_address(int *af, char** address, int* port) { static struct { char* text; int af; } afs[] = { { "ipv4:", AF_INET }, { "ipv6:", AF_INET6 }, { "sdp:", AF_INET_SDP }, { "ssocks:", -1 }, }; unsigned int i; char *b; *af=AF_INET; for (i=0; isin6_port = htons(port); /* sin6->sin6_len = sizeof(*sin6); */ return sizeof(*sin6); } else { /* AF_INET, AF_SDP, AF_SSOCKS, * all use the IPv4 addressing scheme */ struct sockaddr_in *sin = (struct sockaddr_in *)storage; memset(sin, 0, sizeof(*sin)); sin->sin_port = htons(port); sin->sin_family = af; sin->sin_addr.s_addr = resolv(address); return sizeof(*sin); } return 0; } static int conv_addr(struct drbd_argument *ad, struct msg_buff *msg, struct drbd_genlmsghdr *dhdr, char* arg) { struct sockaddr_storage x; int addr_len; if (strncmp(arg, "local:", 6) == 0) arg += 6; else if (strncmp(arg, "peer:", 5) == 0) arg += 5; addr_len = sockaddr_from_str(&x, arg); if (addr_len == 0) { fprintf(stderr, "does not look like an endpoint address '%s'", arg); return OTHER_ERROR; } nla_put(msg, ad->nla_type, addr_len, &x); return NO_ERROR; } /* It will only print the WARNING if the warn flag is set with the _first_ call! */ #define PROC_NET_AF_SCI_FAMILY "/proc/net/af_sci/family" #define PROC_NET_AF_SSOCKS_FAMILY "/proc/net/af_ssocks/family" static int get_af_ssocks(int warn_and_use_default) { char buf[16]; int c, fd; static int af = -1; if (af > 0) return af; fd = open(PROC_NET_AF_SSOCKS_FAMILY, O_RDONLY); if (fd < 0) fd = open(PROC_NET_AF_SCI_FAMILY, O_RDONLY); if (fd < 0) { if (warn_and_use_default) { fprintf(stderr, "open(" PROC_NET_AF_SSOCKS_FAMILY ") " "failed: %m\n WARNING: assuming AF_SSOCKS = 27. " "Socket creation may fail.\n"); af = 27; } return af; } c = read(fd, buf, sizeof(buf)-1); if (c > 0) { buf[c] = 0; if (buf[c-1] == '\n') buf[c-1] = 0; af = m_strtoll(buf,1); } else { if (warn_and_use_default) { fprintf(stderr, "read(" PROC_NET_AF_SSOCKS_FAMILY ") " "failed: %m\n WARNING: assuming AF_SSOCKS = 27. " "Socket creation may fail.\n"); af = 27; } } close(fd); return af; } static struct option *make_longoptions(struct drbd_cmd *cm) { static struct option buffer[47]; int i = 0; int primary_force_index = -1; int connect_tentative_index = -1; if (cm->ctx) { struct field_def *field; /* * Make sure to keep cm->ctx->fields first: we use the index * returned by getopt_long() to access cm->ctx->fields. */ for (field = cm->ctx->fields; field->name; field++) { assert(i < ARRAY_SIZE(buffer)); buffer[i].name = field->name; buffer[i].has_arg = field->argument_is_optional ? optional_argument : required_argument; buffer[i].flag = NULL; buffer[i].val = 0; if (!strcmp(cm->cmd, "primary") && !strcmp(field->name, "force")) primary_force_index = i; if (!strcmp(cm->cmd, "connect") && !strcmp(field->name, "tentative")) connect_tentative_index = i; i++; } assert(field - cm->ctx->fields == i); } if (cm->options) { struct option *option; for (option = cm->options; option->name; option++) { assert(i < ARRAY_SIZE(buffer)); buffer[i] = *option; i++; } } if (primary_force_index != -1) { /* * For backward compatibility, add --overwrite-data-of-peer as * an alias to --force. */ assert(i < ARRAY_SIZE(buffer)); buffer[i] = buffer[primary_force_index]; buffer[i].name = "overwrite-data-of-peer"; buffer[i].val = 1000 + primary_force_index; i++; } if (connect_tentative_index != -1) { /* * For backward compatibility, add --dry-run as an alias to * --tentative. */ assert(i < ARRAY_SIZE(buffer)); buffer[i] = buffer[connect_tentative_index]; buffer[i].name = "dry-run"; buffer[i].val = 1000 + connect_tentative_index; i++; } if (cm->set_defaults) { assert(i < ARRAY_SIZE(buffer)); buffer[i].name = "set-defaults"; buffer[i].has_arg = 0; buffer[i].flag = NULL; buffer[i].val = '('; i++; } assert(i < ARRAY_SIZE(buffer)); buffer[i].name = NULL; buffer[i].has_arg = 0; buffer[i].flag = NULL; buffer[i].val = 0; return buffer; } /* prepends global objname to output (if any) */ static int check_error(int err_no, char *desc) { int rv = 0; if (err_no == NO_ERROR || err_no == SS_SUCCESS) return 0; if (err_no == OTHER_ERROR) { if (desc) fprintf(stderr,"%s: %s\n", objname, desc); return 20; } if ( ( err_no >= AFTER_LAST_ERR_CODE || err_no <= ERR_CODE_BASE ) && ( err_no > SS_CW_NO_NEED || err_no <= SS_AFTER_LAST_ERROR) ) { fprintf(stderr,"%s: Error code %d unknown.\n" "You should update the drbd userland tools.\n", objname, err_no); rv = 20; } else { if(err_no > ERR_CODE_BASE ) { fprintf(stderr,"%s: Failure: (%d) %s\n", objname, err_no, desc ?: error_to_string(err_no)); rv = 10; } else if (err_no == SS_UNKNOWN_ERROR) { fprintf(stderr,"%s: State change failed: (%d)" "unknown error.\n", objname, err_no); rv = 11; } else if (err_no > SS_TWO_PRIMARIES) { // Ignore SS_SUCCESS, SS_NOTHING_TO_DO, SS_CW_Success... } else { fprintf(stderr,"%s: State change failed: (%d) %s\n", objname, err_no, drbd_set_st_err_str(err_no)); if (err_no == SS_NO_UP_TO_DATE_DISK) { /* all available disks are inconsistent, * or I am consistent, but cannot outdate the peer. */ rv = 17; } else if (err_no == SS_LOWER_THAN_OUTDATED) { /* was inconsistent anyways */ rv = 5; } else if (err_no == SS_NO_LOCAL_DISK) { /* Can not start resync, no local disks, try with drbdmeta */ rv = 16; } else { rv = 11; } } } if (global_attrs[DRBD_NLA_CFG_REPLY] && global_attrs[DRBD_NLA_CFG_REPLY]->nla_len) { struct nlattr *nla; int rem; fprintf(stderr, "additional info from kernel:\n"); nla_for_each_nested(nla, global_attrs[DRBD_NLA_CFG_REPLY], rem) { if (nla_type(nla) == __nla_type(T_info_text)) fprintf(stderr, "%s\n", (char*)nla_data(nla)); } } return rv; } static void warn_print_excess_args(int argc, char **argv, int i) { fprintf(stderr, "Excess arguments:"); for (; i < argc; i++) fprintf(stderr, " %s", argv[i]); printf("\n"); } int drbd_tla_parse(struct nlmsghdr *nlh) { return nla_parse(global_attrs, ARRAY_SIZE(drbd_tla_nl_policy)-1, nlmsg_attrdata(nlh, GENL_HDRLEN + drbd_genl_family.hdrsize), nlmsg_attrlen(nlh, GENL_HDRLEN + drbd_genl_family.hdrsize), drbd_tla_nl_policy); } #define ASSERT(exp) if (!(exp)) \ fprintf(stderr,"ASSERT( " #exp " ) in %s:%d\n", __FILE__,__LINE__); static int _generic_config_cmd(struct drbd_cmd *cm, int argc, char **argv) { struct drbd_argument *ad; struct nlattr *nla; struct option *options; int c, i; int rv; char *desc = NULL; /* error description from kernel reply message */ struct drbd_genlmsghdr *dhdr; struct msg_buff *smsg; struct iovec iov; struct nlmsghdr *nlh; struct drbd_genlmsghdr *dh; struct timespec retry_timeout = { .tv_nsec = 62500000L, /* 1/16 second */ }; /* pre allocate request message and reply buffer */ iov.iov_len = DEFAULT_MSG_SIZE; iov.iov_base = malloc(iov.iov_len); smsg = msg_new(DEFAULT_MSG_SIZE); if (!smsg || !iov.iov_base) { desc = "could not allocate netlink messages"; rv = OTHER_ERROR; goto error; } nlh = (struct nlmsghdr*)iov.iov_base; dh = genlmsg_data(nlmsg_data(nlh)); dhdr = genlmsg_put(smsg, &drbd_genl_family, 0, cm->cmd_id); dhdr->minor = -1; dhdr->flags = 0; if (context & CTX_MINOR) dhdr->minor = minor; if (context & ~CTX_MINOR) { nla = nla_nest_start(smsg, DRBD_NLA_CFG_CONTEXT); if (context & CTX_RESOURCE) nla_put_string(smsg, T_ctx_resource_name, objname); if (context & CTX_PEER_NODE_ID) nla_put_u32(smsg, T_ctx_peer_node_id, global_ctx.ctx_peer_node_id); if (context & CTX_VOLUME) nla_put_u32(smsg, T_ctx_volume, global_ctx.ctx_volume); nla_nest_end(smsg, nla); } nla = NULL; options = make_longoptions(cm); optind = 0; /* reset getopt_long() */ for (;;) { int idx; c = getopt_long(argc, argv, "(", options, &idx); if (c == -1) break; if (c >= 1000) { /* This is a field alias. */ idx = c - 1000; c = 0; } if (c == 0) { struct field_def *field = &cm->ctx->fields[idx]; assert (field->name == options[idx].name); if (!nla) { assert (cm->tla_id != NO_PAYLOAD); nla = nla_nest_start(smsg, cm->tla_id); } if (!field->ops->put(cm->ctx, field, smsg, optarg)) { fprintf(stderr, "Option --%s: invalid " "argument '%s'\n", field->name, optarg); rv = OTHER_ERROR; goto error; } } else if (c == '(') dhdr->flags |= DRBD_GENL_F_SET_DEFAULTS; else { rv = OTHER_ERROR; goto error; } } for (i = optind, ad = cm->drbd_args; ad && ad->name; i++) { if (argc < i + 1) { fprintf(stderr, "Missing argument '%s'\n", ad->name); print_command_usage(cm, FULL); rv = OTHER_ERROR; goto error; } if (!nla) { assert (cm->tla_id != NO_PAYLOAD); nla = nla_nest_start(smsg, cm->tla_id); } rv = ad->convert_function(ad, smsg, dhdr, argv[i]); if (rv != NO_ERROR) goto error; ad++; } /* dhdr->minor may have been set by one of the convert functions. */ minor = dhdr->minor; if (nla) nla_nest_end(smsg, nla); /* argc should be cmd + n options + n args; * if it is more, we did not understand some */ if (i < argc) { warn_print_excess_args(argc, argv, i); rv = OTHER_ERROR; goto error; } for(;;) { if (genl_send(drbd_sock, smsg)) { desc = "error sending config command"; rv = OTHER_ERROR; goto error; } do { int received; /* reduce timeout! limit retries */ received = genl_recv_msgs(drbd_sock, &iov, &desc, 120000); if (received <= 0) { if (received == -E_RCV_ERROR_REPLY && !errno) continue; if (!desc) desc = "error receiving config reply"; rv = OTHER_ERROR; goto error; } } while (false); ASSERT(dh->minor == minor); rv = dh->ret_code; if (rv != SS_IN_TRANSIENT_STATE) break; nanosleep(&retry_timeout, NULL); /* Double the timeout, up to 10 seconds. */ if (retry_timeout.tv_sec < 10) { retry_timeout.tv_sec *= 2; retry_timeout.tv_nsec *= 2; if (retry_timeout.tv_nsec > 1000000000L) { retry_timeout.tv_sec++; retry_timeout.tv_nsec -= 1000000000L; } } } if (rv == ERR_RES_NOT_KNOWN) { if (cm->warn_on_missing && isatty(STDERR_FILENO)) fprintf(stderr, "Resource unknown\n"); if (cm->missing_ok) rv = NO_ERROR; } drbd_tla_parse(nlh); error: msg_free(smsg); rv = check_error(rv, desc); free(iov.iov_base); return rv; } static int generic_config_cmd(struct drbd_cmd *cm, int argc, char **argv) { return _generic_config_cmd(cm, argc, argv); } static int del_minor_cmd(struct drbd_cmd *cm, int argc, char **argv) { int rv; rv = generic_config_cmd(cm, argc, argv); if (!rv) unregister_minor(minor); return rv; } static int del_resource_cmd(struct drbd_cmd *cm, int argc, char **argv) { int rv; rv = generic_config_cmd(cm, argc, argv); if (!rv) unregister_resource(objname); return rv; } static struct drbd_cmd *find_cmd_by_name(const char *name) { unsigned int i; for (i = 0; i < ARRAY_SIZE(commands); i++) { if (!strcmp(name, commands[i].cmd)) { return commands + i; } } return NULL; } static void print_options(struct nlattr *attr, struct context_def *ctx, const char *sect_name) { struct field_def *field; int opened = 0; if (!attr) return; if (drbd_nla_parse_nested(nested_attr_tb, ctx->nla_policy_size - 1, attr, ctx->nla_policy)) { fprintf(stderr, "nla_policy violation for %s payload!\n", sect_name); /* still, print those that validated ok */ } for (field = ctx->fields; field->name; field++) { struct nlattr *nlattr; const char *str; bool is_default; nlattr = ntb(field->nla_type); if (!nlattr) continue; str = field->ops->get(ctx, field, nlattr); is_default = field->ops->is_default(field, str); if (is_default && !show_defaults) continue; if (!opened) { opened=1; printI("%s {\n",sect_name); ++indent; } if (field->needs_double_quoting) str = double_quote_string(str); printI("%-16s\t%s;",field->name, str); if (field->unit || is_default) { printf(" # "); if (field->unit) printf("%s", field->unit); if (field->unit && is_default) printf(", "); if (is_default) printf("default"); } printf("\n"); } if(opened) { --indent; printI("}\n"); } } struct choose_timeout_ctx { struct drbd_cfg_context ctx; struct msg_buff *smsg; struct iovec *iov; int timeout; int wfc_timeout; int degr_wfc_timeout; int outdated_wfc_timeout; }; int choose_timeout(struct choose_timeout_ctx *ctx) { char *desc = NULL; struct drbd_genlmsghdr *dhdr; struct nlattr *nla; int rr; if (0 < ctx->wfc_timeout && (ctx->wfc_timeout < ctx->degr_wfc_timeout || ctx->degr_wfc_timeout == 0)) { ctx->degr_wfc_timeout = ctx->wfc_timeout; fprintf(stderr, "degr-wfc-timeout has to be shorter than wfc-timeout\n" "degr-wfc-timeout implicitly set to wfc-timeout (%ds)\n", ctx->degr_wfc_timeout); } if (0 < ctx->degr_wfc_timeout && (ctx->degr_wfc_timeout < ctx->outdated_wfc_timeout || ctx->outdated_wfc_timeout == 0)) { ctx->outdated_wfc_timeout = ctx->wfc_timeout; fprintf(stderr, "outdated-wfc-timeout has to be shorter than degr-wfc-timeout\n" "outdated-wfc-timeout implicitly set to degr-wfc-timeout (%ds)\n", ctx->degr_wfc_timeout); } dhdr = genlmsg_put(ctx->smsg, &drbd_genl_family, 0, DRBD_ADM_GET_TIMEOUT_TYPE); dhdr->minor = -1; dhdr->flags = 0; nla = nla_nest_start(ctx->smsg, DRBD_NLA_CFG_CONTEXT); nla_put_string(ctx->smsg, T_ctx_resource_name, ctx->ctx.ctx_resource_name); nla_put_u32(ctx->smsg, T_ctx_peer_node_id, ctx->ctx.ctx_peer_node_id); nla_put_u32(ctx->smsg, T_ctx_volume, ctx->ctx.ctx_volume); nla_nest_end(ctx->smsg, nla); if (genl_send(drbd_sock, ctx->smsg)) { desc = "error sending config command"; goto error; } rr = genl_recv_msgs(drbd_sock, ctx->iov, &desc, 120000); if (rr > 0) { struct nlmsghdr *nlh = (struct nlmsghdr*)ctx->iov->iov_base; struct genl_info info = { .seq = nlh->nlmsg_seq, .nlhdr = nlh, .genlhdr = nlmsg_data(nlh), .userhdr = genlmsg_data(nlmsg_data(nlh)), .attrs = global_attrs, }; struct drbd_genlmsghdr *dh = info.userhdr; struct timeout_parms parms; rr = dh->ret_code; if (rr == ERR_MINOR_INVALID) { desc = "minor not available"; goto error; } if (rr != NO_ERROR) goto error; if (drbd_tla_parse(nlh) || timeout_parms_from_attrs(&parms, &info)) { desc = "reply did not validate - " "do you need to upgrade your userland tools?"; goto error; } rr = parms.timeout_type; ctx->timeout = (rr == UT_DEGRADED) ? ctx->degr_wfc_timeout : (rr == UT_PEER_OUTDATED) ? ctx->outdated_wfc_timeout : ctx->wfc_timeout; return 0; } error: if (!desc) desc = "error receiving netlink reply"; fprintf(stderr, "error determining which timeout to use: %s\n", desc); return 20; } #include static bool kernel_older_than(int version, int patchlevel, int sublevel) { struct utsname utsname; char *rel; int l; if (uname(&utsname) != 0) return false; rel = utsname.release; l = strtol(rel, &rel, 10); if (l > version) return false; else if (l < version || *rel == 0) return true; l = strtol(rel + 1, &rel, 10); if (l > patchlevel) return false; else if (l < patchlevel || *rel == 0) return true; l = strtol(rel + 1, &rel, 10); if (l >= sublevel) return false; return true; } static int shortest_timeout(struct peer_devices_list *peer_devices) { struct peer_devices_list *peer_device; int timeout = -1; for (peer_device = peer_devices; peer_device; peer_device = peer_device->next) { if (peer_device->timeout_ms > 0 && (peer_device->timeout_ms < timeout || timeout == -1)) timeout = peer_device->timeout_ms; } return timeout; } static bool update_timeouts(struct peer_devices_list *peer_devices, int elapsed) { struct peer_devices_list *peer_device; bool all_expired = true; for (peer_device = peer_devices; peer_device; peer_device = peer_device->next) { if (peer_device->timeout_ms != -1) { peer_device->timeout_ms -= elapsed; if (peer_device->timeout_ms < 0) peer_device->timeout_ms = 0; } if (peer_device->timeout_ms != 0) all_expired = false; } return all_expired; } static bool parse_color_argument(void) { if (!optarg || !strcmp(optarg, "always")) opt_color = ALWAYS_COLOR; else if (!strcmp(optarg, "never")) opt_color = NEVER_COLOR; else if (!strcmp(optarg, "auto")) opt_color = AUTO_COLOR; else return 0; return 1; } static bool opt_now; static bool opt_verbose; static bool opt_statistics; static bool opt_timestamps; static int generic_get(struct drbd_cmd *cm, int timeout_arg, void *u_ptr) { char *desc = NULL; struct drbd_genlmsghdr *dhdr; struct msg_buff *smsg; struct iovec iov; int timeout_ms, flags; int rv = NO_ERROR; int err = 0; /* pre allocate request message and reply buffer */ iov.iov_len = DEFAULT_MSG_SIZE; iov.iov_base = malloc(iov.iov_len); smsg = msg_new(DEFAULT_MSG_SIZE); if (!smsg || !iov.iov_base) { desc = "could not allocate netlink messages"; rv = OTHER_ERROR; goto out; } if (cm->continuous_poll) { if (genl_join_mc_group(drbd_sock, "events") && !kernel_older_than(2, 6, 23)) { desc = "unable to join drbd events multicast group"; rv = OTHER_ERROR; goto out2; } } flags = 0; if (minor == -1U) flags |= NLM_F_DUMP; dhdr = genlmsg_put(smsg, &drbd_genl_family, flags, cm->cmd_id); dhdr->minor = minor; dhdr->flags = 0; if (minor == -1U && strcmp(objname, "all")) { /* Restrict the dump to a single resource. */ struct nlattr *nla; nla = nla_nest_start(smsg, DRBD_NLA_CFG_CONTEXT); nla_put_string(smsg, T_ctx_resource_name, objname); nla_nest_end(smsg, nla); } if (genl_send(drbd_sock, smsg)) { desc = "error sending config command"; rv = OTHER_ERROR; goto out2; } /* disable sequence number check in genl_recv_msgs */ drbd_sock->s_seq_expect = 0; for (;;) { int received, rem, ret; struct nlmsghdr *nlh = (struct nlmsghdr *)iov.iov_base; struct timeval before; struct pollfd pollfds[2] = { [0] = { .fd = 1, .events = POLLHUP, }, [1] = { .fd = drbd_sock->s_fd, .events = POLLIN, }, }; gettimeofday(&before, NULL); timeout_ms = timeout_arg == MULTIPLE_TIMEOUTS ? shortest_timeout(u_ptr) : timeout_arg; ret = poll(pollfds, 2, timeout_arg); if (ret == 0) { err = 5; goto out2; } if (pollfds[0].revents == POLLERR || pollfds[0].revents == POLLHUP) goto out2; received = genl_recv_msgs(drbd_sock, &iov, &desc, -1); if (received < 0) { switch(received) { case E_RCV_TIMEDOUT: err = 5; goto out2; case -E_RCV_FAILED: err = 20; goto out2; case -E_RCV_NO_SOURCE_ADDR: continue; /* ignore invalid message */ case -E_RCV_SEQ_MISMATCH: /* we disabled it, so it should not happen */ err = 20; goto out2; case -E_RCV_MSG_TRUNC: continue; case -E_RCV_UNEXPECTED_TYPE: continue; case -E_RCV_NLMSG_DONE: if (cm->continuous_poll) continue; err = cm->show_function(cm, NULL, u_ptr); if (err) goto out2; err = -*(int*)nlmsg_data(nlh); if (err && (err != ENODEV || !cm->missing_ok)) { fprintf(stderr, "received netlink error reply: %s\n", strerror(err)); err = 20; } goto out2; case -E_RCV_ERROR_REPLY: if (!errno) /* positive ACK message */ continue; if (!desc) desc = strerror(errno); fprintf(stderr, "received netlink error reply: %s\n", desc); err = 20; goto out2; default: if (!desc) desc = "error receiving config reply"; err = 20; goto out2; } } if (timeout_ms != -1) { struct timeval after; int elapsed_ms; bool exit; gettimeofday(&after, NULL); elapsed_ms = (after.tv_sec - before.tv_sec) * 1000 + (after.tv_usec - before.tv_usec) / 1000; if (timeout_arg == MULTIPLE_TIMEOUTS) { exit = update_timeouts(u_ptr, elapsed_ms); } else { timeout_ms -= elapsed_ms; exit = timeout_ms <= 0; } if (exit) { err = 5; goto out2; } } /* There may be multiple messages in one datagram (for dump replies). */ nlmsg_for_each_msg(nlh, nlh, received, rem) { struct drbd_genlmsghdr *dh = genlmsg_data(nlmsg_data(nlh)); struct genl_info info = (struct genl_info){ .seq = nlh->nlmsg_seq, .nlhdr = nlh, .genlhdr = nlmsg_data(nlh), .userhdr = genlmsg_data(nlmsg_data(nlh)), .attrs = global_attrs, }; if (nlh->nlmsg_type < NLMSG_MIN_TYPE) { /* Ignore netlink control messages. */ continue; } if (nlh->nlmsg_type == GENL_ID_CTRL) { #ifdef HAVE_CTRL_CMD_DELMCAST_GRP if (info.genlhdr->cmd == CTRL_CMD_DELMCAST_GRP) { struct nlattr *nla = nlmsg_find_attr(nlh, GENL_HDRLEN, CTRL_ATTR_FAMILY_ID); if (nla && nla_get_u16(nla) == drbd_genl_family.id) { /* FIXME: We could wait for the multicast group to be recreated ... */ goto out2; } } #endif /* Ignore other generic netlink control messages. */ continue; } if (nlh->nlmsg_type != drbd_genl_family.id) { /* Ignore messages for all other netlink families. */ continue; } /* parse early, otherwise drbd_cfg_context_from_attrs * can not work */ if (drbd_tla_parse(nlh)) { /* FIXME * should continuous_poll continue? */ desc = "reply did not validate - " "do you need to upgrade your userland tools?"; rv = OTHER_ERROR; goto out2; } if (cm->continuous_poll) { struct drbd_cfg_context ctx; /* * We will receive all events and have to * filter for what we want ourself. */ /* FIXME * Do we want to ignore broadcasts until the * initial get/dump requests is done? */ if (!drbd_cfg_context_from_attrs(&ctx, &info)) { switch ((int)cm->ctx_key) { case CTX_MINOR: /* Assert that, for an unicast reply, * reply minor matches request minor. * "unsolicited" kernel broadcasts are "pid=0" (netlink "port id") * (and expected to be genlmsghdr.cmd == DRBD_EVENT) */ if (minor != dh->minor) { if (info.nlhdr->nlmsg_pid != 0) dbg(1, "received netlink packet for minor %u, while expecting %u\n", dh->minor, minor); continue; } break; case CTX_PEER_DEVICE: if (ctx.ctx_volume != global_ctx.ctx_volume) continue; /* also needs to match the connection, of course */ case CTX_PEER_NODE: if (ctx.ctx_peer_node_id != global_ctx.ctx_peer_node_id) continue; /* also needs to match the resource, of course */ case CTX_RESOURCE: case CTX_RESOURCE | CTX_ALL: if (!strcmp(objname, "all")) break; if (strcmp(objname, ctx.ctx_resource_name)) continue; break; default: fprintf(stderr, "DRECK: %x\n", cm->ctx_key); assert(0); } } } rv = dh->ret_code; if (rv == ERR_MINOR_INVALID && cm->missing_ok) rv = NO_ERROR; if (rv != NO_ERROR) goto out2; err = cm->show_function(cm, &info, u_ptr); if (err) { if (err < 0) err = 0; goto out2; } } if (!cm->continuous_poll && !(flags & NLM_F_DUMP)) { /* There will be no more reply packets. */ err = cm->show_function(cm, NULL, u_ptr); goto out2; } } out2: msg_free(smsg); out: if (!err) err = check_error(rv, desc); free(iov.iov_base); return err; } static int generic_get_cmd(struct drbd_cmd *cm, int argc, char **argv) { static struct option no_options[] = { { } }; struct choose_timeout_ctx timeo_ctx = { .wfc_timeout = DRBD_WFC_TIMEOUT_DEF, .degr_wfc_timeout = DRBD_DEGR_WFC_TIMEOUT_DEF, .outdated_wfc_timeout = DRBD_OUTDATED_WFC_TIMEOUT_DEF, }; int c, timeout_ms, err = NO_ERROR; struct peer_devices_list *peer_devices = NULL; struct option *options = cm->options ? cm->options : no_options; const char *opts = make_optstring(options); optind = 0; /* reset getopt_long() */ for(;;) { c = getopt_long(argc, argv, opts, options, 0); if (c == -1) break; switch(c) { default: case '?': return 20; case 't': timeo_ctx.wfc_timeout = m_strtoll(optarg, 1); if(DRBD_WFC_TIMEOUT_MIN > timeo_ctx.wfc_timeout || timeo_ctx.wfc_timeout > DRBD_WFC_TIMEOUT_MAX) { fprintf(stderr, "wfc_timeout => %d" " out of range [%d..%d]\n", timeo_ctx.wfc_timeout, DRBD_WFC_TIMEOUT_MIN, DRBD_WFC_TIMEOUT_MAX); return 20; } break; case 'd': timeo_ctx.degr_wfc_timeout = m_strtoll(optarg, 1); if(DRBD_DEGR_WFC_TIMEOUT_MIN > timeo_ctx.degr_wfc_timeout || timeo_ctx.degr_wfc_timeout > DRBD_DEGR_WFC_TIMEOUT_MAX) { fprintf(stderr, "degr_wfc_timeout => %d" " out of range [%d..%d]\n", timeo_ctx.degr_wfc_timeout, DRBD_DEGR_WFC_TIMEOUT_MIN, DRBD_DEGR_WFC_TIMEOUT_MAX); return 20; } break; case 'o': timeo_ctx.outdated_wfc_timeout = m_strtoll(optarg, 1); if(DRBD_OUTDATED_WFC_TIMEOUT_MIN > timeo_ctx.outdated_wfc_timeout || timeo_ctx.outdated_wfc_timeout > DRBD_OUTDATED_WFC_TIMEOUT_MAX) { fprintf(stderr, "outdated_wfc_timeout => %d" " out of range [%d..%d]\n", timeo_ctx.outdated_wfc_timeout, DRBD_OUTDATED_WFC_TIMEOUT_MIN, DRBD_OUTDATED_WFC_TIMEOUT_MAX); return 20; } break; case 'n': opt_now = true; break; case 's': opt_verbose = true; opt_statistics = true; break; case 'w': if (!optarg || !strcmp(optarg, "yes")) wait_after_split_brain = true; break; case 'D': show_defaults = true; break; case 'T': opt_timestamps = true; break; case 'c': if (!parse_color_argument()) print_usage_and_exit("unknown --color argument"); break; } } if (optind < argc) { warn_print_excess_args(argc, argv, optind + 1); return 20; } timeout_ms = -1; if (cm->show_function == &wait_for_family) { struct peer_devices_list *peer_device; struct msg_buff *smsg; struct iovec iov; int rr; char *res_name = cm->ctx_key & CTX_RESOURCE ? objname : "all"; peer_devices = list_peer_devices(res_name); iov.iov_len = DEFAULT_MSG_SIZE; iov.iov_base = malloc(iov.iov_len); smsg = msg_new(DEFAULT_MSG_SIZE); if (!smsg || !iov.iov_base) { msg_free(smsg); free(iov.iov_base); fprintf(stderr, "could not allocate netlink messages\n"); return 20; } timeo_ctx.smsg = smsg; timeo_ctx.iov = &iov; for (peer_device = peer_devices; peer_device; peer_device = peer_device->next) { timeo_ctx.ctx = peer_device->ctx; rr = choose_timeout(&timeo_ctx); if (rr) return rr; peer_device->timeout_ms = timeo_ctx.timeout ? timeo_ctx.timeout * 1000 : -1; /* rewind send message buffer */ smsg->tail = smsg->data; } msg_free(smsg); free(iov.iov_base); timeout_ms = MULTIPLE_TIMEOUTS; } if (!cm->continuous_poll) timeout_ms = 120000; /* normal "get" request, or "show" */ err = generic_get(cm, timeout_ms, peer_devices); free_peer_devices(peer_devices); return err; } static bool options_empty(struct nlattr *attr, struct context_def *ctx) { struct field_def *field; if (!attr) return true; if (drbd_nla_parse_nested(nested_attr_tb, ctx->nla_policy_size - 1, attr, ctx->nla_policy)) { fprintf(stderr, "nla_policy violation\n"); } for (field = ctx->fields; field->name; field++) { struct nlattr *nlattr; const char *str; bool is_default; nlattr = ntb(field->nla_type); if (!nlattr) continue; str = field->ops->get(ctx, field, nlattr); is_default = field->ops->is_default(field, str); if (is_default && !show_defaults) continue; return false; } return true; } static void show_peer_device(struct peer_devices_list *peer_device) { if (options_empty(peer_device->peer_device_conf, &peer_device_options_ctx)) return; printI("volume %d {\n", peer_device->ctx.ctx_volume); ++indent; print_options(peer_device->peer_device_conf, &peer_device_options_ctx, "disk"); --indent; printI("}\n"); } static void print_paths(struct connections_list *connection) { char address[ADDRESS_STR_MAX]; char *colon; struct nlattr *nla; int tmp; if (!connection->path_list) return; nla_for_each_nested(nla, connection->path_list, tmp) { int l = nla_len(nla); if (!address_str(address, nla_data(nla), l)) continue; colon = strchr(address, ':'); if (colon) *colon = ' '; if (nla->nla_type == T_my_addr) { printI("path {\n"); ++indent; printI("_this_host %s;\n", address); } if (nla->nla_type == T_peer_addr) { printI("_remote_host %s;\n", address); --indent; printI("}\n"); } } } static void show_connection(struct connections_list *connection, struct peer_devices_list *peer_devices) { struct peer_devices_list *peer_device; printI("connection {\n"); ++indent; printI("_peer_node_id %d;\n", connection->ctx.ctx_peer_node_id); print_paths(connection); if (connection->info.conn_connection_state == C_STANDALONE) printI("_is_standalone;\n"); print_options(connection->net_conf, &show_net_options_ctx, "net"); for (peer_device = peer_devices; peer_device; peer_device = peer_device->next) { if (connection->ctx.ctx_peer_node_id == peer_device->ctx.ctx_peer_node_id) show_peer_device(peer_device); } --indent; printI("}\n"); } static void show_volume(struct devices_list *device) { printI("volume %d {\n", device->ctx.ctx_volume); ++indent; printI("device\t\t\tminor %d;\n", device->minor); if (device->disk_conf.backing_dev[0]) { printI("disk\t\t\t\"%s\";\n", device->disk_conf.backing_dev); printI("meta-disk\t\t\t"); switch(device->disk_conf.meta_dev_idx) { case DRBD_MD_INDEX_INTERNAL: case DRBD_MD_INDEX_FLEX_INT: printf("internal;\n"); break; case DRBD_MD_INDEX_FLEX_EXT: printf("%s;\n", double_quote_string(device->disk_conf.meta_dev)); break; default: printf("%s [ %d ];\n", double_quote_string(device->disk_conf.meta_dev), device->disk_conf.meta_dev_idx); } } print_options(device->disk_conf_nl, &attach_cmd_ctx, "disk"); --indent; printI("}\n"); /* close volume */ } static int show_cmd(struct drbd_cmd *cm, int argc, char **argv) { struct resources_list *resources_list, *resource; char *old_objname = objname; int c; optind = 0; /* reset getopt_long() */ for (;;) { c = getopt_long(argc, argv, "D", show_cmd_options, 0); if (c == -1) break; switch(c) { default: case '?': return 20; case 'D': show_defaults = true; break; } } resources_list = sort_resources(list_resources()); for (resource = resources_list; resource; resource = resource->next) { struct devices_list *devices, *device; struct connections_list *connections, *connection; struct peer_devices_list *peer_devices = NULL; struct nlattr *nla; if (strcmp(old_objname, "all") && strcmp(old_objname, resource->name)) continue; devices = list_devices(resource->name); connections = sort_connections(list_connections(resource->name)); if (devices && connections) peer_devices = list_peer_devices(resource->name); objname = resource->name; printI("resource %s {\n", resource->name); ++indent; print_options(resource->res_opts, &resource_options_ctx, "options"); printI("_this_host {\n"); ++indent; nla = nla_find_nested(resource->res_opts, __nla_type(T_node_id)); if (nla) printI("node-id\t\t\t%d;\n", *(uint32_t *)nla_data(nla)); for (device = devices; device; device = device->next) show_volume(device); --indent; printI("}\n"); for (connection = connections; connection; connection = connection->next) show_connection(connection, peer_devices); --indent; printI("}\n\n"); free_connections(connections); free_devices(devices); free_peer_devices(peer_devices); } free(resources_list); objname = old_objname; return 0; } static const char *susp_str(struct resource_info *info) { static char buffer[32]; *buffer = 0; if (info->res_susp) strcat(buffer, ",user" + (*buffer == 0)); if (info->res_susp_nod) strcat(buffer, ",no-data" + (*buffer == 0)); if (info->res_susp_fen) strcat(buffer, ",fencing" + (*buffer == 0)); if (*buffer == 0) strcat(buffer, "no"); return buffer; } int nowrap_printf(int indent, const char *format, ...) { va_list ap; int ret; va_start(ap, format); ret = vprintf(format, ap); va_end(ap); return ret; } void print_resource_statistics(int indent, struct resource_statistics *old, struct resource_statistics *new, int (*wrap_printf)(int, const char *, ...)) { static const char *write_ordering_str[] = { [WO_NONE] = "none", [WO_DRAIN_IO] = "drain", [WO_BDEV_FLUSH] = "flush", [WO_BIO_BARRIER] = "barrier", }; uint32_t wo = new->res_stat_write_ordering; if ((!old || old->res_stat_write_ordering != wo) && wo < ARRAY_SIZE(write_ordering_str) && write_ordering_str[wo]) { wrap_printf(indent, " write-ordering:%s", write_ordering_str[wo]); } } void print_device_statistics(int indent, struct device_statistics *old, struct device_statistics *new, int (*wrap_printf)(int, const char *, ...)) { if (opt_statistics) { if (opt_verbose) wrap_printf(indent, " size:" U64, (uint64_t)new->dev_size / 2); wrap_printf(indent, " read:" U64, (uint64_t)new->dev_read / 2); wrap_printf(indent, " written:" U64, (uint64_t)new->dev_write / 2); if (opt_verbose) { wrap_printf(indent, " al-writes:" U64, (uint64_t)new->dev_al_writes); wrap_printf(indent, " bm-writes:" U64, (uint64_t)new->dev_bm_writes); wrap_printf(indent, " upper-pending:" U32, new->dev_upper_pending); wrap_printf(indent, " lower-pending:" U32, new->dev_lower_pending); if (!old || old->dev_al_suspended != new->dev_al_suspended) wrap_printf(indent, " al-suspended:%s", new->dev_al_suspended ? "yes" : "no"); } } if ((!old || old->dev_upper_blocked != new->dev_upper_blocked || old->dev_lower_blocked != new->dev_lower_blocked) && new->dev_size != -1 && (opt_verbose || new->dev_upper_blocked || new->dev_lower_blocked)) { const char *x1 = "", *x2 = ""; bool first = true; if (new->dev_upper_blocked) { x1 = ",upper" + first; first = false; } if (new->dev_lower_blocked) { x2 = ",lower" + first; first = false; } if (first) x1 = "no"; wrap_printf(indent, " blocked:%s%s", x1, x2); } } void print_connection_statistics(int indent, struct connection_statistics *old, struct connection_statistics *new, int (*wrap_printf)(int, const char *, ...)) { if (!old || old->conn_congested != new->conn_congested) wrap_printf(indent, " congested:%s", new->conn_congested ? "yes" : "no"); } void print_peer_device_statistics(int indent, struct peer_device_statistics *old, struct peer_device_statistics *new, int (*wrap_printf)(int, const char *, ...)) { wrap_printf(indent, " received:" U64, (uint64_t)new->peer_dev_received / 2); wrap_printf(indent, " sent:" U64, (uint64_t)new->peer_dev_sent / 2); if (opt_verbose || new->peer_dev_out_of_sync) wrap_printf(indent, " out-of-sync:" U64, (uint64_t)new->peer_dev_out_of_sync / 2); if (opt_verbose) { wrap_printf(indent, " pending:" U32, new->peer_dev_pending); wrap_printf(indent, " unacked:" U32, new->peer_dev_unacked); } } void resource_status(struct resources_list *resource) { enum drbd_role role = resource->info.res_role; wrap_printf(0, "%s", resource->name); if (opt_verbose) { struct nlattr *nla; nla = nla_find_nested(resource->res_opts, __nla_type(T_node_id)); if (nla) wrap_printf(4, " node-id:%d", *(uint32_t *)nla_data(nla)); } wrap_printf(4, " role:%s%s%s", role_color_start(role, true), drbd_role_str(role), role_color_stop(role, true)); if (opt_verbose || resource->info.res_susp || resource->info.res_susp_nod || resource->info.res_susp_fen) wrap_printf(4, " suspended:%s", susp_str(&resource->info)); if (opt_statistics && opt_verbose) { wrap_printf(4, "\n"); print_resource_statistics(4, NULL, &resource->statistics, wrap_printf); } wrap_printf(0, "\n"); } static void device_status(struct devices_list *device, bool single_device) { enum drbd_disk_state disk_state = device->info.dev_disk_state; int indent = 2; if (opt_verbose || !(single_device && device->ctx.ctx_volume == 0)) { wrap_printf(indent, "volume:%u", device->ctx.ctx_volume); indent = 6; if (opt_verbose) wrap_printf(indent, " minor:%u", device->minor); } wrap_printf(indent, " disk:%s%s%s", disk_state_color_start(disk_state, true), drbd_disk_str(disk_state), disk_state_color_stop(disk_state, true)); indent = 6; if (device->statistics.dev_size != -1) { if (opt_statistics) wrap_printf(indent, "\n"); print_device_statistics(indent, NULL, &device->statistics, wrap_printf); } wrap_printf(indent, "\n"); } static const char *resync_susp_str(struct peer_device_info *info) { static char buffer[64]; *buffer = 0; if (info->peer_resync_susp_user) strcat(buffer, ",user" + (*buffer == 0)); if (info->peer_resync_susp_peer) strcat(buffer, ",peer" + (*buffer == 0)); if (info->peer_resync_susp_dependency) strcat(buffer, ",dependency" + (*buffer == 0)); if (*buffer == 0) strcat(buffer, "no"); return buffer; } static void peer_device_status(struct peer_devices_list *peer_device, bool single_device) { int indent = 4; if (opt_verbose || !(single_device && peer_device->ctx.ctx_volume == 0)) { wrap_printf(indent, "volume:%d", peer_device->ctx.ctx_volume); indent = 8; } if (opt_verbose || peer_device->info.peer_repl_state > L_ESTABLISHED) { enum drbd_repl_state repl_state = peer_device->info.peer_repl_state; wrap_printf(indent, " replication:%s%s%s", repl_state_color_start(repl_state), drbd_repl_str(repl_state), repl_state_color_stop(repl_state)); indent = 8; } if (opt_verbose || opt_statistics || peer_device->info.peer_repl_state != L_OFF || peer_device->info.peer_disk_state != D_UNKNOWN) { enum drbd_disk_state disk_state = peer_device->info.peer_disk_state; wrap_printf(indent, " peer-disk:%s%s%s", disk_state_color_start(disk_state, false), drbd_disk_str(disk_state), disk_state_color_stop(disk_state, false)); indent = 8; if (peer_device->info.peer_repl_state >= L_SYNC_SOURCE && peer_device->info.peer_repl_state <= L_PAUSED_SYNC_T) { wrap_printf(indent, " done:%.2f", 100 * (1 - (double)peer_device->statistics.peer_dev_out_of_sync / (double)peer_device->device->statistics.dev_size)); } if (opt_verbose || peer_device->info.peer_resync_susp_user || peer_device->info.peer_resync_susp_peer || peer_device->info.peer_resync_susp_dependency) wrap_printf(indent, " resync-suspended:%s", resync_susp_str(&peer_device->info)); if (opt_statistics && peer_device->statistics.peer_dev_received != -1) { wrap_printf(indent, "\n"); print_peer_device_statistics(indent, NULL, &peer_device->statistics, wrap_printf); } } wrap_printf(0, "\n"); } static void peer_devices_status(struct drbd_cfg_context *ctx, struct peer_devices_list *peer_devices, bool single_device) { struct peer_devices_list *peer_device; for (peer_device = peer_devices; peer_device; peer_device = peer_device->next) { if (ctx->ctx_peer_node_id != peer_device->ctx.ctx_peer_node_id) continue; peer_device_status(peer_device, single_device); } } static void connection_status(struct connections_list *connection, struct peer_devices_list *peer_devices, bool single_device) { if (connection->ctx.ctx_conn_name_len) wrap_printf(2, "%s", connection->ctx.ctx_conn_name); if (opt_verbose || connection->ctx.ctx_conn_name_len == 0) { int in = connection->ctx.ctx_conn_name_len ? 6 : 2; wrap_printf(in, " node-id:%d", connection->ctx.ctx_peer_node_id); } if (opt_verbose || connection->info.conn_connection_state != C_CONNECTED) { enum drbd_conn_state cstate = connection->info.conn_connection_state; wrap_printf(6, " connection:%s%s%s", cstate_color_start(cstate), drbd_conn_str(cstate), cstate_color_stop(cstate)); } if (opt_verbose || connection->info.conn_connection_state == C_CONNECTED) { enum drbd_role role = connection->info.conn_role; wrap_printf(6, " role:%s%s%s", role_color_start(role, false), drbd_role_str(role), role_color_stop(role, false)); } if (opt_verbose || connection->statistics.conn_congested > 0) print_connection_statistics(6, NULL, &connection->statistics, wrap_printf); wrap_printf(0, "\n"); if (opt_verbose || opt_statistics || connection->info.conn_connection_state == C_CONNECTED) peer_devices_status(&connection->ctx, peer_devices, single_device); } static void stop_colors(int sig) { printf("%s", stop_color_code()); signal(sig, SIG_DFL); raise(sig); } static void link_peer_devices_to_devices(struct peer_devices_list *peer_devices, struct devices_list *devices) { struct peer_devices_list *peer_device; struct devices_list *device; for (peer_device = peer_devices; peer_device; peer_device = peer_device->next) { for (device = devices; device; device = device->next) { if (peer_device->ctx.ctx_volume == device->ctx.ctx_volume) { peer_device->device = device; break; } } } } static int status_cmd(struct drbd_cmd *cm, int argc, char **argv) { struct resources_list *resources, *resource; struct sigaction sa = { .sa_handler = stop_colors, .sa_flags = SA_RESETHAND, }; bool found = false; int c; optind = 0; /* reset getopt_long() */ for (;;) { c = getopt_long(argc, argv, make_optstring(cm->options), cm->options, 0); if (c == -1) break; switch(c) { default: case '?': return 20; case 'v': opt_verbose = true; break; case 's': opt_statistics = true; break; case 'c': if (!parse_color_argument()) print_usage_and_exit("unknown --color argument"); break; } } resources = sort_resources(list_resources()); sigaction(SIGHUP, &sa, NULL); sigaction(SIGINT, &sa, NULL); sigaction(SIGPIPE, &sa, NULL); sigaction(SIGTERM, &sa, NULL); for (resource = resources; resource; resource = resource->next) { struct devices_list *devices, *device; struct connections_list *connections, *connection; struct peer_devices_list *peer_devices = NULL; bool single_device; if (strcmp(objname, "all") && strcmp(objname, resource->name)) continue; devices = list_devices(resource->name); connections = sort_connections(list_connections(resource->name)); if (devices && connections) peer_devices = list_peer_devices(resource->name); link_peer_devices_to_devices(peer_devices, devices); resource_status(resource); single_device = devices && !devices->next; for (device = devices; device; device = device->next) device_status(device, single_device); for (connection = connections; connection; connection = connection->next) connection_status(connection, peer_devices, single_device); wrap_printf(0, "\n"); free_connections(connections); free_devices(devices); free_peer_devices(peer_devices); found = true; } free_resources(resources); if (!found && strcmp(objname, "all")) { fprintf(stderr, "%s: No such resource\n", objname); return 10; } return 0; } static int role_cmd(struct drbd_cmd *cm, int argc, char **argv) { struct resources_list *resources, *resource; int ret = ERR_RES_NOT_KNOWN; resources = list_resources(); for (resource = resources; resource; resource = resource->next) { if (strcmp(objname, resource->name)) continue; printf("%s\n", drbd_role_str(resource->info.res_role)); ret = NO_ERROR; break; } free_resources(resources); if (ret != NO_ERROR) { fprintf(stderr, "%s: %s\n", objname, error_to_string(ret)); return 10; } return 0; } static int cstate_cmd(struct drbd_cmd *cm, int argc, char **argv) { struct connections_list *connections, *connection; bool found = false; connections = list_connections(NULL); for (connection = connections; connection; connection = connection->next) { if (connection->ctx.ctx_peer_node_id != global_ctx.ctx_peer_node_id) continue; printf("%s\n", drbd_conn_str(connection->info.conn_connection_state)); found = true; break; } free_connections(connections); if (!found) { fprintf(stderr, "%s: No such connection\n", objname); return 10; } return 0; } static int dstate_cmd(struct drbd_cmd *cm, int argc, char **argv) { struct devices_list *devices, *device; bool found = false; struct peer_devices_list *peer_devices, *peer_device; devices = list_devices(NULL); for (device = devices; device; device = device->next) { if (device->minor != minor) continue; printf("%s", drbd_disk_str(device->info.dev_disk_state)); /* printf("%s/%s\n",drbd_disk_str(state.disk),drbd_disk_str(state.pdsk)); */ peer_devices = list_peer_devices(device->ctx.ctx_resource_name); for (peer_device = peer_devices; peer_device; peer_device = peer_device->next) { if (device->ctx.ctx_volume == peer_device->ctx.ctx_volume) printf("/%s", drbd_disk_str(peer_device->info.peer_disk_state)); } printf("\n"); found = true; break; } free_devices(devices); if (!found) { fprintf(stderr, "%s: No such device\n", objname); return 10; } return 0; } static char *af_to_str(int af) { if (af == AF_INET) return "ipv4"; else if (af == AF_INET6) return "ipv6"; /* AF_SSOCKS typically is 27, the same as AF_INET_SDP. * But with warn_and_use_default = 0, it will stay at -1 if not available. * Just keep the test on ssocks before the one on SDP (which is hard-coded), * and all should be fine. */ else if (af == get_af_ssocks(0)) return "ssocks"; else if (af == AF_INET_SDP) return "sdp"; else return "unknown"; } static char *address_str(char *buffer, void* address, int addr_len) { union { struct sockaddr addr; struct sockaddr_in addr4; struct sockaddr_in6 addr6; } a; /* avoid alignment issues on certain platforms (e.g. armel) */ memset(&a, 0, sizeof(a)); memcpy(&a.addr, address, addr_len); if (a.addr.sa_family == AF_INET || a.addr.sa_family == get_af_ssocks(0) || a.addr.sa_family == AF_INET_SDP) { snprintf(buffer, ADDRESS_STR_MAX, "%s:%s:%u", af_to_str(a.addr4.sin_family), inet_ntoa(a.addr4.sin_addr), ntohs(a.addr4.sin_port)); return buffer; } else if (a.addr.sa_family == AF_INET6) { char buf2[ADDRESS_STR_MAX]; int n; buf2[0] = 0; /* inet_ntop does not include scope info */ getnameinfo(&a.addr, addr_len, buf2, sizeof(buf2), NULL, 0, NI_NUMERICHOST|NI_NUMERICSERV); n = snprintf(buffer, ADDRESS_STR_MAX, "%s:[%s]:%u", af_to_str(a.addr6.sin6_family), buf2, ntohs(a.addr6.sin6_port)); assert(n > 0); assert(n < ADDRESS_STR_MAX); /* there should be no need to truncate */ return buffer; } else return NULL; } static int remember_resource(struct drbd_cmd *cmd, struct genl_info *info, void *u_ptr) { struct resources_list ***tail = u_ptr; struct drbd_cfg_context cfg = { .ctx_volume = -1U, .ctx_peer_node_id = -1U }; if (!info) return 0; drbd_cfg_context_from_attrs(&cfg, info); if (cfg.ctx_resource_name) { struct resources_list *r = calloc(1, sizeof(*r)); struct nlattr *res_opts = global_attrs[DRBD_NLA_RESOURCE_OPTS]; r->name = strdup(cfg.ctx_resource_name); if (res_opts) { int size = nla_total_size(nla_len(res_opts)); r->res_opts = malloc(size); memcpy(r->res_opts, res_opts, size); } resource_info_from_attrs(&r->info, info); memset(&r->statistics, -1, sizeof(r->statistics)); resource_statistics_from_attrs(&r->statistics, info); **tail = r; *tail = &r->next; } return 0; } static void free_resources(struct resources_list *resources) { while (resources) { struct resources_list *r = resources; resources = resources->next; free(r->name); free(r->res_opts); free(r); } } static int resource_name_cmp(const struct resources_list * const *a, const struct resources_list * const *b) { return strcmp((*a)->name, (*b)->name); } static struct resources_list *sort_resources(struct resources_list *resources) { struct resources_list *r; int n; for (r = resources, n = 0; r; r = r->next) n++; if (n > 1) { struct resources_list **array; array = malloc(sizeof(*array) * n); for (r = resources, n = 0; r; r = r->next) array[n++] = r; qsort(array, n, sizeof(*array), (int (*)(const void *, const void *)) resource_name_cmp); n--; array[n]->next = NULL; for (; n > 0; n--) array[n - 1]->next = array[n]; resources = array[0]; free(array); } return resources; } /* * Expects objname to be set to the resource name or "all". */ static struct resources_list *list_resources(void) { struct drbd_cmd cmd = { .cmd_id = DRBD_ADM_GET_RESOURCES, .show_function = remember_resource, .missing_ok = false, }; struct resources_list *list = NULL, **tail = &list; char *old_objname = objname; unsigned old_minor = minor; int old_my_addr_len = global_ctx.ctx_my_addr_len; int old_peer_addr_len = global_ctx.ctx_peer_addr_len; int err; objname = "all"; minor = -1; global_ctx.ctx_my_addr_len = 0; global_ctx.ctx_peer_addr_len = 0; err = generic_get(&cmd, 120000, &tail); objname = old_objname; minor = old_minor; global_ctx.ctx_my_addr_len = old_my_addr_len; global_ctx.ctx_peer_addr_len = old_peer_addr_len; if (err) { free_resources(list); list = NULL; } return list; } static int remember_device(struct drbd_cmd *cm, struct genl_info *info, void *u_ptr) { struct devices_list ***tail = u_ptr; struct drbd_cfg_context ctx = { .ctx_volume = -1U, .ctx_peer_node_id = -1U }; if (!info) return 0; drbd_cfg_context_from_attrs(&ctx, info); if (ctx.ctx_volume != -1U) { struct devices_list *d = calloc(1, sizeof(*d)); struct nlattr *disk_conf_nl = global_attrs[DRBD_NLA_DISK_CONF]; d->minor = ((struct drbd_genlmsghdr*)(info->userhdr))->minor; d->ctx = ctx; if (disk_conf_nl) { int size = nla_total_size(nla_len(disk_conf_nl)); d->disk_conf_nl = malloc(size); memcpy(d->disk_conf_nl, disk_conf_nl, size); } disk_conf_from_attrs(&d->disk_conf, info); d->info.dev_disk_state = D_DISKLESS; device_info_from_attrs(&d->info, info); memset(&d->statistics, -1, sizeof(d->statistics)); device_statistics_from_attrs(&d->statistics, info); **tail = d; *tail = &d->next; } return 0; } /* * Expects objname to be set to the resource name or "all". */ static struct devices_list *list_devices(char *resource_name) { struct drbd_cmd cmd = { .cmd_id = DRBD_ADM_GET_DEVICES, .show_function = remember_device, .missing_ok = false, }; struct devices_list *list = NULL, **tail = &list; char *old_objname = objname; unsigned old_minor = minor; int old_my_addr_len = global_ctx.ctx_my_addr_len; int old_peer_addr_len = global_ctx.ctx_peer_addr_len; int err; objname = resource_name ? resource_name : "all"; minor = -1; global_ctx.ctx_my_addr_len = 0; global_ctx.ctx_peer_addr_len = 0; err = generic_get(&cmd, 120000, &tail); objname = old_objname; minor = old_minor; global_ctx.ctx_my_addr_len = old_my_addr_len; global_ctx.ctx_peer_addr_len = old_peer_addr_len; if (err) { free_devices(list); list = NULL; } return list; } static void free_devices(struct devices_list *devices) { while (devices) { struct devices_list *d = devices; devices = devices->next; free(d->disk_conf_nl); free(d); } } static int remember_connection(struct drbd_cmd *cmd, struct genl_info *info, void *u_ptr) { struct connections_list ***tail = u_ptr; struct drbd_cfg_context ctx = { .ctx_volume = -1U, .ctx_peer_node_id = -1U }; if (!info) return 0; drbd_cfg_context_from_attrs(&ctx, info); if (ctx.ctx_resource_name) { struct connections_list *c = calloc(1, sizeof(*c)); struct nlattr *net_conf = global_attrs[DRBD_NLA_NET_CONF]; struct nlattr *path_list = global_attrs[DRBD_NLA_PATH_PARMS]; c->ctx = ctx; if (net_conf) { int size = nla_total_size(nla_len(net_conf)); c->net_conf = malloc(size); memcpy(c->net_conf, net_conf, size); } if (path_list) { int size = nla_total_size(nla_len(path_list)); c->path_list = malloc(size); memcpy(c->path_list, path_list, size); } connection_info_from_attrs(&c->info, info); memset(&c->statistics, -1, sizeof(c->statistics)); connection_statistics_from_attrs(&c->statistics, info); **tail = c; *tail = &c->next; } return 0; } static int connection_name_cmp(const struct connections_list * const *a, const struct connections_list * const *b) { if (!(*a)->ctx.ctx_conn_name_len != !(*b)->ctx.ctx_conn_name_len) return !(*b)->ctx.ctx_conn_name_len; return strcmp((*a)->ctx.ctx_conn_name, (*b)->ctx.ctx_conn_name); } static struct connections_list *sort_connections(struct connections_list *connections) { struct connections_list *c; int n; for (c = connections, n = 0; c; c = c->next) n++; if (n > 1) { struct connections_list **array; array = malloc(sizeof(*array) * n); for (c = connections, n = 0; c; c = c->next) array[n++] = c; qsort(array, n, sizeof(*array), (int (*)(const void *, const void *)) connection_name_cmp); n--; array[n]->next = NULL; for (; n > 0; n--) array[n - 1]->next = array[n]; connections = array[0]; free(array); } return connections; } /* * Expects objname to be set to the resource name or "all". */ static struct connections_list *list_connections(char *resource_name) { struct drbd_cmd cmd = { .cmd_id = DRBD_ADM_GET_CONNECTIONS, .show_function = remember_connection, .missing_ok = true, }; struct connections_list *list = NULL, **tail = &list; char *old_objname = objname; unsigned old_minor = minor; int old_my_addr_len = global_ctx.ctx_my_addr_len; int old_peer_addr_len = global_ctx.ctx_peer_addr_len; int err; objname = resource_name ? resource_name : "all"; minor = -1; global_ctx.ctx_my_addr_len = 0; global_ctx.ctx_peer_addr_len = 0; err = generic_get(&cmd, 120000, &tail); objname = old_objname; minor = old_minor; global_ctx.ctx_my_addr_len = old_my_addr_len; global_ctx.ctx_peer_addr_len = old_peer_addr_len; if (err) { free_connections(list); list = NULL; } return list; } static void free_connections(struct connections_list *connections) { while (connections) { struct connections_list *l = connections; connections = connections->next; free(l->net_conf); free(l); } } static int remember_peer_device(struct drbd_cmd *cmd, struct genl_info *info, void *u_ptr) { struct peer_devices_list ***tail = u_ptr; struct drbd_cfg_context ctx = { .ctx_volume = -1U, .ctx_peer_node_id = -1U }; if (!info) return 0; drbd_cfg_context_from_attrs(&ctx, info); if (ctx.ctx_resource_name) { struct peer_devices_list *p = calloc(1, sizeof(*p)); struct nlattr *peer_device_conf = global_attrs[DRBD_NLA_PEER_DEVICE_OPTS]; if (!p) exit(20); p->ctx = ctx; if (peer_device_conf) { int size = nla_total_size(nla_len(peer_device_conf)); p->peer_device_conf = malloc(size); memcpy(p->peer_device_conf, peer_device_conf, size); } peer_device_info_from_attrs(&p->info, info); memset(&p->statistics, -1, sizeof(p->statistics)); peer_device_statistics_from_attrs(&p->statistics, info); **tail = p; *tail = &p->next; } return 0; } /* * Expects objname to be set to the resource name or "all". */ static struct peer_devices_list *list_peer_devices(char *resource_name) { struct drbd_cmd cmd = { .cmd_id = DRBD_ADM_GET_PEER_DEVICES, .show_function = remember_peer_device, .missing_ok = false, }; struct peer_devices_list *list = NULL, **tail = &list; char *old_objname = objname; unsigned old_minor = minor; int old_my_addr_len = global_ctx.ctx_my_addr_len; int old_peer_addr_len = global_ctx.ctx_peer_addr_len; int err; objname = resource_name ? resource_name : "all"; minor = -1; global_ctx.ctx_my_addr_len = 0; global_ctx.ctx_peer_addr_len = 0; err = generic_get(&cmd, 120000, &tail); objname = old_objname; minor = old_minor; global_ctx.ctx_my_addr_len = old_my_addr_len; global_ctx.ctx_peer_addr_len = old_peer_addr_len; if (err) { free_peer_devices(list); list = NULL; } return list; } static void free_peer_devices(struct peer_devices_list *peer_devices) { while (peer_devices) { struct peer_devices_list *p = peer_devices; peer_devices = peer_devices->next; free(p->peer_device_conf); free(p); } } static int check_resize_cmd(struct drbd_cmd *cm, int argc, char **argv) { struct devices_list *devices, *device; bool found = false; bool ret = 0; devices = list_devices(NULL); for (device = devices; device; device = device->next) { struct bdev_info bd = { 0, }; uint64_t bd_size; int fd; if (device->minor != minor) continue; found = true; if (!device->disk_conf.backing_dev) { fprintf(stderr, "Has no disk config, try with drbdmeta.\n"); ret = 1; break; } if (device->disk_conf.meta_dev_idx >= 0 || device->disk_conf.meta_dev_idx == DRBD_MD_INDEX_FLEX_EXT) { lk_bdev_delete(minor); break; } fd = open(device->disk_conf.backing_dev, O_RDONLY); if (fd == -1) { fprintf(stderr, "Could not open %s: %m.\n", device->disk_conf.backing_dev); ret = 1; break; } bd_size = bdev_size(fd); close(fd); if (lk_bdev_load(minor, &bd) == 0 && bd.bd_size == bd_size && bd.bd_name && !strcmp(bd.bd_name, device->disk_conf.backing_dev)) break; /* nothing changed. */ bd.bd_size = bd_size; bd.bd_name = device->disk_conf.backing_dev; lk_bdev_save(minor, &bd); break; } free_devices(devices); if (!found) { fprintf(stderr, "%s: No such device\n", objname); return 10; } return ret; } static bool peer_device_ctx_match(struct drbd_cfg_context *a, struct drbd_cfg_context *b) { return strcmp(a->ctx_resource_name, b->ctx_resource_name) == 0 && a->ctx_peer_node_id == b->ctx_peer_node_id && a->ctx_volume == b->ctx_volume; } static int show_or_get_gi_cmd(struct drbd_cmd *cm, int argc, char **argv) { struct peer_devices_list *peer_devices, *peer_device; struct devices_list *devices = NULL, *device; uint64_t uuids[UI_SIZE]; int ret = 0, i; peer_devices = list_peer_devices(NULL); for (peer_device = peer_devices; peer_device; peer_device = peer_device->next) { if (!peer_device_ctx_match(&global_ctx, &peer_device->ctx)) continue; devices = list_devices(peer_device->ctx.ctx_resource_name); for (device = devices; device; device = device->next) { if (device->ctx.ctx_volume == global_ctx.ctx_volume) goto found; } } fprintf(stderr, "%s: No such peer device\n", objname); ret = 10; out: free_devices(devices); free_peer_devices(peer_devices); return ret; found: if (peer_device->info.peer_repl_state == L_OFF && device->info.dev_disk_state == D_DISKLESS) { fprintf(stderr, "Device is unconfigured\n"); ret = 1; goto out; } if (device->info.dev_disk_state == D_DISKLESS) { /* XXX we could print the exposed_data_uuid anyways: */ if (0) printf(X64(016)"\n", (uint64_t)device->statistics.dev_exposed_data_uuid); fprintf(stderr, "Device has no disk\n"); ret = 1; goto out; } memset(uuids, 0, sizeof(uuids)); uuids[UI_CURRENT] = device->statistics.dev_current_uuid; uuids[UI_BITMAP] = peer_device->statistics.peer_dev_bitmap_uuid; i = device->statistics.history_uuids_len / 8; if (i >= HISTORY_UUIDS_V08) i = HISTORY_UUIDS_V08 - 1; for (; i >= 0; i--) uuids[UI_HISTORY_START + i] = ((uint64_t *)device->statistics.history_uuids)[i]; if(!strcmp(cm->cmd, "show-gi")) dt_pretty_print_v9_uuids(uuids, device->statistics.dev_disk_flags, peer_device->statistics.peer_dev_flags); else dt_print_v9_uuids(uuids, device->statistics.dev_disk_flags, peer_device->statistics.peer_dev_flags); goto out; } static int down_cmd(struct drbd_cmd *cm, int argc, char **argv) { struct resources_list *resources, *resource; char *old_objname; int rv = 0; if(argc > 2) { warn_print_excess_args(argc, argv, 2); return OTHER_ERROR; } old_objname = objname; context = CTX_RESOURCE; resources = list_resources(); for (resource = resources; resource; resource = resource->next) { struct devices_list *devices; int rv2; if (strcmp(old_objname, "all") && strcmp(old_objname, resource->name)) continue; objname = resource->name; devices = list_devices(objname); rv2 = _generic_config_cmd(cm, argc, argv); if (!rv2) { struct devices_list *device; for (device = devices; device; device = device->next) unregister_minor(device->minor); unregister_resource(objname); } if (!rv) rv = rv2; free_devices(devices); } free_resources(resources); return rv; } static int event_key(char *key, int size, const char *name, unsigned minor, struct drbd_cfg_context *ctx) { char addr[ADDRESS_STR_MAX]; int ret, pos = 0; ret = snprintf(key + pos, size, "%s", name); if (ret < 0) return ret; pos += ret; if (size) size -= ret; if (ctx->ctx_resource_name) { ret = snprintf(key + pos, size, " name:%s", ctx->ctx_resource_name); if (ret < 0) return ret; pos += ret; if (size) size -= ret; } if (ctx->ctx_peer_node_id != -1U) { ret = snprintf(key + pos, size, " peer-node-id:%d", ctx->ctx_peer_node_id); if (ret < 0) return ret; pos += ret; if (size) size -= ret; } if (ctx->ctx_conn_name_len) { ret = snprintf(key + pos, size, " conn-name:%s", ctx->ctx_conn_name); if (ret < 0) return ret; pos += ret; if (size) size -= ret; } if (ctx->ctx_my_addr_len && address_str(addr, ctx->ctx_my_addr, ctx->ctx_my_addr_len)) { ret = snprintf(key + pos, size, " local:%s", addr); if (ret < 0) return ret; pos += ret; if (size) size -= ret; } if (ctx->ctx_peer_addr_len && address_str(addr, ctx->ctx_peer_addr, ctx->ctx_peer_addr_len)) { ret = snprintf(key + pos, size, " peer:%s", addr); if (ret < 0) return ret; pos += ret; if (size) size -= ret; } if (ctx->ctx_volume != -1U) { ret = snprintf(key + pos, size, " volume:%u", ctx->ctx_volume); if (ret < 0) return ret; pos += ret; if (size) size -= ret; } if (minor != -1U) { ret = snprintf(key + pos, size, " minor:%u", minor); if (ret < 0) return ret; pos += ret; /* if (size) */ /* size -= ret; */ } return pos; } static int known_objects_cmp(const void *a, const void *b) { return strcmp(((const struct entry *)a)->key, ((const struct entry *)b)->key); } static void *update_info(char **key, void *value, size_t size) { static void *known_objects; struct entry entry = { .key = *key }, **found; if (value) { void *old_value = NULL; found = tsearch(&entry, &known_objects, known_objects_cmp); if (*found != &entry) old_value = (*found)->data; else { *found = malloc(sizeof(**found)); if (!*found) goto fail; (*found)->key = *key; *key = NULL; } (*found)->data = malloc(size); if (!(*found)->data) goto fail; memcpy((*found)->data, value, size); return old_value; } else { found = tfind(&entry, &known_objects, known_objects_cmp); if (found) { struct entry *entry = *found; tdelete(entry, &known_objects, known_objects_cmp); free(entry->data); free(entry->key); free(entry); } return NULL; } fail: perror(progname); exit(20); } static int print_notifications(struct drbd_cmd *cm, struct genl_info *info, void *u_ptr) { static const char *action_name[] = { [NOTIFY_EXISTS] = "exists", [NOTIFY_CREATE] = "create", [NOTIFY_CHANGE] = "change", [NOTIFY_DESTROY] = "destroy", [NOTIFY_CALL] = "call", [NOTIFY_RESPONSE] = "response", }; static char *object_name[] = { [DRBD_RESOURCE_STATE] = "resource", [DRBD_DEVICE_STATE] = "device", [DRBD_CONNECTION_STATE] = "connection", [DRBD_PEER_DEVICE_STATE] = "peer-device", [DRBD_HELPER] = "helper", [DRBD_PATH_STATE] = "path", }; static uint32_t last_seq; static bool last_seq_known; static struct timeval tv; static bool keep_tv; struct drbd_cfg_context ctx = { .ctx_volume = -1U, .ctx_peer_node_id = -1U, }; struct drbd_notification_header nh = { .nh_type = -1U }; enum drbd_notification_type action; struct drbd_genlmsghdr *dh; char *key = NULL; if (!info) { keep_tv = false; return 0; } dh = info->userhdr; if (dh->ret_code == ERR_MINOR_INVALID && cm->missing_ok) return 0; if (dh->ret_code != NO_ERROR) return dh->ret_code; if (drbd_notification_header_from_attrs(&nh, info)) return 0; action = nh.nh_type & ~NOTIFY_FLAGS; if (action >= ARRAY_SIZE(action_name) || !action_name[action]) { dbg(1, "unknown notification type\n"); goto out; } if (opt_now && action != NOTIFY_EXISTS) return 0; if (info->genlhdr->cmd != DRBD_INITIAL_STATE_DONE) { if (drbd_cfg_context_from_attrs(&ctx, info)) return 0; if (info->genlhdr->cmd >= ARRAY_SIZE(object_name) || !object_name[info->genlhdr->cmd]) { dbg(1, "unknown notification\n"); goto out; } } if (action != NOTIFY_EXISTS) { if (last_seq_known) { int skipped = info->nlhdr->nlmsg_seq - (last_seq + 1); if (skipped) printf("- skipped %d\n", skipped); } last_seq = info->nlhdr->nlmsg_seq; last_seq_known = true; } if (opt_timestamps) { struct tm *tm; if (!keep_tv) gettimeofday(&tv, NULL); keep_tv = !!(nh.nh_type & NOTIFY_CONTINUES); tm = localtime(&tv.tv_sec); printf("%04u-%02u-%02uT%02u:%02u:%02u.%06u%+03d:%02u ", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)tv.tv_usec, (int)(tm->tm_gmtoff / 3600), (int)((abs(tm->tm_gmtoff) / 60) % 60)); } if (info->genlhdr->cmd != DRBD_INITIAL_STATE_DONE) { const char *name = object_name[info->genlhdr->cmd]; int size; size = event_key(NULL, 0, name, dh->minor, &ctx); if (size < 0) goto fail; key = malloc(size + 1); if (!key) goto fail; event_key(key, size + 1, name, dh->minor, &ctx); } printf("%s %s", action_name[action], key ? key : "-"); switch(info->genlhdr->cmd) { case DRBD_RESOURCE_STATE: if (action != NOTIFY_DESTROY) { struct { struct resource_info i; struct resource_statistics s; } *old, new; if (resource_info_from_attrs(&new.i, info)) { dbg(1, "resource info missing\n"); goto nl_out; } old = update_info(&key, &new, sizeof(new)); if (!old || new.i.res_role != old->i.res_role) printf(" role:%s%s%s", ROLE_COLOR_STRING(new.i.res_role, 1)); if (!old || new.i.res_susp != old->i.res_susp || new.i.res_susp_nod != old->i.res_susp_nod || new.i.res_susp_fen != old->i.res_susp_fen) printf(" suspended:%s", susp_str(&new.i)); if (opt_statistics) { if (resource_statistics_from_attrs(&new.s, info)) { dbg(1, "resource statistics missing\n"); if (old) new.s = old->s; } else print_resource_statistics(0, old ? &old->s : NULL, &new.s, nowrap_printf); } free(old); } else update_info(&key, NULL, 0); break; case DRBD_DEVICE_STATE: if (action != NOTIFY_DESTROY) { struct { struct device_info i; struct device_statistics s; } *old, new; if (device_info_from_attrs(&new.i, info)) { dbg(1, "device info missing\n"); goto nl_out; } old = update_info(&key, &new, sizeof(new)); if (!old || new.i.dev_disk_state != old->i.dev_disk_state) printf(" disk:%s%s%s", DISK_COLOR_STRING(new.i.dev_disk_state, 1)); if (opt_statistics) { if (device_statistics_from_attrs(&new.s, info)) { dbg(1, "device statistics missing\n"); if (old) new.s = old->s; } else print_device_statistics(0, old ? &old->s : NULL, &new.s, nowrap_printf); } free(old); } else update_info(&key, NULL, 0); break; case DRBD_CONNECTION_STATE: if (action != NOTIFY_DESTROY) { struct { struct connection_info i; struct connection_statistics s; } *old, new; if (connection_info_from_attrs(&new.i, info)) { dbg(1, "connection info missing\n"); goto nl_out; } old = update_info(&key, &new, sizeof(new)); if (!old || new.i.conn_connection_state != old->i.conn_connection_state) printf(" connection:%s%s%s", CONN_COLOR_STRING(new.i.conn_connection_state)); if (!old || new.i.conn_role != old->i.conn_role) printf(" role:%s%s%s", ROLE_COLOR_STRING(new.i.conn_role, 0)); if (opt_statistics) { if (connection_statistics_from_attrs(&new.s, info)) { dbg(1, "connection statistics missing\n"); if (old) new.s = old->s; } else print_connection_statistics(0, old ? &old->s : NULL, &new.s, nowrap_printf); } free(old); } else update_info(&key, NULL, 0); break; case DRBD_PEER_DEVICE_STATE: if (action != NOTIFY_DESTROY) { struct { struct peer_device_info i; struct peer_device_statistics s; } *old, new; if (peer_device_info_from_attrs(&new.i, info)) { dbg(1, "peer device info missing\n"); goto nl_out; } old = update_info(&key, &new, sizeof(new)); if (!old || new.i.peer_repl_state != old->i.peer_repl_state) printf(" replication:%s%s%s", REPL_COLOR_STRING(new.i.peer_repl_state)); if (!old || new.i.peer_disk_state != old->i.peer_disk_state) printf(" peer-disk:%s%s%s", DISK_COLOR_STRING(new.i.peer_disk_state, 0)); if (!old || new.i.peer_resync_susp_user != old->i.peer_resync_susp_user || new.i.peer_resync_susp_peer != old->i.peer_resync_susp_peer || new.i.peer_resync_susp_dependency != old->i.peer_resync_susp_dependency) printf(" resync-suspended:%s", resync_susp_str(&new.i)); if (opt_statistics) { if (peer_device_statistics_from_attrs(&new.s, info)) { dbg(1, "peer device statistics missing\n"); if (old) new.s = old->s; } else print_peer_device_statistics(0, old ? &old->s : NULL, &new.s, nowrap_printf); } free(old); } else update_info(&key, NULL, 0); break; case DRBD_PATH_STATE: if (action != NOTIFY_DESTROY) { struct drbd_path_info new = {}, *old; if (drbd_path_info_from_attrs(&new, info)) { dbg(1, "path info missing\n"); goto nl_out; } old = update_info(&key, &new, sizeof(new)); if (!old || old->path_established != new.path_established) printf(" established:%s", new.path_established ? "yes" : "no"); free(old); } else update_info(&key, NULL, 0); break; case DRBD_HELPER: { struct drbd_helper_info helper_info; if (!drbd_helper_info_from_attrs(&helper_info, info)) { printf(" helper:%s", helper_info.helper_name); if (action == NOTIFY_RESPONSE) printf(" status:%u", helper_info.helper_status); } else { dbg(1, "helper info missing\n"); goto nl_out; } } break; case DRBD_INITIAL_STATE_DONE: break; } nl_out: printf("\n"); out: free(key); fflush(stdout); if (opt_now && info->genlhdr->cmd == DRBD_INITIAL_STATE_DONE) return -1; return 0; fail: perror(progname); exit(20); } void peer_devices_append(struct peer_devices_list *peer_devices, struct genl_info *info) { struct peer_devices_list *peer_device, **tail; if (!peer_devices) return; for (peer_device = peer_devices; peer_device; peer_device = peer_device->next) tail = &peer_device->next; remember_peer_device(NULL, info, &tail); } /* Actually waits for all volumes of a connection... */ static int wait_for_family(struct drbd_cmd *cm, struct genl_info *info, void *u_ptr) { struct peer_devices_list *peer_devices = u_ptr; struct drbd_cfg_context ctx = { .ctx_volume = -1U, .ctx_peer_node_id = -1U }; struct drbd_notification_header nh = { .nh_type = -1U }; struct drbd_genlmsghdr *dh; if (!info) return 0; if (drbd_cfg_context_from_attrs(&ctx, info) || drbd_notification_header_from_attrs(&nh, info)) return 0; dh = info->userhdr; if (dh->ret_code != NO_ERROR) return dh->ret_code; if ((nh.nh_type & ~NOTIFY_FLAGS) == NOTIFY_DESTROY) return 0; switch(info->genlhdr->cmd) { case DRBD_CONNECTION_STATE: { struct connection_info connection_info; if ((nh.nh_type & ~NOTIFY_FLAGS) == NOTIFY_CREATE) break; /* Ignore C_STANDALONE while creating it */ if (connection_info_from_attrs(&connection_info, info)) { dbg(1, "connection info missing\n"); break; } if (connection_info.conn_connection_state < C_UNCONNECTED) { if (!wait_after_split_brain) return -1; /* done waiting */ fprintf(stderr, "\ndrbd%u (%s[%u]) is %s, " "but I'm configured to wait anways (--wait-after-sb)\n", dh->minor, ctx.ctx_resource_name, ctx.ctx_volume, drbd_conn_str(connection_info.conn_connection_state)); } break; } case DRBD_PEER_DEVICE_STATE: { struct peer_device_info peer_device_info; struct peer_devices_list *peer_device; int nr_peer_devices = 0, nr_done = 0; bool wait_connect; if (peer_device_info_from_attrs(&peer_device_info, info)) { dbg(1, "peer device info missing\n"); break; } wait_connect = strstr(cm->cmd, "sync") == NULL; if ((nh.nh_type & ~NOTIFY_FLAGS) == NOTIFY_CREATE) peer_devices_append(peer_devices, info); for (peer_device = peer_devices; peer_device; peer_device = peer_device->next) { enum drbd_repl_state rs; if (peer_device_ctx_match(&ctx, &peer_device->ctx)) peer_device->info = peer_device_info; /* wait-*-volume: filter out all but the specific peer device */ if (cm->ctx_key == CTX_PEER_DEVICE && !peer_device_ctx_match(&global_ctx, &peer_device->ctx)) continue; /* wait-*-connection: filter out other connections */ if (cm->ctx_key == CTX_PEER_NODE && peer_device->ctx.ctx_peer_node_id != global_ctx.ctx_peer_node_id) continue; /* wait-*-resource: no filter */ nr_peer_devices++; rs = peer_device->info.peer_repl_state; if (rs == L_ESTABLISHED || (wait_connect && rs > L_ESTABLISHED) || peer_device->timeout_ms == 0) nr_done++; } if (nr_peer_devices == nr_done) return -1; /* Done with waiting */ break; } } return 0; } /* * Check if an integer is a power of two. */ static bool power_of_two(int i) { return i && !(i & (i - 1)); } static void print_command_usage(struct drbd_cmd *cm, enum usage_type ut) { struct drbd_argument *args; if(ut == XML) { printf("\n", cm->cmd); if (cm->summary) printf("\t%s\n", cm->summary); if (cm->ctx_key && ut != BRIEF) { enum cfg_ctx_key ctx = cm->ctx_key, arg; bool more_than_one_choice = !power_of_two(ctx & ~CTX_MULTIPLE_ARGUMENTS) && !(ctx & CTX_MULTIPLE_ARGUMENTS); const char *indent = "\t\t" + !more_than_one_choice; if (more_than_one_choice) printf("\t\n"); ctx |= CTX_MULTIPLE_ARGUMENTS; for (arg = ctx_next_arg(&ctx); arg; arg = ctx_next_arg(&ctx)) printf("%s%s\n", indent, ctx_arg_string(arg, ut)); if (more_than_one_choice) printf("\t\n"); } if(cm->drbd_args) { for (args = cm->drbd_args; args->name; args++) { printf("\t%s\n", args->name); } } if (cm->options) { struct option *option; for (option = cm->options; option->name; option++) { /* * The "string" options here really are * timeouts, but we can't describe them * in a resonable way here. */ printf("\t\n", option->name, option->has_arg == no_argument ? "flag" : "string"); } } if (cm->set_defaults) printf("\t\n"); if (cm->ctx) { struct field_def *field; for (field = cm->ctx->fields; field->name; field++) field->ops->describe_xml(field); } printf("\n"); return; } if (ut == BRIEF) { wrap_printf(4, "%s - ", cm->cmd); if (cm->summary) wrap_printf_wordwise(8, cm->summary); wrap_printf(4, "\n"); } else { wrap_printf(0, "%s %s", progname, cm->cmd); if (cm->summary) wrap_printf(4, " - %s", cm->summary); wrap_printf(4, "\n\n"); wrap_printf(0, "USAGE: %s %s", progname, cm->cmd); if (cm->ctx_key && ut != BRIEF) { enum cfg_ctx_key ctx = cm->ctx_key, arg; bool more_than_one_choice = !power_of_two(ctx & ~CTX_MULTIPLE_ARGUMENTS) && !(ctx & CTX_MULTIPLE_ARGUMENTS); bool first = true; if (more_than_one_choice) wrap_printf(4, " {"); ctx |= CTX_MULTIPLE_ARGUMENTS; for (arg = ctx_next_arg(&ctx); arg; arg = ctx_next_arg(&ctx)) { if (more_than_one_choice && !first) wrap_printf(4, " |"); first = false; wrap_printf(4, " %s", ctx_arg_string(arg, ut)); } if (more_than_one_choice) wrap_printf(4, " }"); } if (cm->drbd_args) { for (args = cm->drbd_args; args->name; args++) wrap_printf(4, " {%s}", args->name); } if (cm->options || cm->set_defaults || cm->ctx) wrap_printf(4, "\n"); if (cm->options) { struct option *option; for (option = cm->options; option->name; option++) wrap_printf(4, " [--%s%s]", option->name, option->has_arg == no_argument ? "" : "=..."); } if (cm->set_defaults) wrap_printf(4, " [--set-defaults]"); if (cm->ctx) { struct field_def *field; for (field = cm->ctx->fields; field->name; field++) { char buffer[300]; int n; n = field->ops->usage(field, buffer, sizeof(buffer)); assert(n < sizeof(buffer)); wrap_printf(4, " %s", buffer); } } wrap_printf(4, "\n"); } } static void print_usage_and_exit(const char* addinfo) { size_t i; printf("drbdsetup - Configure the DRBD kernel module.\n\n" "USAGE: %s command {arguments} [options]\n" "\nCommands:\n",cmdname); for (i = 0; i < ARRAY_SIZE(commands); i++) print_command_usage(&commands[i], BRIEF); printf("\nUse 'drbdsetup help command' for command-specific help.\n\n"); if (addinfo) /* FIXME: ?! */ printf("\n%s\n",addinfo); exit(20); } static int modprobe_drbd(void) { struct stat sb; int ret, retries = 10; ret = stat("/proc/drbd", &sb); if (ret && errno == ENOENT) { ret = system("/sbin/modprobe drbd"); if (ret != 0) { fprintf(stderr, "Failed to modprobe drbd (%m)\n"); return 0; } for(;;) { struct timespec ts = { .tv_nsec = 1000000, }; ret = stat("/proc/drbd", &sb); if (!ret || retries-- == 0) break; nanosleep(&ts, NULL); } } if (ret) { fprintf(stderr, "Could not stat /proc/drbd: %m\n"); fprintf(stderr, "Make sure that the DRBD kernel module is installed " "and can be loaded!\n"); } return ret == 0; } static void maybe_exec_legacy_drbdsetup(char **argv) { const struct version *driver_version = drbd_driver_version(FALLBACK_TO_UTILS); if (driver_version->version.major == 8 && driver_version->version.minor == 3) { #ifdef DRBD_LEGACY_83 static const char * const drbdsetup_83 = "drbdsetup-83"; add_lib_drbd_to_path(); execvp(drbdsetup_83, argv); fprintf(stderr, "execvp() failed to exec %s: %m\n", drbdsetup_83); #else config_help_legacy("drbdsetup", driver_version); #endif exit(20); } if (driver_version->version.major == 8 && driver_version->version.minor == 4) { #ifdef DRBD_LEGACY_84 static const char * const drbdsetup_84 = "drbdsetup-84"; add_lib_drbd_to_path(); execvp(drbdsetup_84, argv); fprintf(stderr, "execvp() failed to exec %s: %m\n", drbdsetup_84); #else config_help_legacy("drbdsetup", driver_version); #endif exit(20); } } int main(int argc, char **argv) { struct drbd_cmd *cmd; struct option *options; int c, rv = 0; int longindex, first_optind; progname = basename(argv[0]); if (chdir("/")) { /* highly unlikely, but gcc is picky */ perror("cannot chdir /"); return -111; } cmdname = strrchr(argv[0],'/'); if (cmdname) argv[0] = ++cmdname; else cmdname = argv[0]; if (argc > 2 && (!strcmp(argv[2], "--help") || !strcmp(argv[2], "-h"))) { char *swap = argv[1]; argv[1] = argv[2]; argv[2] = swap; } if (argc > 1 && (!strcmp(argv[1], "help") || !strcmp(argv[1], "xml-help") || !strcmp(argv[1], "--help") || !strcmp(argv[1], "-h"))) { enum usage_type usage_type = !strcmp(argv[1], "xml-help") ? XML : FULL; if(argc > 2) { cmd = find_cmd_by_name(argv[2]); if(cmd) { print_command_usage(cmd, usage_type); exit(0); } else print_usage_and_exit("unknown command"); } else print_usage_and_exit(0); } /* * drbdsetup previously took the object to operate on as its first argument, * followed by the command. For backwards compatibility, still support his. */ if (argc >= 3 && !find_cmd_by_name(argv[1]) && find_cmd_by_name(argv[2])) { char *swap = argv[1]; argv[1] = argv[2]; argv[2] = swap; } if (argc < 2) print_usage_and_exit(0); if (!modprobe_drbd()) { if (!strcmp(argv[1], "down") || !strcmp(argv[1], "secondary") || !strcmp(argv[1], "disconnect") || !strcmp(argv[1], "detach")) return 0; /* "down" succeeds even if drbd is missing */ return 20; } maybe_exec_legacy_drbdsetup(argv); cmd = find_cmd_by_name(argv[1]); if (!cmd) print_usage_and_exit("invalid command"); /* Make argv[0] the command name so that getopt_long() will leave it in * the first position. */ argv++; argc--; options = make_longoptions(cmd); for (;;) { c = getopt_long(argc, argv, "(", options, &longindex); if (c == -1) break; if (c == '?' || c == ':') print_usage_and_exit(0); } /* All non-option arguments now are in argv[optind .. argc - 1]. */ first_optind = optind; if (cmd->continuous_poll && kernel_older_than(2, 6, 23)) drbd_genl_family.nl_groups = -1; drbd_sock = genl_connect_to_family(&drbd_genl_family); if (!drbd_sock) { fprintf(stderr, "Could not connect to 'drbd' generic netlink family\n"); return 20; } if (drbd_genl_family.version != GENL_MAGIC_VERSION || drbd_genl_family.hdrsize != sizeof(struct drbd_genlmsghdr)) { fprintf(stderr, "API mismatch!\n\t" "API version drbdsetup: %u kernel: %u\n\t" "header size drbdsetup: %u kernel: %u\n", GENL_MAGIC_VERSION, drbd_genl_family.version, (unsigned)sizeof(struct drbd_genlmsghdr), drbd_genl_family.hdrsize); return 20; } context = 0; enum cfg_ctx_key ctx_key = cmd->ctx_key, next_arg; for (next_arg = ctx_next_arg(&ctx_key); next_arg; next_arg = ctx_next_arg(&ctx_key), optind++) { if (argc == optind && !(ctx_key & CTX_MULTIPLE_ARGUMENTS) && (next_arg & CTX_ALL)) { context |= CTX_ALL; /* assume "all" if no argument is given */ objname = "all"; break; } else if (argc <= optind) { fprintf(stderr, "Missing argument %d to command\n", optind); print_command_usage(cmd, FULL); exit(20); } else if (next_arg & (CTX_RESOURCE | CTX_MINOR | CTX_ALL)) { ensure_sanity_of_res_name(argv[optind]); if (!objname) objname = argv[optind]; if (!strcmp(argv[optind], "all")) { if (!(next_arg & CTX_ALL)) print_usage_and_exit("command does not accept argument 'all'"); context |= CTX_ALL; } else if (next_arg & CTX_MINOR) { minor = dt_minor_of_dev(argv[optind]); if (minor == -1U && next_arg == CTX_MINOR) { fprintf(stderr, "Cannot determine minor device number of " "device '%s'\n", argv[optind]); exit(20); } context |= CTX_MINOR; } else /* not "all", and not a minor number/device name */ { if (!(next_arg & CTX_RESOURCE)) { fprintf(stderr, "command does not accept argument '%s'\n", objname); print_command_usage(cmd, FULL); exit(20); } context |= CTX_RESOURCE; assert(strlen(objname) < sizeof(global_ctx.ctx_resource_name)); memset(global_ctx.ctx_resource_name, 0, sizeof(global_ctx.ctx_resource_name)); global_ctx.ctx_resource_name_len = strlen(objname); strcpy(global_ctx.ctx_resource_name, objname); } } else { if (next_arg == CTX_MY_ADDR) { const char *str = argv[optind]; struct sockaddr_storage *x; if (strncmp(str, "local:", 6) == 0) str += 6; assert(sizeof(global_ctx.ctx_my_addr) >= sizeof(*x)); x = (struct sockaddr_storage *)&global_ctx.ctx_my_addr; global_ctx.ctx_my_addr_len = sockaddr_from_str(x, str); } else if (next_arg == CTX_PEER_ADDR) { const char *str = argv[optind]; struct sockaddr_storage *x; if (strncmp(str, "peer:", 5) == 0) str += 5; assert(sizeof(global_ctx.ctx_peer_addr) >= sizeof(*x)); x = (struct sockaddr_storage *)&global_ctx.ctx_peer_addr; global_ctx.ctx_peer_addr_len = sockaddr_from_str(x, str); } else if (next_arg == CTX_VOLUME) { global_ctx.ctx_volume = m_strtoll(argv[optind], 1); } else if (next_arg == CTX_PEER_NODE_ID) { global_ctx.ctx_peer_node_id = m_strtoll(argv[optind], 1); } else assert(0); context |= next_arg; } } /* Remove the options we have already processed from argv */ if (first_optind != optind) { int n; for (n = 0; n < argc - optind; n++) argv[first_optind + n] = argv[optind + n]; argc -= optind - first_optind; } if (!objname) objname = "??"; if ((context & CTX_MINOR) && !cmd->lockless) lock_fd = dt_lock_drbd(minor); rv = cmd->function(cmd, argc, argv); if ((context & CTX_MINOR) && !cmd->lockless) dt_unlock_drbd(lock_fd); return rv; } #endif drbd-utils-8.9.6/user/v9/drbdadm_postparse.c0000644000175000017500000012016212645466445020702 0ustar apoikosapoikos/* drbdadm_postparse.c actions to do after config parsing This file is part of DRBD by Philipp Reisner and Lars Ellenberg. Copyright (C) 2012, LINBIT Information Technologies GmbH drbd is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. drbd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with drbd; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include #include "drbdtool_common.h" #include "drbdadm.h" static void inherit_volumes(struct volumes *from, struct d_host_info *host); static void check_volume_sets_equal(struct d_resource *, struct d_host_info *, struct d_host_info *); static void expand_opts(struct options *common, struct options *options); static void append_names(struct names *head, struct names *to_copy) { struct d_name *new, *copy; STAILQ_FOREACH(copy, to_copy, link) { new = malloc(sizeof(struct d_name)); new->name = strdup(copy->name); insert_tail(head, new); } } void set_on_hosts_in_res(struct d_resource *res) { struct d_resource *l_res; struct d_host_info *host, *host2; struct d_name *h; for_each_host(host, &res->all_hosts) { if (host->lower_name) { for_each_resource(l_res, &config) { if (!strcmp(l_res->name, host->lower_name)) break; } if (l_res == NULL) { err("%s:%d: in resource %s, " "referenced resource '%s' not defined.\n", res->config_file, res->start_line, res->name, host->lower_name); config_valid = 0; continue; } /* Simple: host->on_hosts = concat_names(l_res->me->on_hosts, l_res->peer->on_hosts); */ for_each_host(host2, &l_res->all_hosts) if (!host2->lower_name) { append_names(&host->on_hosts, &host2->on_hosts); for_each_host(h, &host2->on_hosts) { struct d_volume *vol; for_each_volume(vol, &host->volumes) check_uniq("device-minor", "device-minor:%s:%u", h->name, vol->device_minor); for_each_volume(vol, &host->volumes) if (vol->device) check_uniq("device", "device:%s:%s", h->name, vol->device); } } host->lower = l_res; /* */ if (addr_scope_local(host->address.addr)) STAILQ_FOREACH(h, &host->on_hosts, link) check_uniq("IP", "%s:%s:%s", h->name, host->address.addr, host->address.port); } } } struct d_host_info *find_host_info_by_name(struct d_resource* res, char *name) { struct d_host_info *host; for_each_host(host, &res->all_hosts) if (hostname_in_list(name, &host->on_hosts)) return host; return NULL; } static struct d_host_info *find_host_info_by_address(struct d_resource* res, struct d_address *address) { struct d_host_info *host; for_each_host(host, &res->all_hosts) if (!strcmp(host->address.addr, address->addr) && !strcmp(host->address.af, address->af) && !strcmp(host->address.port, address->port)) return host; return NULL; } static bool generate_implicit_node_id(int *addr_hash, struct d_host_info **host_info_array) { if (addr_hash[0] > addr_hash[1]) { host_info_array[0]->node_id = strdup("0"); host_info_array[1]->node_id = strdup("1"); } else if (addr_hash[0] < addr_hash[1]) { host_info_array[0]->node_id = strdup("1"); host_info_array[1]->node_id = strdup("0"); } else { return false; } return true; } static void _set_host_info_in_host_address_pairs(struct d_resource *res, struct connection *conn, struct path *path) { struct hname_address *ha; struct d_host_info *host_info; int addr_hash[2], i = 0; struct d_host_info *host_info_array[2]; STAILQ_FOREACH(ha, &path->hname_address_pairs, link) { if (ha->host_info) { /* Implicit connection have that already set. */ host_info = ha->host_info; if (i == 2) { err("LOGIC BUG in set_host_info_in_host_address_pairs()\n"); exit(20); } if (!host_info->address.addr) { err("\"connection-mesh\" (for \"%s\") with a host (\"%s\") " "that has no \"address\" defined\n", res->name, ha->name); config_valid = 0; return; } addr_hash[i] = crc32c(0x1a656f21, (void *)host_info->address.addr, strlen(host_info->address.addr)); host_info_array[i++] = host_info; } else if (ha->by_address) { host_info = find_host_info_by_address(res, &ha->address); /* The name will be used for nice comments only ... */ ha->name = strdup(names_to_str_c(&host_info->on_hosts, '_')); } else { host_info = find_host_info_by_name(res, ha->name); } if (!host_info && !strcmp(ha->name, "_remote_host")) { if (conn->peer) host_info = conn->peer; /* With new format we create one for _peer_node_id */ else continue; /* Old drbdsetup does not houtput a host section */ } if (!host_info) { err("%s:%d: in resource %s a hostname (\"%s\") is given\n" "with a \"host\" keyword, has no \"address\" keyword, and not matching\n" "host section (\"on\" keyword)\n", config_file, ha->config_line, res->name, ha->name); config_valid = 0; /* Can't continue. */ return; } ha->host_info = host_info; if (!(ha->address.addr && ha->address.af && ha->address.port)) { bool have_address = true; bool have_port = true; if (!(ha->address.addr && ha->address.af)) { if (host_info->address.addr && host_info->address.af) { ha->address.addr = host_info->address.addr; ha->address.af = host_info->address.af; } else have_address = false; } if (!ha->address.port) { if (host_info->address.port) ha->address.port = host_info->address.port; else have_port = false; } if (!(have_address && have_port)) { err("%s:%d: Resource %s, host %s: " "cannot determine which %s%s%s to use\n", config_file, ha->config_line, res->name, ha->name, have_address ? "" : "address", have_address != have_port ? "" : " and ", have_port ? "" : "port"); config_valid = 0; } } fline = ha->config_line; } if (conn->implicit && i == 2 && !host_info_array[0]->node_id && !host_info_array[1]->node_id) { /* This is drbd-8.3 / drbd-8.4 compatibility, auto created node-id */ bool have_node_ids; have_node_ids = generate_implicit_node_id(addr_hash, host_info_array); if (!have_node_ids) { /* That might be a config with equal node addresses, since it is 127.0.0.1:xxx with a proxy... */ i = 0; path = STAILQ_FIRST(&conn->paths); /* there may only be one */ STAILQ_FOREACH(ha, &path->hname_address_pairs, link) { if (!ha->host_info) continue; if (!ha->proxy) break; addr_hash[i++] = crc32c(0x1a656f21, (void *)ha->proxy->outside.addr, strlen(ha->proxy->outside.addr)); } have_node_ids = generate_implicit_node_id(addr_hash, host_info_array); } if (!have_node_ids) { err("BAD LUCK, equal hashes\n"); exit(20); } } } static void set_host_info_in_host_address_pairs(struct d_resource *res, struct connection *conn) { struct path *path; for_each_path(path, &conn->paths) _set_host_info_in_host_address_pairs(res, conn, path); } static bool test_proxy_on_host(struct d_resource* res, struct d_host_info *host) { struct connection *conn; struct path *path; for_each_connection(conn, &res->connections) { struct hname_address *ha; for_each_path(path, &conn->paths) { STAILQ_FOREACH(ha, &path->hname_address_pairs, link) { if (!ha->proxy) continue; if (ha->host_info == host) { return hostname_in_list(hostname, &ha->proxy->on_hosts); } } } } return false; } void set_me_in_resource(struct d_resource* res, int match_on_proxy) { struct d_host_info *host; struct connection *conn; /* Determine the local host section */ for_each_host(host, &res->all_hosts) { /* do we match this host? */ if (match_on_proxy) { if (!test_proxy_on_host(res, host)) continue; } else if (host->by_address) { if (!have_ip(host->address.af, host->address.addr) && /* for debugging only, e.g. __DRBD_NODE__=10.0.0.1 */ strcmp(hostname, host->address.addr)) continue; } else if (host->lower) { if (!host->lower->me) continue; } else if (STAILQ_EMPTY(&host->on_hosts)) { /* huh? a resource without hosts to run on?! */ continue; } else { if (!hostname_in_list(hostname, &host->on_hosts) && strcmp("_this_host", STAILQ_FIRST(&host->on_hosts)->name)) continue; } /* we matched. */ if (res->ignore) { config_valid = 0; err("%s:%d: in resource %s, %s %s { ... }:\n" "\tYou cannot ignore and define at the same time.\n", res->config_file, host->config_line, res->name, host->lower ? "stacked-on-top-of" : "on", host->lower ? host->lower->name : names_to_str(&host->on_hosts)); } if (res->me && res->me != host) { config_valid = 0; err("%s:%d: in resource %s, %s %s { ... } ... %s %s { ... }:\n" "\tThere are multiple host sections for this node.\n", res->config_file, host->config_line, res->name, res->me->lower ? "stacked-on-top-of" : "on", res->me->lower ? res->me->lower->name : names_to_str(&res->me->on_hosts), host->lower ? "stacked-on-top-of" : "on", host->lower ? host->lower->name : names_to_str(&host->on_hosts)); } res->me = host; host->used_as_me = 1; if (host->lower) res->stacked = 1; } /* If there is no me, implicitly ignore that resource */ if (!res->me) { res->ignore = 1; return; } /* set con->my_address in every path in every connection */ for_each_connection(conn, &res->connections) { struct path *path; struct hname_address *h = NULL; for_each_path(path, &conn->paths) { STAILQ_FOREACH(h, &path->hname_address_pairs, link) { if (h->host_info == res->me) break; } if (h) { h->used_as_me = 1; if (!path->my_address) path->my_address = h->address.addr ? &h->address : &res->me->address; path->my_proxy = h->proxy; } else { if (!conn->peer) /* Keep w/o addresses form "drbdsetup show" for adjust */ conn->ignore = 1; } } } } static void set_peer_in_connection(struct d_resource* res, struct connection *conn, int peer_required) { struct hname_address *host = NULL, *candidate = NULL; struct d_host_info *host_info; struct path *path; if (res->ignore || conn->ignore) return; /* me must be already set */ if (!res->me) { /* should have been implicitly ignored. */ err("%s:%d: in resource %s:\n" "\tcannot determine the peer, don't even know myself!\n", res->config_file, res->start_line, res->name); exit(E_THINKO); } for_each_path(path, &conn->paths) { int nr_hosts = 0, candidates = 0; STAILQ_FOREACH(host, &path->hname_address_pairs, link) { nr_hosts++; if (!host->used_as_me) { candidates++; candidate = host; } } if (nr_hosts < 2) { if (peer_required) { err("%s:%d: in connection in resource %s:\n" "\tMissing statement 'host '.\n", res->config_file, conn->config_line, res->name); config_valid = 0; } return; } if (candidates == 1 && nr_hosts == 2) { if (conn->peer) { host_info = conn->peer; } else { host_info = find_host_info_by_name(res, candidate->name); conn->peer = host_info; } path->peer_address = candidate->address.addr ? &candidate->address : &host_info->address; path->peer_proxy = candidate->proxy; path->connect_to = path->my_proxy ? &path->my_proxy->inside : path->peer_address; continue; } err("%s:%d: in connection in resource %s:\n" "\tBug in set_peer_in_connection()\n", res->config_file, conn->config_line, res->name); config_valid = 0; return; } } void create_implicit_net_options(struct connection *conn) { char *value; if (find_opt(&conn->net_options, "_name")) return; if (conn->name) value = conn->name; else if (conn->peer) value = names_to_str_c(&conn->peer->on_hosts, '_'); else return; insert_head(&conn->net_options, new_opt(strdup("_name"), strdup(value))); } void set_peer_in_resource(struct d_resource* res, int peer_required) { struct connection *conn; int peers_addrs_set = 1; for_each_connection(conn, &res->connections) { struct path *path; set_peer_in_connection(res, conn, peer_required); for_each_path(path, &conn->paths) { if (!path->peer_address) peers_addrs_set = 0; } create_implicit_net_options(conn); } res->peers_addrs_set = peers_addrs_set; } void set_disk_in_res(struct d_resource *res) { struct d_host_info *host; struct d_volume *a, *b; if (res->ignore) return; for_each_host(host, &res->all_hosts) { if (!host->lower) continue; if (host->lower->ignore) continue; check_volume_sets_equal(res, host, host->lower->me); if (!config_valid) /* don't even bother for broken config. */ continue; /* volume lists are sorted on vnr */ a = STAILQ_FIRST(&host->volumes); b = STAILQ_FIRST(&host->lower->me->volumes); while (a) { while (b && a->vnr > b->vnr) { /* Lower resource has more volumes. * Probably unusual, but we decided * that it should be legal. * Skip those that do not match */ b = STAILQ_NEXT(b, link); } if (a && b && a->vnr == b->vnr) { if (b->device) m_asprintf(&a->disk, "%s", b->device); else m_asprintf(&a->disk, "/dev/drbd%u", b->device_minor); /* stacked implicit volumes need internal meta data, too */ if (!a->meta_disk) m_asprintf(&a->meta_disk, "internal"); if (!a->meta_index) m_asprintf(&a->meta_index, "internal"); a = STAILQ_NEXT(a, link); b = STAILQ_NEXT(b, link); } else { /* config_invalid should have been set * by check_volume_sets_equal */ assert(0); } } } } static struct d_volume *find_volume(struct volumes *volumes, int vnr) { struct d_volume *vol; for_each_volume(vol, volumes) if (vol->vnr == vnr) return vol; return NULL; } static void derror(struct d_host_info *host, struct d_resource *res, char *text) { config_valid = 0; err("%s:%d: in resource %s, on %s { ... }: '%s' keyword missing.\n", res->config_file, host->config_line, res->name, names_to_str(&host->on_hosts), text); } static void inherit_volumes(struct volumes *from, struct d_host_info *host) { struct d_volume *s, *t; struct d_name *h; for_each_volume(s, from) { t = find_volume(&host->volumes, s->vnr); if (!t) { t = alloc_volume(); t->device_minor = -1; t->vnr = s->vnr; insert_volume(&host->volumes, t); } if (!t->disk && s->disk) { t->disk = strdup(s->disk); STAILQ_FOREACH(h, &host->on_hosts, link) check_uniq("disk", "disk:%s:%s", h->name, t->disk); } if (!t->device && s->device) t->device = strdup(s->device); if (t->device_minor == -1U && s->device_minor != -1U) t->device_minor = s->device_minor; if (!t->meta_disk && s->meta_disk) { t->meta_disk = strdup(s->meta_disk); if (s->meta_index) t->meta_index = strdup(s->meta_index); } } } static void check_volume_complete(struct d_resource *res, struct d_host_info *host, struct d_volume *vol) { if (!vol->device && vol->device_minor == -1U) derror(host, res, "device"); if (vol->disk || vol->meta_disk || vol->meta_index) { if (!(vol->disk && !strcmp(vol->disk, "none"))) { if (!vol->disk) derror(host, res, "disk"); if (!vol->meta_disk) derror(host, res, "meta-disk"); if (!vol->meta_index) derror(host, res, "meta-index"); } } } static void check_volumes_complete(struct d_resource *res, struct d_host_info *host) { struct d_volume *vol; unsigned vnr = -1U; for_each_volume(vol, &host->volumes) { if (vnr == -1U || vnr < vol->vnr) vnr = vol->vnr; else err("internal error: in %s: unsorted volumes list\n", res->name); check_volume_complete(res, host, vol); } } static void check_meta_disk(struct d_volume *vol, struct d_host_info *host) { struct d_name *h; /* when parsing "drbdsetup show[-all]" output, * a detached volume will only have device/minor, * but no disk or meta disk. */ if (vol->meta_disk == NULL) return; if (strcmp(vol->meta_disk, "internal") != 0) { /* index either some number, or "flexible" */ STAILQ_FOREACH(h, &host->on_hosts, link) check_uniq("meta-disk", "%s:%s[%s]", h->name, vol->meta_disk, vol->meta_index); } } static void check_volume_sets_equal(struct d_resource *res, struct d_host_info *host1, struct d_host_info *host2) { struct d_volume *a, *b; /* change the error output, if we have been called to * compare stacked with lower resource volumes */ int compare_stacked = host1->lower && host1->lower->me == host2; if (host1 == host2) return; a = STAILQ_FIRST(&host1->volumes); b = STAILQ_FIRST(&host2->volumes); /* volume lists are supposed to be sorted on vnr */ while (a || b) { while (a && (!b || a->vnr < b->vnr)) { err("%s:%d: in resource %s, on %s { ... }: volume %d not defined on %s\n", config_file, line, res->name, names_to_str(&host1->on_hosts), a->vnr, compare_stacked ? host1->lower->name : names_to_str(&host2->on_hosts)); a = STAILQ_NEXT(a, link); config_valid = 0; } while (b && (!a || a->vnr > b->vnr)) { /* Though unusual, it is "legal" for a lower resource * to have more volumes than the resource stacked on * top of it. Warn (if we have a terminal), * but consider it as valid. */ if (!(compare_stacked && no_tty)) err("%s:%d: in resource %s, on %s { ... }: " "volume %d missing (present on %s)\n", config_file, line, res->name, names_to_str(&host1->on_hosts), b->vnr, compare_stacked ? host1->lower->name : names_to_str(&host2->on_hosts)); if (!compare_stacked) config_valid = 0; b = STAILQ_NEXT(b, link); } if (a && b && a->vnr == b->vnr) { a = STAILQ_NEXT(a, link); b = STAILQ_NEXT(b, link); } } } /* Ensure that in all host sections the same volumes are defined */ static void check_volumes_hosts(struct d_resource *res) { struct d_host_info *host1, *host2; host1 = STAILQ_FIRST(&res->all_hosts); if (!host1) return; for_each_host(host2, &res->all_hosts) check_volume_sets_equal(res, host1, host2); } static struct hname_address *alloc_hname_address() { struct hname_address *ha; ha = calloc(1, sizeof(struct hname_address)); if (ha == NULL) { err("calloc", ": %m\n"); exit(E_EXEC_ERROR); } return ha; } static void create_implicit_connections(struct d_resource *res) { struct connection *conn; struct path *path; struct hname_address *ha; struct d_host_info *host_info; int hosts = 0; if (!STAILQ_EMPTY(&res->connections)) return; conn = alloc_connection(); conn->implicit = 1; path = alloc_path(); path->implicit = 1; insert_tail(&conn->paths, path); for_each_host(host_info, &res->all_hosts) { if (++hosts == 3) { err("Resource %s:\n\t" "Use explicit 'connection' sections with more than two 'on' sections.\n", res->name); break; } if (host_info->address.af && host_info->address.addr && host_info->address.port) { ha = alloc_hname_address(); ha->host_info = host_info; ha->proxy = host_info->proxy_compat_only; if (!host_info->lower) { ha->name = STAILQ_FIRST(&host_info->on_hosts)->name; } else { ha->name = strdup(names_to_str_c(&host_info->on_hosts, '_')); ha->address = host_info->address; ha->faked_hostname = 1; ha->parsed_address = 1; /* not true, but makes dump nicer */ } STAILQ_INSERT_TAIL(&path->hname_address_pairs, ha, link); } } if (hosts == 2) STAILQ_INSERT_TAIL(&res->connections, conn, link); else free_connection(conn); } static struct d_host_info *find_host_info_or_invalid(struct d_resource *res, char *name) { struct d_host_info *host_info = find_host_info_by_name(res, name); if (!host_info) { err("%s:%d: in resource %s:\n\t" "There is no 'on' section for hostname '%s' named in the connection-mesh\n", res->config_file, res->start_line, res->name, name); config_valid = 0; } return host_info; } static void create_connections_from_mesh(struct d_resource *res, struct mesh *mesh) { struct d_name *hname1, *hname2; struct d_host_info *hi1, *hi2; for_each_host(hname1, &mesh->hosts) { hi1 = find_host_info_or_invalid(res, hname1->name); if (!hi1) return; hname2 = STAILQ_NEXT(hname1, link); while (hname2) { struct hname_address *ha; struct connection *conn; struct path *path; hi2 = find_host_info_or_invalid(res, hname2->name); if (!hi2) return; if (hi1 == hi2) goto skip; conn = alloc_connection(); conn->implicit = 1; path = alloc_path(); path->implicit = 1; insert_tail(&conn->paths, path); expand_opts(&mesh->net_options, &conn->net_options); ha = alloc_hname_address(); ha->host_info = hi1; ha->name = STAILQ_FIRST(&hi1->on_hosts)->name; STAILQ_INSERT_TAIL(&path->hname_address_pairs, ha, link); ha = alloc_hname_address(); ha->host_info = hi2; ha->name = STAILQ_FIRST(&hi2->on_hosts)->name; STAILQ_INSERT_TAIL(&path->hname_address_pairs, ha, link); STAILQ_INSERT_TAIL(&res->connections, conn, link); skip: hname2 = STAILQ_NEXT(hname2, link); } } } static bool addresses_equal(struct d_address *addr1, struct d_address *addr2) { if (strcmp(addr1->af, addr2->af)) return false; if (strcmp(addr1->addr, addr2->addr)) return false; if (strcmp(addr1->port, addr2->port)) return false; return true; } static struct hname_address *find_hname_addr_in_res(struct d_resource *res, struct d_address *addr) { struct hname_address *ha; struct connection *conn; struct path *path; for_each_connection(conn, &res->connections) { for_each_path(path, &conn->paths) { STAILQ_FOREACH(ha, &path->hname_address_pairs, link) { struct d_address *addr2; addr2 = ha->address.addr ? &ha->address : &ha->host_info->address; if (addresses_equal(addr, addr2)) return ha; } } } return NULL; } /* An AF/IP/addr triple might be used by multiple connections within one resource, but may not be mentioned in any other resource. Also make sure that the two endpoints are not configured as the same. */ static void check_addr_conflict(struct d_resource *res, struct resources *resources) { struct d_resource *res2; struct hname_address *ha1, *ha2; struct connection *conn; for_each_resource(res2, resources) { if (res2 == res) continue; for_each_connection(conn, &res->connections) { struct path *path; for_each_path(path, &conn->paths) { struct d_address *addr[2]; int i = 0; STAILQ_FOREACH(ha1, &path->hname_address_pairs, link) { addr[i] = ha1->address.addr ? &ha1->address : &ha1->host_info->address; if (addr_scope_local(addr[i]->addr)) continue; if (ha1->conflicts) continue; ha2 = find_hname_addr_in_res(res2, addr[i]); if (!ha2) continue; if (ha2->conflicts) continue; fprintf(stderr, "%s:%d: in resource %s\n" " %s:%s:%s is also used %s:%d (resource %s)\n", res->config_file, ha1->config_line, res->name, addr[i]->af, addr[i]->addr, addr[i]->port, res2->config_file, ha2->config_line, res2->name); ha2->conflicts = 1; ha1->conflicts = 1; config_valid = 0; i++; } if (i == 2 && addresses_equal(addr[0], addr[1]) && !addr_scope_local(addr[0]->addr)) { err("%s:%d: in resource %s %s:%s:%s is used for both endpoints\n", res->config_file, conn->config_line, res->name, addr[0]->af, addr[0]->addr, addr[0]->port); config_valid = 0; } } } } } static void _must_have_two_hosts(struct d_resource *res, struct path *path) { struct hname_address *ha; int i = 0; STAILQ_FOREACH(ha, &path->hname_address_pairs, link) i++; if (i != 2) { err("%s:%d: Resource %s: %s needs to have two endpoints\n", res->config_file, path->config_line, res->name, path->implicit ? "connection" : "path"); config_valid = 0; } } static void must_have_two_hosts(struct d_resource *res, struct connection *conn) { struct path *path; for_each_path(path, &conn->paths) _must_have_two_hosts(res, path); } struct peer_device *find_peer_device(struct connection *conn, int vnr) { struct peer_device *peer_device; STAILQ_FOREACH(peer_device, &conn->peer_devices, connection_link) { if (peer_device->vnr == vnr) return peer_device; } return NULL; } static void fixup_peer_devices(struct d_resource *res) { struct connection *conn; struct d_host_info *some_host = STAILQ_FIRST(&res->all_hosts); /* At this point all hosts of the resource have the same set of volumes */ for_each_connection(conn, &res->connections) { struct peer_device *peer_device; struct d_volume *vol; STAILQ_FOREACH(peer_device, &conn->peer_devices, connection_link) { vol = volume_by_vnr(&some_host->volumes, peer_device->vnr); if (!vol) { err("%s:%d: Resource %s: There is a reference to a volume %d that" "is not known in this resource\n", res->config_file, peer_device->config_line, res->name, peer_device->vnr); config_valid = 0; } peer_device->volume = vol; STAILQ_INSERT_TAIL(&vol->peer_devices, peer_device, volume_link); } for_each_volume(vol, &some_host->volumes) { peer_device = find_peer_device(conn, vol->vnr); if (peer_device) continue; peer_device = alloc_peer_device(); peer_device->vnr = vol->vnr; peer_device->implicit = 1; peer_device->connection = conn; peer_device->volume = vol; STAILQ_INSERT_TAIL(&conn->peer_devices, peer_device, connection_link); STAILQ_INSERT_TAIL(&vol->peer_devices, peer_device, volume_link); } } } void post_parse(struct resources *resources, enum pp_flags flags) { struct d_resource *res; struct connection *con; /* inherit volumes from resource level into the d_host_info objects */ for_each_resource(res, resources) { struct d_host_info *host; for_each_host(host, &res->all_hosts) { struct d_volume *vol; inherit_volumes(&res->volumes, host); for_each_volume(vol, &host->volumes) check_meta_disk(vol, host); if (host->require_minor) check_volumes_complete(res, host); } check_volumes_hosts(res); } for_each_resource(res, resources) if (res->stacked_on_one) set_on_hosts_in_res(res); /* sets on_hosts and host->lower */ for_each_resource(res, resources) { struct d_host_info *host; struct mesh *mesh; if (!(flags & DRBDSETUP_SHOW)) { for_each_connection(con, &res->connections) must_have_two_hosts(res, con); } /* Other steps make no sense. */ if (!config_valid) continue; STAILQ_FOREACH(mesh, &res->meshes, link) create_connections_from_mesh(res, mesh); create_implicit_connections(res); for_each_connection(con, &res->connections) set_host_info_in_host_address_pairs(res, con); for_each_host(host, &res->all_hosts) { if (!host->node_id) derror(host, res, "node-id"); } } if (config_valid) { for_each_resource(res, resources) check_addr_conflict(res, resources); } /* Needs "on_hosts" and host->lower already set */ for_each_resource(res, resources) if (!res->stacked_on_one) set_me_in_resource(res, flags & MATCH_ON_PROXY); /* Needs host->lower->me already set */ for_each_resource(res, resources) if (res->stacked_on_one) set_me_in_resource(res, flags & MATCH_ON_PROXY); // Needs "me" set already for_each_resource(res, resources) if (res->stacked_on_one) set_disk_in_res(res); for_each_resource(res, resources) fixup_peer_devices(res); } static void expand_opts(struct options *common, struct options *options) { struct d_option *option, *new_option; STAILQ_FOREACH(option, common, link) { if (!find_opt(options, option->name)) { new_option = new_opt(strdup(option->name), option->value ? strdup(option->value) : NULL); insert_head(options, new_option); } } } void expand_common(void) { struct d_resource *res; struct d_volume *vol, *host_vol; struct d_host_info *h; struct connection *conn; struct d_resource *template; for_each_resource(res, &config) { /* make sure vol->device is non-NULL */ for_each_host(h, &res->all_hosts) { for_each_volume(vol, &h->volumes) { if (vol->disk && !strcmp(vol->disk, "none")) { free(vol->disk); free(vol->meta_disk); free(vol->meta_index); vol->disk = NULL; vol->meta_disk = NULL; vol->meta_index = NULL; } if (!vol->device) m_asprintf(&vol->device, "/dev/drbd%u", vol->device_minor); } } if (res->template) template = res->template; else template = common; if (template) { expand_opts(&template->net_options, &res->net_options); expand_opts(&template->disk_options, &res->disk_options); expand_opts(&template->pd_options, &res->pd_options); expand_opts(&template->startup_options, &res->startup_options); expand_opts(&template->proxy_options, &res->proxy_options); expand_opts(&template->handlers, &res->handlers); expand_opts(&template->res_options, &res->res_options); if (template->stacked_timeouts) res->stacked_timeouts = 1; expand_opts(&template->proxy_plugins, &res->proxy_plugins); } /* now that common disk options (if any) have been propagated to the * resource level, further propagate them to the volume level. */ for_each_host(h, &res->all_hosts) { for_each_volume(vol, &h->volumes) { expand_opts(&res->disk_options, &vol->disk_options); expand_opts(&res->pd_options, &vol->pd_options); } } /* now from all volume/disk-options on resource level to host level */ for_each_volume(vol, &res->volumes) { for_each_host(h, &res->all_hosts) { host_vol = volume_by_vnr(&h->volumes, vol->vnr); expand_opts(&vol->disk_options, &host_vol->disk_options); expand_opts(&vol->pd_options, &host_vol->pd_options); } } /* inherit network options from resource objects into connection objects */ for_each_connection(conn, &res->connections) expand_opts(&res->net_options, &conn->net_options); /* inherit proxy options from resource to the proxies in the connections */ for_each_connection(conn, &res->connections) { struct path *path; for_each_path(path, &conn->paths) { struct hname_address *ha; STAILQ_FOREACH(ha, &path->hname_address_pairs, link) { if (!ha->proxy) continue; expand_opts(&res->proxy_options, &ha->proxy->options); expand_opts(&res->proxy_plugins, &ha->proxy->plugins); } } } /* inherit peer_device options from connections to peer_devices AND tie the peer_device options from the volume to peer_devices */ for_each_connection(conn, &res->connections) { struct peer_device *peer_device; STAILQ_FOREACH(peer_device, &conn->peer_devices, connection_link) { expand_opts(&conn->pd_options, &peer_device->pd_options); expand_opts(&peer_device->volume->pd_options, &peer_device->pd_options); } } } } struct d_resource *res_by_name(const char *name) { struct d_resource *res; for_each_resource(res, &config) { if (strcmp(name, res->name) == 0) return res; } return NULL; } static int sanity_check_abs_cmd(char *cmd_name) { struct stat sb; if (stat(cmd_name, &sb)) { /* If stat fails, just ignore this sanity check, * we are still iterating over $PATH probably. */ return 0; } if (!(sb.st_mode & S_ISUID) || sb.st_mode & S_IXOTH || sb.st_gid == 0) { static int did_header = 0; if (!did_header) err("WARN:\n" " You are using the 'drbd-peer-outdater' as fence-peer program.\n" " If you use that mechanism the dopd heartbeat plugin program needs\n" " to be able to call drbdsetup and drbdmeta with root privileges.\n\n" " You need to fix this with these commands:\n"); did_header = 1; err(" chgrp haclient %s\n" " chmod o-x %s\n" " chmod u+s %s\n\n", cmd_name, cmd_name, cmd_name); } return 1; } static void sanity_check_cmd(char *cmd_name) { char *path, *pp, *c; char abs_path[100]; if (strchr(cmd_name, '/')) { sanity_check_abs_cmd(cmd_name); } else { path = pp = c = strdup(getenv("PATH")); while (1) { c = strchr(pp, ':'); if (c) *c = 0; snprintf(abs_path, 100, "%s/%s", pp, cmd_name); if (sanity_check_abs_cmd(abs_path)) break; if (!c) break; c++; if (!*c) break; pp = c; } free(path); } } /* if the config file is not readable by haclient, * dopd cannot work. * NOTE: we assume that any gid != 0 will be the group dopd will run as, * typically haclient. */ static void sanity_check_conf(char *c) { struct stat sb; /* if we cannot stat the config file, * we have other things to worry about. */ if (stat(c, &sb)) return; /* permissions are funny: if it is world readable, * but not group readable, and it belongs to my group, * I am denied access. * For the file to be readable by dopd (hacluster:haclient), * it is not enough to be world readable. */ /* ok if world readable, and NOT group haclient (see NOTE above) */ if (sb.st_mode & S_IROTH && sb.st_gid == 0) return; /* ok if group readable, and group haclient (see NOTE above) */ if (sb.st_mode & S_IRGRP && sb.st_gid != 0) return; err("WARN:\n" " You are using the 'drbd-peer-outdater' as fence-peer program.\n" " If you use that mechanism the dopd heartbeat plugin program needs\n" " to be able to read the drbd.config file.\n\n" " You need to fix this with these commands:\n" " chgrp haclient %s\n" " chmod g+r %s\n\n", c, c); } static void sanity_check_perm() { static int checked = 0; if (checked) return; sanity_check_cmd(drbdsetup); sanity_check_cmd(drbdmeta); sanity_check_conf(config_file); checked = 1; } static bool host_name_known(struct d_resource *res, char *name) { struct d_host_info *host; for_each_host(host, &res->all_hosts) if (hostname_in_list(name, &host->on_hosts)) return 1; return 0; } /* Check that either all host sections have a proxy subsection, or none */ static void ensure_proxy_sections(struct d_resource *res) { struct d_host_info *host; struct connection *conn; enum { INIT, HAVE, MISSING } proxy_sect = INIT, prev_proxy_sect; for_each_host(host, &res->all_hosts) { prev_proxy_sect = proxy_sect; proxy_sect = host->proxy_compat_only ? HAVE : MISSING; if (prev_proxy_sect == INIT) continue; if (prev_proxy_sect != proxy_sect) { err("%s:%d: in resource %s:\n\t" "Either all 'on' sections must contain a proxy subsection, or none.\n", res->config_file, res->start_line, res->name); config_valid = 0; } } for_each_connection(conn, &res->connections) { struct path *path; for_each_path(path, &conn->paths) { struct hname_address *ha; proxy_sect = INIT; STAILQ_FOREACH(ha, &path->hname_address_pairs, link) { prev_proxy_sect = proxy_sect; proxy_sect = ha->proxy ? HAVE : MISSING; if (prev_proxy_sect == INIT) continue; if (prev_proxy_sect != proxy_sect) { err("%s:%d: in connection in resource %s:\n" "Either all 'host' statements must have a proxy subsection, or none.\n", res->config_file, conn->config_line, res->name); config_valid = 0; } } } } } static void validate_resource(struct d_resource *res, enum pp_flags flags) { struct d_option *opt; /* there may be more than one "resync-after" statement, * see commit 89cd0585 */ STAILQ_FOREACH(opt, &res->disk_options, link) { struct d_resource *rs_after_res; next: if (strcmp(opt->name, "resync-after")) continue; rs_after_res = res_by_name(opt->value); if (rs_after_res == NULL || (rs_after_res->ignore && !(flags & MATCH_ON_PROXY))) { err("%s:%d: in resource %s:\n\tresource '%s' mentioned in " "'resync-after' option is not known%s.\n", res->config_file, res->start_line, res->name, opt->value, rs_after_res ? " on this host" : ""); /* Non-fatal if run from some script. * When deleting resources, it is an easily made * oversight to leave references to the deleted * resources in resync-after statements. Don't fail on * every pacemaker-induced action, as it would * ultimately lead to all nodes committing suicide. */ if (no_tty) { struct d_option *next = STAILQ_NEXT(opt, link); STAILQ_REMOVE(&res->disk_options, opt, d_option, link); free_opt(opt); opt = next; if (opt) goto next; else break; } else config_valid = 0; } } if (STAILQ_EMPTY(&res->all_hosts)) { err("%s:%d: in resource %s:\n\ta host sections ('on %s { ... }') is missing.\n", res->config_file, res->start_line, res->name, hostname); config_valid = 0; } if (res->ignore) return; if (!res->me) { err("%s:%d: in resource %s:\n\tmissing section 'on %s { ... }'.\n", res->config_file, res->start_line, res->name, hostname); config_valid = 0; } // need to verify that in the discard-node-nodename options only known // nodenames are mentioned. if ((opt = find_opt(&res->net_options, "after-sb-0pri"))) { if (!strncmp(opt->value, "discard-node-", 13)) { if (!host_name_known(res, opt->value + 13)) { err("%s:%d: in resource %s:\n\t" "the nodename in the '%s' option is " "not known.\n", res->config_file, res->start_line, res->name, opt->value); config_valid = 0; } } } if ((opt = find_opt(&res->handlers, "fence-peer"))) { if (strstr(opt->value, "drbd-peer-outdater")) sanity_check_perm(); } ensure_proxy_sections(res); /* All or none. */ } static int ctx_set_implicit_volume(struct cfg_ctx *ctx) { struct d_volume *vol, *v; int volumes = 0; if (ctx->vol || !ctx->res) return 0; if (!ctx->res->me) { return 0; } for_each_volume(vol, &ctx->res->me->volumes) { volumes++; v = vol; } if (volumes == 1) ctx->vol = v; return volumes; } // Need to convert after from resourcename to minor_number. static void _convert_after_option(struct d_resource *res, struct d_volume *vol) { struct d_option *opt; struct cfg_ctx depends_on_ctx = { }; int volumes; if (res == NULL) return; STAILQ_FOREACH(opt, &vol->disk_options, link) { next: if (strcmp(opt->name, "resync-after")) continue; ctx_by_name(&depends_on_ctx, opt->value, CTX_FIRST); volumes = ctx_set_implicit_volume(&depends_on_ctx); if (volumes > 1) { err("%s:%d: in resource %s:\n\t" "resync-after contains '%s', which is ambiguous, since it contains %d volumes\n", res->config_file, res->start_line, res->name, opt->value, volumes); config_valid = 0; return; } if (!depends_on_ctx.res || depends_on_ctx.res->ignore) { struct d_option *next = STAILQ_NEXT(opt, link); STAILQ_REMOVE(&vol->disk_options, opt, d_option, link); free_opt(opt); opt = next; if (opt) goto next; else break; } else { free(opt->value); m_asprintf(&opt->value, "%d", depends_on_ctx.vol->device_minor); } } } // Need to convert after from resourcename/volume to minor_number. static void convert_after_option(struct d_resource *res) { struct d_volume *vol; struct d_host_info *h; for_each_host(h, &res->all_hosts) for_each_volume(vol, &h->volumes) _convert_after_option(res, vol); } // need to convert discard-node-nodename to discard-local or discard-remote. static void convert_discard_opt(struct options *net_options) { struct d_option *opt; if ((opt = find_opt(net_options, "after-sb-0pri"))) { if (!strncmp(opt->value, "discard-node-", 13)) { if (!strcmp(hostname, opt->value + 13)) { free(opt->value); opt->value = strdup("discard-local"); } else { free(opt->value); opt->value = strdup("discard-remote"); } } } } void global_validate_maybe_expand_die_if_invalid(int expand, enum pp_flags flags) { struct d_resource *res; for_each_resource(res, &config) { validate_resource(res, flags); if (!config_valid) exit(E_CONFIG_INVALID); if (expand) { struct connection *conn; convert_after_option(res); convert_discard_opt(&res->net_options); for_each_connection(conn, &res->connections) convert_discard_opt(&conn->net_options); } if (!config_valid) exit(E_CONFIG_INVALID); } } drbd-utils-8.9.6/user/v9/config_flags.h0000644000175000017500000000515112570061477017624 0ustar apoikosapoikos#ifndef __DRBD_CONFIG_FLAGS_H #define __DRBD_CONFIG_FLAGS_H struct msg_buff; struct nlattr; struct context_def; struct field_def; enum check_codes { CC_OK, CC_NOT_AN_ENUM, CC_NOT_A_BOOL, CC_NOT_A_NUMBER, CC_TOO_SMALL, CC_TOO_BIG, }; struct field_class { bool (*is_default)(struct field_def *, const char *); bool (*is_equal)(struct field_def *, const char *, const char *); const char *(*get)(struct context_def *, struct field_def *, struct nlattr *); bool (*put)(struct context_def *, struct field_def *, struct msg_buff *, const char *); int (*usage)(struct field_def *, char *, int); void (*describe_xml)(struct field_def *); enum check_codes (*check)(struct field_def *, const char*); }; struct field_def { const char *name; unsigned short nla_type; const struct field_class *ops; union { struct { const char **map; int size; int def; } e; /* ENUM, ENUM_NOCASE */ struct { long long min; long long max; long long def; bool is_signed; char scale; } n; /* NUMERIC */ struct { bool def; } b; /* BOOLEAN */ } u; bool needs_double_quoting; bool argument_is_optional; bool checked_in_postparse; /* Do not check in drbdadm_parse.c It gets checked and converted later*/ bool implicit_clamp; const char *unit; }; struct context_def { struct nla_policy *nla_policy; int nla_policy_size; int nla_type; struct field_def fields[]; }; extern struct field_class fc_enum; extern struct field_class fc_enum_nocase; extern struct field_class fc_numeric; extern struct field_class fc_boolean; extern struct field_class fc_flag; extern struct field_class fc_string; extern struct context_def disk_options_ctx; extern struct context_def net_options_ctx; extern struct context_def show_net_options_ctx; extern struct context_def primary_cmd_ctx; extern struct context_def attach_cmd_ctx; extern struct context_def detach_cmd_ctx; extern struct context_def connect_cmd_ctx; extern struct context_def new_peer_cmd_ctx; extern struct context_def path_cmd_ctx; extern struct context_def disconnect_cmd_ctx; extern struct context_def resize_cmd_ctx; extern struct context_def resource_options_ctx; extern struct context_def new_current_uuid_cmd_ctx; extern struct context_def verify_cmd_ctx; extern struct context_def device_options_ctx; extern struct context_def invalidate_ctx; extern struct context_def create_md_ctx; extern struct context_def peer_device_options_ctx; extern struct context_def handlers_ctx; extern struct context_def proxy_options_ctx; extern struct context_def startup_options_ctx; extern const char *double_quote_string(const char *str); #endif /* __DRBD_CONFIG_FLAGS_H */ drbd-utils-8.9.6/user/v9/drbdadm_dump.c0000644000175000017500000004160412572043560017616 0ustar apoikosapoikos/* drbdadm_dump.c This file is part of DRBD by Philipp Reisner and Lars Ellenberg. Copyright (C) 2003-2008, LINBIT Information Technologies GmbH. Copyright (C) 2003-2008, Philipp Reisner . Copyright (C) 2003-2008, Lars Ellenberg . drbd is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. drbd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with drbd; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include "drbdadm.h" #include "drbdtool_common.h" static int indent = 0; #define INDENT_WIDTH 4 #define BFMT "%s;\n" #define IPV4FMT "%-16s %s %s:%s%s" #define IPV6FMT "%-16s %s [%s]:%s%s" #define MDISK "%-16s %s;\n" #define MDISKI "%-16s %s [%s];\n" #define printI(fmt, args... ) printf("%*s" fmt,INDENT_WIDTH * indent,"" , ## args ) #define printA(name, val ) \ printf("%*s%*s %3s;\n", \ INDENT_WIDTH * indent,"" , \ -24+INDENT_WIDTH * indent, \ name, val ) static void dump_options(char *name, struct options *options); static void __dump_options(struct options *options) { struct d_option *option; STAILQ_FOREACH(option, options, link) { if (option->value) printA(option->name, option->is_escaped ? option->value : esc(option-> value)); else printI(BFMT, option->name); } } static void dump_options2(char *name, struct options *options, void(*within)(struct options *), struct options *ctx) { if (STAILQ_EMPTY(options) && (!ctx || (ctx && STAILQ_EMPTY(ctx)))) return; printI("%s {\n", name); ++indent; __dump_options(options); if (within) within(ctx); --indent; printI("}\n"); } static void dump_peer_device_options(struct options *options) { if (!STAILQ_EMPTY(options)) { /* printI("# peer device options:\n"); */ __dump_options(options); } } static void dump_options(char *name, struct options *options) { dump_options2(name, options, NULL, NULL); } static void dump_proxy_plugins(struct options *options) { dump_options("plugin", options); } void dump_global_info() { static const char * const yes_no_ask[] = { [UC_YES] = "yes", [UC_NO] = "no", [UC_ASK] = "ask", }; if (!global_options.minor_count && !global_options.disable_ip_verification && global_options.dialog_refresh == 1 && global_options.usage_count == UC_ASK && !verbose) return; printI("global {\n"); ++indent; if (global_options.disable_ip_verification) printI("disable-ip-verification;\n"); if (global_options.minor_count) printI("minor-count %i;\n", global_options.minor_count); if (global_options.dialog_refresh != 1) printI("dialog-refresh %i;\n", global_options.dialog_refresh); if (global_options.usage_count != UC_ASK) printI("usage-count %s;\n", yes_no_ask[global_options.usage_count]); --indent; printI("}\n\n"); } static void fake_startup_options(struct d_resource *res); static void dump_common_info() { if (!common) return; printI("common {\n"); ++indent; fake_startup_options(common); dump_options("options", &common->res_options); dump_options("net", &common->net_options); dump_options2("disk", &common->disk_options, dump_peer_device_options, &common->pd_options); dump_options("startup", &common->startup_options); dump_options2("proxy", &common->proxy_options, dump_proxy_plugins, &common->proxy_plugins); dump_options("handlers", &common->handlers); --indent; printf("}\n\n"); } static void dump_address(char *name, struct d_address *address, char *postfix) { if (!strcmp(address->af, "ipv6")) printI(IPV6FMT, name, address->af, address->addr, address->port, postfix); else printI(IPV4FMT, name, address->af, address->addr, address->port, postfix); } static void dump_proxy_info(const char *prefix, struct d_proxy_info *pi) { printI("%sproxy on %s {\n", prefix, names_to_str(&pi->on_hosts)); ++indent; dump_address("inside", &pi->inside, ";\n"); dump_address("outside", &pi->outside, ";\n"); dump_options2("options", &pi->options, dump_proxy_plugins, &pi->plugins); --indent; printI("}\n"); } static void dump_volume(int has_lower, struct d_volume *vol) { if (!vol->implicit) { printI("volume %d {\n", vol->vnr); ++indent; } /* Handle volume of '_remote_host' */ if (!vol->device && !vol->disk && !vol->meta_disk && !vol->meta_index) goto out; dump_options2("disk", &vol->disk_options, dump_peer_device_options, &vol->pd_options); if (vol->parsed_device || verbose) { printI("device%*s", -19 + INDENT_WIDTH * indent, ""); if (vol->device) printf("%s ", esc(vol->device)); printf("minor %d;\n", vol->device_minor); } if (!has_lower && (vol->parsed_disk || verbose)) printA("disk", esc(vol->disk ? vol->disk : "none")); if (!has_lower && (vol->parsed_meta_disk || verbose) && vol->disk) { if (!strcmp(vol->meta_index, "flexible")) printI(MDISK, "meta-disk", esc(vol->meta_disk)); else if (!strcmp(vol->meta_index, "internal")) printA("meta-disk", "internal"); else printI(MDISKI, "meta-disk", esc(vol->meta_disk), vol->meta_index); } if (!vol->implicit) { out: --indent; printI("}\n"); } } static void dump_host_info(struct d_host_info *hi) { struct d_volume *vol; if (!hi) { printI(" # No host section data available.\n"); return; } if (hi->implicit && !verbose) return; if (hi->lower) { printI("stacked-on-top-of %s {\n", esc(hi->lower->name)); ++indent; printI("# on %s \n", names_to_str(&hi->on_hosts)); } else if (hi->by_address) { dump_address("floating", &hi->address, " {\n"); ++indent; } else { printI("on %s {\n", names_to_str(&hi->on_hosts)); ++indent; } printI("node-id %s;\n", hi->node_id); dump_options("options", &hi->res_options); for_each_volume(vol, &hi->volumes) { if (vol->parsed_device || vol->parsed_disk || vol->parsed_meta_disk || verbose) dump_volume(!!hi->lower, vol); } if (!hi->by_address && hi->address.addr) dump_address("address", &hi->address, ";\n"); if (hi->proxy_compat_only && !verbose) dump_proxy_info("", hi->proxy_compat_only); --indent; printI("}\n"); } static void dump_hname_address_pairs(struct hname_address_pairs *hname_address_pairs) { struct hname_address *ha; STAILQ_FOREACH(ha, hname_address_pairs, link) { if (ha->by_address || ha->faked_hostname) { dump_address("address", &ha->address, ssprintf("%s# on %s\n", ha->proxy ? " " : "; ", ha->name)); } else { printI("host %s", ha->name); if (ha->parsed_address || (verbose && ha->address.addr)) dump_address(" address", &ha->address, ""); else if (ha->parsed_port) printf(" port %s", ha->address.port); } if (ha->proxy) dump_proxy_info(" via ", ha->proxy); else printf(";\n"); } } static void dump_connection(struct connection *conn) { struct peer_device *pd; struct path *path; if (conn->implicit && !verbose) return; printI("connection"); if (conn->name) printf(" %s", esc(conn->name)); printf(" {\n"); ++indent; path = STAILQ_FIRST(&conn->paths); if (path->implicit && !verbose) { dump_hname_address_pairs(&path->hname_address_pairs); } else { for_each_path(path, &conn->paths) { printI("path {\n"); ++indent; dump_hname_address_pairs(&path->hname_address_pairs); --indent; printI("}\n"); } } dump_options("net", &conn->net_options); dump_options("disk", &conn->pd_options); STAILQ_FOREACH(pd, &conn->peer_devices, connection_link) { if (pd->implicit && !verbose) continue; printI("volume %d {\n", pd->vnr); ++indent; dump_options("disk", &pd->pd_options); --indent; printI("}\n"); } --indent; printI("}\n"); } static void __dump_options_xml(struct options *options) { struct d_option *option; STAILQ_FOREACH(option, options, link) { if (option->value) printI("