[PATCH v2 18/20] drbd: add the "drbd2" genl family
From: Christoph Böhmwalder
Date: Tue Oct 06 2026 - 12:07:19 EST
DRBD 9's utilities need the multi-peer administration model that the
version-1 wire cannot express: peers identified by node id, several
paths per connection, per-peer-device options and statistics, and
notifications for all of those. Rather than bump the "drbd" family
and break every existing drbd-utils, add a second family, "drbd2",
written as a YNL specification in Documentation/netlink/specs/ and
following current generic netlink conventions: strict policies with
ranges, nested objects, split do/dump ops, extended ACKs for errors,
and a proper uapi header.
drbd2_nl_gen.[ch] and include/uapi/linux/drbd2.h are generated from
the spec with tools/net/ynl and are not edited by hand.
drbd_nl_drbd2.c is the struct drbd_nl_dialect adapter for the family.
Both families are registered by the same driver and operate on the
same objects; a resource created through either is visible through
both, within what each wire format can express. drbd2 is always
registered, so with DRBD_COMPAT_84=n it is the only family.
Signed-off-by: Christoph Böhmwalder <christoph.boehmwalder@xxxxxxxxxx>
---
Documentation/netlink/specs/drbd2.yaml | 2476 +++++++++++++++++++++++
drivers/block/drbd/Kconfig | 6 +
drivers/block/drbd/Makefile | 1 +
drivers/block/drbd/drbd2_nl_gen.c | 748 +++++++
drivers/block/drbd/drbd2_nl_gen.h | 107 +
drivers/block/drbd/drbd_nl_drbd2.c | 2533 ++++++++++++++++++++++++
include/uapi/linux/drbd2.h | 1012 ++++++++++
7 files changed, 6883 insertions(+)
create mode 100644 Documentation/netlink/specs/drbd2.yaml
create mode 100644 drivers/block/drbd/drbd2_nl_gen.c
create mode 100644 drivers/block/drbd/drbd2_nl_gen.h
create mode 100644 drivers/block/drbd/drbd_nl_drbd2.c
create mode 100644 include/uapi/linux/drbd2.h
diff --git a/Documentation/netlink/specs/drbd2.yaml b/Documentation/netlink/specs/drbd2.yaml
new file mode 100644
index 000000000000..1b3b1fa19d9f
--- /dev/null
+++ b/Documentation/netlink/specs/drbd2.yaml
@@ -0,0 +1,2476 @@
+# SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)
+---
+name: drbd2
+
+protocol: genetlink
+
+doc: 'DRBD 9 management interface: configure and monitor replicated block device resources,
+ their devices, connections to peers, peer devices and network paths.'
+
+uapi-header: linux/drbd2.h
+
+definitions:
+ -
+ name: resource-name-max
+ type: const
+ value: 128
+ doc: Maximum length of a resource name including the terminating NUL.
+
+ -
+ name: connection-name-max
+ type: const
+ value: 64
+ doc: Maximum length of a connection name including the terminating NUL.
+
+ -
+ name: shared-secret-max
+ type: const
+ value: 64
+ doc: Maximum length of the shared secret including the terminating NUL.
+
+ -
+ name: alg-name-max
+ type: const
+ value: 64
+ doc: Maximum length of a crypto algorithm name including the terminating NUL.
+
+ -
+ name: transport-name-max
+ type: const
+ value: 64
+ doc: Maximum length of a network transport name including the terminating NUL.
+
+ -
+ name: device-path-max
+ type: const
+ value: 128
+ doc: Maximum length of a backing/meta device path including the terminating NUL.
+
+ -
+ name: cpu-mask-size
+ type: const
+ value: 256
+ doc: Maximum length of the cpu-mask string.
+
+ -
+ name: helper-name-max
+ type: const
+ value: 32
+ doc: Maximum length of a helper name.
+
+ -
+ name: history-uuids-size
+ type: const
+ value: 256
+ doc: Maximum size in bytes of the history UUID array (32 peer slots of 8 bytes).
+
+ -
+ name: io-error-policy
+ type: enum
+ doc: What to do when the backing device reports an I/O error (on-io-error).
+ entries:
+ -
+ name: pass-on
+ doc: Mark the failed block out of sync, change the disk state to inconsistent and retry the request on a peer.
+ -
+ name: call-local-io-error
+ doc: Call the local-io-error handler.
+ -
+ name: detach
+ doc: Detach the backing device and continue in diskless mode.
+
+ -
+ name: fencing-policy
+ type: enum
+ doc: Fencing policy (fencing).
+ entries:
+ -
+ name: dont-care
+ doc: Take no fencing action at all.
+ -
+ name: resource
+ doc: A node that becomes a disconnected primary calls the fence-peer handler to outdate the peer.
+ -
+ name: stonith
+ doc: A node that becomes a disconnected primary freezes its I/O and calls the fence-peer handler, which may have to shoot the peer.
+
+ -
+ name: after-sb-policy
+ type: enum
+ doc: Split-brain recovery policy (after-sb-0pri, after-sb-1pri, after-sb-2pri, rr-conflict).
+ entries:
+ -
+ name: disconnect
+ doc: Do not resynchronize automatically, simply disconnect.
+ -
+ name: discard-younger-primary
+ doc: Resynchronize from the node that became primary first.
+ -
+ name: discard-older-primary
+ doc: Resynchronize from the node that became primary last.
+ -
+ name: discard-zero-changes
+ doc: Resynchronize from the node that wrote data since the split brain was detected, or disconnect if both nodes wrote.
+ -
+ name: discard-least-changes
+ doc: Resynchronize from the node with more modified blocks.
+ -
+ name: discard-local
+ doc: Discard the data on this node and resynchronize it from the peer.
+ -
+ name: discard-remote
+ doc: Discard the data on the peer and resynchronize it from this node.
+ -
+ name: consensus
+ doc: Discard the data on the secondary if the after-sb-0pri policy would discard it as well, otherwise disconnect.
+ -
+ name: discard-secondary
+ doc: Discard the data on the secondary node.
+ -
+ name: call-pri-lost-after-sb
+ doc: Take the after-sb-0pri decision and call the pri-lost-after-sb handler on the node that has to give up its data.
+ -
+ name: violently-as0p
+ doc: Always take the after-sb-0pri decision, even if that changes the primary's view of the data; this can crash the primary.
+ -
+ name: retry-connect
+ doc: Disconnect now and immediately retry to connect (rr-conflict only).
+ -
+ name: auto-discard
+ doc: Reverse the resync direction so that the current primary is resynchronized from the current secondary (rr-conflict with protocol A only).
+
+ -
+ name: on-no-data-policy
+ type: enum
+ doc: What to do when no data is accessible (on-no-data-accessible).
+ entries:
+ -
+ name: io-error
+ doc: Complete the requests with an I/O error, so that system calls fail with EIO.
+ -
+ name: suspend-io
+ doc: Suspend I/O until the data becomes accessible again or the administrator forces I/O to resume.
+
+ -
+ name: on-no-quorum-policy
+ type: enum
+ doc: What to do when quorum is lost (on-no-quorum).
+ entries:
+ -
+ name: io-error
+ doc: Complete the requests with an I/O error while the resource has no quorum.
+ -
+ name: suspend-io
+ doc: Freeze I/O while the resource has no quorum.
+
+ -
+ name: on-suspended-primary-outdated-policy
+ type: enum
+ doc: What to do with a suspended primary that became outdated.
+ entries:
+ -
+ name: disconnect
+ doc: Reject connection attempts and stay isolated.
+ -
+ name: force-secondary
+ doc: Demote to secondary immediately and fail all pending and new I/O requests.
+
+ -
+ name: on-congestion-policy
+ type: enum
+ doc: What to do when the replication link is congested (on-congestion).
+ entries:
+ -
+ name: block
+ doc: Block application writes until the transport's send queue drains.
+ -
+ name: pull-ahead
+ doc: Switch into ahead/behind mode and record further changes in the bitmap instead of replicating them.
+ -
+ name: disconnect
+ doc: Disconnect from the peer instead of blocking application writes.
+
+ -
+ name: read-balancing-policy
+ type: enum
+ doc: Read balancing policy (read-balancing).
+ entries:
+ -
+ name: prefer-local
+ doc: Always read from the local disk.
+ -
+ name: prefer-remote
+ doc: Always read from a peer's disk.
+ -
+ name: round-robin
+ doc: Alternate between the local disk and a peer for consecutive reads.
+ -
+ name: least-pending
+ doc: Read from the disk with the fewest pending requests.
+ -
+ name: when-congested-remote
+ doc: Read from a peer only while the local disk is congested; deprecated since DRBD 9.1.12.
+ -
+ name: striping-32k
+ doc: Read alternating 32 KiB stripes from the local disk and from a peer.
+ -
+ name: striping-64k
+ doc: Read alternating 64 KiB stripes from the local disk and from a peer.
+ -
+ name: striping-128k
+ doc: Read alternating 128 KiB stripes from the local disk and from a peer.
+ -
+ name: striping-256k
+ doc: Read alternating 256 KiB stripes from the local disk and from a peer.
+ -
+ name: striping-512k
+ doc: Read alternating 512 KiB stripes from the local disk and from a peer.
+ -
+ name: striping-1m
+ doc: Read alternating 1 MiB stripes from the local disk and from a peer.
+
+ -
+ name: wire-protocol
+ type: enum
+ doc: Replication protocol (protocol).
+ entries:
+ -
+ name: a
+ value: 1
+ doc: Writes complete as soon as they reached the local disk and the local send buffer.
+ -
+ name: b
+ doc: Writes complete as soon as they reached the local disk and all peers acknowledged their receipt.
+ -
+ name: c
+ doc: Writes complete as soon as they reached the local disk and all remote disks.
+
+ -
+ name: role
+ type: enum
+ doc: Role of a resource on a node. Values mirror enum drbd_role in linux/drbd.h so both netlink dialects share one numbering.
+ entries:
+ -
+ name: unknown
+ doc: The role is not known, for example because the peer is not connected.
+ -
+ name: primary
+ doc: The resource is primary; its devices may be opened for writing.
+ -
+ name: secondary
+ doc: The resource is secondary; its devices may not be opened for writing.
+
+ -
+ name: connection-state
+ type: enum
+ doc: State of a connection to a peer. Values mirror enum drbd_conn_state in linux/drbd.h so both netlink dialects share one numbering.
+ entries:
+ -
+ name: standalone
+ doc: No network configuration is in effect and no connection is attempted.
+ -
+ name: disconnecting
+ doc: Temporary state on the way to standalone while the connection is torn down.
+ -
+ name: unconnected
+ doc: Temporary state before the next connection attempt starts.
+ -
+ name: timeout
+ doc: The connection was dropped because the peer did not answer in time.
+ -
+ name: broken-pipe
+ doc: The connection was dropped because the transport reported a broken connection.
+ -
+ name: network-failure
+ doc: The connection was dropped because of a network failure.
+ -
+ name: protocol-error
+ doc: The connection was dropped because the peer violated the replication protocol.
+ -
+ name: tear-down
+ doc: Temporary state while the peer closes the connection.
+ -
+ name: connecting
+ doc: Listening for the peer and trying to establish a connection.
+ -
+ name: connected
+ doc: A connection to the peer is established.
+
+ -
+ name: repl-state
+ type: enum
+ doc: Replication state of a peer device. Values mirror enum drbd_repl_state in linux/drbd.h so both netlink dialects share one numbering.
+ entries:
+ -
+ name: 'off'
+ value: 9
+ doc: The peer device does not replicate because the connection is not established.
+ -
+ name: established
+ doc: The peer device is connected and replicating normally.
+ -
+ name: starting-sync-s
+ doc: A full resynchronization was requested by the administrator and starts with this node as the source.
+ -
+ name: starting-sync-t
+ doc: A full resynchronization was requested by the administrator and starts with this node as the target.
+ -
+ name: wf-bitmap-s
+ doc: Waiting for the bitmap exchange to finish, with this node as the prospective resync source.
+ -
+ name: wf-bitmap-t
+ doc: Waiting for the bitmap exchange to finish, with this node as the prospective resync target.
+ -
+ name: wf-sync-uuid
+ doc: Waiting for the resync source to create and send the new resync UUID.
+ -
+ name: sync-source
+ doc: Resynchronization is running with this node as the source.
+ -
+ name: sync-target
+ doc: Resynchronization is running with this node as the target.
+ -
+ name: verify-s
+ doc: Online verification is running with this node as the initiator.
+ -
+ name: verify-t
+ doc: Online verification is running with this node as the target.
+ -
+ name: paused-sync-s
+ doc: Resynchronization with this node as the source is paused.
+ -
+ name: paused-sync-t
+ doc: Resynchronization with this node as the target is paused.
+ -
+ name: ahead
+ doc: Replication is suspended because the link is congested; changes are only recorded in the bitmap.
+ -
+ name: behind
+ doc: The peer is ahead of this node, which will be resynchronized once the congestion is over.
+
+ -
+ name: disk-state
+ type: enum
+ doc: State of a backing disk. Values mirror enum drbd_disk_state in linux/drbd.h so both netlink dialects share one numbering.
+ entries:
+ -
+ name: diskless
+ doc: No backing device is attached.
+ -
+ name: attaching
+ doc: The backing device's metadata is being read.
+ -
+ name: detaching
+ doc: The backing device is being detached while pending I/O drains.
+ -
+ name: failed
+ doc: The backing device failed; the disk becomes diskless once the peers have been told.
+ -
+ name: negotiating
+ doc: Attaching while connected, with the data generation still being negotiated with the peers.
+ -
+ name: inconsistent
+ doc: The data is inconsistent, for example because a resynchronization is in progress.
+ -
+ name: outdated
+ doc: The data is consistent but known to be stale relative to a peer.
+ -
+ name: unknown
+ doc: The disk state is not known; used only for a peer's disk.
+ -
+ name: consistent
+ doc: The data is consistent but it is not yet known whether it is up to date.
+ -
+ name: up-to-date
+ doc: The data is consistent and up to date; only this state allows application I/O.
+
+ -
+ name: write-ordering
+ type: enum
+ doc: Write ordering method in use for the backing device.
+ entries:
+ -
+ name: none
+ doc: No ordering between dependent writes is enforced on the backing device.
+ -
+ name: drain-io
+ doc: Dependent writes are ordered by draining the backing device's request queue.
+ -
+ name: bdev-flush
+ doc: Dependent writes are ordered by issuing flushes to the backing device.
+ -
+ name: bio-barrier
+ doc: Dependent writes are ordered with block device barriers, which the Linux block layer no longer provides.
+
+ -
+ name: timeout-type
+ type: enum
+ doc: Which wait-for-connection timeout applies (timeout-type-get reply).
+ entries:
+ -
+ name: default
+ doc: The regular wait-for-connection timeout applies.
+ -
+ name: degraded
+ doc: The degraded-cluster timeout applies because the local data is not up to date.
+ -
+ name: peer-outdated
+ doc: The timeout for an outdated peer applies.
+
+ -
+ name: helper-phase
+ type: enum
+ doc: Whether a helper notification announces the call or reports its result.
+ entries:
+ -
+ name: call
+ doc: The helper script is about to be called.
+ -
+ name: response
+ doc: The helper script has finished and its exit status is reported.
+
+ -
+ name: state-change-action
+ type: enum
+ doc: What a state-change message reports about the object it carries. Values are assigned independently of the legacy drbd_notification_type.
+ entries:
+ -
+ name: exists
+ doc: The object already existed when the notification stream was opened.
+ -
+ name: create
+ doc: The object was just created.
+ -
+ name: change
+ doc: The state or statistics of the object changed.
+ -
+ name: destroy
+ doc: The object was destroyed.
+ -
+ name: rename
+ doc: The resource was renamed; the new name is carried in resource.new-name.
+
+ -
+ name: state-result
+ type: enum
+ doc: Outcome of a state change request. Error values equal the negated kernel-internal SS_* codes (value 3 is unused); success and the other non-error outcomes follow at 29 and above.
+ entries:
+ -
+ name: unknown-error
+ doc: The state change failed for an unspecified reason.
+ -
+ name: two-primaries
+ doc: Multiple primaries are not allowed by the configuration.
+ -
+ name: no-up-to-date-disk
+ doc: The request needs access to up-to-date data.
+ -
+ name: no-local-disk
+ value: 4
+ doc: Cannot resynchronize without a local disk.
+ -
+ name: no-remote-disk
+ doc: Cannot resynchronize without a remote disk.
+ -
+ name: connected-outdates
+ doc: Refusing to become outdated while connected.
+ -
+ name: primary-nop
+ doc: Refusing to become primary while the peer is not outdated.
+ -
+ name: resync-running
+ doc: Cannot start online verify or resynchronization because one is already active.
+ -
+ name: already-standalone
+ doc: Cannot disconnect a connection that is already standalone.
+ -
+ name: cw-failed-by-peer
+ doc: The cluster-wide state change was refused by a peer node.
+ -
+ name: is-diskless
+ doc: The device is diskless but the requested operation requires a disk.
+ -
+ name: device-in-use
+ doc: The device is held open by someone.
+ -
+ name: no-net-config
+ doc: There is no network configuration for this connection.
+ -
+ name: no-verify-alg
+ doc: Starting online verify requires a verify algorithm to be configured.
+ -
+ name: need-connection
+ doc: The state change requires an established connection.
+ -
+ name: lower-than-outdated
+ doc: The disk state is lower than outdated.
+ -
+ name: not-supported
+ doc: The peer does not support the requested protocol feature.
+ -
+ name: in-transient-state
+ doc: The object is in a transient state; retry after the next state change.
+ -
+ name: concurrent-state-change
+ doc: Concurrent state changes were detected and this one was aborted.
+ -
+ name: other-volume-peer-primary
+ doc: Another volume is primary on the peer, which the configuration does not allow.
+ -
+ name: interrupted
+ doc: The state change was interrupted.
+ -
+ name: primary-reader
+ doc: The peer may not become primary while the device is open for reading here.
+ -
+ name: timeout
+ doc: The state change timed out.
+ -
+ name: weakly-connected
+ doc: Primary nodes must be strongly connected among each other.
+ -
+ name: no-quorum
+ doc: The resource does not have quorum.
+ -
+ name: attach-no-bitmap
+ doc: An intentionally diskless peer may not attach a disk.
+ -
+ name: handshake-disconnect
+ doc: Disconnect was chosen during the connection handshake.
+ -
+ name: handshake-retry
+ doc: Retry was chosen during the connection handshake.
+ -
+ name: success
+ value: 29
+ doc: The state change succeeded.
+ -
+ name: nothing-to-do
+ doc: The requested state was already in effect, so nothing had to be done.
+ -
+ name: cw-success
+ doc: The cluster-wide state change succeeded.
+ -
+ name: cw-no-need
+ doc: No cluster-wide state change was necessary.
+
+attribute-sets:
+ -
+ name: address
+ doc: A socket address.
+ attributes:
+ -
+ name: family
+ type: u16
+ doc: Address family (AF_INET or AF_INET6).
+ -
+ name: port
+ type: u16
+ byte-order: big-endian
+ doc: Port number.
+ -
+ name: ipv4
+ type: u32
+ byte-order: big-endian
+ display-hint: ipv4
+ doc: IPv4 address, present when family is AF_INET.
+ -
+ name: ipv6
+ type: binary
+ checks:
+ exact-len: 16
+ display-hint: ipv6
+ doc: IPv6 address, present when family is AF_INET6.
+
+ -
+ name: context
+ doc: Identifies the object a request, reply or notification refers to.
+ attributes:
+ -
+ name: resource-name
+ type: string
+ checks:
+ max-len: resource-name-max
+ doc: Resource name.
+ -
+ name: volume
+ type: u32
+ doc: Volume number within the resource.
+ -
+ name: minor
+ type: u32
+ doc: Minor number of the DRBD device.
+ -
+ name: peer-node-id
+ type: u32
+ doc: Node ID of the peer.
+ -
+ name: connection-name
+ type: string
+ checks:
+ max-len: connection-name-max
+ doc: Name of the connection to the peer.
+ -
+ name: my-address
+ type: nest
+ nested-attributes: address
+ doc: Local address of a path.
+ -
+ name: peer-address
+ type: nest
+ nested-attributes: address
+ doc: Peer address of a path.
+
+ -
+ name: disk-conf
+ doc: Options of an attached backing disk (drbd.conf disk section).
+ attributes:
+ -
+ name: backing-dev
+ type: string
+ checks:
+ max-len: device-path-max
+ doc: Path of the lower-level block device used to store the actual data (drbd.conf option disk).
+ -
+ name: meta-dev
+ type: string
+ checks:
+ max-len: device-path-max
+ doc: Path of the device holding the metadata, or "internal" to store it on the backing device (drbd.conf option meta-disk).
+ -
+ name: meta-dev-idx
+ type: s32
+ doc: Index selecting which slot to use on a shared external metadata device (drbd.conf option meta-disk index).
+ -
+ name: size
+ type: u64
+ doc: Size of the backing device to use, in sectors, overriding automatic detection.
+ -
+ name: on-io-error
+ type: u32
+ enum: io-error-policy
+ doc: Action to take when the backing disk reports an I/O error.
+ -
+ name: resync-after
+ type: s32
+ doc: Volume number of another volume that must finish resynchronizing before this one starts (drbd.conf option resync-after).
+ -
+ name: al-extents
+ type: u32
+ doc: Number of 4 MiB activity log extents that can be active at the same time.
+ -
+ name: disk-barrier
+ type: u8
+ doc: Whether to use disk barriers to enforce the ordering of dependent write requests on the backing device.
+ -
+ name: disk-flushes
+ type: u8
+ doc: Whether to issue disk flushes to the backing device to enforce the ordering of dependent write requests.
+ -
+ name: disk-drain
+ type: u8
+ doc: Whether to wait for the local I/O request queue to drain before completing a write barrier.
+ -
+ name: md-flushes
+ type: u8
+ doc: Whether to issue disk flushes to the metadata device.
+ -
+ name: disk-timeout
+ type: u32
+ doc: Time to wait for the backing device to complete an I/O request before treating it as failed, in units of 0.1 seconds, or 0 to disable (drbd.conf option disk-timeout).
+ -
+ name: read-balancing
+ type: u32
+ enum: read-balancing-policy
+ doc: Policy for balancing reads across the local disk and peers (drbd.conf option read-balancing).
+ -
+ name: unplug-watermark
+ type: u32
+ doc: Legacy watermark, in pages, that used to trigger an early unplug of the backing device's request queue (drbd.conf option unplug-watermark).
+ -
+ name: rs-discard-granularity
+ type: u32
+ doc: Size, in bytes, of the resync requests DRBD tries to discard on the sync target when the source's data is all zeroes (drbd.conf option rs-discard-granularity).
+ -
+ name: al-updates
+ type: u8
+ doc: Whether to update the activity log on disk, at the cost of a full resync after a primary crash if disabled (drbd.conf option al-updates).
+ -
+ name: discard-zeroes-if-aligned
+ type: u8
+ doc: Whether to treat discarded, aligned blocks on the backing device as reading back as zero (drbd.conf option discard-zeroes-if-aligned).
+ -
+ name: disable-write-same
+ type: u8
+ doc: Whether to avoid using the WRITE SAME command on the backing device, for devices that advertise support but fail such requests (drbd.conf option disable-write-same).
+ -
+ name: bitmap
+ type: u8
+ doc: Whether to allocate the on-disk change-tracking bitmap when the device is attached (drbd.conf option bitmap).
+
+ -
+ name: resource-opts
+ doc: Options of a resource (drbd.conf options section).
+ attributes:
+ -
+ name: cpu-mask
+ type: string
+ checks:
+ max-len: cpu-mask-size
+ doc: CPU affinity mask for DRBD kernel threads, as a hexadecimal number (drbd.conf option cpu-mask).
+ -
+ name: on-no-data-accessible
+ type: u32
+ enum: on-no-data-policy
+ doc: Action to take for I/O requests when the requested data is not available locally or remotely (drbd.conf option on-no-data-accessible).
+ -
+ name: auto-promote
+ type: u8
+ doc: Whether to automatically promote the resource to primary when one of its devices is mounted or opened for writing (drbd.conf option auto-promote).
+ -
+ name: node-id
+ type: u32
+ doc: Unique node identifier of this node in the cluster (drbd.conf option node-id).
+ -
+ name: peer-ack-window
+ type: u32
+ doc: Amount of data, in sectors, DRBD replicates to a peer before issuing a peer-ack for the writes in between (drbd.conf option peer-ack-window).
+ -
+ name: twopc-timeout
+ type: u32
+ doc: Timeout for a two-phase-commit cluster-wide state transition, in units of 0.1 seconds (drbd.conf option twopc-timeout).
+ -
+ name: twopc-retry-timeout
+ type: u32
+ doc: Base multiplier for the randomized backoff before retrying a conflicting two-phase commit, in units of 0.1 seconds (drbd.conf option twopc-retry-timeout).
+ -
+ name: peer-ack-delay
+ type: u32
+ doc: How long to wait after the last write request before sending a peer-ack if no new write request arrives, in milliseconds (drbd.conf option peer-ack-delay).
+ -
+ name: auto-promote-timeout
+ type: u32
+ doc: How long to wait for a device to become promotable when auto-promote triggers a promotion, in units of 0.1 seconds (drbd.conf option auto-promote-timeout).
+ -
+ name: max-io-depth
+ type: u32
+ doc: Maximum number of outstanding application I/O requests on a DRBD device.
+ -
+ name: quorum
+ type: s32
+ doc: Number of nodes with an accessible disk required for a partition to have quorum, or a symbolic value (off, majority, all) (drbd.conf option quorum).
+ -
+ name: on-no-quorum
+ type: u32
+ enum: on-no-quorum-policy
+ doc: Action to take for I/O requests when the resource loses quorum (drbd.conf option on-no-quorum).
+ -
+ name: quorum-min-redundancy
+ type: s32
+ doc: Minimum number of nodes with an UpToDate disk required for a partition to gain quorum, or a symbolic value (off, majority, all) (drbd.conf option quorum-minimum-redundancy).
+ -
+ name: on-suspended-primary-outdated
+ type: u32
+ enum: on-suspended-primary-outdated-policy
+ doc: Action to take for a primary that has I/O suspended due to lost quorum and learns its data is outdated (drbd.conf option on-suspended-primary-outdated).
+ -
+ name: drbd8-compat-mode
+ type: u8
+ doc: Whether the resource operates in DRBD 8 compatible, single-peer mode.
+ -
+ name: explicit-drbd8-compat
+ type: u8
+ doc: Whether to explicitly (re)configure DRBD 8 compatible mode whenever a node-id is configured, instead of leaving it unchanged.
+
+ -
+ name: net-conf
+ doc: Options of a connection to a peer (drbd.conf net section).
+ attributes:
+ -
+ name: shared-secret
+ type: string
+ checks:
+ max-len: shared-secret-max
+ doc: Shared secret used for peer authentication (drbd.conf option shared-secret).
+ -
+ name: cram-hmac-alg
+ type: string
+ checks:
+ max-len: alg-name-max
+ doc: Hash-based message authentication code (HMAC) algorithm used for peer authentication (drbd.conf option cram-hmac-alg).
+ -
+ name: integrity-alg
+ type: string
+ checks:
+ max-len: alg-name-max
+ doc: Data integrity algorithm used, in addition to the TCP/IP checksum, to detect corruption of data received over the network (drbd.conf option data-integrity-alg).
+ -
+ name: verify-alg
+ type: string
+ checks:
+ max-len: alg-name-max
+ doc: Hash algorithm used to compute and compare block checksums during online verification (drbd.conf option verify-alg).
+ -
+ name: csums-alg
+ type: string
+ checks:
+ max-len: alg-name-max
+ doc: Hash algorithm used to compare blocks before resending identical data during a resync (drbd.conf option csums-alg).
+ -
+ name: protocol
+ type: u32
+ enum: wire-protocol
+ doc: Replication protocol used on this connection.
+ -
+ name: connect-int
+ type: u32
+ doc: How long to wait before retrying to establish a connection to the peer, in seconds (drbd.conf option connect-int).
+ -
+ name: timeout
+ type: u32
+ doc: Timeout for replies over the network before considering a peer dead, in units of 0.1 seconds (drbd.conf option timeout).
+ -
+ name: ping-int
+ type: u32
+ doc: Interval of connection idle time after which DRBD sends a keep-alive packet, in seconds (drbd.conf option ping-int).
+ -
+ name: ping-timeo
+ type: u32
+ doc: Timeout for replies to keep-alive packets, in units of 0.1 seconds (drbd.conf option ping-timeout).
+ -
+ name: sndbuf-size
+ type: u32
+ doc: Size of the TCP/IP send buffer, in bytes, or 0 to size it automatically (drbd.conf option sndbuf-size).
+ -
+ name: rcvbuf-size
+ type: u32
+ doc: Size of the TCP/IP receive buffer, in bytes, or 0 to size it automatically (drbd.conf option rcvbuf-size).
+ -
+ name: ko-count
+ type: u32
+ doc: Number of times the timeout may be exceeded before a non-responding peer is excluded from the cluster (drbd.conf option ko-count).
+ -
+ name: max-epoch-size
+ type: u32
+ doc: Maximum number of write requests DRBD may issue before issuing a write barrier (drbd.conf option max-epoch-size).
+ -
+ name: after-sb-0pri
+ type: u32
+ enum: after-sb-policy
+ doc: Split-brain recovery policy when neither node is primary.
+ -
+ name: after-sb-1pri
+ type: u32
+ enum: after-sb-policy
+ doc: Split-brain recovery policy when exactly one node is primary.
+ -
+ name: after-sb-2pri
+ type: u32
+ enum: after-sb-policy
+ doc: Split-brain recovery policy when both nodes are primary.
+ -
+ name: rr-conflict
+ type: u32
+ enum: after-sb-policy
+ doc: Policy for resolving a role/resync conflict left over from a split-brain recovery (drbd.conf option rr-conflict).
+ -
+ name: on-congestion
+ type: u32
+ enum: on-congestion-policy
+ doc: Action to take when the replication link's TCP send queue is congested (drbd.conf option on-congestion).
+ -
+ name: cong-fill
+ type: u32
+ doc: Amount of in-flight data, in sectors, allowed on this connection before switching into ahead/behind mode, or 0 to disable (drbd.conf option congestion-fill).
+ -
+ name: cong-extents
+ type: u32
+ doc: Number of active bitmap extents allowed before switching into ahead/behind mode (drbd.conf option congestion-extents).
+ -
+ name: two-primaries
+ type: u8
+ doc: Whether to allow both nodes of this connection to be primary at the same time (drbd.conf option allow-two-primaries).
+ -
+ name: tcp-cork
+ type: u8
+ doc: Whether to use the TCP_CORK socket option to coalesce partial messages into fewer, bigger packets (drbd.conf option tcp-cork).
+ -
+ name: always-asbp
+ type: u8
+ doc: Whether to apply the automatic split-brain recovery policies even when the UUIDs indicate a third node may be involved (drbd.conf option always-asbp).
+ -
+ name: use-rle
+ type: u8
+ doc: Whether to run-length encode the bitmap exchanged with the peer when a connection is established (drbd.conf option use-rle).
+ -
+ name: fencing
+ type: u32
+ enum: fencing-policy
+ doc: Fencing policy used to avoid a split-brain when both nodes are primary and disconnected.
+ -
+ name: connection-name
+ type: string
+ checks:
+ max-len: connection-name-max
+ doc: Name of the connection this net-conf applies to.
+ -
+ name: csums-after-crash-only
+ type: u8
+ doc: Whether to compare block checksums only for the resync after a primary crash, rather than for every resync (drbd.conf option csums-after-crash-only).
+ -
+ name: sock-check-timeo
+ type: u32
+ doc: Timeout used to poll the send/receive socket for a broken TCP connection when DRBD-proxy is in use, in units of 0.1 seconds (drbd.conf option socket-check-timeout).
+ -
+ name: transport-name
+ type: string
+ checks:
+ max-len: transport-name-max
+ doc: Name of the network transport module used for this connection, e.g. tcp or rdma (drbd.conf option transport).
+ -
+ name: max-buffers
+ type: u32
+ doc: Maximum number of pages used for receive buffers and internal resync/verify buffers per device (drbd.conf option max-buffers).
+ -
+ name: allow-remote-read
+ type: u8
+ doc: Whether to allow reads to be served from a peer's disk when the local disk is not up to date (drbd.conf option allow-remote-read).
+ -
+ name: tls
+ type: u8
+ doc: Whether to encrypt this connection with TLS (drbd.conf option tls).
+ -
+ name: tls-privkey
+ type: s32
+ doc: Serial number of the kernel keyring key holding the private key used for TLS encryption (drbd.conf option tls-privkey).
+ -
+ name: tls-certificate
+ type: s32
+ doc: Serial number of the kernel keyring key holding the certificate used for TLS encryption (drbd.conf option tls-certificate).
+ -
+ name: tls-keyring
+ type: s32
+ doc: Serial number of the kernel keyring used to look up the TLS key material (drbd.conf option tls-keyring).
+ -
+ name: load-balance-paths
+ type: u8
+ doc: Whether to load-balance traffic for this connection across all configured paths instead of using only one at a time (drbd.conf option load-balance-paths).
+ -
+ name: rdma-ctrl-rcvbuf-size
+ type: u32
+ doc: Size, in bytes, of the RDMA transport's control-stream receive buffer, or 0 to derive it from rcvbuf-size (drbd.conf option rdma-ctrl-rcvbuf-size).
+ -
+ name: rdma-ctrl-sndbuf-size
+ type: u32
+ doc: Size, in bytes, of the RDMA transport's control-stream send buffer, or 0 to derive it from sndbuf-size (drbd.conf option rdma-ctrl-sndbuf-size).
+
+ -
+ name: set-role-parms
+ doc: Parameters of the set-role request.
+ attributes:
+ -
+ name: force
+ type: flag
+ doc: Request that the promotion to primary succeed even if some devices are not guaranteed to have up-to-date data (drbdsetup primary option force).
+
+ -
+ name: resize-parms
+ doc: Parameters of the resize request.
+ attributes:
+ -
+ name: size
+ type: u64
+ doc: New size of the device, in sectors, or 0 to use the full size of the backing devices (drbdsetup resize option size).
+ -
+ name: assume-peer-has-space
+ type: flag
+ doc: Request that the resize proceed even though not all peer devices are currently connected, assuming they already have enough space.
+ -
+ name: assume-clean
+ type: flag
+ doc: Request that the additional space not be resynchronized, assuming it is already identical on all nodes.
+ -
+ name: al-stripes
+ type: u32
+ doc: Number of activity log stripes to use after the resize (drbdsetup resize option al-stripes).
+ -
+ name: al-stripe-size
+ type: u32
+ doc: Size of each activity log stripe, in KiB, after the resize (drbdsetup resize option al-stripe-size).
+
+ -
+ name: start-ov-parms
+ doc: Parameters of the start-ov (online verify) request.
+ attributes:
+ -
+ name: start-sector
+ type: u64
+ doc: Sector at which to start online verification, to resume a previously stopped run.
+ -
+ name: stop-sector
+ type: u64
+ doc: Sector at which to stop online verification.
+
+ -
+ name: new-current-uuid-parms
+ doc: Parameters of the new-current-uuid request.
+ attributes:
+ -
+ name: clear-bm
+ type: flag
+ doc: Request that the peer's bitmap also be cleared, marking the peer as fully in sync without a resync (drbdsetup new-current-uuid option clear-bitmap).
+ -
+ name: force-resync
+ type: flag
+ doc: Request that the peer be marked out of sync so that a resync starts, instead of assuming it already has the same data (drbdsetup new-current-uuid option force-resync).
+
+ -
+ name: disconnect-parms
+ doc: Parameters of the disconnect request.
+ attributes:
+ -
+ name: force
+ type: flag
+ doc: Request that the connection be torn down immediately, discarding any pending, not yet acknowledged data instead of waiting for it (drbdsetup disconnect option force).
+
+ -
+ name: detach-parms
+ doc: Parameters of the detach request.
+ attributes:
+ -
+ name: force
+ type: flag
+ doc: Request that the detach proceed immediately, marking the lower-level device failed until pending I/O completes (drbdsetup detach option force).
+ -
+ name: intentional-diskless-detach
+ type: flag
+ doc: Request that the device be marked permanently, intentionally diskless instead of temporarily diskless (drbdsetup detach option diskless).
+
+ -
+ name: device-conf
+ doc: Options of a device, set when the device is created (drbdsetup new-minor).
+ attributes:
+ -
+ name: max-bio-size
+ type: u32
+ doc: Maximum size of a single I/O request the device accepts, in bytes (drbdsetup new-minor option max-bio-size).
+ -
+ name: intentional-diskless
+ type: u8
+ doc: Whether the device is deliberately created without a local disk, e.g. as a diskless client (drbdsetup new-minor option diskless).
+ -
+ name: block-size
+ type: u32
+ doc: Logical block size the device reports, needed to combine differing backing disk block sizes across nodes (drbd.conf option block-size).
+ -
+ name: discard-granularity
+ type: u32
+ doc: Discard granularity, in bytes, advertised by the device; discard requests must be aligned to and a multiple of this value (drbd.conf option discard-granularity).
+
+ -
+ name: resource-info
+ doc: State of a resource.
+ attributes:
+ -
+ name: role
+ type: u32
+ enum: role
+ doc: Role of the resource on this node.
+ -
+ name: susp
+ type: u8
+ doc: Whether I/O on the resource is suspended by the user.
+ -
+ name: susp-nod
+ type: u8
+ doc: Whether I/O on the resource is suspended because no data is accessible.
+ -
+ name: susp-fen
+ type: u8
+ doc: Whether I/O on the resource is suspended because a fence-peer handler is running.
+ -
+ name: susp-quorum
+ type: u8
+ doc: Whether I/O on the resource is suspended because it has lost quorum.
+ -
+ name: fail-io
+ type: u8
+ doc: Whether all I/O on the resource fails because it was forced to demote from primary.
+
+ -
+ name: device-info
+ doc: State of a device.
+ attributes:
+ -
+ name: disk-state
+ type: u32
+ enum: disk-state
+ doc: Current state of the backing disk.
+ -
+ name: is-intentional-diskless
+ type: u8
+ doc: Whether the device is deliberately configured without a local disk.
+ -
+ name: has-quorum
+ type: u8
+ doc: Whether the device currently has quorum.
+ -
+ name: is-open
+ type: u8
+ doc: Whether the device is currently opened by an application.
+ -
+ name: backing-dev-path
+ type: string
+ checks:
+ max-len: device-path-max
+ doc: Path of the backing device, present while it is still accessible after a disk failure.
+
+ -
+ name: connection-info
+ doc: State of a connection to a peer.
+ attributes:
+ -
+ name: connection-state
+ type: u32
+ enum: connection-state
+ doc: Current state of the connection to the peer.
+ -
+ name: role
+ type: u32
+ enum: role
+ doc: Current role of the peer.
+
+ -
+ name: peer-device-info
+ doc: State of a peer device.
+ attributes:
+ -
+ name: repl-state
+ type: u32
+ enum: repl-state
+ doc: Current replication state with the peer.
+ -
+ name: disk-state
+ type: u32
+ enum: disk-state
+ doc: Current state of the peer's disk.
+ -
+ name: resync-susp-user
+ type: u8
+ doc: Whether resynchronization with this peer is suspended by the user.
+ -
+ name: resync-susp-peer
+ type: u8
+ doc: Whether resynchronization with this peer is suspended by the peer.
+ -
+ name: resync-susp-dependency
+ type: u8
+ doc: Whether resynchronization with this peer is suspended because it depends on another volume or connection resynchronizing first.
+ -
+ name: is-intentional-diskless
+ type: u8
+ doc: Whether the peer is deliberately configured without a local disk.
+ -
+ name: resync-susp-max-parallel
+ type: u8
+ doc: Whether resynchronization with this peer is suspended to enforce the maximum number of parallel resyncs.
+
+ -
+ name: resource-statistics
+ doc: Statistics of a resource.
+ attributes:
+ -
+ name: write-ordering
+ type: u32
+ enum: write-ordering
+ doc: Write ordering method currently in use for the resource's backing devices.
+
+ -
+ name: device-statistics
+ doc: Statistics of a device.
+ attributes:
+ -
+ name: size
+ type: u64
+ doc: Capacity of the device, in sectors.
+ -
+ name: read
+ type: u64
+ doc: Total data read from the device, in sectors, since it was attached.
+ -
+ name: write
+ type: u64
+ doc: Total data written to the device, in sectors, since it was attached.
+ -
+ name: al-writes
+ type: u64
+ doc: Number of activity log metadata writes since the device was attached.
+ -
+ name: bm-writes
+ type: u64
+ doc: Number of bitmap metadata writes since the device was attached.
+ -
+ name: upper-pending
+ type: u32
+ doc: Number of application I/O requests currently in flight on the device.
+ -
+ name: lower-pending
+ type: u32
+ doc: Number of I/O requests currently in flight on the backing device.
+ -
+ name: upper-blocked
+ type: u8
+ doc: Whether application I/O to the device is currently throttled.
+ -
+ name: lower-blocked
+ type: u8
+ doc: Whether I/O to the backing device is currently blocked.
+ -
+ name: al-suspended
+ type: u8
+ doc: Whether updates to the activity log are currently suspended.
+ -
+ name: exposed-data-uuid
+ type: u64
+ doc: Data generation UUID currently exposed to peers, identifying the generation of data this node has.
+ -
+ name: current-uuid
+ type: u64
+ doc: Current data generation UUID of the device's metadata.
+ -
+ name: disk-flags
+ type: u32
+ doc: Bitmask of the backing disk's metadata flags.
+ -
+ name: history-uuids
+ type: binary
+ sub-type: u64
+ checks:
+ max-len: history-uuids-size
+ doc: Historical bitmap UUIDs of prior data generations, one slot per peer.
+
+ -
+ name: connection-statistics
+ doc: Statistics of a connection to a peer.
+ attributes:
+ -
+ name: congested
+ type: u8
+ doc: Whether the network transport to the peer is currently congested.
+ -
+ name: ap-in-flight
+ type: u64
+ doc: Application data sent to the peer but not yet acknowledged, in sectors.
+ -
+ name: rs-in-flight
+ type: u64
+ doc: Resync data sent to the peer but not yet acknowledged, in sectors.
+
+ -
+ name: peer-device-statistics
+ doc: Statistics of a peer device.
+ attributes:
+ -
+ name: received
+ type: u64
+ doc: Total data received from the peer for this device, in sectors.
+ -
+ name: sent
+ type: u64
+ doc: Total data sent to the peer for this device, in sectors.
+ -
+ name: pending
+ type: u32
+ doc: Number of requests to this peer waiting for an acknowledgement.
+ -
+ name: unacked
+ type: u32
+ doc: Number of requests from this peer that have not yet been acknowledged.
+ -
+ name: out-of-sync
+ type: u64
+ doc: Amount of data known to differ from this peer, in sectors.
+ -
+ name: resync-failed
+ type: u64
+ doc: Amount of data that failed to resynchronize with this peer, in sectors.
+ -
+ name: bitmap-uuid
+ type: u64
+ doc: Bitmap UUID recorded for this peer.
+ -
+ name: flags
+ type: u32
+ doc: Bitmask of this peer device's metadata flags.
+ -
+ name: rs-total
+ type: u64
+ doc: Total amount of data to resynchronize with this peer for the current resync, in sectors.
+ -
+ name: ov-start-sector
+ type: u64
+ doc: Sector at which the current online verify run started.
+ -
+ name: ov-stop-sector
+ type: u64
+ doc: Sector at which the current online verify run will stop.
+ -
+ name: ov-position
+ type: u64
+ doc: Current position of an ongoing online verify run, in sectors.
+ -
+ name: ov-left
+ type: u64
+ doc: Amount of data left to verify in an ongoing online verify run, in sectors.
+ -
+ name: ov-skipped
+ type: u64
+ doc: Amount of data skipped during an ongoing online verify run, in sectors.
+ -
+ name: rs-same-csum
+ type: u64
+ doc: Amount of resync data found identical by checksum comparison and not retransmitted, in sectors.
+ -
+ name: rs-dt-start-ms
+ type: u64
+ doc: Time elapsed since the current resync with this peer started, in milliseconds.
+ -
+ name: rs-paused-ms
+ type: u64
+ doc: Total time the current resync with this peer has been paused, in milliseconds.
+ -
+ name: rs-dt0-ms
+ type: u64
+ doc: Time since the most recent resync progress mark, in milliseconds.
+ -
+ name: rs-db0-sectors
+ type: u64
+ doc: Data resynchronized since the most recent resync progress mark, in sectors.
+ -
+ name: rs-dt1-ms
+ type: u64
+ doc: Time since the resync progress mark before the most recent one, in milliseconds.
+ -
+ name: rs-db1-sectors
+ type: u64
+ doc: Data resynchronized since the resync progress mark before the most recent one, in sectors.
+ -
+ name: rs-c-sync-rate
+ type: u32
+ doc: Current dynamically controlled resync rate for this peer, in KiB/s.
+ -
+ name: uuid-flags
+ type: u64
+ doc: Bitmask of UUID-related flags negotiated with this peer.
+
+ -
+ name: helper-info
+ doc: Identity and outcome of a handler script invocation.
+ attributes:
+ -
+ name: name
+ type: string
+ checks:
+ max-len: helper-name-max
+ doc: Name of the handler script being invoked.
+ -
+ name: status
+ type: u32
+ doc: Exit status of the handler script, present when phase is response.
+ -
+ name: phase
+ type: u32
+ enum: helper-phase
+ doc: Whether this notification announces the call or reports its result.
+
+ -
+ name: invalidate-parms
+ doc: Parameters of the invalidate request.
+ attributes:
+ -
+ name: sync-from-peer-node-id
+ type: u32
+ doc: Node ID of the peer to resynchronize from; if absent, the kernel chooses a peer.
+ -
+ name: reset-bitmap
+ type: u8
+ doc: Whether to mark the whole bitmap out of sync before starting the resync, instead of resyncing only the blocks already marked out of sync (drbdsetup invalidate option reset-bitmap).
+
+ -
+ name: peer-device-conf
+ doc: Options of a peer device (drbd.conf peer-device-options section).
+ attributes:
+ -
+ name: resync-rate
+ type: u32
+ doc: Bandwidth DRBD may use for resynchronizing with this peer when the dynamic resync controller is disabled, in KiB/s (drbd.conf option resync-rate).
+ -
+ name: c-plan-ahead
+ type: u32
+ doc: How fast the dynamic resync-rate controller adapts to changes in resync speed, in units of 0.1 seconds, or 0 to use a fixed resync-rate instead (drbd.conf option c-plan-ahead).
+ -
+ name: c-delay-target
+ type: u32
+ doc: Delay the dynamic resync-rate controller aims for along the resync path, in units of 0.1 seconds (drbd.conf option c-delay-target).
+ -
+ name: c-fill-target
+ type: u32
+ doc: Amount of resync data the dynamic resync-rate controller aims to keep in flight, in sectors (drbd.conf option c-fill-target).
+ -
+ name: c-max-rate
+ type: u32
+ doc: Maximum bandwidth used by the dynamic resync-rate controller, in KiB/s, or 0 for no limit (drbd.conf option c-max-rate).
+ -
+ name: c-min-rate
+ type: u32
+ doc: Bandwidth reserved for resync I/O against this peer when this node is the sync source and primary, in KiB/s (drbd.conf option c-min-rate).
+ -
+ name: bitmap
+ type: u8
+ doc: Whether to allocate a bitmap slot for this peer, overriding the automatic default for a diskless peer (drbd.conf option bitmap).
+ -
+ name: resync-without-replication
+ type: u8
+ doc: Whether to suspend replication of application writes to this peer while it is being resynchronized (drbd.conf option resync-without-replication).
+ -
+ name: peer-tiebreaker
+ type: u8
+ doc: Whether this peer participates as a tiebreaker in quorum decisions even though it is intentionally diskless (drbd.conf option peer-tiebreaker).
+
+ -
+ name: connect-parms
+ doc: Parameters of the connect request.
+ attributes:
+ -
+ name: tentative
+ type: flag
+ doc: Request that DRBD only determine whether a connection could be established and which resync direction would be used, without actually connecting or resyncing (drbdsetup connect option tentative).
+ -
+ name: discard-my-data
+ type: flag
+ doc: Request that local data be discarded and resynchronized from the peer that has the most up-to-date data (drbdsetup connect option discard-my-data).
+
+ -
+ name: path-info
+ doc: State of a path.
+ attributes:
+ -
+ name: established
+ type: u8
+ doc: Whether the path's transport connection is currently established.
+
+ -
+ name: rename-parms
+ doc: Parameters of the rename request.
+ attributes:
+ -
+ name: new-name
+ type: string
+ checks:
+ max-len: resource-name-max
+ doc: New name for the resource.
+
+ -
+ name: invalidate-peer-parms
+ doc: Parameters of the invalidate-peer request.
+ attributes:
+ -
+ name: reset-bitmap
+ type: u8
+ doc: Whether to mark the whole bitmap out of sync before starting the resync, instead of resyncing only the blocks already marked out of sync (drbdsetup invalidate-remote option reset-bitmap).
+
+ -
+ name: suspend-io-parms
+ doc: Parameters of the suspend-io request.
+ attributes:
+ -
+ name: bdev-freeze
+ type: u8
+ doc: Whether to freeze the filesystem mounted on the device to bring it into a consistent state before suspending I/O (drbdsetup suspend-io option bdev-freeze).
+
+ -
+ name: resource
+ doc: A resource with its context, state, statistics and options.
+ attributes:
+ -
+ name: context
+ type: nest
+ nested-attributes: context
+ doc: Identity of the object.
+ -
+ name: info
+ type: nest
+ nested-attributes: resource-info
+ doc: State of the object.
+ -
+ name: statistics
+ type: nest
+ nested-attributes: resource-statistics
+ doc: Statistics of the object.
+ -
+ name: new-name
+ type: string
+ checks:
+ max-len: resource-name-max
+ doc: New name of the resource; present in state-change messages with action
+ rename.
+ -
+ name: resource-opts
+ type: nest
+ nested-attributes: resource-opts
+ doc: Resource-wide options in effect.
+
+ -
+ name: device
+ doc: A device with its context, state, statistics and options.
+ attributes:
+ -
+ name: context
+ type: nest
+ nested-attributes: context
+ doc: Identity of the object.
+ -
+ name: info
+ type: nest
+ nested-attributes: device-info
+ doc: State of the object.
+ -
+ name: statistics
+ type: nest
+ nested-attributes: device-statistics
+ doc: Statistics of the object.
+ -
+ name: disk-conf
+ type: nest
+ nested-attributes: disk-conf
+ doc: Backing disk options in effect; absent while the device is diskless.
+ -
+ name: device-conf
+ type: nest
+ nested-attributes: device-conf
+ doc: Device options in effect.
+
+ -
+ name: connection
+ doc: A connection with its context, state, statistics, options and paths.
+ attributes:
+ -
+ name: context
+ type: nest
+ nested-attributes: context
+ doc: Identity of the object.
+ -
+ name: info
+ type: nest
+ nested-attributes: connection-info
+ doc: State of the object.
+ -
+ name: statistics
+ type: nest
+ nested-attributes: connection-statistics
+ doc: Statistics of the object.
+ -
+ name: net-conf
+ type: nest
+ nested-attributes: net-conf
+ doc: Connection options in effect; absent when the connection has none.
+ -
+ name: path
+ type: nest
+ nested-attributes: path
+ multi-attr: true
+ doc: The paths of this connection, one attribute each. Also available on
+ their own through path-get.
+
+ -
+ name: peer-device
+ doc: A peer device with its context, state, statistics and options.
+ attributes:
+ -
+ name: context
+ type: nest
+ nested-attributes: context
+ doc: Identity of the object.
+ -
+ name: info
+ type: nest
+ nested-attributes: peer-device-info
+ doc: State of the object.
+ -
+ name: statistics
+ type: nest
+ nested-attributes: peer-device-statistics
+ doc: Statistics of the object.
+ -
+ name: peer-device-conf
+ type: nest
+ nested-attributes: peer-device-conf
+ doc: Peer device options in effect; absent when the peer device has none.
+
+ -
+ name: path
+ doc: A path with its context and state.
+ attributes:
+ -
+ name: context
+ type: nest
+ nested-attributes: context
+ doc: Identity of the object.
+ -
+ name: info
+ type: nest
+ nested-attributes: path-info
+ doc: State of the object.
+
+ -
+ name: drbd2
+ doc: Top-level attributes of drbd2 requests, replies and notifications.
+ attributes:
+ -
+ name: context
+ type: nest
+ nested-attributes: context
+ doc: Object the message refers to.
+ -
+ name: set-defaults
+ type: flag
+ doc: Reset all options not given in this request to their defaults before
+ applying it.
+ -
+ name: state-result
+ type: u32
+ enum: state-result
+ doc: Outcome of the state change performed by the request.
+ -
+ name: message
+ type: string
+ doc: Human-readable explanation accompanying state-result.
+ -
+ name: timeout-type
+ type: u32
+ enum: timeout-type
+ doc: Reply of timeout-type-get.
+ -
+ name: disk-conf
+ type: nest
+ nested-attributes: disk-conf
+ doc: Backing disk options for device-attach and disk-set.
+ -
+ name: resource-opts
+ type: nest
+ nested-attributes: resource-opts
+ doc: Resource-wide options for resource-new and resource-set.
+ -
+ name: net-conf
+ type: nest
+ nested-attributes: net-conf
+ doc: Connection options for connection-new and connection-set.
+ -
+ name: set-role-parms
+ type: nest
+ nested-attributes: set-role-parms
+ doc: Parameters of resource-primary and resource-secondary.
+ -
+ name: resize-parms
+ type: nest
+ nested-attributes: resize-parms
+ doc: Parameters of device-resize.
+ -
+ name: start-ov-parms
+ type: nest
+ nested-attributes: start-ov-parms
+ doc: Parameters of peer-device-start-ov.
+ -
+ name: new-current-uuid-parms
+ type: nest
+ nested-attributes: new-current-uuid-parms
+ doc: Parameters of device-new-current-uuid.
+ -
+ name: disconnect-parms
+ type: nest
+ nested-attributes: disconnect-parms
+ doc: Parameters of connection-disconnect and connection-del.
+ -
+ name: detach-parms
+ type: nest
+ nested-attributes: detach-parms
+ doc: Parameters of device-detach.
+ -
+ name: device-conf
+ type: nest
+ nested-attributes: device-conf
+ doc: Device options set when the device is created by device-new.
+ -
+ name: helper
+ type: nest
+ nested-attributes: helper-info
+ doc: Identity and outcome of the handler script reported by helper-ntf.
+ -
+ name: invalidate-parms
+ type: nest
+ nested-attributes: invalidate-parms
+ doc: Parameters of device-invalidate.
+ -
+ name: peer-device-conf
+ type: nest
+ nested-attributes: peer-device-conf
+ doc: Peer device options for peer-device-set.
+ -
+ name: connect-parms
+ type: nest
+ nested-attributes: connect-parms
+ doc: Parameters of connection-connect.
+ -
+ name: rename-parms
+ type: nest
+ nested-attributes: rename-parms
+ doc: Parameters of resource-rename.
+ -
+ name: invalidate-peer-parms
+ type: nest
+ nested-attributes: invalidate-peer-parms
+ doc: Parameters of peer-device-invalidate.
+ -
+ name: suspend-io-parms
+ type: nest
+ nested-attributes: suspend-io-parms
+ doc: Parameters of resource-suspend-io.
+ -
+ name: resource
+ type: nest
+ nested-attributes: resource
+ doc: A resource (dump reply).
+ -
+ name: device
+ type: nest
+ nested-attributes: device
+ doc: A device (dump reply).
+ -
+ name: connection
+ type: nest
+ nested-attributes: connection
+ doc: A connection (dump reply).
+ -
+ name: peer-device
+ type: nest
+ nested-attributes: peer-device
+ doc: A peer device (dump reply).
+ -
+ name: path
+ type: nest
+ nested-attributes: path
+ doc: A path (dump reply).
+
+ -
+ name: state-change
+ doc: One object of a state change or of the initial state snapshot. Exactly one
+ object nest is present.
+ attributes:
+ -
+ name: action
+ type: u32
+ enum: state-change-action
+ doc: Whether the object exists, was created, changed or destroyed.
+ -
+ name: more
+ type: flag
+ doc: Further messages belong to the same state change.
+ -
+ name: resource
+ type: nest
+ nested-attributes: resource
+ doc: Present when the message describes a resource.
+ -
+ name: device
+ type: nest
+ nested-attributes: device
+ doc: Present when the message describes a device.
+ -
+ name: connection
+ type: nest
+ nested-attributes: connection
+ doc: Present when the message describes a connection.
+ -
+ name: peer-device
+ type: nest
+ nested-attributes: peer-device
+ doc: Present when the message describes a peer device.
+ -
+ name: path
+ type: nest
+ nested-attributes: path
+ doc: Present when the message describes a path.
+
+operations:
+ list:
+ -
+ name: resource-new
+ doc: Create a new DRBD resource.
+ attribute-set: drbd2
+ flags:
+ - admin-perm
+ do:
+ pre: drbd2-pre-doit
+ post: drbd2-post-doit
+ request:
+ attributes:
+ - context
+ - resource-opts
+ reply:
+ attributes:
+ - state-result
+ - message
+
+ -
+ name: resource-del
+ doc: Delete a DRBD resource.
+ attribute-set: drbd2
+ flags:
+ - admin-perm
+ do:
+ pre: drbd2-pre-doit
+ post: drbd2-post-doit
+ request:
+ attributes:
+ - context
+ reply:
+ attributes:
+ - state-result
+ - message
+
+ -
+ name: resource-set
+ doc: Change resource options.
+ attribute-set: drbd2
+ flags:
+ - admin-perm
+ do:
+ pre: drbd2-pre-doit
+ post: drbd2-post-doit
+ request:
+ attributes:
+ - context
+ - resource-opts
+ - set-defaults
+ reply:
+ attributes:
+ - state-result
+ - message
+
+ -
+ name: resource-rename
+ doc: Rename a DRBD resource.
+ attribute-set: drbd2
+ flags:
+ - admin-perm
+ do:
+ pre: drbd2-pre-doit
+ post: drbd2-post-doit
+ request:
+ attributes:
+ - context
+ - rename-parms
+ reply:
+ attributes:
+ - state-result
+ - message
+
+ -
+ name: resource-down
+ doc: Shut down a DRBD resource.
+ attribute-set: drbd2
+ flags:
+ - admin-perm
+ do:
+ pre: drbd2-pre-doit
+ post: drbd2-post-doit
+ request:
+ attributes:
+ - context
+ reply:
+ attributes:
+ - state-result
+ - message
+
+ -
+ name: resource-primary
+ doc: Promote the resource to primary role.
+ attribute-set: drbd2
+ flags:
+ - admin-perm
+ do:
+ pre: drbd2-pre-doit
+ post: drbd2-post-doit
+ request:
+ attributes:
+ - context
+ - set-role-parms
+ reply:
+ attributes:
+ - state-result
+ - message
+
+ -
+ name: resource-secondary
+ doc: Demote the resource to secondary role.
+ attribute-set: drbd2
+ flags:
+ - admin-perm
+ do:
+ pre: drbd2-pre-doit
+ post: drbd2-post-doit
+ request:
+ attributes:
+ - context
+ - set-role-parms
+ reply:
+ attributes:
+ - state-result
+ - message
+
+ -
+ name: resource-suspend-io
+ doc: Suspend I/O on a resource.
+ attribute-set: drbd2
+ flags:
+ - admin-perm
+ do:
+ pre: drbd2-pre-doit
+ post: drbd2-post-doit
+ request:
+ attributes:
+ - context
+ - suspend-io-parms
+ reply:
+ attributes:
+ - state-result
+ - message
+
+ -
+ name: resource-resume-io
+ doc: Resume I/O on a resource.
+ attribute-set: drbd2
+ flags:
+ - admin-perm
+ do:
+ pre: drbd2-pre-doit
+ post: drbd2-post-doit
+ request:
+ attributes:
+ - context
+ reply:
+ attributes:
+ - state-result
+ - message
+
+ -
+ name: device-new
+ doc: Add a DRBD device as a volume to a resource.
+ attribute-set: drbd2
+ flags:
+ - admin-perm
+ do:
+ pre: drbd2-pre-doit
+ post: drbd2-post-doit
+ request:
+ attributes:
+ - context
+ - device-conf
+ reply:
+ attributes:
+ - state-result
+ - message
+
+ -
+ name: device-del
+ doc: Delete a DRBD device.
+ attribute-set: drbd2
+ flags:
+ - admin-perm
+ do:
+ pre: drbd2-pre-doit
+ post: drbd2-post-doit
+ request:
+ attributes:
+ - context
+ reply:
+ attributes:
+ - state-result
+ - message
+
+ -
+ name: device-attach
+ doc: Attach a local backing device to a DRBD device.
+ attribute-set: drbd2
+ flags:
+ - admin-perm
+ do:
+ pre: drbd2-pre-doit
+ post: drbd2-post-doit
+ request:
+ attributes:
+ - context
+ - disk-conf
+ reply:
+ attributes:
+ - state-result
+ - message
+
+ -
+ name: device-detach
+ doc: Detach the local backing device from a DRBD device.
+ attribute-set: drbd2
+ flags:
+ - admin-perm
+ do:
+ pre: drbd2-pre-doit
+ post: drbd2-post-doit
+ request:
+ attributes:
+ - context
+ - detach-parms
+ reply:
+ attributes:
+ - state-result
+ - message
+
+ -
+ name: disk-set
+ doc: Change disk options. Applies to the attached backing disk; see
+ device-attach.
+ attribute-set: drbd2
+ flags:
+ - admin-perm
+ do:
+ pre: drbd2-pre-doit
+ post: drbd2-post-doit
+ request:
+ attributes:
+ - context
+ - disk-conf
+ - set-defaults
+ reply:
+ attributes:
+ - state-result
+ - message
+
+ -
+ name: device-resize
+ doc: Resize the DRBD device.
+ attribute-set: drbd2
+ flags:
+ - admin-perm
+ do:
+ pre: drbd2-pre-doit
+ post: drbd2-post-doit
+ request:
+ attributes:
+ - context
+ - resize-parms
+ reply:
+ attributes:
+ - state-result
+ - message
+
+ -
+ name: device-outdate
+ doc: Mark the local data as outdated.
+ attribute-set: drbd2
+ flags:
+ - admin-perm
+ do:
+ pre: drbd2-pre-doit
+ post: drbd2-post-doit
+ request:
+ attributes:
+ - context
+ reply:
+ attributes:
+ - state-result
+ - message
+
+ -
+ name: device-invalidate
+ doc: Invalidate the local data of a DRBD device.
+ attribute-set: drbd2
+ flags:
+ - admin-perm
+ do:
+ pre: drbd2-pre-doit
+ post: drbd2-post-doit
+ request:
+ attributes:
+ - context
+ - invalidate-parms
+ reply:
+ attributes:
+ - state-result
+ - message
+
+ -
+ name: device-new-current-uuid
+ doc: Generate a new current UUID.
+ attribute-set: drbd2
+ flags:
+ - admin-perm
+ do:
+ pre: drbd2-pre-doit
+ post: drbd2-post-doit
+ request:
+ attributes:
+ - context
+ - new-current-uuid-parms
+ reply:
+ attributes:
+ - state-result
+ - message
+
+ -
+ name: connection-new
+ doc: Add a new peer to a resource.
+ attribute-set: drbd2
+ flags:
+ - admin-perm
+ do:
+ pre: drbd2-pre-doit
+ post: drbd2-post-doit
+ request:
+ attributes:
+ - context
+ - net-conf
+ reply:
+ attributes:
+ - state-result
+ - message
+
+ -
+ name: connection-del
+ doc: Delete a peer from a resource.
+ attribute-set: drbd2
+ flags:
+ - admin-perm
+ do:
+ pre: drbd2-pre-doit
+ post: drbd2-post-doit
+ request:
+ attributes:
+ - context
+ - disconnect-parms
+ reply:
+ attributes:
+ - state-result
+ - message
+
+ -
+ name: connection-connect
+ doc: Connect to a peer.
+ attribute-set: drbd2
+ flags:
+ - admin-perm
+ do:
+ pre: drbd2-pre-doit
+ post: drbd2-post-doit
+ request:
+ attributes:
+ - context
+ - connect-parms
+ reply:
+ attributes:
+ - state-result
+ - message
+
+ -
+ name: connection-disconnect
+ doc: Disconnect from a peer.
+ attribute-set: drbd2
+ flags:
+ - admin-perm
+ do:
+ pre: drbd2-pre-doit
+ post: drbd2-post-doit
+ request:
+ attributes:
+ - context
+ - disconnect-parms
+ reply:
+ attributes:
+ - state-result
+ - message
+
+ -
+ name: connection-set
+ doc: Change network options.
+ attribute-set: drbd2
+ flags:
+ - admin-perm
+ do:
+ pre: drbd2-pre-doit
+ post: drbd2-post-doit
+ request:
+ attributes:
+ - context
+ - net-conf
+ - set-defaults
+ reply:
+ attributes:
+ - state-result
+ - message
+
+ -
+ name: connection-forget
+ doc: Forget a previously connected peer. The peer is identified by
+ context.peer-node-id.
+ attribute-set: drbd2
+ flags:
+ - admin-perm
+ do:
+ pre: drbd2-pre-doit
+ post: drbd2-post-doit
+ request:
+ attributes:
+ - context
+ reply:
+ attributes:
+ - state-result
+ - message
+
+ -
+ name: path-new
+ doc: Add a new network path to a connection.
+ attribute-set: drbd2
+ flags:
+ - admin-perm
+ do:
+ pre: drbd2-pre-doit
+ post: drbd2-post-doit
+ request:
+ attributes:
+ - context
+ reply:
+ attributes:
+ - state-result
+ - message
+
+ -
+ name: path-del
+ doc: Delete a network path from a connection.
+ attribute-set: drbd2
+ flags:
+ - admin-perm
+ do:
+ pre: drbd2-pre-doit
+ post: drbd2-post-doit
+ request:
+ attributes:
+ - context
+ reply:
+ attributes:
+ - state-result
+ - message
+
+ -
+ name: peer-device-set
+ doc: Change peer device options.
+ attribute-set: drbd2
+ flags:
+ - admin-perm
+ do:
+ pre: drbd2-pre-doit
+ post: drbd2-post-doit
+ request:
+ attributes:
+ - context
+ - peer-device-conf
+ - set-defaults
+ reply:
+ attributes:
+ - state-result
+ - message
+
+ -
+ name: peer-device-invalidate
+ doc: Invalidate the peer data of a DRBD peer device.
+ attribute-set: drbd2
+ flags:
+ - admin-perm
+ do:
+ pre: drbd2-pre-doit
+ post: drbd2-post-doit
+ request:
+ attributes:
+ - context
+ - invalidate-peer-parms
+ reply:
+ attributes:
+ - state-result
+ - message
+
+ -
+ name: peer-device-pause-sync
+ doc: Pause resynchronization.
+ attribute-set: drbd2
+ flags:
+ - admin-perm
+ do:
+ pre: drbd2-pre-doit
+ post: drbd2-post-doit
+ request:
+ attributes:
+ - context
+ reply:
+ attributes:
+ - state-result
+ - message
+
+ -
+ name: peer-device-resume-sync
+ doc: Resume resynchronization.
+ attribute-set: drbd2
+ flags:
+ - admin-perm
+ do:
+ pre: drbd2-pre-doit
+ post: drbd2-post-doit
+ request:
+ attributes:
+ - context
+ reply:
+ attributes:
+ - state-result
+ - message
+
+ -
+ name: peer-device-start-ov
+ doc: Start online verification.
+ attribute-set: drbd2
+ flags:
+ - admin-perm
+ do:
+ pre: drbd2-pre-doit
+ post: drbd2-post-doit
+ request:
+ attributes:
+ - context
+ - start-ov-parms
+ reply:
+ attributes:
+ - state-result
+ - message
+
+ -
+ name: timeout-type-get
+ doc: Get the timeout type for a peer device.
+ attribute-set: drbd2
+ do:
+ pre: drbd2-pre-doit
+ post: drbd2-post-doit
+ request:
+ attributes:
+ - context
+ reply:
+ attributes:
+ - timeout-type
+
+ -
+ name: resource-get
+ doc: Dump all DRBD resources. Optionally filtered by context.
+ attribute-set: drbd2
+ dump:
+ request:
+ attributes:
+ - context
+ reply:
+ attributes:
+ - resource
+
+ -
+ name: device-get
+ doc: Dump all DRBD devices. Optionally filtered by context.
+ attribute-set: drbd2
+ dump:
+ post: drbd2-nl-device-get-done
+ request:
+ attributes:
+ - context
+ reply:
+ attributes:
+ - device
+
+ -
+ name: connection-get
+ doc: Dump all DRBD connections. Optionally filtered by context.
+ attribute-set: drbd2
+ dump:
+ post: drbd2-nl-connection-get-done
+ request:
+ attributes:
+ - context
+ reply:
+ attributes:
+ - connection
+
+ -
+ name: peer-device-get
+ doc: Dump all DRBD peer devices. Optionally filtered by context.
+ attribute-set: drbd2
+ dump:
+ post: drbd2-nl-peer-device-get-done
+ request:
+ attributes:
+ - context
+ reply:
+ attributes:
+ - peer-device
+
+ -
+ name: path-get
+ doc: Dump all DRBD paths. Optionally filtered by context.
+ attribute-set: drbd2
+ dump:
+ post: drbd2-nl-path-get-done
+ request:
+ attributes:
+ - context
+ reply:
+ attributes:
+ - path
+
+ -
+ name: state-get
+ doc: Dump a consistent snapshot of all resources, devices, connections, peer
+ devices and paths as state-change messages with action exists.
+ attribute-set: state-change
+ dump:
+ post: drbd2-nl-state-get-done
+ reply:
+ attributes:
+ - action
+ - more
+ - resource
+ - device
+ - connection
+ - peer-device
+ - path
+
+ -
+ name: state-change-ntf
+ doc: Notification about a state change; same layout as state-get replies. Messages
+ of one state change have more set on all but the last.
+ notify: state-get
+ mcgrp: events
+
+ -
+ name: helper-ntf
+ doc: A user-space helper is about to be called (phase call) or has finished
+ (phase response).
+ attribute-set: drbd2
+ event:
+ attributes:
+ - context
+ - helper
+ mcgrp: events
+
+mcast-groups:
+ list:
+ -
+ name: events
diff --git a/drivers/block/drbd/Kconfig b/drivers/block/drbd/Kconfig
index 1b8b3f6efc1b..261965d7b054 100644
--- a/drivers/block/drbd/Kconfig
+++ b/drivers/block/drbd/Kconfig
@@ -108,4 +108,10 @@ config DRBD_COMPAT_84
this compile-time option, creating a resource without a node
ID is not possible.
+ This option also provides the "drbd" generic netlink
+ family at version 1, which drbd-utils have always used to
+ configure DRBD. Without it, DRBD can only be configured
+ through the drbd2 family, which older drbd-utils releases
+ do not know.
+
If unsure, say Y.
diff --git a/drivers/block/drbd/Makefile b/drivers/block/drbd/Makefile
index 0b7bc8f5d53a..74694d95fe39 100644
--- a/drivers/block/drbd/Makefile
+++ b/drivers/block/drbd/Makefile
@@ -6,6 +6,7 @@ drbd-y += drbd_interval.o drbd_state.o
drbd-$(CONFIG_DRBD_COMPAT_84) += drbd_nl_gen.o
drbd-y += drbd_nl_defaults.o
drbd-$(CONFIG_DRBD_COMPAT_84) += drbd_nl_84.o
+drbd-y += drbd_nl_drbd2.o drbd2_nl_gen.o
drbd-y += drbd_transport.o
drbd-$(CONFIG_DEV_DAX_PMEM) += drbd_dax_pmem.o
drbd-$(CONFIG_DEBUG_FS) += drbd_debugfs.o
diff --git a/drivers/block/drbd/drbd2_nl_gen.c b/drivers/block/drbd/drbd2_nl_gen.c
new file mode 100644
index 000000000000..332527091b86
--- /dev/null
+++ b/drivers/block/drbd/drbd2_nl_gen.c
@@ -0,0 +1,748 @@
+// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)
+/* Do not edit directly, auto-generated from: */
+/* Documentation/netlink/specs/drbd2.yaml */
+/* YNL-GEN kernel source */
+/* To regenerate run: tools/net/ynl/ynl-regen.sh */
+
+#include <net/netlink.h>
+#include <net/genetlink.h>
+
+#include "drbd2_nl_gen.h"
+
+#include <uapi/linux/drbd2.h>
+
+/* Common nested types */
+const struct nla_policy drbd2_address_nl_policy[DRBD2_A_ADDRESS_IPV6 + 1] = {
+ [DRBD2_A_ADDRESS_FAMILY] = { .type = NLA_U16, },
+ [DRBD2_A_ADDRESS_PORT] = { .type = NLA_BE16, },
+ [DRBD2_A_ADDRESS_IPV4] = { .type = NLA_BE32, },
+ [DRBD2_A_ADDRESS_IPV6] = NLA_POLICY_EXACT_LEN(16),
+};
+
+const struct nla_policy drbd2_connect_parms_nl_policy[DRBD2_A_CONNECT_PARMS_DISCARD_MY_DATA + 1] = {
+ [DRBD2_A_CONNECT_PARMS_TENTATIVE] = { .type = NLA_FLAG, },
+ [DRBD2_A_CONNECT_PARMS_DISCARD_MY_DATA] = { .type = NLA_FLAG, },
+};
+
+const struct nla_policy drbd2_context_nl_policy[DRBD2_A_CONTEXT_PEER_ADDRESS + 1] = {
+ [DRBD2_A_CONTEXT_RESOURCE_NAME] = { .type = NLA_NUL_STRING, .len = DRBD2_RESOURCE_NAME_MAX, },
+ [DRBD2_A_CONTEXT_VOLUME] = { .type = NLA_U32, },
+ [DRBD2_A_CONTEXT_MINOR] = { .type = NLA_U32, },
+ [DRBD2_A_CONTEXT_PEER_NODE_ID] = { .type = NLA_U32, },
+ [DRBD2_A_CONTEXT_CONNECTION_NAME] = { .type = NLA_NUL_STRING, .len = DRBD2_CONNECTION_NAME_MAX, },
+ [DRBD2_A_CONTEXT_MY_ADDRESS] = NLA_POLICY_NESTED(drbd2_address_nl_policy),
+ [DRBD2_A_CONTEXT_PEER_ADDRESS] = NLA_POLICY_NESTED(drbd2_address_nl_policy),
+};
+
+const struct nla_policy drbd2_detach_parms_nl_policy[DRBD2_A_DETACH_PARMS_INTENTIONAL_DISKLESS_DETACH + 1] = {
+ [DRBD2_A_DETACH_PARMS_FORCE] = { .type = NLA_FLAG, },
+ [DRBD2_A_DETACH_PARMS_INTENTIONAL_DISKLESS_DETACH] = { .type = NLA_FLAG, },
+};
+
+const struct nla_policy drbd2_device_conf_nl_policy[DRBD2_A_DEVICE_CONF_DISCARD_GRANULARITY + 1] = {
+ [DRBD2_A_DEVICE_CONF_MAX_BIO_SIZE] = { .type = NLA_U32, },
+ [DRBD2_A_DEVICE_CONF_INTENTIONAL_DISKLESS] = { .type = NLA_U8, },
+ [DRBD2_A_DEVICE_CONF_BLOCK_SIZE] = { .type = NLA_U32, },
+ [DRBD2_A_DEVICE_CONF_DISCARD_GRANULARITY] = { .type = NLA_U32, },
+};
+
+const struct nla_policy drbd2_disconnect_parms_nl_policy[DRBD2_A_DISCONNECT_PARMS_FORCE + 1] = {
+ [DRBD2_A_DISCONNECT_PARMS_FORCE] = { .type = NLA_FLAG, },
+};
+
+const struct nla_policy drbd2_disk_conf_nl_policy[DRBD2_A_DISK_CONF_BITMAP + 1] = {
+ [DRBD2_A_DISK_CONF_BACKING_DEV] = { .type = NLA_NUL_STRING, .len = DRBD2_DEVICE_PATH_MAX, },
+ [DRBD2_A_DISK_CONF_META_DEV] = { .type = NLA_NUL_STRING, .len = DRBD2_DEVICE_PATH_MAX, },
+ [DRBD2_A_DISK_CONF_META_DEV_IDX] = { .type = NLA_S32, },
+ [DRBD2_A_DISK_CONF_SIZE] = { .type = NLA_U64, },
+ [DRBD2_A_DISK_CONF_ON_IO_ERROR] = NLA_POLICY_MAX(NLA_U32, 2),
+ [DRBD2_A_DISK_CONF_RESYNC_AFTER] = { .type = NLA_S32, },
+ [DRBD2_A_DISK_CONF_AL_EXTENTS] = { .type = NLA_U32, },
+ [DRBD2_A_DISK_CONF_DISK_BARRIER] = { .type = NLA_U8, },
+ [DRBD2_A_DISK_CONF_DISK_FLUSHES] = { .type = NLA_U8, },
+ [DRBD2_A_DISK_CONF_DISK_DRAIN] = { .type = NLA_U8, },
+ [DRBD2_A_DISK_CONF_MD_FLUSHES] = { .type = NLA_U8, },
+ [DRBD2_A_DISK_CONF_DISK_TIMEOUT] = { .type = NLA_U32, },
+ [DRBD2_A_DISK_CONF_READ_BALANCING] = NLA_POLICY_MAX(NLA_U32, 10),
+ [DRBD2_A_DISK_CONF_UNPLUG_WATERMARK] = { .type = NLA_U32, },
+ [DRBD2_A_DISK_CONF_RS_DISCARD_GRANULARITY] = { .type = NLA_U32, },
+ [DRBD2_A_DISK_CONF_AL_UPDATES] = { .type = NLA_U8, },
+ [DRBD2_A_DISK_CONF_DISCARD_ZEROES_IF_ALIGNED] = { .type = NLA_U8, },
+ [DRBD2_A_DISK_CONF_DISABLE_WRITE_SAME] = { .type = NLA_U8, },
+ [DRBD2_A_DISK_CONF_BITMAP] = { .type = NLA_U8, },
+};
+
+const struct nla_policy drbd2_invalidate_parms_nl_policy[DRBD2_A_INVALIDATE_PARMS_RESET_BITMAP + 1] = {
+ [DRBD2_A_INVALIDATE_PARMS_SYNC_FROM_PEER_NODE_ID] = { .type = NLA_U32, },
+ [DRBD2_A_INVALIDATE_PARMS_RESET_BITMAP] = { .type = NLA_U8, },
+};
+
+const struct nla_policy drbd2_invalidate_peer_parms_nl_policy[DRBD2_A_INVALIDATE_PEER_PARMS_RESET_BITMAP + 1] = {
+ [DRBD2_A_INVALIDATE_PEER_PARMS_RESET_BITMAP] = { .type = NLA_U8, },
+};
+
+const struct nla_policy drbd2_net_conf_nl_policy[DRBD2_A_NET_CONF_RDMA_CTRL_SNDBUF_SIZE + 1] = {
+ [DRBD2_A_NET_CONF_SHARED_SECRET] = { .type = NLA_NUL_STRING, .len = DRBD2_SHARED_SECRET_MAX, },
+ [DRBD2_A_NET_CONF_CRAM_HMAC_ALG] = { .type = NLA_NUL_STRING, .len = DRBD2_ALG_NAME_MAX, },
+ [DRBD2_A_NET_CONF_INTEGRITY_ALG] = { .type = NLA_NUL_STRING, .len = DRBD2_ALG_NAME_MAX, },
+ [DRBD2_A_NET_CONF_VERIFY_ALG] = { .type = NLA_NUL_STRING, .len = DRBD2_ALG_NAME_MAX, },
+ [DRBD2_A_NET_CONF_CSUMS_ALG] = { .type = NLA_NUL_STRING, .len = DRBD2_ALG_NAME_MAX, },
+ [DRBD2_A_NET_CONF_PROTOCOL] = NLA_POLICY_RANGE(NLA_U32, 1, 3),
+ [DRBD2_A_NET_CONF_CONNECT_INT] = { .type = NLA_U32, },
+ [DRBD2_A_NET_CONF_TIMEOUT] = { .type = NLA_U32, },
+ [DRBD2_A_NET_CONF_PING_INT] = { .type = NLA_U32, },
+ [DRBD2_A_NET_CONF_PING_TIMEO] = { .type = NLA_U32, },
+ [DRBD2_A_NET_CONF_SNDBUF_SIZE] = { .type = NLA_U32, },
+ [DRBD2_A_NET_CONF_RCVBUF_SIZE] = { .type = NLA_U32, },
+ [DRBD2_A_NET_CONF_KO_COUNT] = { .type = NLA_U32, },
+ [DRBD2_A_NET_CONF_MAX_EPOCH_SIZE] = { .type = NLA_U32, },
+ [DRBD2_A_NET_CONF_AFTER_SB_0PRI] = NLA_POLICY_MAX(NLA_U32, 12),
+ [DRBD2_A_NET_CONF_AFTER_SB_1PRI] = NLA_POLICY_MAX(NLA_U32, 12),
+ [DRBD2_A_NET_CONF_AFTER_SB_2PRI] = NLA_POLICY_MAX(NLA_U32, 12),
+ [DRBD2_A_NET_CONF_RR_CONFLICT] = NLA_POLICY_MAX(NLA_U32, 12),
+ [DRBD2_A_NET_CONF_ON_CONGESTION] = NLA_POLICY_MAX(NLA_U32, 2),
+ [DRBD2_A_NET_CONF_CONG_FILL] = { .type = NLA_U32, },
+ [DRBD2_A_NET_CONF_CONG_EXTENTS] = { .type = NLA_U32, },
+ [DRBD2_A_NET_CONF_TWO_PRIMARIES] = { .type = NLA_U8, },
+ [DRBD2_A_NET_CONF_TCP_CORK] = { .type = NLA_U8, },
+ [DRBD2_A_NET_CONF_ALWAYS_ASBP] = { .type = NLA_U8, },
+ [DRBD2_A_NET_CONF_USE_RLE] = { .type = NLA_U8, },
+ [DRBD2_A_NET_CONF_FENCING] = NLA_POLICY_MAX(NLA_U32, 2),
+ [DRBD2_A_NET_CONF_CONNECTION_NAME] = { .type = NLA_NUL_STRING, .len = DRBD2_CONNECTION_NAME_MAX, },
+ [DRBD2_A_NET_CONF_CSUMS_AFTER_CRASH_ONLY] = { .type = NLA_U8, },
+ [DRBD2_A_NET_CONF_SOCK_CHECK_TIMEO] = { .type = NLA_U32, },
+ [DRBD2_A_NET_CONF_TRANSPORT_NAME] = { .type = NLA_NUL_STRING, .len = DRBD2_TRANSPORT_NAME_MAX, },
+ [DRBD2_A_NET_CONF_MAX_BUFFERS] = { .type = NLA_U32, },
+ [DRBD2_A_NET_CONF_ALLOW_REMOTE_READ] = { .type = NLA_U8, },
+ [DRBD2_A_NET_CONF_TLS] = { .type = NLA_U8, },
+ [DRBD2_A_NET_CONF_TLS_PRIVKEY] = { .type = NLA_S32, },
+ [DRBD2_A_NET_CONF_TLS_CERTIFICATE] = { .type = NLA_S32, },
+ [DRBD2_A_NET_CONF_TLS_KEYRING] = { .type = NLA_S32, },
+ [DRBD2_A_NET_CONF_LOAD_BALANCE_PATHS] = { .type = NLA_U8, },
+ [DRBD2_A_NET_CONF_RDMA_CTRL_RCVBUF_SIZE] = { .type = NLA_U32, },
+ [DRBD2_A_NET_CONF_RDMA_CTRL_SNDBUF_SIZE] = { .type = NLA_U32, },
+};
+
+const struct nla_policy drbd2_new_current_uuid_parms_nl_policy[DRBD2_A_NEW_CURRENT_UUID_PARMS_FORCE_RESYNC + 1] = {
+ [DRBD2_A_NEW_CURRENT_UUID_PARMS_CLEAR_BM] = { .type = NLA_FLAG, },
+ [DRBD2_A_NEW_CURRENT_UUID_PARMS_FORCE_RESYNC] = { .type = NLA_FLAG, },
+};
+
+const struct nla_policy drbd2_peer_device_conf_nl_policy[DRBD2_A_PEER_DEVICE_CONF_PEER_TIEBREAKER + 1] = {
+ [DRBD2_A_PEER_DEVICE_CONF_RESYNC_RATE] = { .type = NLA_U32, },
+ [DRBD2_A_PEER_DEVICE_CONF_C_PLAN_AHEAD] = { .type = NLA_U32, },
+ [DRBD2_A_PEER_DEVICE_CONF_C_DELAY_TARGET] = { .type = NLA_U32, },
+ [DRBD2_A_PEER_DEVICE_CONF_C_FILL_TARGET] = { .type = NLA_U32, },
+ [DRBD2_A_PEER_DEVICE_CONF_C_MAX_RATE] = { .type = NLA_U32, },
+ [DRBD2_A_PEER_DEVICE_CONF_C_MIN_RATE] = { .type = NLA_U32, },
+ [DRBD2_A_PEER_DEVICE_CONF_BITMAP] = { .type = NLA_U8, },
+ [DRBD2_A_PEER_DEVICE_CONF_RESYNC_WITHOUT_REPLICATION] = { .type = NLA_U8, },
+ [DRBD2_A_PEER_DEVICE_CONF_PEER_TIEBREAKER] = { .type = NLA_U8, },
+};
+
+const struct nla_policy drbd2_rename_parms_nl_policy[DRBD2_A_RENAME_PARMS_NEW_NAME + 1] = {
+ [DRBD2_A_RENAME_PARMS_NEW_NAME] = { .type = NLA_NUL_STRING, .len = DRBD2_RESOURCE_NAME_MAX, },
+};
+
+const struct nla_policy drbd2_resize_parms_nl_policy[DRBD2_A_RESIZE_PARMS_AL_STRIPE_SIZE + 1] = {
+ [DRBD2_A_RESIZE_PARMS_SIZE] = { .type = NLA_U64, },
+ [DRBD2_A_RESIZE_PARMS_ASSUME_PEER_HAS_SPACE] = { .type = NLA_FLAG, },
+ [DRBD2_A_RESIZE_PARMS_ASSUME_CLEAN] = { .type = NLA_FLAG, },
+ [DRBD2_A_RESIZE_PARMS_AL_STRIPES] = { .type = NLA_U32, },
+ [DRBD2_A_RESIZE_PARMS_AL_STRIPE_SIZE] = { .type = NLA_U32, },
+};
+
+const struct nla_policy drbd2_resource_opts_nl_policy[DRBD2_A_RESOURCE_OPTS_EXPLICIT_DRBD8_COMPAT + 1] = {
+ [DRBD2_A_RESOURCE_OPTS_CPU_MASK] = { .type = NLA_NUL_STRING, .len = DRBD2_CPU_MASK_SIZE, },
+ [DRBD2_A_RESOURCE_OPTS_ON_NO_DATA_ACCESSIBLE] = NLA_POLICY_MAX(NLA_U32, 1),
+ [DRBD2_A_RESOURCE_OPTS_AUTO_PROMOTE] = { .type = NLA_U8, },
+ [DRBD2_A_RESOURCE_OPTS_NODE_ID] = { .type = NLA_U32, },
+ [DRBD2_A_RESOURCE_OPTS_PEER_ACK_WINDOW] = { .type = NLA_U32, },
+ [DRBD2_A_RESOURCE_OPTS_TWOPC_TIMEOUT] = { .type = NLA_U32, },
+ [DRBD2_A_RESOURCE_OPTS_TWOPC_RETRY_TIMEOUT] = { .type = NLA_U32, },
+ [DRBD2_A_RESOURCE_OPTS_PEER_ACK_DELAY] = { .type = NLA_U32, },
+ [DRBD2_A_RESOURCE_OPTS_AUTO_PROMOTE_TIMEOUT] = { .type = NLA_U32, },
+ [DRBD2_A_RESOURCE_OPTS_MAX_IO_DEPTH] = { .type = NLA_U32, },
+ [DRBD2_A_RESOURCE_OPTS_QUORUM] = { .type = NLA_S32, },
+ [DRBD2_A_RESOURCE_OPTS_ON_NO_QUORUM] = NLA_POLICY_MAX(NLA_U32, 1),
+ [DRBD2_A_RESOURCE_OPTS_QUORUM_MIN_REDUNDANCY] = { .type = NLA_S32, },
+ [DRBD2_A_RESOURCE_OPTS_ON_SUSPENDED_PRIMARY_OUTDATED] = NLA_POLICY_MAX(NLA_U32, 1),
+ [DRBD2_A_RESOURCE_OPTS_DRBD8_COMPAT_MODE] = { .type = NLA_U8, },
+ [DRBD2_A_RESOURCE_OPTS_EXPLICIT_DRBD8_COMPAT] = { .type = NLA_U8, },
+};
+
+const struct nla_policy drbd2_set_role_parms_nl_policy[DRBD2_A_SET_ROLE_PARMS_FORCE + 1] = {
+ [DRBD2_A_SET_ROLE_PARMS_FORCE] = { .type = NLA_FLAG, },
+};
+
+const struct nla_policy drbd2_start_ov_parms_nl_policy[DRBD2_A_START_OV_PARMS_STOP_SECTOR + 1] = {
+ [DRBD2_A_START_OV_PARMS_START_SECTOR] = { .type = NLA_U64, },
+ [DRBD2_A_START_OV_PARMS_STOP_SECTOR] = { .type = NLA_U64, },
+};
+
+const struct nla_policy drbd2_suspend_io_parms_nl_policy[DRBD2_A_SUSPEND_IO_PARMS_BDEV_FREEZE + 1] = {
+ [DRBD2_A_SUSPEND_IO_PARMS_BDEV_FREEZE] = { .type = NLA_U8, },
+};
+
+/* DRBD2_CMD_RESOURCE_NEW - do */
+static const struct nla_policy drbd2_resource_new_nl_policy[DRBD2_A_RESOURCE_OPTS + 1] = {
+ [DRBD2_A_CONTEXT] = NLA_POLICY_NESTED(drbd2_context_nl_policy),
+ [DRBD2_A_RESOURCE_OPTS] = NLA_POLICY_NESTED(drbd2_resource_opts_nl_policy),
+};
+
+/* DRBD2_CMD_RESOURCE_DEL - do */
+static const struct nla_policy drbd2_resource_del_nl_policy[DRBD2_A_CONTEXT + 1] = {
+ [DRBD2_A_CONTEXT] = NLA_POLICY_NESTED(drbd2_context_nl_policy),
+};
+
+/* DRBD2_CMD_RESOURCE_SET - do */
+static const struct nla_policy drbd2_resource_set_nl_policy[DRBD2_A_RESOURCE_OPTS + 1] = {
+ [DRBD2_A_CONTEXT] = NLA_POLICY_NESTED(drbd2_context_nl_policy),
+ [DRBD2_A_RESOURCE_OPTS] = NLA_POLICY_NESTED(drbd2_resource_opts_nl_policy),
+ [DRBD2_A_SET_DEFAULTS] = { .type = NLA_FLAG, },
+};
+
+/* DRBD2_CMD_RESOURCE_RENAME - do */
+static const struct nla_policy drbd2_resource_rename_nl_policy[DRBD2_A_RENAME_PARMS + 1] = {
+ [DRBD2_A_CONTEXT] = NLA_POLICY_NESTED(drbd2_context_nl_policy),
+ [DRBD2_A_RENAME_PARMS] = NLA_POLICY_NESTED(drbd2_rename_parms_nl_policy),
+};
+
+/* DRBD2_CMD_RESOURCE_DOWN - do */
+static const struct nla_policy drbd2_resource_down_nl_policy[DRBD2_A_CONTEXT + 1] = {
+ [DRBD2_A_CONTEXT] = NLA_POLICY_NESTED(drbd2_context_nl_policy),
+};
+
+/* DRBD2_CMD_RESOURCE_PRIMARY - do */
+static const struct nla_policy drbd2_resource_primary_nl_policy[DRBD2_A_SET_ROLE_PARMS + 1] = {
+ [DRBD2_A_CONTEXT] = NLA_POLICY_NESTED(drbd2_context_nl_policy),
+ [DRBD2_A_SET_ROLE_PARMS] = NLA_POLICY_NESTED(drbd2_set_role_parms_nl_policy),
+};
+
+/* DRBD2_CMD_RESOURCE_SECONDARY - do */
+static const struct nla_policy drbd2_resource_secondary_nl_policy[DRBD2_A_SET_ROLE_PARMS + 1] = {
+ [DRBD2_A_CONTEXT] = NLA_POLICY_NESTED(drbd2_context_nl_policy),
+ [DRBD2_A_SET_ROLE_PARMS] = NLA_POLICY_NESTED(drbd2_set_role_parms_nl_policy),
+};
+
+/* DRBD2_CMD_RESOURCE_SUSPEND_IO - do */
+static const struct nla_policy drbd2_resource_suspend_io_nl_policy[DRBD2_A_SUSPEND_IO_PARMS + 1] = {
+ [DRBD2_A_CONTEXT] = NLA_POLICY_NESTED(drbd2_context_nl_policy),
+ [DRBD2_A_SUSPEND_IO_PARMS] = NLA_POLICY_NESTED(drbd2_suspend_io_parms_nl_policy),
+};
+
+/* DRBD2_CMD_RESOURCE_RESUME_IO - do */
+static const struct nla_policy drbd2_resource_resume_io_nl_policy[DRBD2_A_CONTEXT + 1] = {
+ [DRBD2_A_CONTEXT] = NLA_POLICY_NESTED(drbd2_context_nl_policy),
+};
+
+/* DRBD2_CMD_DEVICE_NEW - do */
+static const struct nla_policy drbd2_device_new_nl_policy[DRBD2_A_DEVICE_CONF + 1] = {
+ [DRBD2_A_CONTEXT] = NLA_POLICY_NESTED(drbd2_context_nl_policy),
+ [DRBD2_A_DEVICE_CONF] = NLA_POLICY_NESTED(drbd2_device_conf_nl_policy),
+};
+
+/* DRBD2_CMD_DEVICE_DEL - do */
+static const struct nla_policy drbd2_device_del_nl_policy[DRBD2_A_CONTEXT + 1] = {
+ [DRBD2_A_CONTEXT] = NLA_POLICY_NESTED(drbd2_context_nl_policy),
+};
+
+/* DRBD2_CMD_DEVICE_ATTACH - do */
+static const struct nla_policy drbd2_device_attach_nl_policy[DRBD2_A_DISK_CONF + 1] = {
+ [DRBD2_A_CONTEXT] = NLA_POLICY_NESTED(drbd2_context_nl_policy),
+ [DRBD2_A_DISK_CONF] = NLA_POLICY_NESTED(drbd2_disk_conf_nl_policy),
+};
+
+/* DRBD2_CMD_DEVICE_DETACH - do */
+static const struct nla_policy drbd2_device_detach_nl_policy[DRBD2_A_DETACH_PARMS + 1] = {
+ [DRBD2_A_CONTEXT] = NLA_POLICY_NESTED(drbd2_context_nl_policy),
+ [DRBD2_A_DETACH_PARMS] = NLA_POLICY_NESTED(drbd2_detach_parms_nl_policy),
+};
+
+/* DRBD2_CMD_DISK_SET - do */
+static const struct nla_policy drbd2_disk_set_nl_policy[DRBD2_A_DISK_CONF + 1] = {
+ [DRBD2_A_CONTEXT] = NLA_POLICY_NESTED(drbd2_context_nl_policy),
+ [DRBD2_A_DISK_CONF] = NLA_POLICY_NESTED(drbd2_disk_conf_nl_policy),
+ [DRBD2_A_SET_DEFAULTS] = { .type = NLA_FLAG, },
+};
+
+/* DRBD2_CMD_DEVICE_RESIZE - do */
+static const struct nla_policy drbd2_device_resize_nl_policy[DRBD2_A_RESIZE_PARMS + 1] = {
+ [DRBD2_A_CONTEXT] = NLA_POLICY_NESTED(drbd2_context_nl_policy),
+ [DRBD2_A_RESIZE_PARMS] = NLA_POLICY_NESTED(drbd2_resize_parms_nl_policy),
+};
+
+/* DRBD2_CMD_DEVICE_OUTDATE - do */
+static const struct nla_policy drbd2_device_outdate_nl_policy[DRBD2_A_CONTEXT + 1] = {
+ [DRBD2_A_CONTEXT] = NLA_POLICY_NESTED(drbd2_context_nl_policy),
+};
+
+/* DRBD2_CMD_DEVICE_INVALIDATE - do */
+static const struct nla_policy drbd2_device_invalidate_nl_policy[DRBD2_A_INVALIDATE_PARMS + 1] = {
+ [DRBD2_A_CONTEXT] = NLA_POLICY_NESTED(drbd2_context_nl_policy),
+ [DRBD2_A_INVALIDATE_PARMS] = NLA_POLICY_NESTED(drbd2_invalidate_parms_nl_policy),
+};
+
+/* DRBD2_CMD_DEVICE_NEW_CURRENT_UUID - do */
+static const struct nla_policy drbd2_device_new_current_uuid_nl_policy[DRBD2_A_NEW_CURRENT_UUID_PARMS + 1] = {
+ [DRBD2_A_CONTEXT] = NLA_POLICY_NESTED(drbd2_context_nl_policy),
+ [DRBD2_A_NEW_CURRENT_UUID_PARMS] = NLA_POLICY_NESTED(drbd2_new_current_uuid_parms_nl_policy),
+};
+
+/* DRBD2_CMD_CONNECTION_NEW - do */
+static const struct nla_policy drbd2_connection_new_nl_policy[DRBD2_A_NET_CONF + 1] = {
+ [DRBD2_A_CONTEXT] = NLA_POLICY_NESTED(drbd2_context_nl_policy),
+ [DRBD2_A_NET_CONF] = NLA_POLICY_NESTED(drbd2_net_conf_nl_policy),
+};
+
+/* DRBD2_CMD_CONNECTION_DEL - do */
+static const struct nla_policy drbd2_connection_del_nl_policy[DRBD2_A_DISCONNECT_PARMS + 1] = {
+ [DRBD2_A_CONTEXT] = NLA_POLICY_NESTED(drbd2_context_nl_policy),
+ [DRBD2_A_DISCONNECT_PARMS] = NLA_POLICY_NESTED(drbd2_disconnect_parms_nl_policy),
+};
+
+/* DRBD2_CMD_CONNECTION_CONNECT - do */
+static const struct nla_policy drbd2_connection_connect_nl_policy[DRBD2_A_CONNECT_PARMS + 1] = {
+ [DRBD2_A_CONTEXT] = NLA_POLICY_NESTED(drbd2_context_nl_policy),
+ [DRBD2_A_CONNECT_PARMS] = NLA_POLICY_NESTED(drbd2_connect_parms_nl_policy),
+};
+
+/* DRBD2_CMD_CONNECTION_DISCONNECT - do */
+static const struct nla_policy drbd2_connection_disconnect_nl_policy[DRBD2_A_DISCONNECT_PARMS + 1] = {
+ [DRBD2_A_CONTEXT] = NLA_POLICY_NESTED(drbd2_context_nl_policy),
+ [DRBD2_A_DISCONNECT_PARMS] = NLA_POLICY_NESTED(drbd2_disconnect_parms_nl_policy),
+};
+
+/* DRBD2_CMD_CONNECTION_SET - do */
+static const struct nla_policy drbd2_connection_set_nl_policy[DRBD2_A_NET_CONF + 1] = {
+ [DRBD2_A_CONTEXT] = NLA_POLICY_NESTED(drbd2_context_nl_policy),
+ [DRBD2_A_NET_CONF] = NLA_POLICY_NESTED(drbd2_net_conf_nl_policy),
+ [DRBD2_A_SET_DEFAULTS] = { .type = NLA_FLAG, },
+};
+
+/* DRBD2_CMD_CONNECTION_FORGET - do */
+static const struct nla_policy drbd2_connection_forget_nl_policy[DRBD2_A_CONTEXT + 1] = {
+ [DRBD2_A_CONTEXT] = NLA_POLICY_NESTED(drbd2_context_nl_policy),
+};
+
+/* DRBD2_CMD_PATH_NEW - do */
+static const struct nla_policy drbd2_path_new_nl_policy[DRBD2_A_CONTEXT + 1] = {
+ [DRBD2_A_CONTEXT] = NLA_POLICY_NESTED(drbd2_context_nl_policy),
+};
+
+/* DRBD2_CMD_PATH_DEL - do */
+static const struct nla_policy drbd2_path_del_nl_policy[DRBD2_A_CONTEXT + 1] = {
+ [DRBD2_A_CONTEXT] = NLA_POLICY_NESTED(drbd2_context_nl_policy),
+};
+
+/* DRBD2_CMD_PEER_DEVICE_SET - do */
+static const struct nla_policy drbd2_peer_device_set_nl_policy[DRBD2_A_PEER_DEVICE_CONF + 1] = {
+ [DRBD2_A_CONTEXT] = NLA_POLICY_NESTED(drbd2_context_nl_policy),
+ [DRBD2_A_PEER_DEVICE_CONF] = NLA_POLICY_NESTED(drbd2_peer_device_conf_nl_policy),
+ [DRBD2_A_SET_DEFAULTS] = { .type = NLA_FLAG, },
+};
+
+/* DRBD2_CMD_PEER_DEVICE_INVALIDATE - do */
+static const struct nla_policy drbd2_peer_device_invalidate_nl_policy[DRBD2_A_INVALIDATE_PEER_PARMS + 1] = {
+ [DRBD2_A_CONTEXT] = NLA_POLICY_NESTED(drbd2_context_nl_policy),
+ [DRBD2_A_INVALIDATE_PEER_PARMS] = NLA_POLICY_NESTED(drbd2_invalidate_peer_parms_nl_policy),
+};
+
+/* DRBD2_CMD_PEER_DEVICE_PAUSE_SYNC - do */
+static const struct nla_policy drbd2_peer_device_pause_sync_nl_policy[DRBD2_A_CONTEXT + 1] = {
+ [DRBD2_A_CONTEXT] = NLA_POLICY_NESTED(drbd2_context_nl_policy),
+};
+
+/* DRBD2_CMD_PEER_DEVICE_RESUME_SYNC - do */
+static const struct nla_policy drbd2_peer_device_resume_sync_nl_policy[DRBD2_A_CONTEXT + 1] = {
+ [DRBD2_A_CONTEXT] = NLA_POLICY_NESTED(drbd2_context_nl_policy),
+};
+
+/* DRBD2_CMD_PEER_DEVICE_START_OV - do */
+static const struct nla_policy drbd2_peer_device_start_ov_nl_policy[DRBD2_A_START_OV_PARMS + 1] = {
+ [DRBD2_A_CONTEXT] = NLA_POLICY_NESTED(drbd2_context_nl_policy),
+ [DRBD2_A_START_OV_PARMS] = NLA_POLICY_NESTED(drbd2_start_ov_parms_nl_policy),
+};
+
+/* DRBD2_CMD_TIMEOUT_TYPE_GET - do */
+static const struct nla_policy drbd2_timeout_type_get_nl_policy[DRBD2_A_CONTEXT + 1] = {
+ [DRBD2_A_CONTEXT] = NLA_POLICY_NESTED(drbd2_context_nl_policy),
+};
+
+/* DRBD2_CMD_RESOURCE_GET - dump */
+static const struct nla_policy drbd2_resource_get_nl_policy[DRBD2_A_CONTEXT + 1] = {
+ [DRBD2_A_CONTEXT] = NLA_POLICY_NESTED(drbd2_context_nl_policy),
+};
+
+/* DRBD2_CMD_DEVICE_GET - dump */
+static const struct nla_policy drbd2_device_get_nl_policy[DRBD2_A_CONTEXT + 1] = {
+ [DRBD2_A_CONTEXT] = NLA_POLICY_NESTED(drbd2_context_nl_policy),
+};
+
+/* DRBD2_CMD_CONNECTION_GET - dump */
+static const struct nla_policy drbd2_connection_get_nl_policy[DRBD2_A_CONTEXT + 1] = {
+ [DRBD2_A_CONTEXT] = NLA_POLICY_NESTED(drbd2_context_nl_policy),
+};
+
+/* DRBD2_CMD_PEER_DEVICE_GET - dump */
+static const struct nla_policy drbd2_peer_device_get_nl_policy[DRBD2_A_CONTEXT + 1] = {
+ [DRBD2_A_CONTEXT] = NLA_POLICY_NESTED(drbd2_context_nl_policy),
+};
+
+/* DRBD2_CMD_PATH_GET - dump */
+static const struct nla_policy drbd2_path_get_nl_policy[DRBD2_A_CONTEXT + 1] = {
+ [DRBD2_A_CONTEXT] = NLA_POLICY_NESTED(drbd2_context_nl_policy),
+};
+
+/* Ops table for drbd2 */
+static const struct genl_split_ops drbd2_nl_ops[] = {
+ {
+ .cmd = DRBD2_CMD_RESOURCE_NEW,
+ .pre_doit = drbd2_pre_doit,
+ .doit = drbd2_nl_resource_new_doit,
+ .post_doit = drbd2_post_doit,
+ .policy = drbd2_resource_new_nl_policy,
+ .maxattr = DRBD2_A_RESOURCE_OPTS,
+ .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
+ },
+ {
+ .cmd = DRBD2_CMD_RESOURCE_DEL,
+ .pre_doit = drbd2_pre_doit,
+ .doit = drbd2_nl_resource_del_doit,
+ .post_doit = drbd2_post_doit,
+ .policy = drbd2_resource_del_nl_policy,
+ .maxattr = DRBD2_A_CONTEXT,
+ .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
+ },
+ {
+ .cmd = DRBD2_CMD_RESOURCE_SET,
+ .pre_doit = drbd2_pre_doit,
+ .doit = drbd2_nl_resource_set_doit,
+ .post_doit = drbd2_post_doit,
+ .policy = drbd2_resource_set_nl_policy,
+ .maxattr = DRBD2_A_RESOURCE_OPTS,
+ .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
+ },
+ {
+ .cmd = DRBD2_CMD_RESOURCE_RENAME,
+ .pre_doit = drbd2_pre_doit,
+ .doit = drbd2_nl_resource_rename_doit,
+ .post_doit = drbd2_post_doit,
+ .policy = drbd2_resource_rename_nl_policy,
+ .maxattr = DRBD2_A_RENAME_PARMS,
+ .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
+ },
+ {
+ .cmd = DRBD2_CMD_RESOURCE_DOWN,
+ .pre_doit = drbd2_pre_doit,
+ .doit = drbd2_nl_resource_down_doit,
+ .post_doit = drbd2_post_doit,
+ .policy = drbd2_resource_down_nl_policy,
+ .maxattr = DRBD2_A_CONTEXT,
+ .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
+ },
+ {
+ .cmd = DRBD2_CMD_RESOURCE_PRIMARY,
+ .pre_doit = drbd2_pre_doit,
+ .doit = drbd2_nl_resource_primary_doit,
+ .post_doit = drbd2_post_doit,
+ .policy = drbd2_resource_primary_nl_policy,
+ .maxattr = DRBD2_A_SET_ROLE_PARMS,
+ .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
+ },
+ {
+ .cmd = DRBD2_CMD_RESOURCE_SECONDARY,
+ .pre_doit = drbd2_pre_doit,
+ .doit = drbd2_nl_resource_secondary_doit,
+ .post_doit = drbd2_post_doit,
+ .policy = drbd2_resource_secondary_nl_policy,
+ .maxattr = DRBD2_A_SET_ROLE_PARMS,
+ .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
+ },
+ {
+ .cmd = DRBD2_CMD_RESOURCE_SUSPEND_IO,
+ .pre_doit = drbd2_pre_doit,
+ .doit = drbd2_nl_resource_suspend_io_doit,
+ .post_doit = drbd2_post_doit,
+ .policy = drbd2_resource_suspend_io_nl_policy,
+ .maxattr = DRBD2_A_SUSPEND_IO_PARMS,
+ .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
+ },
+ {
+ .cmd = DRBD2_CMD_RESOURCE_RESUME_IO,
+ .pre_doit = drbd2_pre_doit,
+ .doit = drbd2_nl_resource_resume_io_doit,
+ .post_doit = drbd2_post_doit,
+ .policy = drbd2_resource_resume_io_nl_policy,
+ .maxattr = DRBD2_A_CONTEXT,
+ .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
+ },
+ {
+ .cmd = DRBD2_CMD_DEVICE_NEW,
+ .pre_doit = drbd2_pre_doit,
+ .doit = drbd2_nl_device_new_doit,
+ .post_doit = drbd2_post_doit,
+ .policy = drbd2_device_new_nl_policy,
+ .maxattr = DRBD2_A_DEVICE_CONF,
+ .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
+ },
+ {
+ .cmd = DRBD2_CMD_DEVICE_DEL,
+ .pre_doit = drbd2_pre_doit,
+ .doit = drbd2_nl_device_del_doit,
+ .post_doit = drbd2_post_doit,
+ .policy = drbd2_device_del_nl_policy,
+ .maxattr = DRBD2_A_CONTEXT,
+ .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
+ },
+ {
+ .cmd = DRBD2_CMD_DEVICE_ATTACH,
+ .pre_doit = drbd2_pre_doit,
+ .doit = drbd2_nl_device_attach_doit,
+ .post_doit = drbd2_post_doit,
+ .policy = drbd2_device_attach_nl_policy,
+ .maxattr = DRBD2_A_DISK_CONF,
+ .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
+ },
+ {
+ .cmd = DRBD2_CMD_DEVICE_DETACH,
+ .pre_doit = drbd2_pre_doit,
+ .doit = drbd2_nl_device_detach_doit,
+ .post_doit = drbd2_post_doit,
+ .policy = drbd2_device_detach_nl_policy,
+ .maxattr = DRBD2_A_DETACH_PARMS,
+ .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
+ },
+ {
+ .cmd = DRBD2_CMD_DISK_SET,
+ .pre_doit = drbd2_pre_doit,
+ .doit = drbd2_nl_disk_set_doit,
+ .post_doit = drbd2_post_doit,
+ .policy = drbd2_disk_set_nl_policy,
+ .maxattr = DRBD2_A_DISK_CONF,
+ .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
+ },
+ {
+ .cmd = DRBD2_CMD_DEVICE_RESIZE,
+ .pre_doit = drbd2_pre_doit,
+ .doit = drbd2_nl_device_resize_doit,
+ .post_doit = drbd2_post_doit,
+ .policy = drbd2_device_resize_nl_policy,
+ .maxattr = DRBD2_A_RESIZE_PARMS,
+ .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
+ },
+ {
+ .cmd = DRBD2_CMD_DEVICE_OUTDATE,
+ .pre_doit = drbd2_pre_doit,
+ .doit = drbd2_nl_device_outdate_doit,
+ .post_doit = drbd2_post_doit,
+ .policy = drbd2_device_outdate_nl_policy,
+ .maxattr = DRBD2_A_CONTEXT,
+ .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
+ },
+ {
+ .cmd = DRBD2_CMD_DEVICE_INVALIDATE,
+ .pre_doit = drbd2_pre_doit,
+ .doit = drbd2_nl_device_invalidate_doit,
+ .post_doit = drbd2_post_doit,
+ .policy = drbd2_device_invalidate_nl_policy,
+ .maxattr = DRBD2_A_INVALIDATE_PARMS,
+ .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
+ },
+ {
+ .cmd = DRBD2_CMD_DEVICE_NEW_CURRENT_UUID,
+ .pre_doit = drbd2_pre_doit,
+ .doit = drbd2_nl_device_new_current_uuid_doit,
+ .post_doit = drbd2_post_doit,
+ .policy = drbd2_device_new_current_uuid_nl_policy,
+ .maxattr = DRBD2_A_NEW_CURRENT_UUID_PARMS,
+ .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
+ },
+ {
+ .cmd = DRBD2_CMD_CONNECTION_NEW,
+ .pre_doit = drbd2_pre_doit,
+ .doit = drbd2_nl_connection_new_doit,
+ .post_doit = drbd2_post_doit,
+ .policy = drbd2_connection_new_nl_policy,
+ .maxattr = DRBD2_A_NET_CONF,
+ .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
+ },
+ {
+ .cmd = DRBD2_CMD_CONNECTION_DEL,
+ .pre_doit = drbd2_pre_doit,
+ .doit = drbd2_nl_connection_del_doit,
+ .post_doit = drbd2_post_doit,
+ .policy = drbd2_connection_del_nl_policy,
+ .maxattr = DRBD2_A_DISCONNECT_PARMS,
+ .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
+ },
+ {
+ .cmd = DRBD2_CMD_CONNECTION_CONNECT,
+ .pre_doit = drbd2_pre_doit,
+ .doit = drbd2_nl_connection_connect_doit,
+ .post_doit = drbd2_post_doit,
+ .policy = drbd2_connection_connect_nl_policy,
+ .maxattr = DRBD2_A_CONNECT_PARMS,
+ .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
+ },
+ {
+ .cmd = DRBD2_CMD_CONNECTION_DISCONNECT,
+ .pre_doit = drbd2_pre_doit,
+ .doit = drbd2_nl_connection_disconnect_doit,
+ .post_doit = drbd2_post_doit,
+ .policy = drbd2_connection_disconnect_nl_policy,
+ .maxattr = DRBD2_A_DISCONNECT_PARMS,
+ .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
+ },
+ {
+ .cmd = DRBD2_CMD_CONNECTION_SET,
+ .pre_doit = drbd2_pre_doit,
+ .doit = drbd2_nl_connection_set_doit,
+ .post_doit = drbd2_post_doit,
+ .policy = drbd2_connection_set_nl_policy,
+ .maxattr = DRBD2_A_NET_CONF,
+ .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
+ },
+ {
+ .cmd = DRBD2_CMD_CONNECTION_FORGET,
+ .pre_doit = drbd2_pre_doit,
+ .doit = drbd2_nl_connection_forget_doit,
+ .post_doit = drbd2_post_doit,
+ .policy = drbd2_connection_forget_nl_policy,
+ .maxattr = DRBD2_A_CONTEXT,
+ .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
+ },
+ {
+ .cmd = DRBD2_CMD_PATH_NEW,
+ .pre_doit = drbd2_pre_doit,
+ .doit = drbd2_nl_path_new_doit,
+ .post_doit = drbd2_post_doit,
+ .policy = drbd2_path_new_nl_policy,
+ .maxattr = DRBD2_A_CONTEXT,
+ .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
+ },
+ {
+ .cmd = DRBD2_CMD_PATH_DEL,
+ .pre_doit = drbd2_pre_doit,
+ .doit = drbd2_nl_path_del_doit,
+ .post_doit = drbd2_post_doit,
+ .policy = drbd2_path_del_nl_policy,
+ .maxattr = DRBD2_A_CONTEXT,
+ .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
+ },
+ {
+ .cmd = DRBD2_CMD_PEER_DEVICE_SET,
+ .pre_doit = drbd2_pre_doit,
+ .doit = drbd2_nl_peer_device_set_doit,
+ .post_doit = drbd2_post_doit,
+ .policy = drbd2_peer_device_set_nl_policy,
+ .maxattr = DRBD2_A_PEER_DEVICE_CONF,
+ .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
+ },
+ {
+ .cmd = DRBD2_CMD_PEER_DEVICE_INVALIDATE,
+ .pre_doit = drbd2_pre_doit,
+ .doit = drbd2_nl_peer_device_invalidate_doit,
+ .post_doit = drbd2_post_doit,
+ .policy = drbd2_peer_device_invalidate_nl_policy,
+ .maxattr = DRBD2_A_INVALIDATE_PEER_PARMS,
+ .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
+ },
+ {
+ .cmd = DRBD2_CMD_PEER_DEVICE_PAUSE_SYNC,
+ .pre_doit = drbd2_pre_doit,
+ .doit = drbd2_nl_peer_device_pause_sync_doit,
+ .post_doit = drbd2_post_doit,
+ .policy = drbd2_peer_device_pause_sync_nl_policy,
+ .maxattr = DRBD2_A_CONTEXT,
+ .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
+ },
+ {
+ .cmd = DRBD2_CMD_PEER_DEVICE_RESUME_SYNC,
+ .pre_doit = drbd2_pre_doit,
+ .doit = drbd2_nl_peer_device_resume_sync_doit,
+ .post_doit = drbd2_post_doit,
+ .policy = drbd2_peer_device_resume_sync_nl_policy,
+ .maxattr = DRBD2_A_CONTEXT,
+ .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
+ },
+ {
+ .cmd = DRBD2_CMD_PEER_DEVICE_START_OV,
+ .pre_doit = drbd2_pre_doit,
+ .doit = drbd2_nl_peer_device_start_ov_doit,
+ .post_doit = drbd2_post_doit,
+ .policy = drbd2_peer_device_start_ov_nl_policy,
+ .maxattr = DRBD2_A_START_OV_PARMS,
+ .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
+ },
+ {
+ .cmd = DRBD2_CMD_TIMEOUT_TYPE_GET,
+ .pre_doit = drbd2_pre_doit,
+ .doit = drbd2_nl_timeout_type_get_doit,
+ .post_doit = drbd2_post_doit,
+ .policy = drbd2_timeout_type_get_nl_policy,
+ .maxattr = DRBD2_A_CONTEXT,
+ .flags = GENL_CMD_CAP_DO,
+ },
+ {
+ .cmd = DRBD2_CMD_RESOURCE_GET,
+ .dumpit = drbd2_nl_resource_get_dumpit,
+ .policy = drbd2_resource_get_nl_policy,
+ .maxattr = DRBD2_A_CONTEXT,
+ .flags = GENL_CMD_CAP_DUMP,
+ },
+ {
+ .cmd = DRBD2_CMD_DEVICE_GET,
+ .dumpit = drbd2_nl_device_get_dumpit,
+ .done = drbd2_nl_device_get_done,
+ .policy = drbd2_device_get_nl_policy,
+ .maxattr = DRBD2_A_CONTEXT,
+ .flags = GENL_CMD_CAP_DUMP,
+ },
+ {
+ .cmd = DRBD2_CMD_CONNECTION_GET,
+ .dumpit = drbd2_nl_connection_get_dumpit,
+ .done = drbd2_nl_connection_get_done,
+ .policy = drbd2_connection_get_nl_policy,
+ .maxattr = DRBD2_A_CONTEXT,
+ .flags = GENL_CMD_CAP_DUMP,
+ },
+ {
+ .cmd = DRBD2_CMD_PEER_DEVICE_GET,
+ .dumpit = drbd2_nl_peer_device_get_dumpit,
+ .done = drbd2_nl_peer_device_get_done,
+ .policy = drbd2_peer_device_get_nl_policy,
+ .maxattr = DRBD2_A_CONTEXT,
+ .flags = GENL_CMD_CAP_DUMP,
+ },
+ {
+ .cmd = DRBD2_CMD_PATH_GET,
+ .dumpit = drbd2_nl_path_get_dumpit,
+ .done = drbd2_nl_path_get_done,
+ .policy = drbd2_path_get_nl_policy,
+ .maxattr = DRBD2_A_CONTEXT,
+ .flags = GENL_CMD_CAP_DUMP,
+ },
+ {
+ .cmd = DRBD2_CMD_STATE_GET,
+ .dumpit = drbd2_nl_state_get_dumpit,
+ .done = drbd2_nl_state_get_done,
+ .flags = GENL_CMD_CAP_DUMP,
+ },
+};
+
+static const struct genl_multicast_group drbd2_nl_mcgrps[] = {
+ [DRBD2_NLGRP_EVENTS] = { "events", },
+};
+
+struct genl_family drbd2_nl_family __ro_after_init = {
+ .name = DRBD2_FAMILY_NAME,
+ .version = DRBD2_FAMILY_VERSION,
+ .netnsok = true,
+ .parallel_ops = true,
+ .module = THIS_MODULE,
+ .split_ops = drbd2_nl_ops,
+ .n_split_ops = ARRAY_SIZE(drbd2_nl_ops),
+ .mcgrps = drbd2_nl_mcgrps,
+ .n_mcgrps = ARRAY_SIZE(drbd2_nl_mcgrps),
+};
diff --git a/drivers/block/drbd/drbd2_nl_gen.h b/drivers/block/drbd/drbd2_nl_gen.h
new file mode 100644
index 000000000000..fd586cf317da
--- /dev/null
+++ b/drivers/block/drbd/drbd2_nl_gen.h
@@ -0,0 +1,107 @@
+/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
+/* Do not edit directly, auto-generated from: */
+/* Documentation/netlink/specs/drbd2.yaml */
+/* YNL-GEN kernel header */
+/* To regenerate run: tools/net/ynl/ynl-regen.sh */
+
+#ifndef _LINUX_DRBD2_GEN_H
+#define _LINUX_DRBD2_GEN_H
+
+#include <net/netlink.h>
+#include <net/genetlink.h>
+
+#include <uapi/linux/drbd2.h>
+
+/* Common nested types */
+extern const struct nla_policy drbd2_address_nl_policy[DRBD2_A_ADDRESS_IPV6 + 1];
+extern const struct nla_policy drbd2_connect_parms_nl_policy[DRBD2_A_CONNECT_PARMS_DISCARD_MY_DATA + 1];
+extern const struct nla_policy drbd2_context_nl_policy[DRBD2_A_CONTEXT_PEER_ADDRESS + 1];
+extern const struct nla_policy drbd2_detach_parms_nl_policy[DRBD2_A_DETACH_PARMS_INTENTIONAL_DISKLESS_DETACH + 1];
+extern const struct nla_policy drbd2_device_conf_nl_policy[DRBD2_A_DEVICE_CONF_DISCARD_GRANULARITY + 1];
+extern const struct nla_policy drbd2_disconnect_parms_nl_policy[DRBD2_A_DISCONNECT_PARMS_FORCE + 1];
+extern const struct nla_policy drbd2_disk_conf_nl_policy[DRBD2_A_DISK_CONF_BITMAP + 1];
+extern const struct nla_policy drbd2_invalidate_parms_nl_policy[DRBD2_A_INVALIDATE_PARMS_RESET_BITMAP + 1];
+extern const struct nla_policy drbd2_invalidate_peer_parms_nl_policy[DRBD2_A_INVALIDATE_PEER_PARMS_RESET_BITMAP + 1];
+extern const struct nla_policy drbd2_net_conf_nl_policy[DRBD2_A_NET_CONF_RDMA_CTRL_SNDBUF_SIZE + 1];
+extern const struct nla_policy drbd2_new_current_uuid_parms_nl_policy[DRBD2_A_NEW_CURRENT_UUID_PARMS_FORCE_RESYNC + 1];
+extern const struct nla_policy drbd2_peer_device_conf_nl_policy[DRBD2_A_PEER_DEVICE_CONF_PEER_TIEBREAKER + 1];
+extern const struct nla_policy drbd2_rename_parms_nl_policy[DRBD2_A_RENAME_PARMS_NEW_NAME + 1];
+extern const struct nla_policy drbd2_resize_parms_nl_policy[DRBD2_A_RESIZE_PARMS_AL_STRIPE_SIZE + 1];
+extern const struct nla_policy drbd2_resource_opts_nl_policy[DRBD2_A_RESOURCE_OPTS_EXPLICIT_DRBD8_COMPAT + 1];
+extern const struct nla_policy drbd2_set_role_parms_nl_policy[DRBD2_A_SET_ROLE_PARMS_FORCE + 1];
+extern const struct nla_policy drbd2_start_ov_parms_nl_policy[DRBD2_A_START_OV_PARMS_STOP_SECTOR + 1];
+extern const struct nla_policy drbd2_suspend_io_parms_nl_policy[DRBD2_A_SUSPEND_IO_PARMS_BDEV_FREEZE + 1];
+
+int drbd2_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
+ struct genl_info *info);
+void
+drbd2_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
+ struct genl_info *info);
+int drbd2_nl_device_get_done(struct netlink_callback *cb);
+int drbd2_nl_connection_get_done(struct netlink_callback *cb);
+int drbd2_nl_peer_device_get_done(struct netlink_callback *cb);
+int drbd2_nl_path_get_done(struct netlink_callback *cb);
+int drbd2_nl_state_get_done(struct netlink_callback *cb);
+
+int drbd2_nl_resource_new_doit(struct sk_buff *skb, struct genl_info *info);
+int drbd2_nl_resource_del_doit(struct sk_buff *skb, struct genl_info *info);
+int drbd2_nl_resource_set_doit(struct sk_buff *skb, struct genl_info *info);
+int drbd2_nl_resource_rename_doit(struct sk_buff *skb, struct genl_info *info);
+int drbd2_nl_resource_down_doit(struct sk_buff *skb, struct genl_info *info);
+int drbd2_nl_resource_primary_doit(struct sk_buff *skb, struct genl_info *info);
+int drbd2_nl_resource_secondary_doit(struct sk_buff *skb,
+ struct genl_info *info);
+int drbd2_nl_resource_suspend_io_doit(struct sk_buff *skb,
+ struct genl_info *info);
+int drbd2_nl_resource_resume_io_doit(struct sk_buff *skb,
+ struct genl_info *info);
+int drbd2_nl_device_new_doit(struct sk_buff *skb, struct genl_info *info);
+int drbd2_nl_device_del_doit(struct sk_buff *skb, struct genl_info *info);
+int drbd2_nl_device_attach_doit(struct sk_buff *skb, struct genl_info *info);
+int drbd2_nl_device_detach_doit(struct sk_buff *skb, struct genl_info *info);
+int drbd2_nl_disk_set_doit(struct sk_buff *skb, struct genl_info *info);
+int drbd2_nl_device_resize_doit(struct sk_buff *skb, struct genl_info *info);
+int drbd2_nl_device_outdate_doit(struct sk_buff *skb, struct genl_info *info);
+int drbd2_nl_device_invalidate_doit(struct sk_buff *skb,
+ struct genl_info *info);
+int drbd2_nl_device_new_current_uuid_doit(struct sk_buff *skb,
+ struct genl_info *info);
+int drbd2_nl_connection_new_doit(struct sk_buff *skb, struct genl_info *info);
+int drbd2_nl_connection_del_doit(struct sk_buff *skb, struct genl_info *info);
+int drbd2_nl_connection_connect_doit(struct sk_buff *skb,
+ struct genl_info *info);
+int drbd2_nl_connection_disconnect_doit(struct sk_buff *skb,
+ struct genl_info *info);
+int drbd2_nl_connection_set_doit(struct sk_buff *skb, struct genl_info *info);
+int drbd2_nl_connection_forget_doit(struct sk_buff *skb,
+ struct genl_info *info);
+int drbd2_nl_path_new_doit(struct sk_buff *skb, struct genl_info *info);
+int drbd2_nl_path_del_doit(struct sk_buff *skb, struct genl_info *info);
+int drbd2_nl_peer_device_set_doit(struct sk_buff *skb, struct genl_info *info);
+int drbd2_nl_peer_device_invalidate_doit(struct sk_buff *skb,
+ struct genl_info *info);
+int drbd2_nl_peer_device_pause_sync_doit(struct sk_buff *skb,
+ struct genl_info *info);
+int drbd2_nl_peer_device_resume_sync_doit(struct sk_buff *skb,
+ struct genl_info *info);
+int drbd2_nl_peer_device_start_ov_doit(struct sk_buff *skb,
+ struct genl_info *info);
+int drbd2_nl_timeout_type_get_doit(struct sk_buff *skb, struct genl_info *info);
+int drbd2_nl_resource_get_dumpit(struct sk_buff *skb,
+ struct netlink_callback *cb);
+int drbd2_nl_device_get_dumpit(struct sk_buff *skb,
+ struct netlink_callback *cb);
+int drbd2_nl_connection_get_dumpit(struct sk_buff *skb,
+ struct netlink_callback *cb);
+int drbd2_nl_peer_device_get_dumpit(struct sk_buff *skb,
+ struct netlink_callback *cb);
+int drbd2_nl_path_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb);
+int drbd2_nl_state_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb);
+
+enum {
+ DRBD2_NLGRP_EVENTS,
+};
+
+extern struct genl_family drbd2_nl_family;
+
+#endif /* _LINUX_DRBD2_GEN_H */
diff --git a/drivers/block/drbd/drbd_nl_drbd2.c b/drivers/block/drbd/drbd_nl_drbd2.c
new file mode 100644
index 000000000000..89fe5810ab17
--- /dev/null
+++ b/drivers/block/drbd/drbd_nl_drbd2.c
@@ -0,0 +1,2533 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2026, LINBIT HA-Solutions GmbH.
+ */
+
+/*
+ * The "drbd2" generic netlink family: everything that knows about the
+ * bytes on the wire of that dialect. The command implementations
+ * themselves live in drbd_nl.c and only ever see a struct drbd_adm_ctx.
+ *
+ * Unlike the legacy "drbd" family, drbd2 has no fixed message header and
+ * no place to carry a drbd_ret_code, so the outcome of a request is split
+ * in two, as the specification prescribes:
+ *
+ * - A state change reports its drbd_state_rv in the state-result
+ * attribute of the reply, together with the accumulated info messages
+ * in message. A refused state change is data, not a transport error.
+ * - Everything that failed for a configuration reason (the ERR_* codes)
+ * becomes an errno plus a description in the extended ACK, and no
+ * reply is sent at all.
+ *
+ * The description in the extended ACK is the command's own account of the
+ * failure where it left one -- the first of the info messages the core
+ * collected, formatted into the ACK's buffer so that it outlives the
+ * command context -- and the generic text of the ERR_* code otherwise.
+ * Failures that are about one attribute of the request also name that
+ * attribute, the way the netlink policy checks do. Further info messages
+ * are lost on the errno path; the reply of a completed command carries
+ * them all.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/slab.h>
+#include <linux/drbd.h>
+#include "drbd2_nl_gen.h"
+#include <net/genetlink.h>
+#include <net/sock.h>
+
+#include "drbd_int.h"
+#include "drbd_nl.h"
+
+static const struct drbd_nl_dialect drbd2_dialect;
+
+/* Per-request state of the drbd2 dialect; hangs off drbd_adm_ctx.req. */
+struct drbd2_req {
+ struct genl_info *info;
+ struct sk_buff *reply_skb;
+ void *reply_hdr;
+ /* the command filled the reply itself; do not add state-result */
+ bool payload_reply;
+};
+
+/* One allocation for both, so that pre_doit zeroes the context only once. */
+struct drbd2_ctx {
+ struct drbd_adm_ctx ctx;
+ struct drbd2_req req;
+};
+
+static inline struct drbd2_req *drbd2_req(struct drbd_adm_ctx *ctx)
+{
+ return ctx->req;
+}
+
+/*
+ * drbd2 numbers its attributes from 1, so attribute 0 is free to serve as
+ * the padding attribute of the 64 bit values, the same way the legacy
+ * marshalling code uses it.
+ */
+#define DRBD2_A_PAD 0
+
+static int drbd2_put_u64(struct sk_buff *skb, int attrtype, u64 value)
+{
+ return nla_put_u64_64bit(skb, attrtype, value, DRBD2_A_PAD);
+}
+
+/*
+ * The internal string buffers carry an explicit length and are
+ * NUL-terminated unless they are completely full; emit them including
+ * that terminating NUL, as the drbd2 policies expect.
+ */
+static int drbd2_put_str(struct sk_buff *skb, int attrtype,
+ const char *val, u32 len, u32 size)
+{
+ return nla_put(skb, attrtype, min_t(u32, size, len + (len < size)), val);
+}
+
+/* A socket address as the address nest of "attrtype". */
+static int drbd2_put_address(struct sk_buff *skb, int attrtype,
+ const struct sockaddr_storage *addr)
+{
+ struct nlattr *nla = nla_nest_start(skb, attrtype);
+
+ if (!nla)
+ return -EMSGSIZE;
+ if (nla_put_u16(skb, DRBD2_A_ADDRESS_FAMILY, addr->ss_family))
+ goto fail;
+ switch (addr->ss_family) {
+ case AF_INET: {
+ const struct sockaddr_in *sin = (const struct sockaddr_in *)addr;
+
+ if (nla_put_be16(skb, DRBD2_A_ADDRESS_PORT, sin->sin_port) ||
+ nla_put_be32(skb, DRBD2_A_ADDRESS_IPV4, sin->sin_addr.s_addr))
+ goto fail;
+ break;
+ }
+ case AF_INET6: {
+ const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)addr;
+
+ if (nla_put_be16(skb, DRBD2_A_ADDRESS_PORT, sin6->sin6_port) ||
+ nla_put(skb, DRBD2_A_ADDRESS_IPV6,
+ sizeof(sin6->sin6_addr), &sin6->sin6_addr))
+ goto fail;
+ break;
+ }
+ default:
+ /* the family alone is all this dialect can say about it */
+ break;
+ }
+ nla_nest_end(skb, nla);
+ return 0;
+
+fail:
+ nla_nest_cancel(skb, nla);
+ return -EMSGSIZE;
+}
+
+/*
+ * The reverse: one address nest into the sockaddr_storage the transports
+ * work with. Returns -ENOMSG if the nest does not describe an address of
+ * a family this dialect knows.
+ */
+static int drbd2_get_address(const struct nlattr *nla, char *dst, __u32 *dst_len)
+{
+ struct nlattr *tb[DRBD2_A_ADDRESS_IPV6 + 1];
+ int err;
+
+ err = nla_parse_nested(tb, DRBD2_A_ADDRESS_IPV6, nla,
+ drbd2_address_nl_policy, NULL);
+ if (err)
+ return err;
+ if (!tb[DRBD2_A_ADDRESS_FAMILY] || !tb[DRBD2_A_ADDRESS_PORT])
+ return -ENOMSG;
+
+ switch (nla_get_u16(tb[DRBD2_A_ADDRESS_FAMILY])) {
+ case AF_INET: {
+ struct sockaddr_in sin = { .sin_family = AF_INET };
+
+ if (!tb[DRBD2_A_ADDRESS_IPV4])
+ return -ENOMSG;
+ sin.sin_port = nla_get_be16(tb[DRBD2_A_ADDRESS_PORT]);
+ sin.sin_addr.s_addr = nla_get_be32(tb[DRBD2_A_ADDRESS_IPV4]);
+ memcpy(dst, &sin, sizeof(sin));
+ *dst_len = sizeof(sin);
+ return 0;
+ }
+ case AF_INET6: {
+ struct sockaddr_in6 sin6 = { .sin6_family = AF_INET6 };
+
+ if (!tb[DRBD2_A_ADDRESS_IPV6])
+ return -ENOMSG;
+ sin6.sin6_port = nla_get_be16(tb[DRBD2_A_ADDRESS_PORT]);
+ memcpy(&sin6.sin6_addr, nla_data(tb[DRBD2_A_ADDRESS_IPV6]),
+ sizeof(sin6.sin6_addr));
+ memcpy(dst, &sin6, sizeof(sin6));
+ *dst_len = sizeof(sin6);
+ return 0;
+ }
+ }
+ return -ENOMSG;
+}
+
+static int drbd2_genl_multicast_events(struct sk_buff *skb)
+{
+ return genlmsg_multicast_allns(&drbd2_nl_family, skb, 0,
+ DRBD2_NLGRP_EVENTS);
+}
+
+/*
+ * The ERR_* codes of the command core translated into what a modern
+ * netlink family reports: an errno and a description for the extended
+ * ACK. The texts are the ones drbdsetup prints for the legacy family.
+ */
+static const struct {
+ int err;
+ const char *msg;
+} drbd2_error_map[AFTER_LAST_ERR_CODE] = {
+ [ERR_LOCAL_ADDR] = { -EADDRINUSE, "local address(port) already in use" },
+ [ERR_PEER_ADDR] = { -EADDRINUSE, "remote address(port) already in use" },
+ [ERR_OPEN_DISK] = { -ENOENT, "can not open backing device" },
+ [ERR_OPEN_MD_DISK] = { -ENOENT, "can not open meta device" },
+ [ERR_DISK_NOT_BDEV] = { -ENOTBLK, "lower device is not a block device" },
+ [ERR_MD_NOT_BDEV] = { -ENOTBLK, "meta device is not a block device" },
+ [ERR_DISK_TOO_SMALL] = { -ENOSPC, "lower device smaller than the requested size" },
+ [ERR_MD_DISK_TOO_SMALL] = { -ENOSPC, "meta device too small" },
+ [ERR_BDCLAIM_DISK] = { -EBUSY, "lower device is already claimed" },
+ [ERR_BDCLAIM_MD_DISK] = { -EBUSY, "meta device is already claimed" },
+ [ERR_MD_IDX_INVALID] = { -EINVAL,
+ "lower device / meta device / index combination invalid" },
+ [ERR_IO_MD_DISK] = { -EIO, "I/O error during initial access to meta-data" },
+ [ERR_MD_INVALID] = { -EINVAL, "no valid meta-data signature found" },
+ [ERR_AUTH_ALG] = { -EINVAL, "cram-hmac-alg not known to the kernel" },
+ [ERR_AUTH_ALG_ND] = { -EINVAL, "cram-hmac-alg is not a digest" },
+ [ERR_NOMEM] = { -ENOMEM, "out of memory" },
+ [ERR_DISCARD_IMPOSSIBLE] = { -EINVAL, "discard-my-data not allowed when primary" },
+ [ERR_DISK_CONFIGURED] = { -EEXIST, "device is attached to a disk" },
+ [ERR_NET_CONFIGURED] = { -EEXIST, "connection has a net-config" },
+ [ERR_MANDATORY_TAG] = { -EINVAL, "invalid or missing attribute" },
+ [ERR_MINOR_INVALID] = { -ENOENT, "device minor not allocated" },
+ [ERR_INTR] = { -EINTR, "interrupted by signal" },
+ [ERR_RESIZE_RESYNC] = { -EBUSY, "resize not allowed during resync" },
+ [ERR_NO_PRIMARY] = { -EINVAL, "need one primary node to resize" },
+ [ERR_RESYNC_AFTER] = { -EINVAL, "the resync-after minor number is invalid" },
+ [ERR_RESYNC_AFTER_CYCLE] = { -EINVAL, "this would cause a resync-after dependency cycle" },
+ [ERR_PAUSE_IS_SET] = { -EALREADY, "sync-pause flag is already set" },
+ [ERR_PAUSE_IS_CLEAR] = { -EALREADY, "sync-pause flag is already cleared" },
+ [ERR_PACKET_NR] = { -EPROTO, "kernel does not know how to handle this request" },
+ [ERR_NO_DISK] = { -ENODEV, "device does not have a disk-config" },
+ [ERR_NOT_PROTO_C] = { -EINVAL, "protocol C required" },
+ [ERR_NOMEM_BITMAP] = { -ENOMEM, "out of memory for the bitmap" },
+ [ERR_INTEGRITY_ALG] = { -EINVAL, "data-integrity-alg not known to the kernel" },
+ [ERR_INTEGRITY_ALG_ND] = { -EINVAL, "data-integrity-alg is not a digest" },
+ [ERR_CPU_MASK_PARSE] = { -EINVAL, "invalid cpu-mask" },
+ [ERR_CSUMS_ALG] = { -EINVAL, "csums-alg not known to the kernel" },
+ [ERR_CSUMS_ALG_ND] = { -EINVAL, "csums-alg is not a digest" },
+ [ERR_VERIFY_ALG] = { -EINVAL, "verify-alg not known to the kernel" },
+ [ERR_VERIFY_ALG_ND] = { -EINVAL, "verify-alg is not a digest" },
+ [ERR_CSUMS_RESYNC_RUNNING] = { -EBUSY,
+ "can not change csums-alg while resync is in progress" },
+ [ERR_VERIFY_RUNNING] = { -EBUSY, "can not change verify-alg while online verify runs" },
+ [ERR_DATA_NOT_CURRENT] = { -EINVAL, "can only attach to the data we lost last" },
+ [ERR_CONNECTED] = { -EBUSY, "need to be standalone" },
+ [ERR_PERM] = { -EPERM, "permission denied" },
+ [ERR_NEED_APV_93] = { -EOPNOTSUPP, "protocol version 93 required for assume-clean" },
+ [ERR_STONITH_AND_PROT_A] = { -EINVAL,
+ "fencing resource-and-stonith needs protocol B or C" },
+ [ERR_CONG_NOT_PROTO_A] = { -EINVAL, "on-congestion pull-ahead needs protocol A" },
+ [ERR_PIC_AFTER_DEP] = { -EALREADY, "sync-pause is cleared, but a dependency is paused" },
+ [ERR_PIC_PEER_DEP] = { -EALREADY, "sync-pause is cleared, but the peer paused" },
+ [ERR_RES_NOT_KNOWN] = { -ENOENT, "unknown resource" },
+ [ERR_RES_IN_USE] = { -EBUSY, "resource still in use" },
+ [ERR_MINOR_CONFIGURED] = { -EBUSY, "minor still configured" },
+ [ERR_MINOR_OR_VOLUME_EXISTS] = { -EEXIST, "minor or volume exists already" },
+ [ERR_INVALID_REQUEST] = { -EINVAL, "invalid configuration request" },
+ [ERR_NEED_APV_100] = { -EOPNOTSUPP, "protocol version 100 required" },
+ [ERR_NEED_ALLOW_TWO_PRI] = { -EINVAL, "can not clear allow-two-primaries now" },
+ [ERR_MD_UNCLEAN] = { -EINVAL, "unclean meta-data found" },
+ [ERR_MD_LAYOUT_CONNECTED] = { -EBUSY, "online meta-data layout change needs a connection" },
+ [ERR_MD_LAYOUT_TOO_BIG] = { -ENOSPC, "resulting activity log area too big" },
+ [ERR_MD_LAYOUT_TOO_SMALL] = { -ENOSPC, "resulting activity log area too small" },
+ [ERR_MD_LAYOUT_NO_FIT] = { -ENOSPC, "resulting activity log does not fit the meta-data" },
+ [ERR_IMPLICIT_SHRINK] = { -EINVAL, "implicit device shrinking not allowed" },
+ [ERR_INVALID_PEER_NODE_ID] = { -EINVAL, "invalid peer-node-id" },
+ [ERR_CREATE_TRANSPORT] = { -ENOENT, "failed to create transport" },
+ [ERR_LOCAL_AND_PEER_ADDR] = { -EADDRINUSE,
+ "combination of local and remote address already in use" },
+ [ERR_ALREADY_EXISTS] = { -EEXIST, "already exists" },
+ [ERR_APV_TOO_LOW] = { -EOPNOTSUPP, "a higher DRBD protocol level is required" },
+ [ERR_PATH_COLLISION] = { -EEXIST, "path collides with an existing path" },
+};
+
+static bool drbd2_is_ret_code(int result)
+{
+ return result > NO_ERROR && result < AFTER_LAST_ERR_CODE;
+}
+
+/* The errno an ERR_* code becomes on the wire. */
+static int drbd2_errno(int result)
+{
+ if (result == NO_ERROR)
+ return 0;
+ if (!drbd2_is_ret_code(result))
+ return result < 0 ? result : -EINVAL;
+ return drbd2_error_map[result].err ? : -EINVAL;
+}
+
+/*
+ * The request attribute a failure is about, for the codes that are
+ * specific to one: the top level nest and the attribute within it.
+ */
+static const struct {
+ u16 nest;
+ u16 attr;
+} drbd2_error_attr[AFTER_LAST_ERR_CODE] = {
+ [ERR_OPEN_DISK] = { DRBD2_A_DISK_CONF, DRBD2_A_DISK_CONF_BACKING_DEV },
+ [ERR_DISK_NOT_BDEV] = { DRBD2_A_DISK_CONF, DRBD2_A_DISK_CONF_BACKING_DEV },
+ [ERR_BDCLAIM_DISK] = { DRBD2_A_DISK_CONF, DRBD2_A_DISK_CONF_BACKING_DEV },
+ [ERR_DISK_TOO_SMALL] = { DRBD2_A_DISK_CONF, DRBD2_A_DISK_CONF_BACKING_DEV },
+ [ERR_OPEN_MD_DISK] = { DRBD2_A_DISK_CONF, DRBD2_A_DISK_CONF_META_DEV },
+ [ERR_MD_NOT_BDEV] = { DRBD2_A_DISK_CONF, DRBD2_A_DISK_CONF_META_DEV },
+ [ERR_BDCLAIM_MD_DISK] = { DRBD2_A_DISK_CONF, DRBD2_A_DISK_CONF_META_DEV },
+ [ERR_MD_DISK_TOO_SMALL] = { DRBD2_A_DISK_CONF, DRBD2_A_DISK_CONF_META_DEV },
+ [ERR_MD_IDX_INVALID] = { DRBD2_A_DISK_CONF, DRBD2_A_DISK_CONF_META_DEV_IDX },
+ [ERR_RESYNC_AFTER] = { DRBD2_A_DISK_CONF, DRBD2_A_DISK_CONF_RESYNC_AFTER },
+ [ERR_RESYNC_AFTER_CYCLE] = { DRBD2_A_DISK_CONF, DRBD2_A_DISK_CONF_RESYNC_AFTER },
+ [ERR_CPU_MASK_PARSE] = { DRBD2_A_RESOURCE_OPTS, DRBD2_A_RESOURCE_OPTS_CPU_MASK },
+ [ERR_AUTH_ALG] = { DRBD2_A_NET_CONF, DRBD2_A_NET_CONF_CRAM_HMAC_ALG },
+ [ERR_AUTH_ALG_ND] = { DRBD2_A_NET_CONF, DRBD2_A_NET_CONF_CRAM_HMAC_ALG },
+ [ERR_INTEGRITY_ALG] = { DRBD2_A_NET_CONF, DRBD2_A_NET_CONF_INTEGRITY_ALG },
+ [ERR_INTEGRITY_ALG_ND] = { DRBD2_A_NET_CONF, DRBD2_A_NET_CONF_INTEGRITY_ALG },
+ [ERR_VERIFY_ALG] = { DRBD2_A_NET_CONF, DRBD2_A_NET_CONF_VERIFY_ALG },
+ [ERR_VERIFY_ALG_ND] = { DRBD2_A_NET_CONF, DRBD2_A_NET_CONF_VERIFY_ALG },
+ [ERR_VERIFY_RUNNING] = { DRBD2_A_NET_CONF, DRBD2_A_NET_CONF_VERIFY_ALG },
+ [ERR_CSUMS_ALG] = { DRBD2_A_NET_CONF, DRBD2_A_NET_CONF_CSUMS_ALG },
+ [ERR_CSUMS_ALG_ND] = { DRBD2_A_NET_CONF, DRBD2_A_NET_CONF_CSUMS_ALG },
+ [ERR_CSUMS_RESYNC_RUNNING] = { DRBD2_A_NET_CONF, DRBD2_A_NET_CONF_CSUMS_ALG },
+ [ERR_STONITH_AND_PROT_A] = { DRBD2_A_NET_CONF, DRBD2_A_NET_CONF_FENCING },
+ [ERR_CONG_NOT_PROTO_A] = { DRBD2_A_NET_CONF, DRBD2_A_NET_CONF_ON_CONGESTION },
+ [ERR_INVALID_PEER_NODE_ID] = { DRBD2_A_CONTEXT, DRBD2_A_CONTEXT_PEER_NODE_ID },
+};
+
+/*
+ * Describe a failed command in the extended ACK: its own first info
+ * message if it left one, the generic text of its ERR_* code otherwise,
+ * and the request attribute the failure is about if there is one.
+ */
+static void drbd2_set_extack(struct genl_info *info, struct drbd_adm_ctx *ctx)
+{
+ struct netlink_ext_ack *extack = info->extack;
+ int result = ctx->result;
+ const char *msg = NULL;
+ int len = 0;
+
+ if (!extack)
+ return;
+
+ /* what the command itself said, its first message only */
+ if (ctx->msg_len) {
+ len = strnlen(ctx->msg, ctx->msg_len);
+ while (len && (ctx->msg[len - 1] == '\n' || ctx->msg[len - 1] == ' '))
+ len--;
+ if (len)
+ msg = ctx->msg;
+ }
+ if (!msg) {
+ msg = drbd2_is_ret_code(result) && drbd2_error_map[result].msg ?
+ drbd2_error_map[result].msg : "DRBD command failed";
+ len = strlen(msg);
+ }
+ NL_SET_ERR_MSG_FMT(extack, "%.*s",
+ min(len, NETLINK_MAX_FMTMSG_LEN - 1), msg);
+
+ if (drbd2_is_ret_code(result) && drbd2_error_attr[result].nest) {
+ struct nlattr *nest = info->attrs[drbd2_error_attr[result].nest];
+ struct nlattr *attr = nest ?
+ nla_find_nested(nest, drbd2_error_attr[result].attr) : NULL;
+
+ if (attr)
+ NL_SET_BAD_ATTR(extack, attr);
+ }
+}
+
+/*
+ * The drbd_state_rv of a completed state change as the state-result
+ * attribute: the error values are the negated SS_* codes, the successful
+ * outcomes follow above them in the order of the enum.
+ */
+static u32 drbd2_state_result(int result)
+{
+ if (result == NO_ERROR)
+ return DRBD2_STATE_RESULT_SUCCESS;
+ if (result >= SS_SUCCESS && result <= SS_CW_NO_NEED)
+ return DRBD2_STATE_RESULT_SUCCESS + (result - SS_SUCCESS);
+ if (result <= SS_UNKNOWN_ERROR && result > SS_AFTER_LAST_ERROR)
+ return -result;
+ return DRBD2_STATE_RESULT_UNKNOWN_ERROR;
+}
+
+/*
+ * The info messages of the command, joined into the one string the
+ * message attribute carries. They are NUL-separated in ctx->msg and this
+ * is their last user, so the separators can be turned into newlines in
+ * place; the final NUL stays and terminates the string.
+ */
+static int drbd2_put_message(struct sk_buff *skb, struct drbd_adm_ctx *ctx)
+{
+ unsigned int i;
+
+ if (!ctx->msg_len)
+ return 0;
+ for (i = 0; i + 1 < ctx->msg_len; i++)
+ if (ctx->msg[i] == '\0')
+ ctx->msg[i] = '\n';
+ return nla_put(skb, DRBD2_A_MESSAGE, ctx->msg_len, ctx->msg);
+}
+
+/*
+ * Serialize the outcome of a completed command into the reply. The state
+ * result always fits into a fresh message; the info text may not, and is
+ * then dropped, exactly as the over-full legacy reply dropped it.
+ */
+static void drbd2_put_outcome(struct drbd_adm_ctx *ctx)
+{
+ struct drbd2_req *req = drbd2_req(ctx);
+
+ if (req->payload_reply)
+ return;
+ if (nla_put_u32(req->reply_skb, DRBD2_A_STATE_RESULT,
+ drbd2_state_result(ctx->result)))
+ return;
+ drbd2_put_message(req->reply_skb, ctx);
+}
+
+/*
+ * The identity of an object, as the context nest of "attrtype". Every
+ * pointer is optional; only the parts that are given are described.
+ */
+static int drbd2_put_context(struct sk_buff *skb, int attrtype,
+ struct drbd_resource *resource,
+ struct drbd_connection *connection,
+ struct drbd_device *device,
+ struct drbd_path *path)
+{
+ struct nlattr *nla = nla_nest_start(skb, attrtype);
+
+ if (!nla)
+ return -EMSGSIZE;
+ if (resource && nla_put_string(skb, DRBD2_A_CONTEXT_RESOURCE_NAME, resource->name))
+ goto fail;
+ if (device &&
+ (nla_put_u32(skb, DRBD2_A_CONTEXT_VOLUME, device->vnr) ||
+ nla_put_u32(skb, DRBD2_A_CONTEXT_MINOR, device->minor)))
+ goto fail;
+ if (connection) {
+ struct drbd_net_conf *nc;
+ int err = 0;
+
+ if (nla_put_u32(skb, DRBD2_A_CONTEXT_PEER_NODE_ID, connection->peer_node_id))
+ goto fail;
+ rcu_read_lock();
+ nc = rcu_dereference(connection->transport.net_conf);
+ if (nc)
+ err = nla_put_string(skb, DRBD2_A_CONTEXT_CONNECTION_NAME, nc->name);
+ rcu_read_unlock();
+ if (err)
+ goto fail;
+ }
+ if (path &&
+ (drbd2_put_address(skb, DRBD2_A_CONTEXT_MY_ADDRESS, &path->my_addr) ||
+ drbd2_put_address(skb, DRBD2_A_CONTEXT_PEER_ADDRESS, &path->peer_addr)))
+ goto fail;
+ nla_nest_end(skb, nla);
+ return 0;
+
+fail:
+ nla_nest_cancel(skb, nla);
+ return -EMSGSIZE;
+}
+
+/*
+ * State and statistics of the five object types. The values of the drbd2
+ * enums are those of the kernel-internal ones, so they go on the wire
+ * unchanged.
+ */
+
+static int drbd2_put_resource_info(struct sk_buff *skb, int attrtype,
+ struct drbd_resource_info *info)
+{
+ struct nlattr *nla = nla_nest_start(skb, attrtype);
+
+ if (!nla)
+ return -EMSGSIZE;
+ if (nla_put_u32(skb, DRBD2_A_RESOURCE_INFO_ROLE, info->res_role) ||
+ nla_put_u8(skb, DRBD2_A_RESOURCE_INFO_SUSP, info->res_susp) ||
+ nla_put_u8(skb, DRBD2_A_RESOURCE_INFO_SUSP_NOD, info->res_susp_nod) ||
+ nla_put_u8(skb, DRBD2_A_RESOURCE_INFO_SUSP_FEN, info->res_susp_fen) ||
+ nla_put_u8(skb, DRBD2_A_RESOURCE_INFO_SUSP_QUORUM, info->res_susp_quorum) ||
+ nla_put_u8(skb, DRBD2_A_RESOURCE_INFO_FAIL_IO, info->res_fail_io))
+ goto fail;
+ nla_nest_end(skb, nla);
+ return 0;
+
+fail:
+ nla_nest_cancel(skb, nla);
+ return -EMSGSIZE;
+}
+
+static int drbd2_put_resource_statistics(struct sk_buff *skb, int attrtype,
+ struct drbd_resource_statistics *s)
+{
+ struct nlattr *nla = nla_nest_start(skb, attrtype);
+
+ if (!nla)
+ return -EMSGSIZE;
+ if (nla_put_u32(skb, DRBD2_A_RESOURCE_STATISTICS_WRITE_ORDERING,
+ s->res_stat_write_ordering))
+ goto fail;
+ nla_nest_end(skb, nla);
+ return 0;
+
+fail:
+ nla_nest_cancel(skb, nla);
+ return -EMSGSIZE;
+}
+
+static int drbd2_put_device_info(struct sk_buff *skb, int attrtype,
+ struct drbd_device_info *info)
+{
+ struct nlattr *nla = nla_nest_start(skb, attrtype);
+
+ if (!nla)
+ return -EMSGSIZE;
+ if (nla_put_u32(skb, DRBD2_A_DEVICE_INFO_DISK_STATE, info->dev_disk_state) ||
+ nla_put_u8(skb, DRBD2_A_DEVICE_INFO_IS_INTENTIONAL_DISKLESS,
+ info->is_intentional_diskless) ||
+ nla_put_u8(skb, DRBD2_A_DEVICE_INFO_HAS_QUORUM, info->dev_has_quorum) ||
+ nla_put_u8(skb, DRBD2_A_DEVICE_INFO_IS_OPEN, info->dev_is_open) ||
+ drbd2_put_str(skb, DRBD2_A_DEVICE_INFO_BACKING_DEV_PATH,
+ info->backing_dev_path, info->backing_dev_path_len,
+ sizeof(info->backing_dev_path)))
+ goto fail;
+ nla_nest_end(skb, nla);
+ return 0;
+
+fail:
+ nla_nest_cancel(skb, nla);
+ return -EMSGSIZE;
+}
+
+static int drbd2_put_device_statistics(struct sk_buff *skb, int attrtype,
+ struct drbd_device_statistics *s)
+{
+ struct nlattr *nla = nla_nest_start(skb, attrtype);
+
+ if (!nla)
+ return -EMSGSIZE;
+ if (drbd2_put_u64(skb, DRBD2_A_DEVICE_STATISTICS_SIZE, s->dev_size) ||
+ drbd2_put_u64(skb, DRBD2_A_DEVICE_STATISTICS_READ, s->dev_read) ||
+ drbd2_put_u64(skb, DRBD2_A_DEVICE_STATISTICS_WRITE, s->dev_write) ||
+ drbd2_put_u64(skb, DRBD2_A_DEVICE_STATISTICS_AL_WRITES, s->dev_al_writes) ||
+ drbd2_put_u64(skb, DRBD2_A_DEVICE_STATISTICS_BM_WRITES, s->dev_bm_writes) ||
+ nla_put_u32(skb, DRBD2_A_DEVICE_STATISTICS_UPPER_PENDING, s->dev_upper_pending) ||
+ nla_put_u32(skb, DRBD2_A_DEVICE_STATISTICS_LOWER_PENDING, s->dev_lower_pending) ||
+ nla_put_u8(skb, DRBD2_A_DEVICE_STATISTICS_UPPER_BLOCKED, s->dev_upper_blocked) ||
+ nla_put_u8(skb, DRBD2_A_DEVICE_STATISTICS_LOWER_BLOCKED, s->dev_lower_blocked) ||
+ nla_put_u8(skb, DRBD2_A_DEVICE_STATISTICS_AL_SUSPENDED, s->dev_al_suspended) ||
+ drbd2_put_u64(skb, DRBD2_A_DEVICE_STATISTICS_EXPOSED_DATA_UUID,
+ s->dev_exposed_data_uuid) ||
+ drbd2_put_u64(skb, DRBD2_A_DEVICE_STATISTICS_CURRENT_UUID, s->dev_current_uuid) ||
+ nla_put_u32(skb, DRBD2_A_DEVICE_STATISTICS_DISK_FLAGS, s->dev_disk_flags) ||
+ nla_put(skb, DRBD2_A_DEVICE_STATISTICS_HISTORY_UUIDS,
+ min_t(u32, HISTORY_UUIDS_SIZE, s->history_uuids_len), s->history_uuids))
+ goto fail;
+ nla_nest_end(skb, nla);
+ return 0;
+
+fail:
+ nla_nest_cancel(skb, nla);
+ return -EMSGSIZE;
+}
+
+static int drbd2_put_connection_info(struct sk_buff *skb, int attrtype,
+ struct drbd_connection_info *info)
+{
+ struct nlattr *nla = nla_nest_start(skb, attrtype);
+
+ if (!nla)
+ return -EMSGSIZE;
+ if (nla_put_u32(skb, DRBD2_A_CONNECTION_INFO_CONNECTION_STATE,
+ info->conn_connection_state) ||
+ nla_put_u32(skb, DRBD2_A_CONNECTION_INFO_ROLE, info->conn_role))
+ goto fail;
+ nla_nest_end(skb, nla);
+ return 0;
+
+fail:
+ nla_nest_cancel(skb, nla);
+ return -EMSGSIZE;
+}
+
+static int drbd2_put_connection_statistics(struct sk_buff *skb, int attrtype,
+ struct drbd_connection_statistics *s)
+{
+ struct nlattr *nla = nla_nest_start(skb, attrtype);
+
+ if (!nla)
+ return -EMSGSIZE;
+ if (nla_put_u8(skb, DRBD2_A_CONNECTION_STATISTICS_CONGESTED, s->conn_congested) ||
+ drbd2_put_u64(skb, DRBD2_A_CONNECTION_STATISTICS_AP_IN_FLIGHT, s->ap_in_flight) ||
+ drbd2_put_u64(skb, DRBD2_A_CONNECTION_STATISTICS_RS_IN_FLIGHT, s->rs_in_flight))
+ goto fail;
+ nla_nest_end(skb, nla);
+ return 0;
+
+fail:
+ nla_nest_cancel(skb, nla);
+ return -EMSGSIZE;
+}
+
+static int drbd2_put_peer_device_info(struct sk_buff *skb, int attrtype,
+ struct drbd_peer_device_info *info)
+{
+ struct nlattr *nla = nla_nest_start(skb, attrtype);
+
+ if (!nla)
+ return -EMSGSIZE;
+ if (nla_put_u32(skb, DRBD2_A_PEER_DEVICE_INFO_REPL_STATE, info->peer_repl_state) ||
+ nla_put_u32(skb, DRBD2_A_PEER_DEVICE_INFO_DISK_STATE, info->peer_disk_state) ||
+ nla_put_u8(skb, DRBD2_A_PEER_DEVICE_INFO_RESYNC_SUSP_USER,
+ !!info->peer_resync_susp_user) ||
+ nla_put_u8(skb, DRBD2_A_PEER_DEVICE_INFO_RESYNC_SUSP_PEER,
+ !!info->peer_resync_susp_peer) ||
+ nla_put_u8(skb, DRBD2_A_PEER_DEVICE_INFO_RESYNC_SUSP_DEPENDENCY,
+ !!info->peer_resync_susp_dependency) ||
+ nla_put_u8(skb, DRBD2_A_PEER_DEVICE_INFO_IS_INTENTIONAL_DISKLESS,
+ info->peer_is_intentional_diskless) ||
+ nla_put_u8(skb, DRBD2_A_PEER_DEVICE_INFO_RESYNC_SUSP_MAX_PARALLEL,
+ !!info->peer_resync_susp_max_parallel))
+ goto fail;
+ nla_nest_end(skb, nla);
+ return 0;
+
+fail:
+ nla_nest_cancel(skb, nla);
+ return -EMSGSIZE;
+}
+
+static int drbd2_put_peer_device_statistics(struct sk_buff *skb, int attrtype,
+ struct drbd_peer_device_statistics *s)
+{
+ struct nlattr *nla = nla_nest_start(skb, attrtype);
+
+ if (!nla)
+ return -EMSGSIZE;
+ if (drbd2_put_u64(skb, DRBD2_A_PEER_DEVICE_STATISTICS_RECEIVED, s->peer_dev_received) ||
+ drbd2_put_u64(skb, DRBD2_A_PEER_DEVICE_STATISTICS_SENT, s->peer_dev_sent) ||
+ nla_put_u32(skb, DRBD2_A_PEER_DEVICE_STATISTICS_PENDING, s->peer_dev_pending) ||
+ nla_put_u32(skb, DRBD2_A_PEER_DEVICE_STATISTICS_UNACKED, s->peer_dev_unacked) ||
+ drbd2_put_u64(skb, DRBD2_A_PEER_DEVICE_STATISTICS_OUT_OF_SYNC,
+ s->peer_dev_out_of_sync) ||
+ drbd2_put_u64(skb, DRBD2_A_PEER_DEVICE_STATISTICS_RESYNC_FAILED,
+ s->peer_dev_resync_failed) ||
+ drbd2_put_u64(skb, DRBD2_A_PEER_DEVICE_STATISTICS_BITMAP_UUID,
+ s->peer_dev_bitmap_uuid) ||
+ nla_put_u32(skb, DRBD2_A_PEER_DEVICE_STATISTICS_FLAGS, s->peer_dev_flags) ||
+ drbd2_put_u64(skb, DRBD2_A_PEER_DEVICE_STATISTICS_RS_TOTAL, s->peer_dev_rs_total) ||
+ drbd2_put_u64(skb, DRBD2_A_PEER_DEVICE_STATISTICS_OV_START_SECTOR,
+ s->peer_dev_ov_start_sector) ||
+ drbd2_put_u64(skb, DRBD2_A_PEER_DEVICE_STATISTICS_OV_STOP_SECTOR,
+ s->peer_dev_ov_stop_sector) ||
+ drbd2_put_u64(skb, DRBD2_A_PEER_DEVICE_STATISTICS_OV_POSITION,
+ s->peer_dev_ov_position) ||
+ drbd2_put_u64(skb, DRBD2_A_PEER_DEVICE_STATISTICS_OV_LEFT, s->peer_dev_ov_left) ||
+ drbd2_put_u64(skb, DRBD2_A_PEER_DEVICE_STATISTICS_OV_SKIPPED,
+ s->peer_dev_ov_skipped) ||
+ drbd2_put_u64(skb, DRBD2_A_PEER_DEVICE_STATISTICS_RS_SAME_CSUM,
+ s->peer_dev_rs_same_csum) ||
+ drbd2_put_u64(skb, DRBD2_A_PEER_DEVICE_STATISTICS_RS_DT_START_MS,
+ s->peer_dev_rs_dt_start_ms) ||
+ drbd2_put_u64(skb, DRBD2_A_PEER_DEVICE_STATISTICS_RS_PAUSED_MS,
+ s->peer_dev_rs_paused_ms) ||
+ drbd2_put_u64(skb, DRBD2_A_PEER_DEVICE_STATISTICS_RS_DT0_MS,
+ s->peer_dev_rs_dt0_ms) ||
+ drbd2_put_u64(skb, DRBD2_A_PEER_DEVICE_STATISTICS_RS_DB0_SECTORS,
+ s->peer_dev_rs_db0_sectors) ||
+ drbd2_put_u64(skb, DRBD2_A_PEER_DEVICE_STATISTICS_RS_DT1_MS,
+ s->peer_dev_rs_dt1_ms) ||
+ drbd2_put_u64(skb, DRBD2_A_PEER_DEVICE_STATISTICS_RS_DB1_SECTORS,
+ s->peer_dev_rs_db1_sectors) ||
+ nla_put_u32(skb, DRBD2_A_PEER_DEVICE_STATISTICS_RS_C_SYNC_RATE,
+ s->peer_dev_rs_c_sync_rate) ||
+ drbd2_put_u64(skb, DRBD2_A_PEER_DEVICE_STATISTICS_UUID_FLAGS,
+ s->peer_dev_uuid_flags))
+ goto fail;
+ nla_nest_end(skb, nla);
+ return 0;
+
+fail:
+ nla_nest_cancel(skb, nla);
+ return -EMSGSIZE;
+}
+
+static int drbd2_put_path_info(struct sk_buff *skb, int attrtype,
+ struct drbd_nl_path_info *info)
+{
+ struct nlattr *nla = nla_nest_start(skb, attrtype);
+
+ if (!nla)
+ return -EMSGSIZE;
+ if (nla_put_u8(skb, DRBD2_A_PATH_INFO_ESTABLISHED, info->path_established))
+ goto fail;
+ nla_nest_end(skb, nla);
+ return 0;
+
+fail:
+ nla_nest_cancel(skb, nla);
+ return -EMSGSIZE;
+}
+
+/*
+ * The configuration of a live object, for the dumps. The notifications
+ * describe state changes and carry no configuration, so they pass NULL.
+ */
+
+static int drbd2_put_res_opts(struct sk_buff *skb, int attrtype, struct drbd_res_opts *c)
+{
+ struct nlattr *nla = nla_nest_start(skb, attrtype);
+
+ if (!nla)
+ return -EMSGSIZE;
+ if (drbd2_put_str(skb, DRBD2_A_RESOURCE_OPTS_CPU_MASK, c->cpu_mask,
+ c->cpu_mask_len, sizeof(c->cpu_mask)) ||
+ nla_put_u32(skb, DRBD2_A_RESOURCE_OPTS_ON_NO_DATA_ACCESSIBLE, c->on_no_data) ||
+ nla_put_u8(skb, DRBD2_A_RESOURCE_OPTS_AUTO_PROMOTE, c->auto_promote) ||
+ nla_put_u32(skb, DRBD2_A_RESOURCE_OPTS_NODE_ID, c->node_id) ||
+ nla_put_u32(skb, DRBD2_A_RESOURCE_OPTS_PEER_ACK_WINDOW, c->peer_ack_window) ||
+ nla_put_u32(skb, DRBD2_A_RESOURCE_OPTS_TWOPC_TIMEOUT, c->twopc_timeout) ||
+ nla_put_u32(skb, DRBD2_A_RESOURCE_OPTS_TWOPC_RETRY_TIMEOUT,
+ c->twopc_retry_timeout) ||
+ nla_put_u32(skb, DRBD2_A_RESOURCE_OPTS_PEER_ACK_DELAY, c->peer_ack_delay) ||
+ nla_put_u32(skb, DRBD2_A_RESOURCE_OPTS_AUTO_PROMOTE_TIMEOUT,
+ c->auto_promote_timeout) ||
+ nla_put_u32(skb, DRBD2_A_RESOURCE_OPTS_MAX_IO_DEPTH, c->nr_requests) ||
+ nla_put_s32(skb, DRBD2_A_RESOURCE_OPTS_QUORUM, c->quorum) ||
+ nla_put_u32(skb, DRBD2_A_RESOURCE_OPTS_ON_NO_QUORUM, c->on_no_quorum) ||
+ nla_put_s32(skb, DRBD2_A_RESOURCE_OPTS_QUORUM_MIN_REDUNDANCY,
+ c->quorum_min_redundancy) ||
+ nla_put_u32(skb, DRBD2_A_RESOURCE_OPTS_ON_SUSPENDED_PRIMARY_OUTDATED,
+ c->on_susp_primary_outdated) ||
+ nla_put_u8(skb, DRBD2_A_RESOURCE_OPTS_DRBD8_COMPAT_MODE, c->drbd8_compat_mode) ||
+ nla_put_u8(skb, DRBD2_A_RESOURCE_OPTS_EXPLICIT_DRBD8_COMPAT,
+ c->explicit_drbd8_compat))
+ goto fail;
+ nla_nest_end(skb, nla);
+ return 0;
+
+fail:
+ nla_nest_cancel(skb, nla);
+ return -EMSGSIZE;
+}
+
+static int drbd2_put_disk_conf(struct sk_buff *skb, int attrtype, struct drbd_disk_conf *c)
+{
+ struct nlattr *nla = nla_nest_start(skb, attrtype);
+
+ if (!nla)
+ return -EMSGSIZE;
+ if (drbd2_put_str(skb, DRBD2_A_DISK_CONF_BACKING_DEV, c->backing_dev,
+ c->backing_dev_len, sizeof(c->backing_dev)) ||
+ drbd2_put_str(skb, DRBD2_A_DISK_CONF_META_DEV, c->meta_dev,
+ c->meta_dev_len, sizeof(c->meta_dev)) ||
+ nla_put_s32(skb, DRBD2_A_DISK_CONF_META_DEV_IDX, c->meta_dev_idx) ||
+ drbd2_put_u64(skb, DRBD2_A_DISK_CONF_SIZE, c->disk_size) ||
+ nla_put_u32(skb, DRBD2_A_DISK_CONF_ON_IO_ERROR, c->on_io_error) ||
+ nla_put_s32(skb, DRBD2_A_DISK_CONF_RESYNC_AFTER, c->resync_after) ||
+ nla_put_u32(skb, DRBD2_A_DISK_CONF_AL_EXTENTS, c->al_extents) ||
+ nla_put_u8(skb, DRBD2_A_DISK_CONF_DISK_BARRIER, c->disk_barrier) ||
+ nla_put_u8(skb, DRBD2_A_DISK_CONF_DISK_FLUSHES, c->disk_flushes) ||
+ nla_put_u8(skb, DRBD2_A_DISK_CONF_DISK_DRAIN, c->disk_drain) ||
+ nla_put_u8(skb, DRBD2_A_DISK_CONF_MD_FLUSHES, c->md_flushes) ||
+ nla_put_u32(skb, DRBD2_A_DISK_CONF_DISK_TIMEOUT, c->disk_timeout) ||
+ nla_put_u32(skb, DRBD2_A_DISK_CONF_READ_BALANCING, c->read_balancing) ||
+ nla_put_u32(skb, DRBD2_A_DISK_CONF_UNPLUG_WATERMARK, c->unplug_watermark) ||
+ nla_put_u32(skb, DRBD2_A_DISK_CONF_RS_DISCARD_GRANULARITY,
+ c->rs_discard_granularity) ||
+ nla_put_u8(skb, DRBD2_A_DISK_CONF_AL_UPDATES, c->al_updates) ||
+ nla_put_u8(skb, DRBD2_A_DISK_CONF_DISCARD_ZEROES_IF_ALIGNED,
+ c->discard_zeroes_if_aligned) ||
+ nla_put_u8(skb, DRBD2_A_DISK_CONF_DISABLE_WRITE_SAME, c->disable_write_same) ||
+ nla_put_u8(skb, DRBD2_A_DISK_CONF_BITMAP, c->d_bitmap))
+ goto fail;
+ nla_nest_end(skb, nla);
+ return 0;
+
+fail:
+ nla_nest_cancel(skb, nla);
+ return -EMSGSIZE;
+}
+
+/*
+ * The caller decides what the reader may see: the dump hands us a copy
+ * with the shared secret cleared unless the reader has CAP_SYS_ADMIN.
+ */
+static int drbd2_put_net_conf(struct sk_buff *skb, int attrtype, struct drbd_net_conf *c)
+{
+ struct nlattr *nla = nla_nest_start(skb, attrtype);
+
+ if (!nla)
+ return -EMSGSIZE;
+ if (drbd2_put_str(skb, DRBD2_A_NET_CONF_SHARED_SECRET, c->shared_secret,
+ c->shared_secret_len, sizeof(c->shared_secret)) ||
+ drbd2_put_str(skb, DRBD2_A_NET_CONF_CRAM_HMAC_ALG, c->cram_hmac_alg,
+ c->cram_hmac_alg_len, sizeof(c->cram_hmac_alg)) ||
+ drbd2_put_str(skb, DRBD2_A_NET_CONF_INTEGRITY_ALG, c->integrity_alg,
+ c->integrity_alg_len, sizeof(c->integrity_alg)) ||
+ drbd2_put_str(skb, DRBD2_A_NET_CONF_VERIFY_ALG, c->verify_alg,
+ c->verify_alg_len, sizeof(c->verify_alg)) ||
+ drbd2_put_str(skb, DRBD2_A_NET_CONF_CSUMS_ALG, c->csums_alg,
+ c->csums_alg_len, sizeof(c->csums_alg)) ||
+ nla_put_u32(skb, DRBD2_A_NET_CONF_PROTOCOL, c->wire_protocol) ||
+ nla_put_u32(skb, DRBD2_A_NET_CONF_CONNECT_INT, c->connect_int) ||
+ nla_put_u32(skb, DRBD2_A_NET_CONF_TIMEOUT, c->timeout) ||
+ nla_put_u32(skb, DRBD2_A_NET_CONF_PING_INT, c->ping_int) ||
+ nla_put_u32(skb, DRBD2_A_NET_CONF_PING_TIMEO, c->ping_timeo) ||
+ nla_put_u32(skb, DRBD2_A_NET_CONF_SNDBUF_SIZE, c->sndbuf_size) ||
+ nla_put_u32(skb, DRBD2_A_NET_CONF_RCVBUF_SIZE, c->rcvbuf_size) ||
+ nla_put_u32(skb, DRBD2_A_NET_CONF_KO_COUNT, c->ko_count) ||
+ nla_put_u32(skb, DRBD2_A_NET_CONF_MAX_EPOCH_SIZE, c->max_epoch_size) ||
+ nla_put_u32(skb, DRBD2_A_NET_CONF_AFTER_SB_0PRI, c->after_sb_0p) ||
+ nla_put_u32(skb, DRBD2_A_NET_CONF_AFTER_SB_1PRI, c->after_sb_1p) ||
+ nla_put_u32(skb, DRBD2_A_NET_CONF_AFTER_SB_2PRI, c->after_sb_2p) ||
+ nla_put_u32(skb, DRBD2_A_NET_CONF_RR_CONFLICT, c->rr_conflict) ||
+ nla_put_u32(skb, DRBD2_A_NET_CONF_ON_CONGESTION, c->on_congestion) ||
+ nla_put_u32(skb, DRBD2_A_NET_CONF_CONG_FILL, c->cong_fill) ||
+ nla_put_u32(skb, DRBD2_A_NET_CONF_CONG_EXTENTS, c->cong_extents) ||
+ nla_put_u8(skb, DRBD2_A_NET_CONF_TWO_PRIMARIES, c->two_primaries) ||
+ nla_put_u8(skb, DRBD2_A_NET_CONF_TCP_CORK, c->tcp_cork) ||
+ nla_put_u8(skb, DRBD2_A_NET_CONF_ALWAYS_ASBP, c->always_asbp) ||
+ nla_put_u8(skb, DRBD2_A_NET_CONF_USE_RLE, c->use_rle) ||
+ nla_put_u32(skb, DRBD2_A_NET_CONF_FENCING, c->fencing_policy) ||
+ drbd2_put_str(skb, DRBD2_A_NET_CONF_CONNECTION_NAME, c->name,
+ c->name_len, sizeof(c->name)) ||
+ nla_put_u8(skb, DRBD2_A_NET_CONF_CSUMS_AFTER_CRASH_ONLY,
+ c->csums_after_crash_only) ||
+ nla_put_u32(skb, DRBD2_A_NET_CONF_SOCK_CHECK_TIMEO, c->sock_check_timeo) ||
+ drbd2_put_str(skb, DRBD2_A_NET_CONF_TRANSPORT_NAME, c->transport_name,
+ c->transport_name_len, sizeof(c->transport_name)) ||
+ nla_put_u32(skb, DRBD2_A_NET_CONF_MAX_BUFFERS, c->max_buffers) ||
+ nla_put_u8(skb, DRBD2_A_NET_CONF_ALLOW_REMOTE_READ, c->allow_remote_read) ||
+ nla_put_u8(skb, DRBD2_A_NET_CONF_TLS, c->tls) ||
+ nla_put_s32(skb, DRBD2_A_NET_CONF_TLS_PRIVKEY, c->tls_privkey) ||
+ nla_put_s32(skb, DRBD2_A_NET_CONF_TLS_CERTIFICATE, c->tls_certificate) ||
+ nla_put_s32(skb, DRBD2_A_NET_CONF_TLS_KEYRING, c->tls_keyring) ||
+ nla_put_u8(skb, DRBD2_A_NET_CONF_LOAD_BALANCE_PATHS, c->load_balance_paths) ||
+ nla_put_u32(skb, DRBD2_A_NET_CONF_RDMA_CTRL_RCVBUF_SIZE,
+ c->rdma_ctrl_rcvbuf_size) ||
+ nla_put_u32(skb, DRBD2_A_NET_CONF_RDMA_CTRL_SNDBUF_SIZE,
+ c->rdma_ctrl_sndbuf_size))
+ goto fail;
+ nla_nest_end(skb, nla);
+ return 0;
+
+fail:
+ nla_nest_cancel(skb, nla);
+ return -EMSGSIZE;
+}
+
+static int drbd2_put_device_conf(struct sk_buff *skb, int attrtype, struct drbd_device_conf *c)
+{
+ struct nlattr *nla = nla_nest_start(skb, attrtype);
+
+ if (!nla)
+ return -EMSGSIZE;
+ if (nla_put_u32(skb, DRBD2_A_DEVICE_CONF_MAX_BIO_SIZE, c->max_bio_size) ||
+ nla_put_u8(skb, DRBD2_A_DEVICE_CONF_INTENTIONAL_DISKLESS,
+ c->intentional_diskless) ||
+ nla_put_u32(skb, DRBD2_A_DEVICE_CONF_BLOCK_SIZE, c->block_size) ||
+ nla_put_u32(skb, DRBD2_A_DEVICE_CONF_DISCARD_GRANULARITY,
+ c->discard_granularity))
+ goto fail;
+ nla_nest_end(skb, nla);
+ return 0;
+
+fail:
+ nla_nest_cancel(skb, nla);
+ return -EMSGSIZE;
+}
+
+static int drbd2_put_peer_device_conf(struct sk_buff *skb, int attrtype,
+ struct drbd_peer_device_conf *c)
+{
+ struct nlattr *nla = nla_nest_start(skb, attrtype);
+
+ if (!nla)
+ return -EMSGSIZE;
+ if (nla_put_u32(skb, DRBD2_A_PEER_DEVICE_CONF_RESYNC_RATE, c->resync_rate) ||
+ nla_put_u32(skb, DRBD2_A_PEER_DEVICE_CONF_C_PLAN_AHEAD, c->c_plan_ahead) ||
+ nla_put_u32(skb, DRBD2_A_PEER_DEVICE_CONF_C_DELAY_TARGET, c->c_delay_target) ||
+ nla_put_u32(skb, DRBD2_A_PEER_DEVICE_CONF_C_FILL_TARGET, c->c_fill_target) ||
+ nla_put_u32(skb, DRBD2_A_PEER_DEVICE_CONF_C_MAX_RATE, c->c_max_rate) ||
+ nla_put_u32(skb, DRBD2_A_PEER_DEVICE_CONF_C_MIN_RATE, c->c_min_rate) ||
+ nla_put_u8(skb, DRBD2_A_PEER_DEVICE_CONF_BITMAP, c->bitmap) ||
+ nla_put_u8(skb, DRBD2_A_PEER_DEVICE_CONF_RESYNC_WITHOUT_REPLICATION,
+ c->resync_without_replication) ||
+ nla_put_u8(skb, DRBD2_A_PEER_DEVICE_CONF_PEER_TIEBREAKER, c->peer_tiebreaker))
+ goto fail;
+ nla_nest_end(skb, nla);
+ return 0;
+
+fail:
+ nla_nest_cancel(skb, nla);
+ return -EMSGSIZE;
+}
+
+/*
+ * The paths of a connection, one attribute each, carried inside the
+ * connection nest as the legacy family carried them inside its
+ * connection message. Only the addresses identify a path here; the
+ * enclosing nest already names the resource and the peer.
+ */
+static int drbd2_put_connection_paths(struct sk_buff *skb,
+ struct drbd_connection *connection)
+{
+ struct drbd_path *path;
+ int err = 0;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(path, &connection->transport.paths, list) {
+ struct drbd_nl_path_info info = {
+ .path_established = test_bit(TR_ESTABLISHED, &path->flags),
+ };
+ struct nlattr *nla = nla_nest_start(skb, DRBD2_A_CONNECTION_PATH);
+
+ if (!nla) {
+ err = -EMSGSIZE;
+ break;
+ }
+ if (drbd2_put_context(skb, DRBD2_A_PATH_CONTEXT, NULL, NULL, NULL, path) ||
+ drbd2_put_path_info(skb, DRBD2_A_PATH_INFO, &info)) {
+ nla_nest_cancel(skb, nla);
+ err = -EMSGSIZE;
+ break;
+ }
+ nla_nest_end(skb, nla);
+ }
+ rcu_read_unlock();
+ return err;
+}
+
+/*
+ * The object nests shared by the dumps and the state change messages:
+ * one nest per object type, holding its context, state and statistics.
+ */
+
+static int drbd2_put_resource(struct sk_buff *skb, int attrtype,
+ struct drbd_resource *resource,
+ struct drbd_res_opts *res_opts,
+ struct drbd_resource_info *info,
+ struct drbd_resource_statistics *statistics,
+ struct drbd_rename_resource_info *rename_info)
+{
+ struct nlattr *nla = nla_nest_start(skb, attrtype);
+
+ if (!nla)
+ return -EMSGSIZE;
+ if (drbd2_put_context(skb, DRBD2_A_RESOURCE_CONTEXT, resource, NULL, NULL, NULL))
+ goto fail;
+ if (info && drbd2_put_resource_info(skb, DRBD2_A_RESOURCE_INFO, info))
+ goto fail;
+ if (statistics &&
+ drbd2_put_resource_statistics(skb, DRBD2_A_RESOURCE_STATISTICS, statistics))
+ goto fail;
+ if (rename_info &&
+ drbd2_put_str(skb, DRBD2_A_RESOURCE_NEW_NAME, rename_info->res_new_name,
+ rename_info->res_new_name_len, sizeof(rename_info->res_new_name)))
+ goto fail;
+ if (res_opts && drbd2_put_res_opts(skb, DRBD2_A_RESOURCE_RESOURCE_OPTS, res_opts))
+ goto fail;
+ nla_nest_end(skb, nla);
+ return 0;
+
+fail:
+ nla_nest_cancel(skb, nla);
+ return -EMSGSIZE;
+}
+
+static int drbd2_put_device(struct sk_buff *skb, int attrtype,
+ struct drbd_device *device,
+ struct drbd_disk_conf *disk_conf,
+ struct drbd_device_conf *device_conf,
+ struct drbd_device_info *info,
+ struct drbd_device_statistics *statistics)
+{
+ struct nlattr *nla = nla_nest_start(skb, attrtype);
+
+ if (!nla)
+ return -EMSGSIZE;
+ if (drbd2_put_context(skb, DRBD2_A_DEVICE_CONTEXT, device->resource, NULL, device, NULL))
+ goto fail;
+ if (info && drbd2_put_device_info(skb, DRBD2_A_DEVICE_INFO, info))
+ goto fail;
+ if (statistics &&
+ drbd2_put_device_statistics(skb, DRBD2_A_DEVICE_STATISTICS, statistics))
+ goto fail;
+ if (disk_conf && drbd2_put_disk_conf(skb, DRBD2_A_DEVICE_DISK_CONF, disk_conf))
+ goto fail;
+ if (device_conf &&
+ drbd2_put_device_conf(skb, DRBD2_A_DEVICE_DEVICE_CONF, device_conf))
+ goto fail;
+ nla_nest_end(skb, nla);
+ return 0;
+
+fail:
+ nla_nest_cancel(skb, nla);
+ return -EMSGSIZE;
+}
+
+static int drbd2_put_connection(struct sk_buff *skb, int attrtype,
+ struct drbd_resource *resource,
+ struct drbd_connection *connection,
+ struct drbd_net_conf *net_conf,
+ struct drbd_connection_info *info,
+ struct drbd_connection_statistics *statistics)
+{
+ struct nlattr *nla = nla_nest_start(skb, attrtype);
+
+ if (!nla)
+ return -EMSGSIZE;
+ if (drbd2_put_context(skb, DRBD2_A_CONNECTION_CONTEXT, resource, connection, NULL, NULL))
+ goto fail;
+ if (info && drbd2_put_connection_info(skb, DRBD2_A_CONNECTION_INFO, info))
+ goto fail;
+ if (statistics &&
+ drbd2_put_connection_statistics(skb, DRBD2_A_CONNECTION_STATISTICS, statistics))
+ goto fail;
+ if (net_conf && drbd2_put_net_conf(skb, DRBD2_A_CONNECTION_NET_CONF, net_conf))
+ goto fail;
+ if (drbd2_put_connection_paths(skb, connection))
+ goto fail;
+ nla_nest_end(skb, nla);
+ return 0;
+
+fail:
+ nla_nest_cancel(skb, nla);
+ return -EMSGSIZE;
+}
+
+static int drbd2_put_peer_device(struct sk_buff *skb, int attrtype,
+ struct drbd_peer_device *peer_device,
+ struct drbd_peer_device_conf *conf,
+ struct drbd_peer_device_info *info,
+ struct drbd_peer_device_statistics *statistics)
+{
+ struct drbd_device *device = peer_device->device;
+ struct nlattr *nla = nla_nest_start(skb, attrtype);
+
+ if (!nla)
+ return -EMSGSIZE;
+ if (drbd2_put_context(skb, DRBD2_A_PEER_DEVICE_CONTEXT, device->resource,
+ peer_device->connection, device, NULL))
+ goto fail;
+ if (info && drbd2_put_peer_device_info(skb, DRBD2_A_PEER_DEVICE_INFO, info))
+ goto fail;
+ if (statistics &&
+ drbd2_put_peer_device_statistics(skb, DRBD2_A_PEER_DEVICE_STATISTICS, statistics))
+ goto fail;
+ if (conf &&
+ drbd2_put_peer_device_conf(skb, DRBD2_A_PEER_DEVICE_PEER_DEVICE_CONF, conf))
+ goto fail;
+ nla_nest_end(skb, nla);
+ return 0;
+
+fail:
+ nla_nest_cancel(skb, nla);
+ return -EMSGSIZE;
+}
+
+static int drbd2_put_path(struct sk_buff *skb, int attrtype,
+ struct drbd_resource *resource,
+ struct drbd_connection *connection,
+ struct drbd_path *path,
+ struct drbd_nl_path_info *info)
+{
+ struct nlattr *nla = nla_nest_start(skb, attrtype);
+
+ if (!nla)
+ return -EMSGSIZE;
+ if (drbd2_put_context(skb, DRBD2_A_PATH_CONTEXT, resource, connection, NULL, path))
+ goto fail;
+ if (info && drbd2_put_path_info(skb, DRBD2_A_PATH_INFO, info))
+ goto fail;
+ nla_nest_end(skb, nla);
+ return 0;
+
+fail:
+ nla_nest_cancel(skb, nla);
+ return -EMSGSIZE;
+}
+
+/*
+ * pre_doit / post_doit.
+ */
+
+/* Which objects a command needs resolved, indexed by DRBD2_CMD_*. */
+static const unsigned int drbd2_cmd_flags[] = {
+ [DRBD2_CMD_RESOURCE_NEW] = 0,
+ [DRBD2_CMD_RESOURCE_DEL] = DRBD_ADM_NEED_RESOURCE,
+ [DRBD2_CMD_RESOURCE_SET] = DRBD_ADM_NEED_RESOURCE,
+ [DRBD2_CMD_RESOURCE_RENAME] = DRBD_ADM_NEED_RESOURCE,
+ [DRBD2_CMD_RESOURCE_DOWN] = DRBD_ADM_NEED_RESOURCE,
+ [DRBD2_CMD_RESOURCE_PRIMARY] = DRBD_ADM_NEED_RESOURCE,
+ [DRBD2_CMD_RESOURCE_SECONDARY] = DRBD_ADM_NEED_RESOURCE,
+ /* both act on all devices of the resource, but reach it via a minor */
+ [DRBD2_CMD_RESOURCE_SUSPEND_IO] = DRBD_ADM_NEED_MINOR,
+ [DRBD2_CMD_RESOURCE_RESUME_IO] = DRBD_ADM_NEED_MINOR,
+ [DRBD2_CMD_DEVICE_NEW] = DRBD_ADM_NEED_RESOURCE,
+ [DRBD2_CMD_DEVICE_DEL] = DRBD_ADM_NEED_MINOR,
+ [DRBD2_CMD_DEVICE_ATTACH] = DRBD_ADM_NEED_MINOR,
+ [DRBD2_CMD_DEVICE_DETACH] = DRBD_ADM_NEED_MINOR,
+ [DRBD2_CMD_DISK_SET] = DRBD_ADM_NEED_MINOR,
+ [DRBD2_CMD_DEVICE_RESIZE] = DRBD_ADM_NEED_MINOR,
+ [DRBD2_CMD_DEVICE_OUTDATE] = DRBD_ADM_NEED_MINOR,
+ [DRBD2_CMD_DEVICE_INVALIDATE] = DRBD_ADM_NEED_MINOR,
+ [DRBD2_CMD_DEVICE_NEW_CURRENT_UUID] = DRBD_ADM_NEED_MINOR,
+ [DRBD2_CMD_CONNECTION_NEW] = DRBD_ADM_NEED_PEER_NODE,
+ [DRBD2_CMD_CONNECTION_DEL] = DRBD_ADM_NEED_CONNECTION,
+ [DRBD2_CMD_CONNECTION_CONNECT] = DRBD_ADM_NEED_CONNECTION,
+ [DRBD2_CMD_CONNECTION_DISCONNECT] = DRBD_ADM_NEED_CONNECTION,
+ [DRBD2_CMD_CONNECTION_SET] = DRBD_ADM_NEED_CONNECTION,
+ /* the peer to forget must not have a connection any more */
+ [DRBD2_CMD_CONNECTION_FORGET] = DRBD_ADM_NEED_RESOURCE,
+ [DRBD2_CMD_PATH_NEW] = DRBD_ADM_NEED_CONNECTION,
+ [DRBD2_CMD_PATH_DEL] = DRBD_ADM_NEED_CONNECTION,
+ [DRBD2_CMD_PEER_DEVICE_SET] = DRBD_ADM_NEED_PEER_DEVICE,
+ [DRBD2_CMD_PEER_DEVICE_INVALIDATE] = DRBD_ADM_NEED_PEER_DEVICE,
+ [DRBD2_CMD_PEER_DEVICE_PAUSE_SYNC] = DRBD_ADM_NEED_PEER_DEVICE,
+ [DRBD2_CMD_PEER_DEVICE_RESUME_SYNC] = DRBD_ADM_NEED_PEER_DEVICE,
+ [DRBD2_CMD_PEER_DEVICE_START_OV] = DRBD_ADM_NEED_PEER_DEVICE,
+ [DRBD2_CMD_TIMEOUT_TYPE_GET] = DRBD_ADM_NEED_PEER_DEVICE,
+};
+
+/* Fill in the identity of the object the request refers to. */
+static int drbd2_parse_context(struct drbd_adm_ctx *ctx, struct genl_info *info)
+{
+ struct nlattr *tb[DRBD2_A_CONTEXT_PEER_ADDRESS + 1];
+ int err;
+
+ ctx->minor = MINORMASK + 1; /* no such minor */
+ ctx->volume = VOLUME_UNSPECIFIED;
+ ctx->peer_node_id = PEER_NODE_ID_UNSPECIFIED;
+
+ if (!info->attrs[DRBD2_A_CONTEXT])
+ return 0;
+
+ err = nla_parse_nested(tb, DRBD2_A_CONTEXT_PEER_ADDRESS,
+ info->attrs[DRBD2_A_CONTEXT],
+ drbd2_context_nl_policy, info->extack);
+ if (err)
+ return err;
+
+ if (tb[DRBD2_A_CONTEXT_MINOR])
+ ctx->minor = nla_get_u32(tb[DRBD2_A_CONTEXT_MINOR]);
+ if (tb[DRBD2_A_CONTEXT_VOLUME])
+ ctx->volume = nla_get_u32(tb[DRBD2_A_CONTEXT_VOLUME]);
+ if (tb[DRBD2_A_CONTEXT_PEER_NODE_ID])
+ ctx->peer_node_id = nla_get_u32(tb[DRBD2_A_CONTEXT_PEER_NODE_ID]);
+ if (tb[DRBD2_A_CONTEXT_RESOURCE_NAME])
+ ctx->resource_name = nla_data(tb[DRBD2_A_CONTEXT_RESOURCE_NAME]);
+ return 0;
+}
+
+/*
+ * Allocates the command context together with the drbd2 request state,
+ * stores it in info->user_ptr[0], prepares the reply message and resolves
+ * the objects the command refers to. A failure here means post_doit is
+ * not called, so everything is cleaned up before returning.
+ */
+int drbd2_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
+ struct genl_info *info)
+{
+ const u8 cmd = info->genlhdr->cmd;
+ struct drbd_adm_ctx *adm_ctx;
+ struct drbd2_ctx *dctx;
+ struct drbd2_req *req;
+ unsigned int flags;
+ int err;
+
+ /*
+ * genl_rcv_msg() checked CAP_NET_ADMIN for the commands with the
+ * admin-perm flag; as in the legacy family, configuring DRBD also
+ * requires CAP_SYS_ADMIN.
+ */
+ if ((ops->flags & GENL_ADMIN_PERM) && !capable(CAP_SYS_ADMIN)) {
+ GENL_SET_ERR_MSG(info, "CAP_SYS_ADMIN required");
+ return -EPERM;
+ }
+
+ dctx = kzalloc_obj(struct drbd2_ctx);
+ if (!dctx)
+ return -ENOMEM;
+
+ adm_ctx = &dctx->ctx;
+ req = &dctx->req;
+ adm_ctx->d = &drbd2_dialect;
+ adm_ctx->req = req;
+ adm_ctx->result = NO_ERROR;
+ adm_ctx->net = sock_net(skb->sk);
+ /*
+ * Only the *-set commands accept set-defaults; genl sizes info->attrs
+ * to the maxattr of the command, so do not index past it elsewhere.
+ */
+ adm_ctx->set_defaults = ops->maxattr >= DRBD2_A_SET_DEFAULTS &&
+ info->attrs[DRBD2_A_SET_DEFAULTS];
+ req->info = info;
+
+ err = drbd2_parse_context(adm_ctx, info);
+ if (err)
+ goto fail;
+
+ req->reply_skb = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+ if (!req->reply_skb) {
+ err = -ENOMEM;
+ goto fail;
+ }
+ req->reply_hdr = genlmsg_put_reply(req->reply_skb, info,
+ &drbd2_nl_family, 0, cmd);
+ if (!req->reply_hdr) {
+ err = -EMSGSIZE;
+ goto fail;
+ }
+
+ flags = cmd < ARRAY_SIZE(drbd2_cmd_flags) ? drbd2_cmd_flags[cmd] : 0;
+ if (drbd_adm_ctx_resolve(adm_ctx, flags) != NO_ERROR) {
+ err = drbd2_errno(adm_ctx->result);
+ drbd2_set_extack(info, adm_ctx);
+ drbd_adm_ctx_release(adm_ctx);
+ goto fail;
+ }
+
+ info->user_ptr[0] = adm_ctx;
+ return 0;
+
+fail:
+ nlmsg_free(req->reply_skb);
+ kfree(dctx);
+ info->user_ptr[0] = NULL;
+ return err;
+}
+
+/*
+ * Sends the reply, drops the references acquired while resolving, and
+ * frees the context. The reply is gone when the command failed with an
+ * ERR_* code; the errno and the extended ACK describe that instead.
+ */
+void drbd2_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
+ struct genl_info *info)
+{
+ struct drbd_adm_ctx *adm_ctx = info->user_ptr[0];
+ struct drbd2_req *req;
+
+ if (!adm_ctx)
+ return;
+
+ req = drbd2_req(adm_ctx);
+ if (req->reply_skb) {
+ drbd2_put_outcome(adm_ctx);
+ genlmsg_end(req->reply_skb, req->reply_hdr);
+ if (genlmsg_reply(req->reply_skb, info))
+ pr_err("error sending genl reply\n");
+ }
+
+ drbd_adm_ctx_release(adm_ctx);
+ kfree(container_of(adm_ctx, struct drbd2_ctx, ctx));
+}
+
+/*
+ * The attribute sets of a request.
+ */
+
+static bool drbd2_has_set(struct drbd_adm_ctx *ctx, enum drbd_nl_attr_set set)
+{
+ static const u16 tla[__DRBD_NL_SET_MAX] = {
+ [DRBD_NL_SET_DISK_CONF] = DRBD2_A_DISK_CONF,
+ [DRBD_NL_SET_NET_CONF] = DRBD2_A_NET_CONF,
+ [DRBD_NL_SET_RES_OPTS] = DRBD2_A_RESOURCE_OPTS,
+ [DRBD_NL_SET_PEER_DEVICE_CONF] = DRBD2_A_PEER_DEVICE_CONF,
+ [DRBD_NL_SET_DEVICE_CONF] = DRBD2_A_DEVICE_CONF,
+ [DRBD_NL_SET_SET_ROLE_PARMS] = DRBD2_A_SET_ROLE_PARMS,
+ [DRBD_NL_SET_RESIZE_PARMS] = DRBD2_A_RESIZE_PARMS,
+ [DRBD_NL_SET_START_OV_PARMS] = DRBD2_A_START_OV_PARMS,
+ [DRBD_NL_SET_NEW_C_UUID_PARMS] = DRBD2_A_NEW_CURRENT_UUID_PARMS,
+ [DRBD_NL_SET_DISCONNECT_PARMS] = DRBD2_A_DISCONNECT_PARMS,
+ [DRBD_NL_SET_DETACH_PARMS] = DRBD2_A_DETACH_PARMS,
+ [DRBD_NL_SET_INVALIDATE_PARMS] = DRBD2_A_INVALIDATE_PARMS,
+ [DRBD_NL_SET_INVALIDATE_PEER_PARMS] = DRBD2_A_INVALIDATE_PEER_PARMS,
+ [DRBD_NL_SET_CONNECT_PARMS] = DRBD2_A_CONNECT_PARMS,
+ [DRBD_NL_SET_RENAME_RESOURCE_PARMS] = DRBD2_A_RENAME_PARMS,
+ [DRBD_NL_SET_SUSPEND_IO_PARMS] = DRBD2_A_SUSPEND_IO_PARMS,
+ /* both are carried by the context nest of the request */
+ [DRBD_NL_SET_FORGET_PEER_PARMS] = DRBD2_A_CONTEXT,
+ [DRBD_NL_SET_PATH_PARMS] = DRBD2_A_CONTEXT,
+ };
+
+ return drbd2_req(ctx)->info->attrs[tla[set]] != NULL;
+}
+
+/*
+ * Parse the nest of "attrtype" into "tb". Returns -ENOMSG when the nest
+ * is not part of the request at all, which is what the core expects for
+ * a missing parameter set.
+ */
+static int drbd2_parse_set(struct drbd_adm_ctx *ctx, int attrtype, int maxtype,
+ const struct nla_policy *policy, struct nlattr **tb)
+{
+ struct genl_info *info = drbd2_req(ctx)->info;
+
+ if (!info->attrs[attrtype])
+ return -ENOMSG;
+ return nla_parse_nested(tb, maxtype, info->attrs[attrtype], policy,
+ info->extack);
+}
+
+#define DRBD2_PARSE_SET(ctx, name, NAME, tb) \
+ drbd2_parse_set((ctx), DRBD2_A_##NAME, ARRAY_SIZE(tb) - 1, \
+ drbd2_##name##_nl_policy, (tb))
+
+static int drbd2_overlay_disk_conf(struct drbd_adm_ctx *ctx, struct drbd_disk_conf *s)
+{
+ struct nlattr *tb[DRBD2_A_DISK_CONF_BITMAP + 1];
+ int err;
+
+ err = DRBD2_PARSE_SET(ctx, disk_conf, DISK_CONF, tb);
+ if (err)
+ return err;
+
+ /* the three attributes that describe the disk itself are required */
+ if (!tb[DRBD2_A_DISK_CONF_BACKING_DEV] || !tb[DRBD2_A_DISK_CONF_META_DEV] ||
+ !tb[DRBD2_A_DISK_CONF_META_DEV_IDX])
+ err = -ENOMSG;
+
+ if (tb[DRBD2_A_DISK_CONF_BACKING_DEV])
+ s->backing_dev_len = nla_strscpy(s->backing_dev,
+ tb[DRBD2_A_DISK_CONF_BACKING_DEV],
+ sizeof(s->backing_dev));
+ if (tb[DRBD2_A_DISK_CONF_META_DEV])
+ s->meta_dev_len = nla_strscpy(s->meta_dev, tb[DRBD2_A_DISK_CONF_META_DEV],
+ sizeof(s->meta_dev));
+ if (tb[DRBD2_A_DISK_CONF_META_DEV_IDX])
+ s->meta_dev_idx = nla_get_s32(tb[DRBD2_A_DISK_CONF_META_DEV_IDX]);
+ if (tb[DRBD2_A_DISK_CONF_SIZE])
+ s->disk_size = nla_get_u64(tb[DRBD2_A_DISK_CONF_SIZE]);
+ if (tb[DRBD2_A_DISK_CONF_ON_IO_ERROR])
+ s->on_io_error = nla_get_u32(tb[DRBD2_A_DISK_CONF_ON_IO_ERROR]);
+ if (tb[DRBD2_A_DISK_CONF_RESYNC_AFTER])
+ s->resync_after = nla_get_s32(tb[DRBD2_A_DISK_CONF_RESYNC_AFTER]);
+ if (tb[DRBD2_A_DISK_CONF_AL_EXTENTS])
+ s->al_extents = nla_get_u32(tb[DRBD2_A_DISK_CONF_AL_EXTENTS]);
+ if (tb[DRBD2_A_DISK_CONF_DISK_BARRIER])
+ s->disk_barrier = nla_get_u8(tb[DRBD2_A_DISK_CONF_DISK_BARRIER]);
+ if (tb[DRBD2_A_DISK_CONF_DISK_FLUSHES])
+ s->disk_flushes = nla_get_u8(tb[DRBD2_A_DISK_CONF_DISK_FLUSHES]);
+ if (tb[DRBD2_A_DISK_CONF_DISK_DRAIN])
+ s->disk_drain = nla_get_u8(tb[DRBD2_A_DISK_CONF_DISK_DRAIN]);
+ if (tb[DRBD2_A_DISK_CONF_MD_FLUSHES])
+ s->md_flushes = nla_get_u8(tb[DRBD2_A_DISK_CONF_MD_FLUSHES]);
+ if (tb[DRBD2_A_DISK_CONF_DISK_TIMEOUT])
+ s->disk_timeout = nla_get_u32(tb[DRBD2_A_DISK_CONF_DISK_TIMEOUT]);
+ if (tb[DRBD2_A_DISK_CONF_READ_BALANCING])
+ s->read_balancing = nla_get_u32(tb[DRBD2_A_DISK_CONF_READ_BALANCING]);
+ if (tb[DRBD2_A_DISK_CONF_UNPLUG_WATERMARK])
+ s->unplug_watermark = nla_get_u32(tb[DRBD2_A_DISK_CONF_UNPLUG_WATERMARK]);
+ if (tb[DRBD2_A_DISK_CONF_RS_DISCARD_GRANULARITY])
+ s->rs_discard_granularity =
+ nla_get_u32(tb[DRBD2_A_DISK_CONF_RS_DISCARD_GRANULARITY]);
+ if (tb[DRBD2_A_DISK_CONF_AL_UPDATES])
+ s->al_updates = nla_get_u8(tb[DRBD2_A_DISK_CONF_AL_UPDATES]);
+ if (tb[DRBD2_A_DISK_CONF_DISCARD_ZEROES_IF_ALIGNED])
+ s->discard_zeroes_if_aligned =
+ nla_get_u8(tb[DRBD2_A_DISK_CONF_DISCARD_ZEROES_IF_ALIGNED]);
+ if (tb[DRBD2_A_DISK_CONF_DISABLE_WRITE_SAME])
+ s->disable_write_same = nla_get_u8(tb[DRBD2_A_DISK_CONF_DISABLE_WRITE_SAME]);
+ if (tb[DRBD2_A_DISK_CONF_BITMAP])
+ s->d_bitmap = nla_get_u8(tb[DRBD2_A_DISK_CONF_BITMAP]);
+ return err;
+}
+
+static int drbd2_overlay_res_opts(struct drbd_adm_ctx *ctx, struct drbd_res_opts *s)
+{
+ struct nlattr *tb[DRBD2_A_RESOURCE_OPTS_EXPLICIT_DRBD8_COMPAT + 1];
+ int err;
+
+ err = DRBD2_PARSE_SET(ctx, resource_opts, RESOURCE_OPTS, tb);
+ if (err)
+ return err;
+
+ /* the node id identifies this node in the resource; it is required */
+ if (!tb[DRBD2_A_RESOURCE_OPTS_NODE_ID])
+ err = -ENOMSG;
+
+ if (tb[DRBD2_A_RESOURCE_OPTS_CPU_MASK])
+ s->cpu_mask_len = nla_strscpy(s->cpu_mask, tb[DRBD2_A_RESOURCE_OPTS_CPU_MASK],
+ sizeof(s->cpu_mask));
+ if (tb[DRBD2_A_RESOURCE_OPTS_ON_NO_DATA_ACCESSIBLE])
+ s->on_no_data = nla_get_u32(tb[DRBD2_A_RESOURCE_OPTS_ON_NO_DATA_ACCESSIBLE]);
+ if (tb[DRBD2_A_RESOURCE_OPTS_AUTO_PROMOTE])
+ s->auto_promote = nla_get_u8(tb[DRBD2_A_RESOURCE_OPTS_AUTO_PROMOTE]);
+ if (tb[DRBD2_A_RESOURCE_OPTS_NODE_ID])
+ s->node_id = nla_get_u32(tb[DRBD2_A_RESOURCE_OPTS_NODE_ID]);
+ if (tb[DRBD2_A_RESOURCE_OPTS_PEER_ACK_WINDOW])
+ s->peer_ack_window = nla_get_u32(tb[DRBD2_A_RESOURCE_OPTS_PEER_ACK_WINDOW]);
+ if (tb[DRBD2_A_RESOURCE_OPTS_TWOPC_TIMEOUT])
+ s->twopc_timeout = nla_get_u32(tb[DRBD2_A_RESOURCE_OPTS_TWOPC_TIMEOUT]);
+ if (tb[DRBD2_A_RESOURCE_OPTS_TWOPC_RETRY_TIMEOUT])
+ s->twopc_retry_timeout =
+ nla_get_u32(tb[DRBD2_A_RESOURCE_OPTS_TWOPC_RETRY_TIMEOUT]);
+ if (tb[DRBD2_A_RESOURCE_OPTS_PEER_ACK_DELAY])
+ s->peer_ack_delay = nla_get_u32(tb[DRBD2_A_RESOURCE_OPTS_PEER_ACK_DELAY]);
+ if (tb[DRBD2_A_RESOURCE_OPTS_AUTO_PROMOTE_TIMEOUT])
+ s->auto_promote_timeout =
+ nla_get_u32(tb[DRBD2_A_RESOURCE_OPTS_AUTO_PROMOTE_TIMEOUT]);
+ if (tb[DRBD2_A_RESOURCE_OPTS_MAX_IO_DEPTH])
+ s->nr_requests = nla_get_u32(tb[DRBD2_A_RESOURCE_OPTS_MAX_IO_DEPTH]);
+ if (tb[DRBD2_A_RESOURCE_OPTS_QUORUM])
+ s->quorum = nla_get_s32(tb[DRBD2_A_RESOURCE_OPTS_QUORUM]);
+ if (tb[DRBD2_A_RESOURCE_OPTS_ON_NO_QUORUM])
+ s->on_no_quorum = nla_get_u32(tb[DRBD2_A_RESOURCE_OPTS_ON_NO_QUORUM]);
+ if (tb[DRBD2_A_RESOURCE_OPTS_QUORUM_MIN_REDUNDANCY])
+ s->quorum_min_redundancy =
+ nla_get_s32(tb[DRBD2_A_RESOURCE_OPTS_QUORUM_MIN_REDUNDANCY]);
+ if (tb[DRBD2_A_RESOURCE_OPTS_ON_SUSPENDED_PRIMARY_OUTDATED])
+ s->on_susp_primary_outdated =
+ nla_get_u32(tb[DRBD2_A_RESOURCE_OPTS_ON_SUSPENDED_PRIMARY_OUTDATED]);
+ if (tb[DRBD2_A_RESOURCE_OPTS_DRBD8_COMPAT_MODE])
+ s->drbd8_compat_mode = nla_get_u8(tb[DRBD2_A_RESOURCE_OPTS_DRBD8_COMPAT_MODE]);
+ if (tb[DRBD2_A_RESOURCE_OPTS_EXPLICIT_DRBD8_COMPAT])
+ s->explicit_drbd8_compat =
+ nla_get_u8(tb[DRBD2_A_RESOURCE_OPTS_EXPLICIT_DRBD8_COMPAT]);
+ return err;
+}
+
+static int drbd2_overlay_net_conf(struct drbd_adm_ctx *ctx, struct drbd_net_conf *s)
+{
+ struct nlattr *tb[DRBD2_A_NET_CONF_RDMA_CTRL_SNDBUF_SIZE + 1];
+ int err;
+
+ err = DRBD2_PARSE_SET(ctx, net_conf, NET_CONF, tb);
+ if (err)
+ return err;
+
+ if (tb[DRBD2_A_NET_CONF_SHARED_SECRET])
+ s->shared_secret_len = nla_strscpy(s->shared_secret,
+ tb[DRBD2_A_NET_CONF_SHARED_SECRET],
+ sizeof(s->shared_secret));
+ if (tb[DRBD2_A_NET_CONF_CRAM_HMAC_ALG])
+ s->cram_hmac_alg_len = nla_strscpy(s->cram_hmac_alg,
+ tb[DRBD2_A_NET_CONF_CRAM_HMAC_ALG],
+ sizeof(s->cram_hmac_alg));
+ if (tb[DRBD2_A_NET_CONF_INTEGRITY_ALG])
+ s->integrity_alg_len = nla_strscpy(s->integrity_alg,
+ tb[DRBD2_A_NET_CONF_INTEGRITY_ALG],
+ sizeof(s->integrity_alg));
+ if (tb[DRBD2_A_NET_CONF_VERIFY_ALG])
+ s->verify_alg_len = nla_strscpy(s->verify_alg,
+ tb[DRBD2_A_NET_CONF_VERIFY_ALG],
+ sizeof(s->verify_alg));
+ if (tb[DRBD2_A_NET_CONF_CSUMS_ALG])
+ s->csums_alg_len = nla_strscpy(s->csums_alg, tb[DRBD2_A_NET_CONF_CSUMS_ALG],
+ sizeof(s->csums_alg));
+ if (tb[DRBD2_A_NET_CONF_PROTOCOL])
+ s->wire_protocol = nla_get_u32(tb[DRBD2_A_NET_CONF_PROTOCOL]);
+ if (tb[DRBD2_A_NET_CONF_CONNECT_INT])
+ s->connect_int = nla_get_u32(tb[DRBD2_A_NET_CONF_CONNECT_INT]);
+ if (tb[DRBD2_A_NET_CONF_TIMEOUT])
+ s->timeout = nla_get_u32(tb[DRBD2_A_NET_CONF_TIMEOUT]);
+ if (tb[DRBD2_A_NET_CONF_PING_INT])
+ s->ping_int = nla_get_u32(tb[DRBD2_A_NET_CONF_PING_INT]);
+ if (tb[DRBD2_A_NET_CONF_PING_TIMEO])
+ s->ping_timeo = nla_get_u32(tb[DRBD2_A_NET_CONF_PING_TIMEO]);
+ if (tb[DRBD2_A_NET_CONF_SNDBUF_SIZE])
+ s->sndbuf_size = nla_get_u32(tb[DRBD2_A_NET_CONF_SNDBUF_SIZE]);
+ if (tb[DRBD2_A_NET_CONF_RCVBUF_SIZE])
+ s->rcvbuf_size = nla_get_u32(tb[DRBD2_A_NET_CONF_RCVBUF_SIZE]);
+ if (tb[DRBD2_A_NET_CONF_KO_COUNT])
+ s->ko_count = nla_get_u32(tb[DRBD2_A_NET_CONF_KO_COUNT]);
+ if (tb[DRBD2_A_NET_CONF_MAX_EPOCH_SIZE])
+ s->max_epoch_size = nla_get_u32(tb[DRBD2_A_NET_CONF_MAX_EPOCH_SIZE]);
+ if (tb[DRBD2_A_NET_CONF_AFTER_SB_0PRI])
+ s->after_sb_0p = nla_get_u32(tb[DRBD2_A_NET_CONF_AFTER_SB_0PRI]);
+ if (tb[DRBD2_A_NET_CONF_AFTER_SB_1PRI])
+ s->after_sb_1p = nla_get_u32(tb[DRBD2_A_NET_CONF_AFTER_SB_1PRI]);
+ if (tb[DRBD2_A_NET_CONF_AFTER_SB_2PRI])
+ s->after_sb_2p = nla_get_u32(tb[DRBD2_A_NET_CONF_AFTER_SB_2PRI]);
+ if (tb[DRBD2_A_NET_CONF_RR_CONFLICT])
+ s->rr_conflict = nla_get_u32(tb[DRBD2_A_NET_CONF_RR_CONFLICT]);
+ if (tb[DRBD2_A_NET_CONF_ON_CONGESTION])
+ s->on_congestion = nla_get_u32(tb[DRBD2_A_NET_CONF_ON_CONGESTION]);
+ if (tb[DRBD2_A_NET_CONF_CONG_FILL])
+ s->cong_fill = nla_get_u32(tb[DRBD2_A_NET_CONF_CONG_FILL]);
+ if (tb[DRBD2_A_NET_CONF_CONG_EXTENTS])
+ s->cong_extents = nla_get_u32(tb[DRBD2_A_NET_CONF_CONG_EXTENTS]);
+ if (tb[DRBD2_A_NET_CONF_TWO_PRIMARIES])
+ s->two_primaries = nla_get_u8(tb[DRBD2_A_NET_CONF_TWO_PRIMARIES]);
+ if (tb[DRBD2_A_NET_CONF_TCP_CORK])
+ s->tcp_cork = nla_get_u8(tb[DRBD2_A_NET_CONF_TCP_CORK]);
+ if (tb[DRBD2_A_NET_CONF_ALWAYS_ASBP])
+ s->always_asbp = nla_get_u8(tb[DRBD2_A_NET_CONF_ALWAYS_ASBP]);
+ if (tb[DRBD2_A_NET_CONF_USE_RLE])
+ s->use_rle = nla_get_u8(tb[DRBD2_A_NET_CONF_USE_RLE]);
+ if (tb[DRBD2_A_NET_CONF_FENCING])
+ s->fencing_policy = nla_get_u32(tb[DRBD2_A_NET_CONF_FENCING]);
+ if (tb[DRBD2_A_NET_CONF_CONNECTION_NAME])
+ s->name_len = nla_strscpy(s->name, tb[DRBD2_A_NET_CONF_CONNECTION_NAME],
+ sizeof(s->name));
+ if (tb[DRBD2_A_NET_CONF_CSUMS_AFTER_CRASH_ONLY])
+ s->csums_after_crash_only =
+ nla_get_u8(tb[DRBD2_A_NET_CONF_CSUMS_AFTER_CRASH_ONLY]);
+ if (tb[DRBD2_A_NET_CONF_SOCK_CHECK_TIMEO])
+ s->sock_check_timeo = nla_get_u32(tb[DRBD2_A_NET_CONF_SOCK_CHECK_TIMEO]);
+ if (tb[DRBD2_A_NET_CONF_TRANSPORT_NAME])
+ s->transport_name_len = nla_strscpy(s->transport_name,
+ tb[DRBD2_A_NET_CONF_TRANSPORT_NAME],
+ sizeof(s->transport_name));
+ if (tb[DRBD2_A_NET_CONF_MAX_BUFFERS])
+ s->max_buffers = nla_get_u32(tb[DRBD2_A_NET_CONF_MAX_BUFFERS]);
+ if (tb[DRBD2_A_NET_CONF_ALLOW_REMOTE_READ])
+ s->allow_remote_read = nla_get_u8(tb[DRBD2_A_NET_CONF_ALLOW_REMOTE_READ]);
+ if (tb[DRBD2_A_NET_CONF_TLS])
+ s->tls = nla_get_u8(tb[DRBD2_A_NET_CONF_TLS]);
+ if (tb[DRBD2_A_NET_CONF_TLS_PRIVKEY])
+ s->tls_privkey = nla_get_s32(tb[DRBD2_A_NET_CONF_TLS_PRIVKEY]);
+ if (tb[DRBD2_A_NET_CONF_TLS_CERTIFICATE])
+ s->tls_certificate = nla_get_s32(tb[DRBD2_A_NET_CONF_TLS_CERTIFICATE]);
+ if (tb[DRBD2_A_NET_CONF_TLS_KEYRING])
+ s->tls_keyring = nla_get_s32(tb[DRBD2_A_NET_CONF_TLS_KEYRING]);
+ if (tb[DRBD2_A_NET_CONF_LOAD_BALANCE_PATHS])
+ s->load_balance_paths = nla_get_u8(tb[DRBD2_A_NET_CONF_LOAD_BALANCE_PATHS]);
+ if (tb[DRBD2_A_NET_CONF_RDMA_CTRL_RCVBUF_SIZE])
+ s->rdma_ctrl_rcvbuf_size =
+ nla_get_u32(tb[DRBD2_A_NET_CONF_RDMA_CTRL_RCVBUF_SIZE]);
+ if (tb[DRBD2_A_NET_CONF_RDMA_CTRL_SNDBUF_SIZE])
+ s->rdma_ctrl_sndbuf_size =
+ nla_get_u32(tb[DRBD2_A_NET_CONF_RDMA_CTRL_SNDBUF_SIZE]);
+ return 0;
+}
+
+static int drbd2_overlay_peer_device_conf(struct drbd_adm_ctx *ctx,
+ struct drbd_peer_device_conf *s)
+{
+ struct nlattr *tb[DRBD2_A_PEER_DEVICE_CONF_PEER_TIEBREAKER + 1];
+ int err;
+
+ err = DRBD2_PARSE_SET(ctx, peer_device_conf, PEER_DEVICE_CONF, tb);
+ if (err)
+ return err;
+
+ if (tb[DRBD2_A_PEER_DEVICE_CONF_RESYNC_RATE])
+ s->resync_rate = nla_get_u32(tb[DRBD2_A_PEER_DEVICE_CONF_RESYNC_RATE]);
+ if (tb[DRBD2_A_PEER_DEVICE_CONF_C_PLAN_AHEAD])
+ s->c_plan_ahead = nla_get_u32(tb[DRBD2_A_PEER_DEVICE_CONF_C_PLAN_AHEAD]);
+ if (tb[DRBD2_A_PEER_DEVICE_CONF_C_DELAY_TARGET])
+ s->c_delay_target = nla_get_u32(tb[DRBD2_A_PEER_DEVICE_CONF_C_DELAY_TARGET]);
+ if (tb[DRBD2_A_PEER_DEVICE_CONF_C_FILL_TARGET])
+ s->c_fill_target = nla_get_u32(tb[DRBD2_A_PEER_DEVICE_CONF_C_FILL_TARGET]);
+ if (tb[DRBD2_A_PEER_DEVICE_CONF_C_MAX_RATE])
+ s->c_max_rate = nla_get_u32(tb[DRBD2_A_PEER_DEVICE_CONF_C_MAX_RATE]);
+ if (tb[DRBD2_A_PEER_DEVICE_CONF_C_MIN_RATE])
+ s->c_min_rate = nla_get_u32(tb[DRBD2_A_PEER_DEVICE_CONF_C_MIN_RATE]);
+ if (tb[DRBD2_A_PEER_DEVICE_CONF_BITMAP])
+ s->bitmap = nla_get_u8(tb[DRBD2_A_PEER_DEVICE_CONF_BITMAP]);
+ if (tb[DRBD2_A_PEER_DEVICE_CONF_RESYNC_WITHOUT_REPLICATION])
+ s->resync_without_replication =
+ nla_get_u8(tb[DRBD2_A_PEER_DEVICE_CONF_RESYNC_WITHOUT_REPLICATION]);
+ if (tb[DRBD2_A_PEER_DEVICE_CONF_PEER_TIEBREAKER])
+ s->peer_tiebreaker = nla_get_u8(tb[DRBD2_A_PEER_DEVICE_CONF_PEER_TIEBREAKER]);
+ return 0;
+}
+
+static int drbd2_overlay_device_conf(struct drbd_adm_ctx *ctx, struct drbd_device_conf *s)
+{
+ struct nlattr *tb[DRBD2_A_DEVICE_CONF_DISCARD_GRANULARITY + 1];
+ int err;
+
+ err = DRBD2_PARSE_SET(ctx, device_conf, DEVICE_CONF, tb);
+ if (err)
+ return err;
+
+ if (tb[DRBD2_A_DEVICE_CONF_MAX_BIO_SIZE])
+ s->max_bio_size = nla_get_u32(tb[DRBD2_A_DEVICE_CONF_MAX_BIO_SIZE]);
+ if (tb[DRBD2_A_DEVICE_CONF_INTENTIONAL_DISKLESS])
+ s->intentional_diskless =
+ nla_get_u8(tb[DRBD2_A_DEVICE_CONF_INTENTIONAL_DISKLESS]);
+ if (tb[DRBD2_A_DEVICE_CONF_BLOCK_SIZE])
+ s->block_size = nla_get_u32(tb[DRBD2_A_DEVICE_CONF_BLOCK_SIZE]);
+ if (tb[DRBD2_A_DEVICE_CONF_DISCARD_GRANULARITY])
+ s->discard_granularity =
+ nla_get_u32(tb[DRBD2_A_DEVICE_CONF_DISCARD_GRANULARITY]);
+ return 0;
+}
+
+static int drbd2_overlay_set_role_parms(struct drbd_adm_ctx *ctx, struct drbd_set_role_parms *s)
+{
+ struct nlattr *tb[DRBD2_A_SET_ROLE_PARMS_FORCE + 1];
+ int err;
+
+ err = DRBD2_PARSE_SET(ctx, set_role_parms, SET_ROLE_PARMS, tb);
+ if (err)
+ return err;
+
+ s->force = !!tb[DRBD2_A_SET_ROLE_PARMS_FORCE];
+ return 0;
+}
+
+static int drbd2_overlay_resize_parms(struct drbd_adm_ctx *ctx, struct drbd_resize_parms *s)
+{
+ struct nlattr *tb[DRBD2_A_RESIZE_PARMS_AL_STRIPE_SIZE + 1];
+ int err;
+
+ err = DRBD2_PARSE_SET(ctx, resize_parms, RESIZE_PARMS, tb);
+ if (err)
+ return err;
+
+ if (tb[DRBD2_A_RESIZE_PARMS_SIZE])
+ s->resize_size = nla_get_u64(tb[DRBD2_A_RESIZE_PARMS_SIZE]);
+ s->resize_force = !!tb[DRBD2_A_RESIZE_PARMS_ASSUME_PEER_HAS_SPACE];
+ s->no_resync = !!tb[DRBD2_A_RESIZE_PARMS_ASSUME_CLEAN];
+ if (tb[DRBD2_A_RESIZE_PARMS_AL_STRIPES])
+ s->al_stripes = nla_get_u32(tb[DRBD2_A_RESIZE_PARMS_AL_STRIPES]);
+ if (tb[DRBD2_A_RESIZE_PARMS_AL_STRIPE_SIZE])
+ s->al_stripe_size = nla_get_u32(tb[DRBD2_A_RESIZE_PARMS_AL_STRIPE_SIZE]);
+ return 0;
+}
+
+static int drbd2_overlay_start_ov_parms(struct drbd_adm_ctx *ctx, struct drbd_start_ov_parms *s)
+{
+ struct nlattr *tb[DRBD2_A_START_OV_PARMS_STOP_SECTOR + 1];
+ int err;
+
+ err = DRBD2_PARSE_SET(ctx, start_ov_parms, START_OV_PARMS, tb);
+ if (err)
+ return err;
+
+ if (tb[DRBD2_A_START_OV_PARMS_START_SECTOR])
+ s->ov_start_sector = nla_get_u64(tb[DRBD2_A_START_OV_PARMS_START_SECTOR]);
+ if (tb[DRBD2_A_START_OV_PARMS_STOP_SECTOR])
+ s->ov_stop_sector = nla_get_u64(tb[DRBD2_A_START_OV_PARMS_STOP_SECTOR]);
+ return 0;
+}
+
+static int drbd2_overlay_new_c_uuid_parms(struct drbd_adm_ctx *ctx,
+ struct drbd_new_c_uuid_parms *s)
+{
+ struct nlattr *tb[DRBD2_A_NEW_CURRENT_UUID_PARMS_FORCE_RESYNC + 1];
+ int err;
+
+ err = DRBD2_PARSE_SET(ctx, new_current_uuid_parms, NEW_CURRENT_UUID_PARMS, tb);
+ if (err)
+ return err;
+
+ s->clear_bm = !!tb[DRBD2_A_NEW_CURRENT_UUID_PARMS_CLEAR_BM];
+ s->force_resync = !!tb[DRBD2_A_NEW_CURRENT_UUID_PARMS_FORCE_RESYNC];
+ return 0;
+}
+
+static int drbd2_overlay_disconnect_parms(struct drbd_adm_ctx *ctx,
+ struct drbd_disconnect_parms *s)
+{
+ struct nlattr *tb[DRBD2_A_DISCONNECT_PARMS_FORCE + 1];
+ int err;
+
+ err = DRBD2_PARSE_SET(ctx, disconnect_parms, DISCONNECT_PARMS, tb);
+ if (err)
+ return err;
+
+ s->force_disconnect = !!tb[DRBD2_A_DISCONNECT_PARMS_FORCE];
+ return 0;
+}
+
+static int drbd2_overlay_detach_parms(struct drbd_adm_ctx *ctx, struct drbd_detach_parms *s)
+{
+ struct nlattr *tb[DRBD2_A_DETACH_PARMS_INTENTIONAL_DISKLESS_DETACH + 1];
+ int err;
+
+ err = DRBD2_PARSE_SET(ctx, detach_parms, DETACH_PARMS, tb);
+ if (err)
+ return err;
+
+ s->force_detach = !!tb[DRBD2_A_DETACH_PARMS_FORCE];
+ s->intentional_diskless_detach =
+ !!tb[DRBD2_A_DETACH_PARMS_INTENTIONAL_DISKLESS_DETACH];
+ return 0;
+}
+
+static int drbd2_overlay_invalidate_parms(struct drbd_adm_ctx *ctx,
+ struct drbd_invalidate_parms *s)
+{
+ struct nlattr *tb[DRBD2_A_INVALIDATE_PARMS_RESET_BITMAP + 1];
+ int err;
+
+ err = DRBD2_PARSE_SET(ctx, invalidate_parms, INVALIDATE_PARMS, tb);
+ if (err)
+ return err;
+
+ if (tb[DRBD2_A_INVALIDATE_PARMS_SYNC_FROM_PEER_NODE_ID])
+ s->sync_from_peer_node_id =
+ nla_get_u32(tb[DRBD2_A_INVALIDATE_PARMS_SYNC_FROM_PEER_NODE_ID]);
+ if (tb[DRBD2_A_INVALIDATE_PARMS_RESET_BITMAP])
+ s->reset_bitmap = nla_get_u8(tb[DRBD2_A_INVALIDATE_PARMS_RESET_BITMAP]);
+ return 0;
+}
+
+static int drbd2_overlay_invalidate_peer_parms(struct drbd_adm_ctx *ctx,
+ struct drbd_invalidate_peer_parms *s)
+{
+ struct nlattr *tb[DRBD2_A_INVALIDATE_PEER_PARMS_RESET_BITMAP + 1];
+ int err;
+
+ err = DRBD2_PARSE_SET(ctx, invalidate_peer_parms, INVALIDATE_PEER_PARMS, tb);
+ if (err)
+ return err;
+
+ if (tb[DRBD2_A_INVALIDATE_PEER_PARMS_RESET_BITMAP])
+ s->p_reset_bitmap =
+ nla_get_u8(tb[DRBD2_A_INVALIDATE_PEER_PARMS_RESET_BITMAP]);
+ return 0;
+}
+
+/*
+ * connection-forget names the peer in the context of the request, not in
+ * a parameter set of its own.
+ */
+static int drbd2_overlay_forget_peer_parms(struct drbd_adm_ctx *ctx,
+ struct drbd_forget_peer_parms *s)
+{
+ if (ctx->peer_node_id == PEER_NODE_ID_UNSPECIFIED)
+ return -ENOMSG;
+ s->forget_peer_node_id = ctx->peer_node_id;
+ return 0;
+}
+
+static int drbd2_overlay_connect_parms(struct drbd_adm_ctx *ctx, struct drbd_connect_parms *s)
+{
+ struct nlattr *tb[DRBD2_A_CONNECT_PARMS_DISCARD_MY_DATA + 1];
+ int err;
+
+ err = DRBD2_PARSE_SET(ctx, connect_parms, CONNECT_PARMS, tb);
+ if (err)
+ return err;
+
+ s->tentative = !!tb[DRBD2_A_CONNECT_PARMS_TENTATIVE];
+ s->discard_my_data = !!tb[DRBD2_A_CONNECT_PARMS_DISCARD_MY_DATA];
+ return 0;
+}
+
+/*
+ * A path is identified by the two addresses in the context of the
+ * request; both are required.
+ */
+static int drbd2_overlay_path_parms(struct drbd_adm_ctx *ctx, struct drbd_path_parms *s)
+{
+ struct nlattr *tb[DRBD2_A_CONTEXT_PEER_ADDRESS + 1];
+ struct genl_info *info = drbd2_req(ctx)->info;
+ int err;
+
+ if (!info->attrs[DRBD2_A_CONTEXT])
+ return -ENOMSG;
+ err = nla_parse_nested(tb, DRBD2_A_CONTEXT_PEER_ADDRESS,
+ info->attrs[DRBD2_A_CONTEXT],
+ drbd2_context_nl_policy, info->extack);
+ if (err)
+ return err;
+ if (!tb[DRBD2_A_CONTEXT_MY_ADDRESS] || !tb[DRBD2_A_CONTEXT_PEER_ADDRESS])
+ return -ENOMSG;
+
+ err = drbd2_get_address(tb[DRBD2_A_CONTEXT_MY_ADDRESS], s->my_addr, &s->my_addr_len);
+ if (err)
+ return err;
+ return drbd2_get_address(tb[DRBD2_A_CONTEXT_PEER_ADDRESS],
+ s->peer_addr, &s->peer_addr_len);
+}
+
+static int drbd2_overlay_rename_resource_parms(struct drbd_adm_ctx *ctx,
+ struct drbd_rename_resource_parms *s)
+{
+ struct nlattr *tb[DRBD2_A_RENAME_PARMS_NEW_NAME + 1];
+ int err;
+
+ err = DRBD2_PARSE_SET(ctx, rename_parms, RENAME_PARMS, tb);
+ if (err)
+ return err;
+ if (!tb[DRBD2_A_RENAME_PARMS_NEW_NAME])
+ return -ENOMSG;
+
+ s->new_resource_name_len = nla_strscpy(s->new_resource_name,
+ tb[DRBD2_A_RENAME_PARMS_NEW_NAME],
+ sizeof(s->new_resource_name));
+ return 0;
+}
+
+static int drbd2_overlay_suspend_io_parms(struct drbd_adm_ctx *ctx,
+ struct drbd_suspend_io_parms *s)
+{
+ struct nlattr *tb[DRBD2_A_SUSPEND_IO_PARMS_BDEV_FREEZE + 1];
+ int err;
+
+ err = DRBD2_PARSE_SET(ctx, suspend_io_parms, SUSPEND_IO_PARMS, tb);
+ if (err)
+ return err;
+
+ if (tb[DRBD2_A_SUSPEND_IO_PARMS_BDEV_FREEZE])
+ s->bdev_freeze = nla_get_u8(tb[DRBD2_A_SUSPEND_IO_PARMS_BDEV_FREEZE]);
+ return 0;
+}
+
+static int drbd2_overlay(struct drbd_adm_ctx *ctx, enum drbd_nl_attr_set set, void *dst)
+{
+ switch (set) {
+ case DRBD_NL_SET_DISK_CONF: return drbd2_overlay_disk_conf(ctx, dst);
+ case DRBD_NL_SET_NET_CONF: return drbd2_overlay_net_conf(ctx, dst);
+ case DRBD_NL_SET_RES_OPTS: return drbd2_overlay_res_opts(ctx, dst);
+ case DRBD_NL_SET_PEER_DEVICE_CONF: return drbd2_overlay_peer_device_conf(ctx, dst);
+ case DRBD_NL_SET_DEVICE_CONF: return drbd2_overlay_device_conf(ctx, dst);
+ case DRBD_NL_SET_SET_ROLE_PARMS: return drbd2_overlay_set_role_parms(ctx, dst);
+ case DRBD_NL_SET_RESIZE_PARMS: return drbd2_overlay_resize_parms(ctx, dst);
+ case DRBD_NL_SET_START_OV_PARMS: return drbd2_overlay_start_ov_parms(ctx, dst);
+ case DRBD_NL_SET_NEW_C_UUID_PARMS: return drbd2_overlay_new_c_uuid_parms(ctx, dst);
+ case DRBD_NL_SET_DISCONNECT_PARMS: return drbd2_overlay_disconnect_parms(ctx, dst);
+ case DRBD_NL_SET_DETACH_PARMS: return drbd2_overlay_detach_parms(ctx, dst);
+ case DRBD_NL_SET_INVALIDATE_PARMS: return drbd2_overlay_invalidate_parms(ctx, dst);
+ case DRBD_NL_SET_INVALIDATE_PEER_PARMS:
+ return drbd2_overlay_invalidate_peer_parms(ctx, dst);
+ case DRBD_NL_SET_FORGET_PEER_PARMS: return drbd2_overlay_forget_peer_parms(ctx, dst);
+ case DRBD_NL_SET_CONNECT_PARMS: return drbd2_overlay_connect_parms(ctx, dst);
+ case DRBD_NL_SET_PATH_PARMS: return drbd2_overlay_path_parms(ctx, dst);
+ case DRBD_NL_SET_RENAME_RESOURCE_PARMS:
+ return drbd2_overlay_rename_resource_parms(ctx, dst);
+ case DRBD_NL_SET_SUSPEND_IO_PARMS: return drbd2_overlay_suspend_io_parms(ctx, dst);
+ case __DRBD_NL_SET_MAX:
+ break;
+ }
+ return -EINVAL;
+}
+
+/*
+ * The core asks about one invariant field at a time and stops at the
+ * first one that is present, so exactly one message is logged, for that
+ * field. Parsing the nest per query keeps that short-circuit intact.
+ */
+static bool drbd2_attr_present(struct drbd_adm_ctx *ctx, enum drbd_adm_field field)
+{
+ static const struct {
+ u16 tla;
+ u16 maxtype;
+ const struct nla_policy *policy;
+ u16 attr;
+ const char *name;
+ } invariant[] = {
+ [DRBD_ADM_F_DISK_BACKING_DEV] = { DRBD2_A_DISK_CONF,
+ DRBD2_A_DISK_CONF_BITMAP, drbd2_disk_conf_nl_policy,
+ DRBD2_A_DISK_CONF_BACKING_DEV, "disk-conf.backing-dev" },
+ [DRBD_ADM_F_DISK_META_DEV] = { DRBD2_A_DISK_CONF,
+ DRBD2_A_DISK_CONF_BITMAP, drbd2_disk_conf_nl_policy,
+ DRBD2_A_DISK_CONF_META_DEV, "disk-conf.meta-dev" },
+ [DRBD_ADM_F_DISK_META_DEV_IDX] = { DRBD2_A_DISK_CONF,
+ DRBD2_A_DISK_CONF_BITMAP, drbd2_disk_conf_nl_policy,
+ DRBD2_A_DISK_CONF_META_DEV_IDX, "disk-conf.meta-dev-idx" },
+ [DRBD_ADM_F_DISK_SIZE] = { DRBD2_A_DISK_CONF,
+ DRBD2_A_DISK_CONF_BITMAP, drbd2_disk_conf_nl_policy,
+ DRBD2_A_DISK_CONF_SIZE, "disk-conf.size" },
+ [DRBD_ADM_F_NET_TRANSPORT_NAME] = { DRBD2_A_NET_CONF,
+ DRBD2_A_NET_CONF_RDMA_CTRL_SNDBUF_SIZE, drbd2_net_conf_nl_policy,
+ DRBD2_A_NET_CONF_TRANSPORT_NAME, "net-conf.transport-name" },
+ [DRBD_ADM_F_NET_LOAD_BALANCE_PATHS] = { DRBD2_A_NET_CONF,
+ DRBD2_A_NET_CONF_RDMA_CTRL_SNDBUF_SIZE, drbd2_net_conf_nl_policy,
+ DRBD2_A_NET_CONF_LOAD_BALANCE_PATHS, "net-conf.load-balance-paths" },
+ [DRBD_ADM_F_RES_NODE_ID] = { DRBD2_A_RESOURCE_OPTS,
+ DRBD2_A_RESOURCE_OPTS_EXPLICIT_DRBD8_COMPAT,
+ drbd2_resource_opts_nl_policy,
+ DRBD2_A_RESOURCE_OPTS_NODE_ID, "resource-opts.node-id" },
+ };
+ struct genl_info *info = drbd2_req(ctx)->info;
+ struct nlattr **tb;
+ bool found;
+
+ if (!info->attrs[invariant[field].tla])
+ return false;
+
+ tb = kcalloc(invariant[field].maxtype + 1, sizeof(*tb), GFP_KERNEL);
+ if (!tb)
+ return false;
+ found = !nla_parse_nested(tb, invariant[field].maxtype,
+ info->attrs[invariant[field].tla],
+ invariant[field].policy, NULL) &&
+ tb[invariant[field].attr];
+ kfree(tb);
+ if (found)
+ pr_info("must not change invariant attr: %s\n", invariant[field].name);
+ return found;
+}
+
+static int drbd2_put_timeout_type(struct drbd_adm_ctx *ctx, enum drbd_timeout_flag type)
+{
+ struct drbd2_req *req = drbd2_req(ctx);
+
+ if (nla_put_u32(req->reply_skb, DRBD2_A_TIMEOUT_TYPE, type)) {
+ nlmsg_free(req->reply_skb);
+ req->reply_skb = NULL;
+ return -EMSGSIZE;
+ }
+ req->payload_reply = true;
+ return NO_ERROR;
+}
+
+/*
+ * The generated entry points. Each runs the wire-format independent
+ * command implementation in drbd_nl.c and turns an ERR_* outcome into the
+ * errno and extended ACK this dialect reports errors with.
+ */
+static int drbd2_do(struct genl_info *info, int (*fn)(struct drbd_adm_ctx *ctx))
+{
+ struct drbd_adm_ctx *ctx = info->user_ptr[0];
+ struct drbd2_req *req = drbd2_req(ctx);
+ int err;
+
+ err = fn(ctx);
+ if (!err) {
+ if (drbd2_is_ret_code(ctx->result))
+ err = drbd2_errno(ctx->result);
+ else if (ctx->result < SS_AFTER_LAST_ERROR)
+ err = ctx->result; /* a plain -errno */
+ }
+ if (err) {
+ drbd2_set_extack(info, ctx);
+ nlmsg_free(req->reply_skb);
+ req->reply_skb = NULL;
+ }
+ return err;
+}
+
+#define DRBD2_DOIT(cmd, fn) \
+int drbd2_nl_##cmd##_doit(struct sk_buff *skb, struct genl_info *info) \
+{ \
+ return drbd2_do(info, fn); \
+}
+
+DRBD2_DOIT(resource_new, drbd_adm_new_resource)
+DRBD2_DOIT(resource_del, drbd_adm_del_resource)
+DRBD2_DOIT(resource_set, drbd_adm_resource_opts)
+DRBD2_DOIT(resource_rename, drbd_adm_rename_resource)
+DRBD2_DOIT(resource_down, drbd_adm_down)
+DRBD2_DOIT(resource_primary, drbd_adm_primary)
+DRBD2_DOIT(resource_secondary, drbd_adm_secondary)
+DRBD2_DOIT(resource_suspend_io, drbd_adm_suspend_io)
+DRBD2_DOIT(resource_resume_io, drbd_adm_resume_io)
+DRBD2_DOIT(device_new, drbd_adm_new_minor)
+DRBD2_DOIT(device_del, drbd_adm_del_minor)
+DRBD2_DOIT(device_attach, drbd_adm_attach)
+DRBD2_DOIT(device_detach, drbd_adm_detach)
+DRBD2_DOIT(disk_set, drbd_adm_disk_opts)
+DRBD2_DOIT(device_resize, drbd_adm_resize)
+DRBD2_DOIT(device_outdate, drbd_adm_outdate)
+DRBD2_DOIT(device_invalidate, drbd_adm_invalidate)
+DRBD2_DOIT(device_new_current_uuid, drbd_adm_new_c_uuid)
+DRBD2_DOIT(connection_new, drbd_adm_new_peer)
+DRBD2_DOIT(connection_del, drbd_adm_del_peer)
+DRBD2_DOIT(connection_connect, drbd_adm_connect)
+DRBD2_DOIT(connection_disconnect, drbd_adm_disconnect)
+DRBD2_DOIT(connection_set, drbd_adm_net_opts)
+DRBD2_DOIT(connection_forget, drbd_adm_forget_peer)
+DRBD2_DOIT(path_new, drbd_adm_new_path)
+DRBD2_DOIT(path_del, drbd_adm_del_path)
+DRBD2_DOIT(peer_device_set, drbd_adm_peer_device_opts)
+DRBD2_DOIT(peer_device_invalidate, drbd_adm_invalidate_peer)
+DRBD2_DOIT(peer_device_pause_sync, drbd_adm_pause_sync)
+DRBD2_DOIT(peer_device_resume_sync, drbd_adm_resume_sync)
+DRBD2_DOIT(peer_device_start_ov, drbd_adm_start_ov)
+DRBD2_DOIT(timeout_type_get, drbd_adm_get_timeout_type)
+
+/*
+ * Dumps.
+ *
+ * The core walks the objects; everything below turns one object into one
+ * message of this dialect. This dialect has no room for a result code in
+ * a dump message, so a "retcode" other than NO_ERROR aborts the dump with
+ * the matching errno instead.
+ */
+
+static void *drbd2_dump_put(struct sk_buff *skb, struct netlink_callback *cb, u8 cmd)
+{
+ return genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
+ &drbd2_nl_family, NLM_F_MULTI, cmd);
+}
+
+static int drbd2_emit_resource(struct sk_buff *skb, struct netlink_callback *cb,
+ struct drbd_resource *resource,
+ struct drbd_resource_info *info,
+ struct drbd_resource_statistics *statistics)
+{
+ void *dh = drbd2_dump_put(skb, cb, DRBD2_CMD_RESOURCE_GET);
+
+ if (!dh)
+ return -EMSGSIZE;
+ if (drbd2_put_resource(skb, DRBD2_A_RESOURCE, resource, &resource->res_opts,
+ info, statistics, NULL)) {
+ genlmsg_cancel(skb, dh);
+ return -EMSGSIZE;
+ }
+ genlmsg_end(skb, dh);
+ return 0;
+}
+
+static int drbd2_emit_device(struct sk_buff *skb, struct netlink_callback *cb, int retcode,
+ struct drbd_device *device, struct drbd_disk_conf *disk_conf,
+ struct drbd_device_info *info,
+ struct drbd_device_statistics *statistics)
+{
+ void *dh;
+
+ if (retcode != NO_ERROR)
+ return drbd2_errno(retcode);
+ dh = drbd2_dump_put(skb, cb, DRBD2_CMD_DEVICE_GET);
+ if (!dh)
+ return -EMSGSIZE;
+ if (drbd2_put_device(skb, DRBD2_A_DEVICE, device, disk_conf,
+ &device->device_conf, info, statistics)) {
+ genlmsg_cancel(skb, dh);
+ return -EMSGSIZE;
+ }
+ genlmsg_end(skb, dh);
+ return 0;
+}
+
+static int drbd2_emit_connection(struct sk_buff *skb, struct netlink_callback *cb, int retcode,
+ struct drbd_resource *resource,
+ struct drbd_connection *connection,
+ struct drbd_net_conf *net_conf,
+ struct drbd_connection_info *info,
+ struct drbd_connection_statistics *statistics)
+{
+ void *dh;
+
+ if (retcode != NO_ERROR)
+ return drbd2_errno(retcode);
+ dh = drbd2_dump_put(skb, cb, DRBD2_CMD_CONNECTION_GET);
+ if (!dh)
+ return -EMSGSIZE;
+ if (drbd2_put_connection(skb, DRBD2_A_CONNECTION, resource, connection,
+ net_conf, info, statistics)) {
+ genlmsg_cancel(skb, dh);
+ return -EMSGSIZE;
+ }
+ genlmsg_end(skb, dh);
+ return 0;
+}
+
+static int drbd2_emit_peer_device(struct sk_buff *skb, struct netlink_callback *cb, int retcode,
+ struct drbd_peer_device *peer_device, unsigned int minor,
+ struct drbd_peer_device_info *info,
+ struct drbd_peer_device_statistics *statistics,
+ struct drbd_peer_device_conf *conf)
+{
+ void *dh;
+
+ if (retcode != NO_ERROR)
+ return drbd2_errno(retcode);
+ dh = drbd2_dump_put(skb, cb, DRBD2_CMD_PEER_DEVICE_GET);
+ if (!dh)
+ return -EMSGSIZE;
+ if (drbd2_put_peer_device(skb, DRBD2_A_PEER_DEVICE, peer_device, conf,
+ info, statistics)) {
+ genlmsg_cancel(skb, dh);
+ return -EMSGSIZE;
+ }
+ genlmsg_end(skb, dh);
+ return 0;
+}
+
+static int drbd2_emit_path(struct sk_buff *skb, struct netlink_callback *cb, int retcode,
+ struct drbd_resource *resource, struct drbd_connection *connection,
+ struct drbd_path *path, struct drbd_nl_path_info *info)
+{
+ void *dh;
+
+ if (retcode != NO_ERROR)
+ return drbd2_errno(retcode);
+ dh = drbd2_dump_put(skb, cb, DRBD2_CMD_PATH_GET);
+ if (!dh)
+ return -EMSGSIZE;
+ if (drbd2_put_path(skb, DRBD2_A_PATH, resource, connection, path, info)) {
+ genlmsg_cancel(skb, dh);
+ return -EMSGSIZE;
+ }
+ genlmsg_end(skb, dh);
+ return 0;
+}
+
+/*
+ * The dump callbacks run outside the genl lock and get the request as a
+ * raw message, so the optional context nest is looked up by hand.
+ */
+static struct nlattr *drbd2_find_context_attr(const struct nlmsghdr *nlh, int attr)
+{
+ struct nlattr *nla;
+
+ nla = nla_find(nlmsg_attrdata(nlh, GENL_HDRLEN),
+ nlmsg_attrlen(nlh, GENL_HDRLEN), DRBD2_A_CONTEXT);
+ if (!nla)
+ return NULL;
+ return nla_find_nested(nla, attr);
+}
+
+/*
+ * Resolve the optional resource-name filter of a dump on its first call.
+ * The core expects the resource in cb->args[0], with a reference that the
+ * matching _done callback drops again. Returns -ENOENT when the name does
+ * not name a resource, and 0 when there is nothing to filter by.
+ */
+static int drbd2_dump_filter(struct netlink_callback *cb, int holder_nr)
+{
+ struct drbd_resource *resource;
+ struct nlattr *filter;
+
+ filter = drbd2_find_context_attr(cb->nlh, DRBD2_A_CONTEXT_RESOURCE_NAME);
+ if (IS_ERR_OR_NULL(filter))
+ return 0;
+ resource = drbd_find_resource(nla_data(filter));
+ if (!resource)
+ return -ENOENT;
+ cb->args[0] = (long)resource;
+ return 0;
+}
+
+int drbd2_nl_resource_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
+{
+ return drbd_dump_resources(skb, cb, &drbd2_dialect);
+}
+
+int drbd2_nl_device_get_done(struct netlink_callback *cb)
+{
+ return drbd_dump_devices_done(cb);
+}
+
+int drbd2_nl_device_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
+{
+ if (!cb->args[0] && !cb->args[1]) {
+ int err = drbd2_dump_filter(cb, 7);
+
+ if (err)
+ return err;
+ }
+ return drbd_dump_devices(skb, cb, &drbd2_dialect);
+}
+
+int drbd2_nl_connection_get_done(struct netlink_callback *cb)
+{
+ return drbd_dump_connections_done(cb);
+}
+
+int drbd2_nl_connection_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
+{
+ if (!cb->args[0]) {
+ int err = drbd2_dump_filter(cb, 6);
+
+ if (err)
+ return err;
+ if (cb->args[0])
+ cb->args[1] = DRBD_DUMP_SINGLE_RESOURCE;
+ }
+ return drbd_dump_connections(skb, cb, &drbd2_dialect);
+}
+
+int drbd2_nl_peer_device_get_done(struct netlink_callback *cb)
+{
+ return drbd_dump_peer_devices_done(cb);
+}
+
+int drbd2_nl_peer_device_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
+{
+ if (!cb->args[0] && !cb->args[1]) {
+ int err = drbd2_dump_filter(cb, 9);
+
+ if (err)
+ return err;
+ }
+ return drbd_dump_peer_devices(skb, cb, &drbd2_dialect);
+}
+
+int drbd2_nl_path_get_done(struct netlink_callback *cb)
+{
+ return drbd_dump_paths_done(cb);
+}
+
+int drbd2_nl_path_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
+{
+ if (!cb->args[0]) {
+ int err = drbd2_dump_filter(cb, 10);
+
+ if (err)
+ return err;
+ if (cb->args[0])
+ cb->args[1] = DRBD_DUMP_SINGLE_RESOURCE;
+ }
+ return drbd_dump_paths(skb, cb, &drbd2_dialect);
+}
+
+int drbd2_nl_state_get_done(struct netlink_callback *cb)
+{
+ return drbd_dump_initial_state_done(cb);
+}
+
+int drbd2_nl_state_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
+{
+ /* the replayed state changes are sent under the sequence number of the dump */
+ return drbd_dump_initial_state(skb, cb, &drbd2_dialect, cb->nlh->nlmsg_seq);
+}
+
+/*
+ * Notifications.
+ *
+ * With an skb this is the initial state snapshot of the state-get dump:
+ * append the message to that skb. Without one, allocate a message and
+ * multicast it to the "events" group. Both carry the same attributes; the
+ * command tells them apart. The sequence number comes from the core; it
+ * is the same for every dialect describing the event.
+ */
+
+static u32 drbd2_state_change_action(enum drbd_notification_type type)
+{
+ switch (type & ~NOTIFY_FLAGS) {
+ case NOTIFY_CREATE: return DRBD2_STATE_CHANGE_ACTION_CREATE;
+ case NOTIFY_CHANGE: return DRBD2_STATE_CHANGE_ACTION_CHANGE;
+ case NOTIFY_DESTROY: return DRBD2_STATE_CHANGE_ACTION_DESTROY;
+ case NOTIFY_RENAME: return DRBD2_STATE_CHANGE_ACTION_RENAME;
+ default: return DRBD2_STATE_CHANGE_ACTION_EXISTS;
+ }
+}
+
+static void *drbd2_state_change_put(struct sk_buff *skb, unsigned int seq, bool replay,
+ enum drbd_notification_type type)
+{
+ void *dh = genlmsg_put(skb, 0, seq, &drbd2_nl_family,
+ replay ? NLM_F_MULTI : 0,
+ replay ? DRBD2_CMD_STATE_GET : DRBD2_CMD_STATE_CHANGE_NTF);
+
+ if (!dh)
+ return NULL;
+ if (nla_put_u32(skb, DRBD2_A_STATE_CHANGE_ACTION,
+ drbd2_state_change_action(type)))
+ goto fail;
+ if ((type & NOTIFY_CONTINUES) &&
+ nla_put_flag(skb, DRBD2_A_STATE_CHANGE_MORE))
+ goto fail;
+ return dh;
+
+fail:
+ genlmsg_cancel(skb, dh);
+ return NULL;
+}
+
+static int drbd2_notify_resource_state(struct sk_buff *skb, unsigned int seq,
+ struct drbd_resource *resource,
+ struct drbd_resource_info *info,
+ struct drbd_rename_resource_info *rename_info,
+ enum drbd_notification_type type)
+{
+ struct drbd_resource_statistics statistics;
+ bool multicast = !skb;
+ void *dh;
+ int err;
+
+ if (multicast) {
+ skb = genlmsg_new(NLMSG_GOODSIZE, GFP_NOIO);
+ err = -ENOMEM;
+ if (!skb)
+ goto failed;
+ }
+
+ err = -EMSGSIZE;
+ dh = drbd2_state_change_put(skb, seq, !multicast, type);
+ if (!dh)
+ goto nla_put_failure;
+ resource_to_statistics(&statistics, resource);
+ if (drbd2_put_resource(skb, DRBD2_A_STATE_CHANGE_RESOURCE, resource, NULL,
+ info, &statistics, rename_info))
+ goto nla_put_failure;
+ genlmsg_end(skb, dh);
+ if (multicast) {
+ err = drbd2_genl_multicast_events(skb);
+ /* skb has been consumed or freed in netlink_broadcast() */
+ if (err && err != -ESRCH)
+ goto failed;
+ }
+ return 0;
+
+nla_put_failure:
+ nlmsg_free(skb);
+failed:
+ drbd_err(resource, "Error %d while broadcasting event. Event seq:%u\n", err, seq);
+ return err;
+}
+
+static int drbd2_notify_device_state(struct sk_buff *skb, unsigned int seq,
+ struct drbd_device *device,
+ struct drbd_device_info *info,
+ enum drbd_notification_type type)
+{
+ struct drbd_device_statistics statistics;
+ bool multicast = !skb;
+ void *dh;
+ int err;
+
+ if (multicast) {
+ skb = genlmsg_new(NLMSG_GOODSIZE, GFP_NOIO);
+ err = -ENOMEM;
+ if (!skb)
+ goto failed;
+ }
+
+ err = -EMSGSIZE;
+ dh = drbd2_state_change_put(skb, seq, !multicast, type);
+ if (!dh)
+ goto nla_put_failure;
+ device_to_statistics(&statistics, device);
+ if (drbd2_put_device(skb, DRBD2_A_STATE_CHANGE_DEVICE, device, NULL, NULL,
+ (type & ~NOTIFY_FLAGS) == NOTIFY_DESTROY ? NULL : info,
+ &statistics))
+ goto nla_put_failure;
+ genlmsg_end(skb, dh);
+ if (multicast) {
+ err = drbd2_genl_multicast_events(skb);
+ /* skb has been consumed or freed in netlink_broadcast() */
+ if (err && err != -ESRCH)
+ goto failed;
+ }
+ return 0;
+
+nla_put_failure:
+ nlmsg_free(skb);
+failed:
+ drbd_err(device, "Error %d while broadcasting event. Event seq:%u\n", err, seq);
+ return err;
+}
+
+static int drbd2_notify_connection_state(struct sk_buff *skb, unsigned int seq,
+ struct drbd_connection *connection,
+ struct drbd_connection_info *info,
+ enum drbd_notification_type type)
+{
+ struct drbd_connection_statistics statistics;
+ bool multicast = !skb;
+ void *dh;
+ int err;
+
+ if (multicast) {
+ skb = genlmsg_new(NLMSG_GOODSIZE, GFP_NOIO);
+ err = -ENOMEM;
+ if (!skb)
+ goto failed;
+ }
+
+ err = -EMSGSIZE;
+ dh = drbd2_state_change_put(skb, seq, !multicast, type);
+ if (!dh)
+ goto nla_put_failure;
+ connection_to_statistics(&statistics, connection);
+ if (drbd2_put_connection(skb, DRBD2_A_STATE_CHANGE_CONNECTION,
+ connection->resource, connection, NULL,
+ (type & ~NOTIFY_FLAGS) == NOTIFY_DESTROY ? NULL : info,
+ &statistics))
+ goto nla_put_failure;
+ genlmsg_end(skb, dh);
+ if (multicast) {
+ err = drbd2_genl_multicast_events(skb);
+ /* skb has been consumed or freed in netlink_broadcast() */
+ if (err && err != -ESRCH)
+ goto failed;
+ }
+ return 0;
+
+nla_put_failure:
+ nlmsg_free(skb);
+failed:
+ drbd_err(connection, "Error %d while broadcasting event. Event seq:%u\n", err, seq);
+ return err;
+}
+
+static int drbd2_notify_peer_device_state(struct sk_buff *skb, unsigned int seq,
+ struct drbd_peer_device *peer_device,
+ struct drbd_peer_device_info *info,
+ enum drbd_notification_type type)
+{
+ struct drbd_peer_device_statistics statistics;
+ bool multicast = !skb;
+ void *dh;
+ int err;
+
+ if (multicast) {
+ skb = genlmsg_new(NLMSG_GOODSIZE, GFP_NOIO);
+ err = -ENOMEM;
+ if (!skb)
+ goto failed;
+ }
+
+ err = -EMSGSIZE;
+ dh = drbd2_state_change_put(skb, seq, !multicast, type);
+ if (!dh)
+ goto nla_put_failure;
+ peer_device_to_statistics(&statistics, peer_device);
+ if (drbd2_put_peer_device(skb, DRBD2_A_STATE_CHANGE_PEER_DEVICE, peer_device, NULL,
+ (type & ~NOTIFY_FLAGS) == NOTIFY_DESTROY ? NULL : info,
+ &statistics))
+ goto nla_put_failure;
+ genlmsg_end(skb, dh);
+ if (multicast) {
+ err = drbd2_genl_multicast_events(skb);
+ /* skb has been consumed or freed in netlink_broadcast() */
+ if (err && err != -ESRCH)
+ goto failed;
+ }
+ return 0;
+
+nla_put_failure:
+ nlmsg_free(skb);
+failed:
+ drbd_err(peer_device, "Error %d while broadcasting event. Event seq:%u\n", err, seq);
+ return err;
+}
+
+static int drbd2_notify_path_state(struct sk_buff *skb, unsigned int seq,
+ /* until we have a backpointer in drbd_path,
+ * we need an explicit connection:
+ */
+ struct drbd_connection *connection,
+ struct drbd_path *path,
+ struct drbd_nl_path_info *info,
+ enum drbd_notification_type type)
+{
+ bool multicast = !skb;
+ void *dh;
+ int err;
+
+ if (multicast) {
+ skb = genlmsg_new(NLMSG_GOODSIZE, GFP_NOIO);
+ err = -ENOMEM;
+ if (!skb)
+ goto failed;
+ }
+
+ err = -EMSGSIZE;
+ dh = drbd2_state_change_put(skb, seq, !multicast, type);
+ if (!dh)
+ goto nla_put_failure;
+ if (drbd2_put_path(skb, DRBD2_A_STATE_CHANGE_PATH, connection->resource,
+ connection, path, info))
+ goto nla_put_failure;
+ genlmsg_end(skb, dh);
+ if (multicast) {
+ err = drbd2_genl_multicast_events(skb);
+ /* skb has been consumed or freed in netlink_broadcast() */
+ if (err && err != -ESRCH)
+ goto failed;
+ }
+ return 0;
+
+nla_put_failure:
+ nlmsg_free(skb);
+failed:
+ /* FIXME add path specifics to our drbd_polymorph_printk.h */
+ drbd_err(connection, "path: Error %d while broadcasting event. Event seq:%u\n",
+ err, seq);
+ return err;
+}
+
+/* Helper events are never replayed, so "skb" is always NULL here. */
+static int drbd2_notify_helper(struct sk_buff *skb, unsigned int seq,
+ struct drbd_device *device, struct drbd_connection *connection,
+ const char *name, int status,
+ enum drbd_notification_type type)
+{
+ struct drbd_resource *resource = device ? device->resource : connection->resource;
+ struct nlattr *nla;
+ void *dh;
+ int err;
+
+ skb = genlmsg_new(NLMSG_GOODSIZE, GFP_NOIO);
+ err = -ENOMEM;
+ if (!skb)
+ goto fail;
+
+ err = -EMSGSIZE;
+ dh = genlmsg_put(skb, 0, seq, &drbd2_nl_family, 0, DRBD2_CMD_HELPER_NTF);
+ if (!dh)
+ goto fail;
+ if (drbd2_put_context(skb, DRBD2_A_CONTEXT, resource, connection, device, NULL))
+ goto fail;
+ nla = nla_nest_start(skb, DRBD2_A_HELPER);
+ if (!nla)
+ goto fail;
+ if (nla_put_string(skb, DRBD2_A_HELPER_INFO_NAME, name) ||
+ nla_put_u32(skb, DRBD2_A_HELPER_INFO_STATUS, status) ||
+ nla_put_u32(skb, DRBD2_A_HELPER_INFO_PHASE,
+ (type & ~NOTIFY_FLAGS) == NOTIFY_RESPONSE ?
+ DRBD2_HELPER_PHASE_RESPONSE : DRBD2_HELPER_PHASE_CALL))
+ goto fail;
+ nla_nest_end(skb, nla);
+ genlmsg_end(skb, dh);
+ err = drbd2_genl_multicast_events(skb);
+ skb = NULL;
+ /* skb has been consumed or freed in netlink_broadcast() */
+ if (err && err != -ESRCH)
+ goto fail;
+ return 0;
+
+fail:
+ nlmsg_free(skb);
+ drbd_err(resource, "Error %d while broadcasting event. Event seq:%u\n", err, seq);
+ return err;
+}
+
+/*
+ * The end of the state-get dump needs no message of its own: appending
+ * nothing ends the dump, and netlink terminates it with NLMSG_DONE.
+ */
+static int drbd2_notify_initial_state_done(struct sk_buff *skb, unsigned int seq)
+{
+ return 0;
+}
+
+static const struct drbd_nl_dialect drbd2_dialect = {
+ .name = "drbd2",
+ .has_set = drbd2_has_set,
+ .overlay = drbd2_overlay,
+ .attr_present = drbd2_attr_present,
+ .put_timeout_type = drbd2_put_timeout_type,
+ .emit_resource = drbd2_emit_resource,
+ .emit_device = drbd2_emit_device,
+ .emit_connection = drbd2_emit_connection,
+ .emit_peer_device = drbd2_emit_peer_device,
+ .emit_path = drbd2_emit_path,
+ .notify_resource_state = drbd2_notify_resource_state,
+ .notify_device_state = drbd2_notify_device_state,
+ .notify_connection_state = drbd2_notify_connection_state,
+ .notify_peer_device_state = drbd2_notify_peer_device_state,
+ .notify_path_state = drbd2_notify_path_state,
+ .notify_helper = drbd2_notify_helper,
+ .notify_initial_state_done = drbd2_notify_initial_state_done,
+};
+
+int drbd_nl_drbd2_init(void)
+{
+ int err = genl_register_family(&drbd2_nl_family);
+
+ if (err)
+ return err;
+ err = drbd_nl_register_dialect(&drbd2_dialect);
+ if (err)
+ genl_unregister_family(&drbd2_nl_family);
+ return err;
+}
+
+void drbd_nl_drbd2_exit(void)
+{
+ genl_unregister_family(&drbd2_nl_family);
+}
diff --git a/include/uapi/linux/drbd2.h b/include/uapi/linux/drbd2.h
new file mode 100644
index 000000000000..d148779eae64
--- /dev/null
+++ b/include/uapi/linux/drbd2.h
@@ -0,0 +1,1012 @@
+/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
+/* Do not edit directly, auto-generated from: */
+/* Documentation/netlink/specs/drbd2.yaml */
+/* YNL-GEN uapi header */
+/* To regenerate run: tools/net/ynl/ynl-regen.sh */
+
+#ifndef _UAPI_LINUX_DRBD2_H
+#define _UAPI_LINUX_DRBD2_H
+
+#define DRBD2_FAMILY_NAME "drbd2"
+#define DRBD2_FAMILY_VERSION 1
+
+#define DRBD2_RESOURCE_NAME_MAX 128
+#define DRBD2_CONNECTION_NAME_MAX 64
+#define DRBD2_SHARED_SECRET_MAX 64
+#define DRBD2_ALG_NAME_MAX 64
+#define DRBD2_TRANSPORT_NAME_MAX 64
+#define DRBD2_DEVICE_PATH_MAX 128
+#define DRBD2_CPU_MASK_SIZE 256
+#define DRBD2_HELPER_NAME_MAX 32
+#define DRBD2_HISTORY_UUIDS_SIZE 256
+
+/**
+ * enum drbd2_io_error_policy - What to do when the backing device reports an
+ * I/O error (on-io-error).
+ * @DRBD2_IO_ERROR_POLICY_PASS_ON: Mark the failed block out of sync, change
+ * the disk state to inconsistent and retry the request on a peer.
+ * @DRBD2_IO_ERROR_POLICY_CALL_LOCAL_IO_ERROR: Call the local-io-error handler.
+ * @DRBD2_IO_ERROR_POLICY_DETACH: Detach the backing device and continue in
+ * diskless mode.
+ */
+enum drbd2_io_error_policy {
+ DRBD2_IO_ERROR_POLICY_PASS_ON,
+ DRBD2_IO_ERROR_POLICY_CALL_LOCAL_IO_ERROR,
+ DRBD2_IO_ERROR_POLICY_DETACH,
+};
+
+/**
+ * enum drbd2_fencing_policy - Fencing policy (fencing).
+ * @DRBD2_FENCING_POLICY_DONT_CARE: Take no fencing action at all.
+ * @DRBD2_FENCING_POLICY_RESOURCE: A node that becomes a disconnected primary
+ * calls the fence-peer handler to outdate the peer.
+ * @DRBD2_FENCING_POLICY_STONITH: A node that becomes a disconnected primary
+ * freezes its I/O and calls the fence-peer handler, which may have to shoot
+ * the peer.
+ */
+enum drbd2_fencing_policy {
+ DRBD2_FENCING_POLICY_DONT_CARE,
+ DRBD2_FENCING_POLICY_RESOURCE,
+ DRBD2_FENCING_POLICY_STONITH,
+};
+
+/**
+ * enum drbd2_after_sb_policy - Split-brain recovery policy (after-sb-0pri,
+ * after-sb-1pri, after-sb-2pri, rr-conflict).
+ * @DRBD2_AFTER_SB_POLICY_DISCONNECT: Do not resynchronize automatically,
+ * simply disconnect.
+ * @DRBD2_AFTER_SB_POLICY_DISCARD_YOUNGER_PRIMARY: Resynchronize from the node
+ * that became primary first.
+ * @DRBD2_AFTER_SB_POLICY_DISCARD_OLDER_PRIMARY: Resynchronize from the node
+ * that became primary last.
+ * @DRBD2_AFTER_SB_POLICY_DISCARD_ZERO_CHANGES: Resynchronize from the node
+ * that wrote data since the split brain was detected, or disconnect if both
+ * nodes wrote.
+ * @DRBD2_AFTER_SB_POLICY_DISCARD_LEAST_CHANGES: Resynchronize from the node
+ * with more modified blocks.
+ * @DRBD2_AFTER_SB_POLICY_DISCARD_LOCAL: Discard the data on this node and
+ * resynchronize it from the peer.
+ * @DRBD2_AFTER_SB_POLICY_DISCARD_REMOTE: Discard the data on the peer and
+ * resynchronize it from this node.
+ * @DRBD2_AFTER_SB_POLICY_CONSENSUS: Discard the data on the secondary if the
+ * after-sb-0pri policy would discard it as well, otherwise disconnect.
+ * @DRBD2_AFTER_SB_POLICY_DISCARD_SECONDARY: Discard the data on the secondary
+ * node.
+ * @DRBD2_AFTER_SB_POLICY_CALL_PRI_LOST_AFTER_SB: Take the after-sb-0pri
+ * decision and call the pri-lost-after-sb handler on the node that has to
+ * give up its data.
+ * @DRBD2_AFTER_SB_POLICY_VIOLENTLY_AS0P: Always take the after-sb-0pri
+ * decision, even if that changes the primary's view of the data; this can
+ * crash the primary.
+ * @DRBD2_AFTER_SB_POLICY_RETRY_CONNECT: Disconnect now and immediately retry
+ * to connect (rr-conflict only).
+ * @DRBD2_AFTER_SB_POLICY_AUTO_DISCARD: Reverse the resync direction so that
+ * the current primary is resynchronized from the current secondary
+ * (rr-conflict with protocol A only).
+ */
+enum drbd2_after_sb_policy {
+ DRBD2_AFTER_SB_POLICY_DISCONNECT,
+ DRBD2_AFTER_SB_POLICY_DISCARD_YOUNGER_PRIMARY,
+ DRBD2_AFTER_SB_POLICY_DISCARD_OLDER_PRIMARY,
+ DRBD2_AFTER_SB_POLICY_DISCARD_ZERO_CHANGES,
+ DRBD2_AFTER_SB_POLICY_DISCARD_LEAST_CHANGES,
+ DRBD2_AFTER_SB_POLICY_DISCARD_LOCAL,
+ DRBD2_AFTER_SB_POLICY_DISCARD_REMOTE,
+ DRBD2_AFTER_SB_POLICY_CONSENSUS,
+ DRBD2_AFTER_SB_POLICY_DISCARD_SECONDARY,
+ DRBD2_AFTER_SB_POLICY_CALL_PRI_LOST_AFTER_SB,
+ DRBD2_AFTER_SB_POLICY_VIOLENTLY_AS0P,
+ DRBD2_AFTER_SB_POLICY_RETRY_CONNECT,
+ DRBD2_AFTER_SB_POLICY_AUTO_DISCARD,
+};
+
+/**
+ * enum drbd2_on_no_data_policy - What to do when no data is accessible
+ * (on-no-data-accessible).
+ * @DRBD2_ON_NO_DATA_POLICY_IO_ERROR: Complete the requests with an I/O error,
+ * so that system calls fail with EIO.
+ * @DRBD2_ON_NO_DATA_POLICY_SUSPEND_IO: Suspend I/O until the data becomes
+ * accessible again or the administrator forces I/O to resume.
+ */
+enum drbd2_on_no_data_policy {
+ DRBD2_ON_NO_DATA_POLICY_IO_ERROR,
+ DRBD2_ON_NO_DATA_POLICY_SUSPEND_IO,
+};
+
+/**
+ * enum drbd2_on_no_quorum_policy - What to do when quorum is lost
+ * (on-no-quorum).
+ * @DRBD2_ON_NO_QUORUM_POLICY_IO_ERROR: Complete the requests with an I/O error
+ * while the resource has no quorum.
+ * @DRBD2_ON_NO_QUORUM_POLICY_SUSPEND_IO: Freeze I/O while the resource has no
+ * quorum.
+ */
+enum drbd2_on_no_quorum_policy {
+ DRBD2_ON_NO_QUORUM_POLICY_IO_ERROR,
+ DRBD2_ON_NO_QUORUM_POLICY_SUSPEND_IO,
+};
+
+/**
+ * enum drbd2_on_suspended_primary_outdated_policy - What to do with a
+ * suspended primary that became outdated.
+ * @DRBD2_ON_SUSPENDED_PRIMARY_OUTDATED_POLICY_DISCONNECT: Reject connection
+ * attempts and stay isolated.
+ * @DRBD2_ON_SUSPENDED_PRIMARY_OUTDATED_POLICY_FORCE_SECONDARY: Demote to
+ * secondary immediately and fail all pending and new I/O requests.
+ */
+enum drbd2_on_suspended_primary_outdated_policy {
+ DRBD2_ON_SUSPENDED_PRIMARY_OUTDATED_POLICY_DISCONNECT,
+ DRBD2_ON_SUSPENDED_PRIMARY_OUTDATED_POLICY_FORCE_SECONDARY,
+};
+
+/**
+ * enum drbd2_on_congestion_policy - What to do when the replication link is
+ * congested (on-congestion).
+ * @DRBD2_ON_CONGESTION_POLICY_BLOCK: Block application writes until the
+ * transport's send queue drains.
+ * @DRBD2_ON_CONGESTION_POLICY_PULL_AHEAD: Switch into ahead/behind mode and
+ * record further changes in the bitmap instead of replicating them.
+ * @DRBD2_ON_CONGESTION_POLICY_DISCONNECT: Disconnect from the peer instead of
+ * blocking application writes.
+ */
+enum drbd2_on_congestion_policy {
+ DRBD2_ON_CONGESTION_POLICY_BLOCK,
+ DRBD2_ON_CONGESTION_POLICY_PULL_AHEAD,
+ DRBD2_ON_CONGESTION_POLICY_DISCONNECT,
+};
+
+/**
+ * enum drbd2_read_balancing_policy - Read balancing policy (read-balancing).
+ * @DRBD2_READ_BALANCING_POLICY_PREFER_LOCAL: Always read from the local disk.
+ * @DRBD2_READ_BALANCING_POLICY_PREFER_REMOTE: Always read from a peer's disk.
+ * @DRBD2_READ_BALANCING_POLICY_ROUND_ROBIN: Alternate between the local disk
+ * and a peer for consecutive reads.
+ * @DRBD2_READ_BALANCING_POLICY_LEAST_PENDING: Read from the disk with the
+ * fewest pending requests.
+ * @DRBD2_READ_BALANCING_POLICY_WHEN_CONGESTED_REMOTE: Read from a peer only
+ * while the local disk is congested; deprecated since DRBD 9.1.12.
+ * @DRBD2_READ_BALANCING_POLICY_STRIPING_32K: Read alternating 32 KiB stripes
+ * from the local disk and from a peer.
+ * @DRBD2_READ_BALANCING_POLICY_STRIPING_64K: Read alternating 64 KiB stripes
+ * from the local disk and from a peer.
+ * @DRBD2_READ_BALANCING_POLICY_STRIPING_128K: Read alternating 128 KiB stripes
+ * from the local disk and from a peer.
+ * @DRBD2_READ_BALANCING_POLICY_STRIPING_256K: Read alternating 256 KiB stripes
+ * from the local disk and from a peer.
+ * @DRBD2_READ_BALANCING_POLICY_STRIPING_512K: Read alternating 512 KiB stripes
+ * from the local disk and from a peer.
+ * @DRBD2_READ_BALANCING_POLICY_STRIPING_1M: Read alternating 1 MiB stripes
+ * from the local disk and from a peer.
+ */
+enum drbd2_read_balancing_policy {
+ DRBD2_READ_BALANCING_POLICY_PREFER_LOCAL,
+ DRBD2_READ_BALANCING_POLICY_PREFER_REMOTE,
+ DRBD2_READ_BALANCING_POLICY_ROUND_ROBIN,
+ DRBD2_READ_BALANCING_POLICY_LEAST_PENDING,
+ DRBD2_READ_BALANCING_POLICY_WHEN_CONGESTED_REMOTE,
+ DRBD2_READ_BALANCING_POLICY_STRIPING_32K,
+ DRBD2_READ_BALANCING_POLICY_STRIPING_64K,
+ DRBD2_READ_BALANCING_POLICY_STRIPING_128K,
+ DRBD2_READ_BALANCING_POLICY_STRIPING_256K,
+ DRBD2_READ_BALANCING_POLICY_STRIPING_512K,
+ DRBD2_READ_BALANCING_POLICY_STRIPING_1M,
+};
+
+/**
+ * enum drbd2_wire_protocol - Replication protocol (protocol).
+ * @DRBD2_WIRE_PROTOCOL_A: Writes complete as soon as they reached the local
+ * disk and the local send buffer.
+ * @DRBD2_WIRE_PROTOCOL_B: Writes complete as soon as they reached the local
+ * disk and all peers acknowledged their receipt.
+ * @DRBD2_WIRE_PROTOCOL_C: Writes complete as soon as they reached the local
+ * disk and all remote disks.
+ */
+enum drbd2_wire_protocol {
+ DRBD2_WIRE_PROTOCOL_A = 1,
+ DRBD2_WIRE_PROTOCOL_B,
+ DRBD2_WIRE_PROTOCOL_C,
+};
+
+/**
+ * enum drbd2_role - Role of a resource on a node. Values mirror enum drbd_role
+ * in linux/drbd.h so both netlink dialects share one numbering.
+ * @DRBD2_ROLE_UNKNOWN: The role is not known, for example because the peer is
+ * not connected.
+ * @DRBD2_ROLE_PRIMARY: The resource is primary; its devices may be opened for
+ * writing.
+ * @DRBD2_ROLE_SECONDARY: The resource is secondary; its devices may not be
+ * opened for writing.
+ */
+enum drbd2_role {
+ DRBD2_ROLE_UNKNOWN,
+ DRBD2_ROLE_PRIMARY,
+ DRBD2_ROLE_SECONDARY,
+};
+
+/**
+ * enum drbd2_connection_state - State of a connection to a peer. Values mirror
+ * enum drbd_conn_state in linux/drbd.h so both netlink dialects share one
+ * numbering.
+ * @DRBD2_CONNECTION_STATE_STANDALONE: No network configuration is in effect
+ * and no connection is attempted.
+ * @DRBD2_CONNECTION_STATE_DISCONNECTING: Temporary state on the way to
+ * standalone while the connection is torn down.
+ * @DRBD2_CONNECTION_STATE_UNCONNECTED: Temporary state before the next
+ * connection attempt starts.
+ * @DRBD2_CONNECTION_STATE_TIMEOUT: The connection was dropped because the peer
+ * did not answer in time.
+ * @DRBD2_CONNECTION_STATE_BROKEN_PIPE: The connection was dropped because the
+ * transport reported a broken connection.
+ * @DRBD2_CONNECTION_STATE_NETWORK_FAILURE: The connection was dropped because
+ * of a network failure.
+ * @DRBD2_CONNECTION_STATE_PROTOCOL_ERROR: The connection was dropped because
+ * the peer violated the replication protocol.
+ * @DRBD2_CONNECTION_STATE_TEAR_DOWN: Temporary state while the peer closes the
+ * connection.
+ * @DRBD2_CONNECTION_STATE_CONNECTING: Listening for the peer and trying to
+ * establish a connection.
+ * @DRBD2_CONNECTION_STATE_CONNECTED: A connection to the peer is established.
+ */
+enum drbd2_connection_state {
+ DRBD2_CONNECTION_STATE_STANDALONE,
+ DRBD2_CONNECTION_STATE_DISCONNECTING,
+ DRBD2_CONNECTION_STATE_UNCONNECTED,
+ DRBD2_CONNECTION_STATE_TIMEOUT,
+ DRBD2_CONNECTION_STATE_BROKEN_PIPE,
+ DRBD2_CONNECTION_STATE_NETWORK_FAILURE,
+ DRBD2_CONNECTION_STATE_PROTOCOL_ERROR,
+ DRBD2_CONNECTION_STATE_TEAR_DOWN,
+ DRBD2_CONNECTION_STATE_CONNECTING,
+ DRBD2_CONNECTION_STATE_CONNECTED,
+};
+
+/**
+ * enum drbd2_repl_state - Replication state of a peer device. Values mirror
+ * enum drbd_repl_state in linux/drbd.h so both netlink dialects share one
+ * numbering.
+ * @DRBD2_REPL_STATE_OFF: The peer device does not replicate because the
+ * connection is not established.
+ * @DRBD2_REPL_STATE_ESTABLISHED: The peer device is connected and replicating
+ * normally.
+ * @DRBD2_REPL_STATE_STARTING_SYNC_S: A full resynchronization was requested by
+ * the administrator and starts with this node as the source.
+ * @DRBD2_REPL_STATE_STARTING_SYNC_T: A full resynchronization was requested by
+ * the administrator and starts with this node as the target.
+ * @DRBD2_REPL_STATE_WF_BITMAP_S: Waiting for the bitmap exchange to finish,
+ * with this node as the prospective resync source.
+ * @DRBD2_REPL_STATE_WF_BITMAP_T: Waiting for the bitmap exchange to finish,
+ * with this node as the prospective resync target.
+ * @DRBD2_REPL_STATE_WF_SYNC_UUID: Waiting for the resync source to create and
+ * send the new resync UUID.
+ * @DRBD2_REPL_STATE_SYNC_SOURCE: Resynchronization is running with this node
+ * as the source.
+ * @DRBD2_REPL_STATE_SYNC_TARGET: Resynchronization is running with this node
+ * as the target.
+ * @DRBD2_REPL_STATE_VERIFY_S: Online verification is running with this node as
+ * the initiator.
+ * @DRBD2_REPL_STATE_VERIFY_T: Online verification is running with this node as
+ * the target.
+ * @DRBD2_REPL_STATE_PAUSED_SYNC_S: Resynchronization with this node as the
+ * source is paused.
+ * @DRBD2_REPL_STATE_PAUSED_SYNC_T: Resynchronization with this node as the
+ * target is paused.
+ * @DRBD2_REPL_STATE_AHEAD: Replication is suspended because the link is
+ * congested; changes are only recorded in the bitmap.
+ * @DRBD2_REPL_STATE_BEHIND: The peer is ahead of this node, which will be
+ * resynchronized once the congestion is over.
+ */
+enum drbd2_repl_state {
+ DRBD2_REPL_STATE_OFF = 9,
+ DRBD2_REPL_STATE_ESTABLISHED,
+ DRBD2_REPL_STATE_STARTING_SYNC_S,
+ DRBD2_REPL_STATE_STARTING_SYNC_T,
+ DRBD2_REPL_STATE_WF_BITMAP_S,
+ DRBD2_REPL_STATE_WF_BITMAP_T,
+ DRBD2_REPL_STATE_WF_SYNC_UUID,
+ DRBD2_REPL_STATE_SYNC_SOURCE,
+ DRBD2_REPL_STATE_SYNC_TARGET,
+ DRBD2_REPL_STATE_VERIFY_S,
+ DRBD2_REPL_STATE_VERIFY_T,
+ DRBD2_REPL_STATE_PAUSED_SYNC_S,
+ DRBD2_REPL_STATE_PAUSED_SYNC_T,
+ DRBD2_REPL_STATE_AHEAD,
+ DRBD2_REPL_STATE_BEHIND,
+};
+
+/**
+ * enum drbd2_disk_state - State of a backing disk. Values mirror enum
+ * drbd_disk_state in linux/drbd.h so both netlink dialects share one
+ * numbering.
+ * @DRBD2_DISK_STATE_DISKLESS: No backing device is attached.
+ * @DRBD2_DISK_STATE_ATTACHING: The backing device's metadata is being read.
+ * @DRBD2_DISK_STATE_DETACHING: The backing device is being detached while
+ * pending I/O drains.
+ * @DRBD2_DISK_STATE_FAILED: The backing device failed; the disk becomes
+ * diskless once the peers have been told.
+ * @DRBD2_DISK_STATE_NEGOTIATING: Attaching while connected, with the data
+ * generation still being negotiated with the peers.
+ * @DRBD2_DISK_STATE_INCONSISTENT: The data is inconsistent, for example
+ * because a resynchronization is in progress.
+ * @DRBD2_DISK_STATE_OUTDATED: The data is consistent but known to be stale
+ * relative to a peer.
+ * @DRBD2_DISK_STATE_UNKNOWN: The disk state is not known; used only for a
+ * peer's disk.
+ * @DRBD2_DISK_STATE_CONSISTENT: The data is consistent but it is not yet known
+ * whether it is up to date.
+ * @DRBD2_DISK_STATE_UP_TO_DATE: The data is consistent and up to date; only
+ * this state allows application I/O.
+ */
+enum drbd2_disk_state {
+ DRBD2_DISK_STATE_DISKLESS,
+ DRBD2_DISK_STATE_ATTACHING,
+ DRBD2_DISK_STATE_DETACHING,
+ DRBD2_DISK_STATE_FAILED,
+ DRBD2_DISK_STATE_NEGOTIATING,
+ DRBD2_DISK_STATE_INCONSISTENT,
+ DRBD2_DISK_STATE_OUTDATED,
+ DRBD2_DISK_STATE_UNKNOWN,
+ DRBD2_DISK_STATE_CONSISTENT,
+ DRBD2_DISK_STATE_UP_TO_DATE,
+};
+
+/**
+ * enum drbd2_write_ordering - Write ordering method in use for the backing
+ * device.
+ * @DRBD2_WRITE_ORDERING_NONE: No ordering between dependent writes is enforced
+ * on the backing device.
+ * @DRBD2_WRITE_ORDERING_DRAIN_IO: Dependent writes are ordered by draining the
+ * backing device's request queue.
+ * @DRBD2_WRITE_ORDERING_BDEV_FLUSH: Dependent writes are ordered by issuing
+ * flushes to the backing device.
+ * @DRBD2_WRITE_ORDERING_BIO_BARRIER: Dependent writes are ordered with block
+ * device barriers, which the Linux block layer no longer provides.
+ */
+enum drbd2_write_ordering {
+ DRBD2_WRITE_ORDERING_NONE,
+ DRBD2_WRITE_ORDERING_DRAIN_IO,
+ DRBD2_WRITE_ORDERING_BDEV_FLUSH,
+ DRBD2_WRITE_ORDERING_BIO_BARRIER,
+};
+
+/**
+ * enum drbd2_timeout_type - Which wait-for-connection timeout applies
+ * (timeout-type-get reply).
+ * @DRBD2_TIMEOUT_TYPE_DEFAULT: The regular wait-for-connection timeout
+ * applies.
+ * @DRBD2_TIMEOUT_TYPE_DEGRADED: The degraded-cluster timeout applies because
+ * the local data is not up to date.
+ * @DRBD2_TIMEOUT_TYPE_PEER_OUTDATED: The timeout for an outdated peer applies.
+ */
+enum drbd2_timeout_type {
+ DRBD2_TIMEOUT_TYPE_DEFAULT,
+ DRBD2_TIMEOUT_TYPE_DEGRADED,
+ DRBD2_TIMEOUT_TYPE_PEER_OUTDATED,
+};
+
+/**
+ * enum drbd2_helper_phase - Whether a helper notification announces the call
+ * or reports its result.
+ * @DRBD2_HELPER_PHASE_CALL: The helper script is about to be called.
+ * @DRBD2_HELPER_PHASE_RESPONSE: The helper script has finished and its exit
+ * status is reported.
+ */
+enum drbd2_helper_phase {
+ DRBD2_HELPER_PHASE_CALL,
+ DRBD2_HELPER_PHASE_RESPONSE,
+};
+
+/**
+ * enum drbd2_state_change_action - What a state-change message reports about
+ * the object it carries. Values are assigned independently of the legacy
+ * drbd_notification_type.
+ * @DRBD2_STATE_CHANGE_ACTION_EXISTS: The object already existed when the
+ * notification stream was opened.
+ * @DRBD2_STATE_CHANGE_ACTION_CREATE: The object was just created.
+ * @DRBD2_STATE_CHANGE_ACTION_CHANGE: The state or statistics of the object
+ * changed.
+ * @DRBD2_STATE_CHANGE_ACTION_DESTROY: The object was destroyed.
+ * @DRBD2_STATE_CHANGE_ACTION_RENAME: The resource was renamed; the new name is
+ * carried in resource.new-name.
+ */
+enum drbd2_state_change_action {
+ DRBD2_STATE_CHANGE_ACTION_EXISTS,
+ DRBD2_STATE_CHANGE_ACTION_CREATE,
+ DRBD2_STATE_CHANGE_ACTION_CHANGE,
+ DRBD2_STATE_CHANGE_ACTION_DESTROY,
+ DRBD2_STATE_CHANGE_ACTION_RENAME,
+};
+
+/**
+ * enum drbd2_state_result - Outcome of a state change request. Error values
+ * equal the negated kernel-internal SS_* codes (value 3 is unused); success
+ * and the other non-error outcomes follow at 29 and above.
+ * @DRBD2_STATE_RESULT_UNKNOWN_ERROR: The state change failed for an
+ * unspecified reason.
+ * @DRBD2_STATE_RESULT_TWO_PRIMARIES: Multiple primaries are not allowed by the
+ * configuration.
+ * @DRBD2_STATE_RESULT_NO_UP_TO_DATE_DISK: The request needs access to
+ * up-to-date data.
+ * @DRBD2_STATE_RESULT_NO_LOCAL_DISK: Cannot resynchronize without a local
+ * disk.
+ * @DRBD2_STATE_RESULT_NO_REMOTE_DISK: Cannot resynchronize without a remote
+ * disk.
+ * @DRBD2_STATE_RESULT_CONNECTED_OUTDATES: Refusing to become outdated while
+ * connected.
+ * @DRBD2_STATE_RESULT_PRIMARY_NOP: Refusing to become primary while the peer
+ * is not outdated.
+ * @DRBD2_STATE_RESULT_RESYNC_RUNNING: Cannot start online verify or
+ * resynchronization because one is already active.
+ * @DRBD2_STATE_RESULT_ALREADY_STANDALONE: Cannot disconnect a connection that
+ * is already standalone.
+ * @DRBD2_STATE_RESULT_CW_FAILED_BY_PEER: The cluster-wide state change was
+ * refused by a peer node.
+ * @DRBD2_STATE_RESULT_IS_DISKLESS: The device is diskless but the requested
+ * operation requires a disk.
+ * @DRBD2_STATE_RESULT_DEVICE_IN_USE: The device is held open by someone.
+ * @DRBD2_STATE_RESULT_NO_NET_CONFIG: There is no network configuration for
+ * this connection.
+ * @DRBD2_STATE_RESULT_NO_VERIFY_ALG: Starting online verify requires a verify
+ * algorithm to be configured.
+ * @DRBD2_STATE_RESULT_NEED_CONNECTION: The state change requires an
+ * established connection.
+ * @DRBD2_STATE_RESULT_LOWER_THAN_OUTDATED: The disk state is lower than
+ * outdated.
+ * @DRBD2_STATE_RESULT_NOT_SUPPORTED: The peer does not support the requested
+ * protocol feature.
+ * @DRBD2_STATE_RESULT_IN_TRANSIENT_STATE: The object is in a transient state;
+ * retry after the next state change.
+ * @DRBD2_STATE_RESULT_CONCURRENT_STATE_CHANGE: Concurrent state changes were
+ * detected and this one was aborted.
+ * @DRBD2_STATE_RESULT_OTHER_VOLUME_PEER_PRIMARY: Another volume is primary on
+ * the peer, which the configuration does not allow.
+ * @DRBD2_STATE_RESULT_INTERRUPTED: The state change was interrupted.
+ * @DRBD2_STATE_RESULT_PRIMARY_READER: The peer may not become primary while
+ * the device is open for reading here.
+ * @DRBD2_STATE_RESULT_TIMEOUT: The state change timed out.
+ * @DRBD2_STATE_RESULT_WEAKLY_CONNECTED: Primary nodes must be strongly
+ * connected among each other.
+ * @DRBD2_STATE_RESULT_NO_QUORUM: The resource does not have quorum.
+ * @DRBD2_STATE_RESULT_ATTACH_NO_BITMAP: An intentionally diskless peer may not
+ * attach a disk.
+ * @DRBD2_STATE_RESULT_HANDSHAKE_DISCONNECT: Disconnect was chosen during the
+ * connection handshake.
+ * @DRBD2_STATE_RESULT_HANDSHAKE_RETRY: Retry was chosen during the connection
+ * handshake.
+ * @DRBD2_STATE_RESULT_SUCCESS: The state change succeeded.
+ * @DRBD2_STATE_RESULT_NOTHING_TO_DO: The requested state was already in
+ * effect, so nothing had to be done.
+ * @DRBD2_STATE_RESULT_CW_SUCCESS: The cluster-wide state change succeeded.
+ * @DRBD2_STATE_RESULT_CW_NO_NEED: No cluster-wide state change was necessary.
+ */
+enum drbd2_state_result {
+ DRBD2_STATE_RESULT_UNKNOWN_ERROR,
+ DRBD2_STATE_RESULT_TWO_PRIMARIES,
+ DRBD2_STATE_RESULT_NO_UP_TO_DATE_DISK,
+ DRBD2_STATE_RESULT_NO_LOCAL_DISK = 4,
+ DRBD2_STATE_RESULT_NO_REMOTE_DISK,
+ DRBD2_STATE_RESULT_CONNECTED_OUTDATES,
+ DRBD2_STATE_RESULT_PRIMARY_NOP,
+ DRBD2_STATE_RESULT_RESYNC_RUNNING,
+ DRBD2_STATE_RESULT_ALREADY_STANDALONE,
+ DRBD2_STATE_RESULT_CW_FAILED_BY_PEER,
+ DRBD2_STATE_RESULT_IS_DISKLESS,
+ DRBD2_STATE_RESULT_DEVICE_IN_USE,
+ DRBD2_STATE_RESULT_NO_NET_CONFIG,
+ DRBD2_STATE_RESULT_NO_VERIFY_ALG,
+ DRBD2_STATE_RESULT_NEED_CONNECTION,
+ DRBD2_STATE_RESULT_LOWER_THAN_OUTDATED,
+ DRBD2_STATE_RESULT_NOT_SUPPORTED,
+ DRBD2_STATE_RESULT_IN_TRANSIENT_STATE,
+ DRBD2_STATE_RESULT_CONCURRENT_STATE_CHANGE,
+ DRBD2_STATE_RESULT_OTHER_VOLUME_PEER_PRIMARY,
+ DRBD2_STATE_RESULT_INTERRUPTED,
+ DRBD2_STATE_RESULT_PRIMARY_READER,
+ DRBD2_STATE_RESULT_TIMEOUT,
+ DRBD2_STATE_RESULT_WEAKLY_CONNECTED,
+ DRBD2_STATE_RESULT_NO_QUORUM,
+ DRBD2_STATE_RESULT_ATTACH_NO_BITMAP,
+ DRBD2_STATE_RESULT_HANDSHAKE_DISCONNECT,
+ DRBD2_STATE_RESULT_HANDSHAKE_RETRY,
+ DRBD2_STATE_RESULT_SUCCESS,
+ DRBD2_STATE_RESULT_NOTHING_TO_DO,
+ DRBD2_STATE_RESULT_CW_SUCCESS,
+ DRBD2_STATE_RESULT_CW_NO_NEED,
+};
+
+enum {
+ DRBD2_A_ADDRESS_FAMILY = 1,
+ DRBD2_A_ADDRESS_PORT,
+ DRBD2_A_ADDRESS_IPV4,
+ DRBD2_A_ADDRESS_IPV6,
+
+ __DRBD2_A_ADDRESS_MAX,
+ DRBD2_A_ADDRESS_MAX = (__DRBD2_A_ADDRESS_MAX - 1)
+};
+
+enum {
+ DRBD2_A_CONTEXT_RESOURCE_NAME = 1,
+ DRBD2_A_CONTEXT_VOLUME,
+ DRBD2_A_CONTEXT_MINOR,
+ DRBD2_A_CONTEXT_PEER_NODE_ID,
+ DRBD2_A_CONTEXT_CONNECTION_NAME,
+ DRBD2_A_CONTEXT_MY_ADDRESS,
+ DRBD2_A_CONTEXT_PEER_ADDRESS,
+
+ __DRBD2_A_CONTEXT_MAX,
+ DRBD2_A_CONTEXT_MAX = (__DRBD2_A_CONTEXT_MAX - 1)
+};
+
+enum {
+ DRBD2_A_DISK_CONF_BACKING_DEV = 1,
+ DRBD2_A_DISK_CONF_META_DEV,
+ DRBD2_A_DISK_CONF_META_DEV_IDX,
+ DRBD2_A_DISK_CONF_SIZE,
+ DRBD2_A_DISK_CONF_ON_IO_ERROR,
+ DRBD2_A_DISK_CONF_RESYNC_AFTER,
+ DRBD2_A_DISK_CONF_AL_EXTENTS,
+ DRBD2_A_DISK_CONF_DISK_BARRIER,
+ DRBD2_A_DISK_CONF_DISK_FLUSHES,
+ DRBD2_A_DISK_CONF_DISK_DRAIN,
+ DRBD2_A_DISK_CONF_MD_FLUSHES,
+ DRBD2_A_DISK_CONF_DISK_TIMEOUT,
+ DRBD2_A_DISK_CONF_READ_BALANCING,
+ DRBD2_A_DISK_CONF_UNPLUG_WATERMARK,
+ DRBD2_A_DISK_CONF_RS_DISCARD_GRANULARITY,
+ DRBD2_A_DISK_CONF_AL_UPDATES,
+ DRBD2_A_DISK_CONF_DISCARD_ZEROES_IF_ALIGNED,
+ DRBD2_A_DISK_CONF_DISABLE_WRITE_SAME,
+ DRBD2_A_DISK_CONF_BITMAP,
+
+ __DRBD2_A_DISK_CONF_MAX,
+ DRBD2_A_DISK_CONF_MAX = (__DRBD2_A_DISK_CONF_MAX - 1)
+};
+
+enum {
+ DRBD2_A_RESOURCE_OPTS_CPU_MASK = 1,
+ DRBD2_A_RESOURCE_OPTS_ON_NO_DATA_ACCESSIBLE,
+ DRBD2_A_RESOURCE_OPTS_AUTO_PROMOTE,
+ DRBD2_A_RESOURCE_OPTS_NODE_ID,
+ DRBD2_A_RESOURCE_OPTS_PEER_ACK_WINDOW,
+ DRBD2_A_RESOURCE_OPTS_TWOPC_TIMEOUT,
+ DRBD2_A_RESOURCE_OPTS_TWOPC_RETRY_TIMEOUT,
+ DRBD2_A_RESOURCE_OPTS_PEER_ACK_DELAY,
+ DRBD2_A_RESOURCE_OPTS_AUTO_PROMOTE_TIMEOUT,
+ DRBD2_A_RESOURCE_OPTS_MAX_IO_DEPTH,
+ DRBD2_A_RESOURCE_OPTS_QUORUM,
+ DRBD2_A_RESOURCE_OPTS_ON_NO_QUORUM,
+ DRBD2_A_RESOURCE_OPTS_QUORUM_MIN_REDUNDANCY,
+ DRBD2_A_RESOURCE_OPTS_ON_SUSPENDED_PRIMARY_OUTDATED,
+ DRBD2_A_RESOURCE_OPTS_DRBD8_COMPAT_MODE,
+ DRBD2_A_RESOURCE_OPTS_EXPLICIT_DRBD8_COMPAT,
+
+ __DRBD2_A_RESOURCE_OPTS_MAX,
+ DRBD2_A_RESOURCE_OPTS_MAX = (__DRBD2_A_RESOURCE_OPTS_MAX - 1)
+};
+
+enum {
+ DRBD2_A_NET_CONF_SHARED_SECRET = 1,
+ DRBD2_A_NET_CONF_CRAM_HMAC_ALG,
+ DRBD2_A_NET_CONF_INTEGRITY_ALG,
+ DRBD2_A_NET_CONF_VERIFY_ALG,
+ DRBD2_A_NET_CONF_CSUMS_ALG,
+ DRBD2_A_NET_CONF_PROTOCOL,
+ DRBD2_A_NET_CONF_CONNECT_INT,
+ DRBD2_A_NET_CONF_TIMEOUT,
+ DRBD2_A_NET_CONF_PING_INT,
+ DRBD2_A_NET_CONF_PING_TIMEO,
+ DRBD2_A_NET_CONF_SNDBUF_SIZE,
+ DRBD2_A_NET_CONF_RCVBUF_SIZE,
+ DRBD2_A_NET_CONF_KO_COUNT,
+ DRBD2_A_NET_CONF_MAX_EPOCH_SIZE,
+ DRBD2_A_NET_CONF_AFTER_SB_0PRI,
+ DRBD2_A_NET_CONF_AFTER_SB_1PRI,
+ DRBD2_A_NET_CONF_AFTER_SB_2PRI,
+ DRBD2_A_NET_CONF_RR_CONFLICT,
+ DRBD2_A_NET_CONF_ON_CONGESTION,
+ DRBD2_A_NET_CONF_CONG_FILL,
+ DRBD2_A_NET_CONF_CONG_EXTENTS,
+ DRBD2_A_NET_CONF_TWO_PRIMARIES,
+ DRBD2_A_NET_CONF_TCP_CORK,
+ DRBD2_A_NET_CONF_ALWAYS_ASBP,
+ DRBD2_A_NET_CONF_USE_RLE,
+ DRBD2_A_NET_CONF_FENCING,
+ DRBD2_A_NET_CONF_CONNECTION_NAME,
+ DRBD2_A_NET_CONF_CSUMS_AFTER_CRASH_ONLY,
+ DRBD2_A_NET_CONF_SOCK_CHECK_TIMEO,
+ DRBD2_A_NET_CONF_TRANSPORT_NAME,
+ DRBD2_A_NET_CONF_MAX_BUFFERS,
+ DRBD2_A_NET_CONF_ALLOW_REMOTE_READ,
+ DRBD2_A_NET_CONF_TLS,
+ DRBD2_A_NET_CONF_TLS_PRIVKEY,
+ DRBD2_A_NET_CONF_TLS_CERTIFICATE,
+ DRBD2_A_NET_CONF_TLS_KEYRING,
+ DRBD2_A_NET_CONF_LOAD_BALANCE_PATHS,
+ DRBD2_A_NET_CONF_RDMA_CTRL_RCVBUF_SIZE,
+ DRBD2_A_NET_CONF_RDMA_CTRL_SNDBUF_SIZE,
+
+ __DRBD2_A_NET_CONF_MAX,
+ DRBD2_A_NET_CONF_MAX = (__DRBD2_A_NET_CONF_MAX - 1)
+};
+
+enum {
+ DRBD2_A_SET_ROLE_PARMS_FORCE = 1,
+
+ __DRBD2_A_SET_ROLE_PARMS_MAX,
+ DRBD2_A_SET_ROLE_PARMS_MAX = (__DRBD2_A_SET_ROLE_PARMS_MAX - 1)
+};
+
+enum {
+ DRBD2_A_RESIZE_PARMS_SIZE = 1,
+ DRBD2_A_RESIZE_PARMS_ASSUME_PEER_HAS_SPACE,
+ DRBD2_A_RESIZE_PARMS_ASSUME_CLEAN,
+ DRBD2_A_RESIZE_PARMS_AL_STRIPES,
+ DRBD2_A_RESIZE_PARMS_AL_STRIPE_SIZE,
+
+ __DRBD2_A_RESIZE_PARMS_MAX,
+ DRBD2_A_RESIZE_PARMS_MAX = (__DRBD2_A_RESIZE_PARMS_MAX - 1)
+};
+
+enum {
+ DRBD2_A_START_OV_PARMS_START_SECTOR = 1,
+ DRBD2_A_START_OV_PARMS_STOP_SECTOR,
+
+ __DRBD2_A_START_OV_PARMS_MAX,
+ DRBD2_A_START_OV_PARMS_MAX = (__DRBD2_A_START_OV_PARMS_MAX - 1)
+};
+
+enum {
+ DRBD2_A_NEW_CURRENT_UUID_PARMS_CLEAR_BM = 1,
+ DRBD2_A_NEW_CURRENT_UUID_PARMS_FORCE_RESYNC,
+
+ __DRBD2_A_NEW_CURRENT_UUID_PARMS_MAX,
+ DRBD2_A_NEW_CURRENT_UUID_PARMS_MAX = (__DRBD2_A_NEW_CURRENT_UUID_PARMS_MAX - 1)
+};
+
+enum {
+ DRBD2_A_DISCONNECT_PARMS_FORCE = 1,
+
+ __DRBD2_A_DISCONNECT_PARMS_MAX,
+ DRBD2_A_DISCONNECT_PARMS_MAX = (__DRBD2_A_DISCONNECT_PARMS_MAX - 1)
+};
+
+enum {
+ DRBD2_A_DETACH_PARMS_FORCE = 1,
+ DRBD2_A_DETACH_PARMS_INTENTIONAL_DISKLESS_DETACH,
+
+ __DRBD2_A_DETACH_PARMS_MAX,
+ DRBD2_A_DETACH_PARMS_MAX = (__DRBD2_A_DETACH_PARMS_MAX - 1)
+};
+
+enum {
+ DRBD2_A_DEVICE_CONF_MAX_BIO_SIZE = 1,
+ DRBD2_A_DEVICE_CONF_INTENTIONAL_DISKLESS,
+ DRBD2_A_DEVICE_CONF_BLOCK_SIZE,
+ DRBD2_A_DEVICE_CONF_DISCARD_GRANULARITY,
+
+ __DRBD2_A_DEVICE_CONF_MAX,
+ DRBD2_A_DEVICE_CONF_MAX = (__DRBD2_A_DEVICE_CONF_MAX - 1)
+};
+
+enum {
+ DRBD2_A_RESOURCE_INFO_ROLE = 1,
+ DRBD2_A_RESOURCE_INFO_SUSP,
+ DRBD2_A_RESOURCE_INFO_SUSP_NOD,
+ DRBD2_A_RESOURCE_INFO_SUSP_FEN,
+ DRBD2_A_RESOURCE_INFO_SUSP_QUORUM,
+ DRBD2_A_RESOURCE_INFO_FAIL_IO,
+
+ __DRBD2_A_RESOURCE_INFO_MAX,
+ DRBD2_A_RESOURCE_INFO_MAX = (__DRBD2_A_RESOURCE_INFO_MAX - 1)
+};
+
+enum {
+ DRBD2_A_DEVICE_INFO_DISK_STATE = 1,
+ DRBD2_A_DEVICE_INFO_IS_INTENTIONAL_DISKLESS,
+ DRBD2_A_DEVICE_INFO_HAS_QUORUM,
+ DRBD2_A_DEVICE_INFO_IS_OPEN,
+ DRBD2_A_DEVICE_INFO_BACKING_DEV_PATH,
+
+ __DRBD2_A_DEVICE_INFO_MAX,
+ DRBD2_A_DEVICE_INFO_MAX = (__DRBD2_A_DEVICE_INFO_MAX - 1)
+};
+
+enum {
+ DRBD2_A_CONNECTION_INFO_CONNECTION_STATE = 1,
+ DRBD2_A_CONNECTION_INFO_ROLE,
+
+ __DRBD2_A_CONNECTION_INFO_MAX,
+ DRBD2_A_CONNECTION_INFO_MAX = (__DRBD2_A_CONNECTION_INFO_MAX - 1)
+};
+
+enum {
+ DRBD2_A_PEER_DEVICE_INFO_REPL_STATE = 1,
+ DRBD2_A_PEER_DEVICE_INFO_DISK_STATE,
+ DRBD2_A_PEER_DEVICE_INFO_RESYNC_SUSP_USER,
+ DRBD2_A_PEER_DEVICE_INFO_RESYNC_SUSP_PEER,
+ DRBD2_A_PEER_DEVICE_INFO_RESYNC_SUSP_DEPENDENCY,
+ DRBD2_A_PEER_DEVICE_INFO_IS_INTENTIONAL_DISKLESS,
+ DRBD2_A_PEER_DEVICE_INFO_RESYNC_SUSP_MAX_PARALLEL,
+
+ __DRBD2_A_PEER_DEVICE_INFO_MAX,
+ DRBD2_A_PEER_DEVICE_INFO_MAX = (__DRBD2_A_PEER_DEVICE_INFO_MAX - 1)
+};
+
+enum {
+ DRBD2_A_RESOURCE_STATISTICS_WRITE_ORDERING = 1,
+
+ __DRBD2_A_RESOURCE_STATISTICS_MAX,
+ DRBD2_A_RESOURCE_STATISTICS_MAX = (__DRBD2_A_RESOURCE_STATISTICS_MAX - 1)
+};
+
+enum {
+ DRBD2_A_DEVICE_STATISTICS_SIZE = 1,
+ DRBD2_A_DEVICE_STATISTICS_READ,
+ DRBD2_A_DEVICE_STATISTICS_WRITE,
+ DRBD2_A_DEVICE_STATISTICS_AL_WRITES,
+ DRBD2_A_DEVICE_STATISTICS_BM_WRITES,
+ DRBD2_A_DEVICE_STATISTICS_UPPER_PENDING,
+ DRBD2_A_DEVICE_STATISTICS_LOWER_PENDING,
+ DRBD2_A_DEVICE_STATISTICS_UPPER_BLOCKED,
+ DRBD2_A_DEVICE_STATISTICS_LOWER_BLOCKED,
+ DRBD2_A_DEVICE_STATISTICS_AL_SUSPENDED,
+ DRBD2_A_DEVICE_STATISTICS_EXPOSED_DATA_UUID,
+ DRBD2_A_DEVICE_STATISTICS_CURRENT_UUID,
+ DRBD2_A_DEVICE_STATISTICS_DISK_FLAGS,
+ DRBD2_A_DEVICE_STATISTICS_HISTORY_UUIDS,
+
+ __DRBD2_A_DEVICE_STATISTICS_MAX,
+ DRBD2_A_DEVICE_STATISTICS_MAX = (__DRBD2_A_DEVICE_STATISTICS_MAX - 1)
+};
+
+enum {
+ DRBD2_A_CONNECTION_STATISTICS_CONGESTED = 1,
+ DRBD2_A_CONNECTION_STATISTICS_AP_IN_FLIGHT,
+ DRBD2_A_CONNECTION_STATISTICS_RS_IN_FLIGHT,
+
+ __DRBD2_A_CONNECTION_STATISTICS_MAX,
+ DRBD2_A_CONNECTION_STATISTICS_MAX = (__DRBD2_A_CONNECTION_STATISTICS_MAX - 1)
+};
+
+enum {
+ DRBD2_A_PEER_DEVICE_STATISTICS_RECEIVED = 1,
+ DRBD2_A_PEER_DEVICE_STATISTICS_SENT,
+ DRBD2_A_PEER_DEVICE_STATISTICS_PENDING,
+ DRBD2_A_PEER_DEVICE_STATISTICS_UNACKED,
+ DRBD2_A_PEER_DEVICE_STATISTICS_OUT_OF_SYNC,
+ DRBD2_A_PEER_DEVICE_STATISTICS_RESYNC_FAILED,
+ DRBD2_A_PEER_DEVICE_STATISTICS_BITMAP_UUID,
+ DRBD2_A_PEER_DEVICE_STATISTICS_FLAGS,
+ DRBD2_A_PEER_DEVICE_STATISTICS_RS_TOTAL,
+ DRBD2_A_PEER_DEVICE_STATISTICS_OV_START_SECTOR,
+ DRBD2_A_PEER_DEVICE_STATISTICS_OV_STOP_SECTOR,
+ DRBD2_A_PEER_DEVICE_STATISTICS_OV_POSITION,
+ DRBD2_A_PEER_DEVICE_STATISTICS_OV_LEFT,
+ DRBD2_A_PEER_DEVICE_STATISTICS_OV_SKIPPED,
+ DRBD2_A_PEER_DEVICE_STATISTICS_RS_SAME_CSUM,
+ DRBD2_A_PEER_DEVICE_STATISTICS_RS_DT_START_MS,
+ DRBD2_A_PEER_DEVICE_STATISTICS_RS_PAUSED_MS,
+ DRBD2_A_PEER_DEVICE_STATISTICS_RS_DT0_MS,
+ DRBD2_A_PEER_DEVICE_STATISTICS_RS_DB0_SECTORS,
+ DRBD2_A_PEER_DEVICE_STATISTICS_RS_DT1_MS,
+ DRBD2_A_PEER_DEVICE_STATISTICS_RS_DB1_SECTORS,
+ DRBD2_A_PEER_DEVICE_STATISTICS_RS_C_SYNC_RATE,
+ DRBD2_A_PEER_DEVICE_STATISTICS_UUID_FLAGS,
+
+ __DRBD2_A_PEER_DEVICE_STATISTICS_MAX,
+ DRBD2_A_PEER_DEVICE_STATISTICS_MAX = (__DRBD2_A_PEER_DEVICE_STATISTICS_MAX - 1)
+};
+
+enum {
+ DRBD2_A_HELPER_INFO_NAME = 1,
+ DRBD2_A_HELPER_INFO_STATUS,
+ DRBD2_A_HELPER_INFO_PHASE,
+
+ __DRBD2_A_HELPER_INFO_MAX,
+ DRBD2_A_HELPER_INFO_MAX = (__DRBD2_A_HELPER_INFO_MAX - 1)
+};
+
+enum {
+ DRBD2_A_INVALIDATE_PARMS_SYNC_FROM_PEER_NODE_ID = 1,
+ DRBD2_A_INVALIDATE_PARMS_RESET_BITMAP,
+
+ __DRBD2_A_INVALIDATE_PARMS_MAX,
+ DRBD2_A_INVALIDATE_PARMS_MAX = (__DRBD2_A_INVALIDATE_PARMS_MAX - 1)
+};
+
+enum {
+ DRBD2_A_PEER_DEVICE_CONF_RESYNC_RATE = 1,
+ DRBD2_A_PEER_DEVICE_CONF_C_PLAN_AHEAD,
+ DRBD2_A_PEER_DEVICE_CONF_C_DELAY_TARGET,
+ DRBD2_A_PEER_DEVICE_CONF_C_FILL_TARGET,
+ DRBD2_A_PEER_DEVICE_CONF_C_MAX_RATE,
+ DRBD2_A_PEER_DEVICE_CONF_C_MIN_RATE,
+ DRBD2_A_PEER_DEVICE_CONF_BITMAP,
+ DRBD2_A_PEER_DEVICE_CONF_RESYNC_WITHOUT_REPLICATION,
+ DRBD2_A_PEER_DEVICE_CONF_PEER_TIEBREAKER,
+
+ __DRBD2_A_PEER_DEVICE_CONF_MAX,
+ DRBD2_A_PEER_DEVICE_CONF_MAX = (__DRBD2_A_PEER_DEVICE_CONF_MAX - 1)
+};
+
+enum {
+ DRBD2_A_CONNECT_PARMS_TENTATIVE = 1,
+ DRBD2_A_CONNECT_PARMS_DISCARD_MY_DATA,
+
+ __DRBD2_A_CONNECT_PARMS_MAX,
+ DRBD2_A_CONNECT_PARMS_MAX = (__DRBD2_A_CONNECT_PARMS_MAX - 1)
+};
+
+enum {
+ DRBD2_A_PATH_INFO_ESTABLISHED = 1,
+
+ __DRBD2_A_PATH_INFO_MAX,
+ DRBD2_A_PATH_INFO_MAX = (__DRBD2_A_PATH_INFO_MAX - 1)
+};
+
+enum {
+ DRBD2_A_RENAME_PARMS_NEW_NAME = 1,
+
+ __DRBD2_A_RENAME_PARMS_MAX,
+ DRBD2_A_RENAME_PARMS_MAX = (__DRBD2_A_RENAME_PARMS_MAX - 1)
+};
+
+enum {
+ DRBD2_A_INVALIDATE_PEER_PARMS_RESET_BITMAP = 1,
+
+ __DRBD2_A_INVALIDATE_PEER_PARMS_MAX,
+ DRBD2_A_INVALIDATE_PEER_PARMS_MAX = (__DRBD2_A_INVALIDATE_PEER_PARMS_MAX - 1)
+};
+
+enum {
+ DRBD2_A_SUSPEND_IO_PARMS_BDEV_FREEZE = 1,
+
+ __DRBD2_A_SUSPEND_IO_PARMS_MAX,
+ DRBD2_A_SUSPEND_IO_PARMS_MAX = (__DRBD2_A_SUSPEND_IO_PARMS_MAX - 1)
+};
+
+enum {
+ DRBD2_A_RESOURCE_CONTEXT = 1,
+ DRBD2_A_RESOURCE_INFO,
+ DRBD2_A_RESOURCE_STATISTICS,
+ DRBD2_A_RESOURCE_NEW_NAME,
+ DRBD2_A_RESOURCE_RESOURCE_OPTS,
+
+ __DRBD2_A_RESOURCE_MAX,
+ DRBD2_A_RESOURCE_MAX = (__DRBD2_A_RESOURCE_MAX - 1)
+};
+
+enum {
+ DRBD2_A_DEVICE_CONTEXT = 1,
+ DRBD2_A_DEVICE_INFO,
+ DRBD2_A_DEVICE_STATISTICS,
+ DRBD2_A_DEVICE_DISK_CONF,
+ DRBD2_A_DEVICE_DEVICE_CONF,
+
+ __DRBD2_A_DEVICE_MAX,
+ DRBD2_A_DEVICE_MAX = (__DRBD2_A_DEVICE_MAX - 1)
+};
+
+enum {
+ DRBD2_A_CONNECTION_CONTEXT = 1,
+ DRBD2_A_CONNECTION_INFO,
+ DRBD2_A_CONNECTION_STATISTICS,
+ DRBD2_A_CONNECTION_NET_CONF,
+ DRBD2_A_CONNECTION_PATH,
+
+ __DRBD2_A_CONNECTION_MAX,
+ DRBD2_A_CONNECTION_MAX = (__DRBD2_A_CONNECTION_MAX - 1)
+};
+
+enum {
+ DRBD2_A_PEER_DEVICE_CONTEXT = 1,
+ DRBD2_A_PEER_DEVICE_INFO,
+ DRBD2_A_PEER_DEVICE_STATISTICS,
+ DRBD2_A_PEER_DEVICE_PEER_DEVICE_CONF,
+
+ __DRBD2_A_PEER_DEVICE_MAX,
+ DRBD2_A_PEER_DEVICE_MAX = (__DRBD2_A_PEER_DEVICE_MAX - 1)
+};
+
+enum {
+ DRBD2_A_PATH_CONTEXT = 1,
+ DRBD2_A_PATH_INFO,
+
+ __DRBD2_A_PATH_MAX,
+ DRBD2_A_PATH_MAX = (__DRBD2_A_PATH_MAX - 1)
+};
+
+enum {
+ DRBD2_A_CONTEXT = 1,
+ DRBD2_A_SET_DEFAULTS,
+ DRBD2_A_STATE_RESULT,
+ DRBD2_A_MESSAGE,
+ DRBD2_A_TIMEOUT_TYPE,
+ DRBD2_A_DISK_CONF,
+ DRBD2_A_RESOURCE_OPTS,
+ DRBD2_A_NET_CONF,
+ DRBD2_A_SET_ROLE_PARMS,
+ DRBD2_A_RESIZE_PARMS,
+ DRBD2_A_START_OV_PARMS,
+ DRBD2_A_NEW_CURRENT_UUID_PARMS,
+ DRBD2_A_DISCONNECT_PARMS,
+ DRBD2_A_DETACH_PARMS,
+ DRBD2_A_DEVICE_CONF,
+ DRBD2_A_HELPER,
+ DRBD2_A_INVALIDATE_PARMS,
+ DRBD2_A_PEER_DEVICE_CONF,
+ DRBD2_A_CONNECT_PARMS,
+ DRBD2_A_RENAME_PARMS,
+ DRBD2_A_INVALIDATE_PEER_PARMS,
+ DRBD2_A_SUSPEND_IO_PARMS,
+ DRBD2_A_RESOURCE,
+ DRBD2_A_DEVICE,
+ DRBD2_A_CONNECTION,
+ DRBD2_A_PEER_DEVICE,
+ DRBD2_A_PATH,
+
+ __DRBD2_A_MAX,
+ DRBD2_A_MAX = (__DRBD2_A_MAX - 1)
+};
+
+enum {
+ DRBD2_A_STATE_CHANGE_ACTION = 1,
+ DRBD2_A_STATE_CHANGE_MORE,
+ DRBD2_A_STATE_CHANGE_RESOURCE,
+ DRBD2_A_STATE_CHANGE_DEVICE,
+ DRBD2_A_STATE_CHANGE_CONNECTION,
+ DRBD2_A_STATE_CHANGE_PEER_DEVICE,
+ DRBD2_A_STATE_CHANGE_PATH,
+
+ __DRBD2_A_STATE_CHANGE_MAX,
+ DRBD2_A_STATE_CHANGE_MAX = (__DRBD2_A_STATE_CHANGE_MAX - 1)
+};
+
+enum {
+ DRBD2_CMD_RESOURCE_NEW = 1,
+ DRBD2_CMD_RESOURCE_DEL,
+ DRBD2_CMD_RESOURCE_SET,
+ DRBD2_CMD_RESOURCE_RENAME,
+ DRBD2_CMD_RESOURCE_DOWN,
+ DRBD2_CMD_RESOURCE_PRIMARY,
+ DRBD2_CMD_RESOURCE_SECONDARY,
+ DRBD2_CMD_RESOURCE_SUSPEND_IO,
+ DRBD2_CMD_RESOURCE_RESUME_IO,
+ DRBD2_CMD_DEVICE_NEW,
+ DRBD2_CMD_DEVICE_DEL,
+ DRBD2_CMD_DEVICE_ATTACH,
+ DRBD2_CMD_DEVICE_DETACH,
+ DRBD2_CMD_DISK_SET,
+ DRBD2_CMD_DEVICE_RESIZE,
+ DRBD2_CMD_DEVICE_OUTDATE,
+ DRBD2_CMD_DEVICE_INVALIDATE,
+ DRBD2_CMD_DEVICE_NEW_CURRENT_UUID,
+ DRBD2_CMD_CONNECTION_NEW,
+ DRBD2_CMD_CONNECTION_DEL,
+ DRBD2_CMD_CONNECTION_CONNECT,
+ DRBD2_CMD_CONNECTION_DISCONNECT,
+ DRBD2_CMD_CONNECTION_SET,
+ DRBD2_CMD_CONNECTION_FORGET,
+ DRBD2_CMD_PATH_NEW,
+ DRBD2_CMD_PATH_DEL,
+ DRBD2_CMD_PEER_DEVICE_SET,
+ DRBD2_CMD_PEER_DEVICE_INVALIDATE,
+ DRBD2_CMD_PEER_DEVICE_PAUSE_SYNC,
+ DRBD2_CMD_PEER_DEVICE_RESUME_SYNC,
+ DRBD2_CMD_PEER_DEVICE_START_OV,
+ DRBD2_CMD_TIMEOUT_TYPE_GET,
+ DRBD2_CMD_RESOURCE_GET,
+ DRBD2_CMD_DEVICE_GET,
+ DRBD2_CMD_CONNECTION_GET,
+ DRBD2_CMD_PEER_DEVICE_GET,
+ DRBD2_CMD_PATH_GET,
+ DRBD2_CMD_STATE_GET,
+ DRBD2_CMD_STATE_CHANGE_NTF,
+ DRBD2_CMD_HELPER_NTF,
+
+ __DRBD2_CMD_MAX,
+ DRBD2_CMD_MAX = (__DRBD2_CMD_MAX - 1)
+};
+
+#define DRBD2_MCGRP_EVENTS "events"
+
+#endif /* _UAPI_LINUX_DRBD2_H */
--
2.55.0