From a54f499838292c1768f6575ed1ec7cf35f1b6489 Mon Sep 17 00:00:00 2001 From: Christoph Böhmwalder Date: Wed, 6 May 2026 14:45:40 +0200 Subject: drbd: move UAPI headers to include/uapi/linux/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drbd.h and drbd_limits.h contain only type definitions, enums, and constants shared between kernel and userspace. These should be part of UAPI. Split the genl_api header into two: the genlmsghdr and the enums are UAPI, the rest stays there for now (it will be removed by one of the next commits in this series). drbd_config.h is clearly DRBD-internal, so move it there. Signed-off-by: Christoph Böhmwalder Acked-by: Jakub Kicinski Link: https://patch.msgid.link/20260506124541.1951772-2-christoph.boehmwalder@linbit.com Signed-off-by: Jens Axboe --- include/linux/drbd.h | 392 ----------------------------------- include/linux/drbd_config.h | 16 -- include/linux/drbd_genl_api.h | 40 ---- include/linux/drbd_limits.h | 251 ----------------------- include/uapi/linux/drbd.h | 432 +++++++++++++++++++++++++++++++++++++++ include/uapi/linux/drbd_limits.h | 251 +++++++++++++++++++++++ 6 files changed, 683 insertions(+), 699 deletions(-) delete mode 100644 include/linux/drbd.h delete mode 100644 include/linux/drbd_config.h delete mode 100644 include/linux/drbd_limits.h create mode 100644 include/uapi/linux/drbd.h create mode 100644 include/uapi/linux/drbd_limits.h (limited to 'include') diff --git a/include/linux/drbd.h b/include/linux/drbd.h deleted file mode 100644 index 5468a2399d48..000000000000 --- a/include/linux/drbd.h +++ /dev/null @@ -1,392 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - drbd.h - Kernel module for 2.6.x Kernels - - This file is part of DRBD by Philipp Reisner and Lars Ellenberg. - - Copyright (C) 2001-2008, LINBIT Information Technologies GmbH. - Copyright (C) 2001-2008, Philipp Reisner . - Copyright (C) 2001-2008, Lars Ellenberg . - - -*/ -#ifndef DRBD_H -#define DRBD_H -#include - -#ifdef __KERNEL__ -#include -#include -#else -#include -#include -#include - -/* Although the Linux source code makes a difference between - generic endianness and the bitfields' endianness, there is no - architecture as of Linux-2.6.24-rc4 where the bitfields' endianness - does not match the generic endianness. */ - -#if __BYTE_ORDER == __LITTLE_ENDIAN -#define __LITTLE_ENDIAN_BITFIELD -#elif __BYTE_ORDER == __BIG_ENDIAN -#define __BIG_ENDIAN_BITFIELD -#else -# error "sorry, weird endianness on this box" -#endif - -#endif - -enum drbd_io_error_p { - EP_PASS_ON, /* FIXME should the better be named "Ignore"? */ - EP_CALL_HELPER, - EP_DETACH -}; - -enum drbd_fencing_p { - FP_NOT_AVAIL = -1, /* Not a policy */ - FP_DONT_CARE = 0, - FP_RESOURCE, - FP_STONITH -}; - -enum drbd_disconnect_p { - DP_RECONNECT, - DP_DROP_NET_CONF, - DP_FREEZE_IO -}; - -enum drbd_after_sb_p { - ASB_DISCONNECT, - ASB_DISCARD_YOUNGER_PRI, - ASB_DISCARD_OLDER_PRI, - ASB_DISCARD_ZERO_CHG, - ASB_DISCARD_LEAST_CHG, - ASB_DISCARD_LOCAL, - ASB_DISCARD_REMOTE, - ASB_CONSENSUS, - ASB_DISCARD_SECONDARY, - ASB_CALL_HELPER, - ASB_VIOLENTLY -}; - -enum drbd_on_no_data { - OND_IO_ERROR, - OND_SUSPEND_IO -}; - -enum drbd_on_congestion { - OC_BLOCK, - OC_PULL_AHEAD, - OC_DISCONNECT, -}; - -enum drbd_read_balancing { - RB_PREFER_LOCAL, - RB_PREFER_REMOTE, - RB_ROUND_ROBIN, - RB_LEAST_PENDING, - RB_CONGESTED_REMOTE, - RB_32K_STRIPING, - RB_64K_STRIPING, - RB_128K_STRIPING, - RB_256K_STRIPING, - RB_512K_STRIPING, - RB_1M_STRIPING, -}; - -/* KEEP the order, do not delete or insert. Only append. */ -enum drbd_ret_code { - ERR_CODE_BASE = 100, - NO_ERROR = 101, - ERR_LOCAL_ADDR = 102, - ERR_PEER_ADDR = 103, - ERR_OPEN_DISK = 104, - ERR_OPEN_MD_DISK = 105, - ERR_DISK_NOT_BDEV = 107, - ERR_MD_NOT_BDEV = 108, - ERR_DISK_TOO_SMALL = 111, - ERR_MD_DISK_TOO_SMALL = 112, - ERR_BDCLAIM_DISK = 114, - ERR_BDCLAIM_MD_DISK = 115, - ERR_MD_IDX_INVALID = 116, - ERR_IO_MD_DISK = 118, - ERR_MD_INVALID = 119, - ERR_AUTH_ALG = 120, - ERR_AUTH_ALG_ND = 121, - ERR_NOMEM = 122, - ERR_DISCARD_IMPOSSIBLE = 123, - ERR_DISK_CONFIGURED = 124, - ERR_NET_CONFIGURED = 125, - ERR_MANDATORY_TAG = 126, - ERR_MINOR_INVALID = 127, - ERR_INTR = 129, /* EINTR */ - ERR_RESIZE_RESYNC = 130, - ERR_NO_PRIMARY = 131, - ERR_RESYNC_AFTER = 132, - ERR_RESYNC_AFTER_CYCLE = 133, - ERR_PAUSE_IS_SET = 134, - ERR_PAUSE_IS_CLEAR = 135, - ERR_PACKET_NR = 137, - ERR_NO_DISK = 138, - ERR_NOT_PROTO_C = 139, - ERR_NOMEM_BITMAP = 140, - ERR_INTEGRITY_ALG = 141, /* DRBD 8.2 only */ - ERR_INTEGRITY_ALG_ND = 142, /* DRBD 8.2 only */ - ERR_CPU_MASK_PARSE = 143, /* DRBD 8.2 only */ - ERR_CSUMS_ALG = 144, /* DRBD 8.2 only */ - ERR_CSUMS_ALG_ND = 145, /* DRBD 8.2 only */ - ERR_VERIFY_ALG = 146, /* DRBD 8.2 only */ - ERR_VERIFY_ALG_ND = 147, /* DRBD 8.2 only */ - ERR_CSUMS_RESYNC_RUNNING= 148, /* DRBD 8.2 only */ - ERR_VERIFY_RUNNING = 149, /* DRBD 8.2 only */ - ERR_DATA_NOT_CURRENT = 150, - ERR_CONNECTED = 151, /* DRBD 8.3 only */ - ERR_PERM = 152, - ERR_NEED_APV_93 = 153, - ERR_STONITH_AND_PROT_A = 154, - ERR_CONG_NOT_PROTO_A = 155, - ERR_PIC_AFTER_DEP = 156, - ERR_PIC_PEER_DEP = 157, - ERR_RES_NOT_KNOWN = 158, - ERR_RES_IN_USE = 159, - ERR_MINOR_CONFIGURED = 160, - ERR_MINOR_OR_VOLUME_EXISTS = 161, - ERR_INVALID_REQUEST = 162, - ERR_NEED_APV_100 = 163, - ERR_NEED_ALLOW_TWO_PRI = 164, - ERR_MD_UNCLEAN = 165, - ERR_MD_LAYOUT_CONNECTED = 166, - ERR_MD_LAYOUT_TOO_BIG = 167, - ERR_MD_LAYOUT_TOO_SMALL = 168, - ERR_MD_LAYOUT_NO_FIT = 169, - ERR_IMPLICIT_SHRINK = 170, - /* insert new ones above this line */ - AFTER_LAST_ERR_CODE -}; - -#define DRBD_PROT_A 1 -#define DRBD_PROT_B 2 -#define DRBD_PROT_C 3 - -enum drbd_role { - R_UNKNOWN = 0, - R_PRIMARY = 1, /* role */ - R_SECONDARY = 2, /* role */ - R_MASK = 3, -}; - -/* The order of these constants is important. - * The lower ones (=C_WF_REPORT_PARAMS ==> There is a socket - */ -enum drbd_conns { - C_STANDALONE, - C_DISCONNECTING, /* Temporal state on the way to StandAlone. */ - C_UNCONNECTED, /* >= C_UNCONNECTED -> inc_net() succeeds */ - - /* These temporal states are all used on the way - * from >= C_CONNECTED to Unconnected. - * The 'disconnect reason' states - * I do not allow to change between them. */ - C_TIMEOUT, - C_BROKEN_PIPE, - C_NETWORK_FAILURE, - C_PROTOCOL_ERROR, - C_TEAR_DOWN, - - C_WF_CONNECTION, - C_WF_REPORT_PARAMS, /* we have a socket */ - C_CONNECTED, /* we have introduced each other */ - C_STARTING_SYNC_S, /* starting full sync by admin request. */ - C_STARTING_SYNC_T, /* starting full sync by admin request. */ - C_WF_BITMAP_S, - C_WF_BITMAP_T, - C_WF_SYNC_UUID, - - /* All SyncStates are tested with this comparison - * xx >= C_SYNC_SOURCE && xx <= C_PAUSED_SYNC_T */ - C_SYNC_SOURCE, - C_SYNC_TARGET, - C_VERIFY_S, - C_VERIFY_T, - C_PAUSED_SYNC_S, - C_PAUSED_SYNC_T, - - C_AHEAD, - C_BEHIND, - - C_MASK = 31 -}; - -enum drbd_disk_state { - D_DISKLESS, - D_ATTACHING, /* In the process of reading the meta-data */ - D_FAILED, /* Becomes D_DISKLESS as soon as we told it the peer */ - /* when >= D_FAILED it is legal to access mdev->ldev */ - D_NEGOTIATING, /* Late attaching state, we need to talk to the peer */ - D_INCONSISTENT, - D_OUTDATED, - D_UNKNOWN, /* Only used for the peer, never for myself */ - D_CONSISTENT, /* Might be D_OUTDATED, might be D_UP_TO_DATE ... */ - D_UP_TO_DATE, /* Only this disk state allows applications' IO ! */ - D_MASK = 15 -}; - -union drbd_state { -/* According to gcc's docs is the ... - * The order of allocation of bit-fields within a unit (C90 6.5.2.1, C99 6.7.2.1). - * Determined by ABI. - * pointed out by Maxim Uvarov q - * even though we transmit as "cpu_to_be32(state)", - * the offsets of the bitfields still need to be swapped - * on different endianness. - */ - struct { -#if defined(__LITTLE_ENDIAN_BITFIELD) - unsigned role:2 ; /* 3/4 primary/secondary/unknown */ - unsigned peer:2 ; /* 3/4 primary/secondary/unknown */ - unsigned conn:5 ; /* 17/32 cstates */ - unsigned disk:4 ; /* 8/16 from D_DISKLESS to D_UP_TO_DATE */ - unsigned pdsk:4 ; /* 8/16 from D_DISKLESS to D_UP_TO_DATE */ - unsigned susp:1 ; /* 2/2 IO suspended no/yes (by user) */ - unsigned aftr_isp:1 ; /* isp .. imposed sync pause */ - unsigned peer_isp:1 ; - unsigned user_isp:1 ; - unsigned susp_nod:1 ; /* IO suspended because no data */ - unsigned susp_fen:1 ; /* IO suspended because fence peer handler runs*/ - unsigned _pad:9; /* 0 unused */ -#elif defined(__BIG_ENDIAN_BITFIELD) - unsigned _pad:9; - unsigned susp_fen:1 ; - unsigned susp_nod:1 ; - unsigned user_isp:1 ; - unsigned peer_isp:1 ; - unsigned aftr_isp:1 ; /* isp .. imposed sync pause */ - unsigned susp:1 ; /* 2/2 IO suspended no/yes */ - unsigned pdsk:4 ; /* 8/16 from D_DISKLESS to D_UP_TO_DATE */ - unsigned disk:4 ; /* 8/16 from D_DISKLESS to D_UP_TO_DATE */ - unsigned conn:5 ; /* 17/32 cstates */ - unsigned peer:2 ; /* 3/4 primary/secondary/unknown */ - unsigned role:2 ; /* 3/4 primary/secondary/unknown */ -#else -# error "this endianness is not supported" -#endif - }; - unsigned int i; -}; - -enum drbd_state_rv { - SS_CW_NO_NEED = 4, - SS_CW_SUCCESS = 3, - SS_NOTHING_TO_DO = 2, - SS_SUCCESS = 1, - SS_UNKNOWN_ERROR = 0, /* Used to sleep longer in _drbd_request_state */ - SS_TWO_PRIMARIES = -1, - SS_NO_UP_TO_DATE_DISK = -2, - SS_NO_LOCAL_DISK = -4, - SS_NO_REMOTE_DISK = -5, - SS_CONNECTED_OUTDATES = -6, - SS_PRIMARY_NOP = -7, - SS_RESYNC_RUNNING = -8, - SS_ALREADY_STANDALONE = -9, - SS_CW_FAILED_BY_PEER = -10, - SS_IS_DISKLESS = -11, - SS_DEVICE_IN_USE = -12, - SS_NO_NET_CONFIG = -13, - SS_NO_VERIFY_ALG = -14, /* drbd-8.2 only */ - SS_NEED_CONNECTION = -15, /* drbd-8.2 only */ - SS_LOWER_THAN_OUTDATED = -16, - SS_NOT_SUPPORTED = -17, /* drbd-8.2 only */ - SS_IN_TRANSIENT_STATE = -18, /* Retry after the next state change */ - SS_CONCURRENT_ST_CHG = -19, /* Concurrent cluster side state change! */ - SS_O_VOL_PEER_PRI = -20, - SS_OUTDATE_WO_CONN = -21, - SS_AFTER_LAST_ERROR = -22, /* Keep this at bottom */ -}; - -#define SHARED_SECRET_MAX 64 - -#define MDF_CONSISTENT (1 << 0) -#define MDF_PRIMARY_IND (1 << 1) -#define MDF_CONNECTED_IND (1 << 2) -#define MDF_FULL_SYNC (1 << 3) -#define MDF_WAS_UP_TO_DATE (1 << 4) -#define MDF_PEER_OUT_DATED (1 << 5) -#define MDF_CRASHED_PRIMARY (1 << 6) -#define MDF_AL_CLEAN (1 << 7) -#define MDF_AL_DISABLED (1 << 8) - -#define MAX_PEERS 32 - -enum drbd_uuid_index { - UI_CURRENT, - UI_BITMAP, - UI_HISTORY_START, - UI_HISTORY_END, - UI_SIZE, /* nl-packet: number of dirty bits */ - UI_FLAGS, /* nl-packet: flags */ - UI_EXTENDED_SIZE /* Everything. */ -}; - -#define HISTORY_UUIDS MAX_PEERS - -enum drbd_timeout_flag { - UT_DEFAULT = 0, - UT_DEGRADED = 1, - UT_PEER_OUTDATED = 2, -}; - -enum drbd_notification_type { - NOTIFY_EXISTS, - NOTIFY_CREATE, - NOTIFY_CHANGE, - NOTIFY_DESTROY, - NOTIFY_CALL, - NOTIFY_RESPONSE, - - NOTIFY_CONTINUES = 0x8000, - NOTIFY_FLAGS = NOTIFY_CONTINUES, -}; - -enum drbd_peer_state { - P_INCONSISTENT = 3, - P_OUTDATED = 4, - P_DOWN = 5, - P_PRIMARY = 6, - P_FENCING = 7, -}; - -#define UUID_JUST_CREATED ((__u64)4) - -enum write_ordering_e { - WO_NONE, - WO_DRAIN_IO, - WO_BDEV_FLUSH, - WO_BIO_BARRIER -}; - -/* magic numbers used in meta data and network packets */ -#define DRBD_MAGIC 0x83740267 -#define DRBD_MAGIC_BIG 0x835a -#define DRBD_MAGIC_100 0x8620ec20 - -#define DRBD_MD_MAGIC_07 (DRBD_MAGIC+3) -#define DRBD_MD_MAGIC_08 (DRBD_MAGIC+4) -#define DRBD_MD_MAGIC_84_UNCLEAN (DRBD_MAGIC+5) - - -/* how I came up with this magic? - * base64 decode "actlog==" ;) */ -#define DRBD_AL_MAGIC 0x69cb65a2 - -/* these are of type "int" */ -#define DRBD_MD_INDEX_INTERNAL -1 -#define DRBD_MD_INDEX_FLEX_EXT -2 -#define DRBD_MD_INDEX_FLEX_INT -3 - -#define DRBD_CPU_MASK_SIZE 32 - -#endif diff --git a/include/linux/drbd_config.h b/include/linux/drbd_config.h deleted file mode 100644 index d215365c6bb1..000000000000 --- a/include/linux/drbd_config.h +++ /dev/null @@ -1,16 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * drbd_config.h - * DRBD's compile time configuration. - */ - -#ifndef DRBD_CONFIG_H -#define DRBD_CONFIG_H - -extern const char *drbd_buildtag(void); - -#define REL_VERSION "8.4.11" -#define PRO_VERSION_MIN 86 -#define PRO_VERSION_MAX 101 - -#endif diff --git a/include/linux/drbd_genl_api.h b/include/linux/drbd_genl_api.h index 70682c058027..19d263924852 100644 --- a/include/linux/drbd_genl_api.h +++ b/include/linux/drbd_genl_api.h @@ -2,46 +2,6 @@ #ifndef DRBD_GENL_STRUCT_H #define DRBD_GENL_STRUCT_H -/** - * struct drbd_genlmsghdr - DRBD specific header used in NETLINK_GENERIC requests - * @minor: - * For admin requests (user -> kernel): which minor device to operate on. - * For (unicast) replies or informational (broadcast) messages - * (kernel -> user): which minor device the information is about. - * If we do not operate on minors, but on connections or resources, - * the minor value shall be (~0), and the attribute DRBD_NLA_CFG_CONTEXT - * is used instead. - * @flags: possible operation modifiers (relevant only for user->kernel): - * DRBD_GENL_F_SET_DEFAULTS - * @volume: - * When creating a new minor (adding it to a resource), the resource needs - * to know which volume number within the resource this is supposed to be. - * The volume number corresponds to the same volume number on the remote side, - * whereas the minor number on the remote side may be different - * (union with flags). - * @ret_code: kernel->userland unicast cfg reply return code (union with flags); - */ -struct drbd_genlmsghdr { - __u32 minor; - union { - __u32 flags; - __s32 ret_code; - }; -}; - -/* To be used in drbd_genlmsghdr.flags */ -enum { - DRBD_GENL_F_SET_DEFAULTS = 1, -}; - -enum drbd_state_info_bcast_reason { - SIB_GET_STATUS_REPLY = 1, - SIB_STATE_CHANGE = 2, - SIB_HELPER_PRE = 3, - SIB_HELPER_POST = 4, - SIB_SYNC_PROGRESS = 5, -}; - /* hack around predefined gcc/cpp "linux=1", * we cannot possibly include <1/drbd_genl.h> */ #undef linux diff --git a/include/linux/drbd_limits.h b/include/linux/drbd_limits.h deleted file mode 100644 index 5b042fb427e9..000000000000 --- a/include/linux/drbd_limits.h +++ /dev/null @@ -1,251 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - drbd_limits.h - This file is part of DRBD by Philipp Reisner and Lars Ellenberg. -*/ - -/* - * Our current limitations. - * Some of them are hard limits, - * some of them are arbitrary range limits, that make it easier to provide - * feedback about nonsense settings for certain configurable values. - */ - -#ifndef DRBD_LIMITS_H -#define DRBD_LIMITS_H 1 - -#define DEBUG_RANGE_CHECK 0 - -#define DRBD_MINOR_COUNT_MIN 1U -#define DRBD_MINOR_COUNT_MAX 255U -#define DRBD_MINOR_COUNT_DEF 32U -#define DRBD_MINOR_COUNT_SCALE '1' - -#define DRBD_VOLUME_MAX 65534U - -#define DRBD_DIALOG_REFRESH_MIN 0U -#define DRBD_DIALOG_REFRESH_MAX 600U -#define DRBD_DIALOG_REFRESH_SCALE '1' - -/* valid port number */ -#define DRBD_PORT_MIN 1U -#define DRBD_PORT_MAX 0xffffU -#define DRBD_PORT_SCALE '1' - -/* startup { */ - /* if you want more than 3.4 days, disable */ -#define DRBD_WFC_TIMEOUT_MIN 0U -#define DRBD_WFC_TIMEOUT_MAX 300000U -#define DRBD_WFC_TIMEOUT_DEF 0U -#define DRBD_WFC_TIMEOUT_SCALE '1' - -#define DRBD_DEGR_WFC_TIMEOUT_MIN 0U -#define DRBD_DEGR_WFC_TIMEOUT_MAX 300000U -#define DRBD_DEGR_WFC_TIMEOUT_DEF 0U -#define DRBD_DEGR_WFC_TIMEOUT_SCALE '1' - -#define DRBD_OUTDATED_WFC_TIMEOUT_MIN 0U -#define DRBD_OUTDATED_WFC_TIMEOUT_MAX 300000U -#define DRBD_OUTDATED_WFC_TIMEOUT_DEF 0U -#define DRBD_OUTDATED_WFC_TIMEOUT_SCALE '1' -/* }*/ - -/* net { */ - /* timeout, unit centi seconds - * more than one minute timeout is not useful */ -#define DRBD_TIMEOUT_MIN 1U -#define DRBD_TIMEOUT_MAX 600U -#define DRBD_TIMEOUT_DEF 60U /* 6 seconds */ -#define DRBD_TIMEOUT_SCALE '1' - - /* If backing disk takes longer than disk_timeout, mark the disk as failed */ -#define DRBD_DISK_TIMEOUT_MIN 0U /* 0 = disabled */ -#define DRBD_DISK_TIMEOUT_MAX 6000U /* 10 Minutes */ -#define DRBD_DISK_TIMEOUT_DEF 0U /* disabled */ -#define DRBD_DISK_TIMEOUT_SCALE '1' - - /* active connection retries when C_WF_CONNECTION */ -#define DRBD_CONNECT_INT_MIN 1U -#define DRBD_CONNECT_INT_MAX 120U -#define DRBD_CONNECT_INT_DEF 10U /* seconds */ -#define DRBD_CONNECT_INT_SCALE '1' - - /* keep-alive probes when idle */ -#define DRBD_PING_INT_MIN 1U -#define DRBD_PING_INT_MAX 120U -#define DRBD_PING_INT_DEF 10U -#define DRBD_PING_INT_SCALE '1' - - /* timeout for the ping packets.*/ -#define DRBD_PING_TIMEO_MIN 1U -#define DRBD_PING_TIMEO_MAX 300U -#define DRBD_PING_TIMEO_DEF 5U -#define DRBD_PING_TIMEO_SCALE '1' - - /* max number of write requests between write barriers */ -#define DRBD_MAX_EPOCH_SIZE_MIN 1U -#define DRBD_MAX_EPOCH_SIZE_MAX 20000U -#define DRBD_MAX_EPOCH_SIZE_DEF 2048U -#define DRBD_MAX_EPOCH_SIZE_SCALE '1' - - /* I don't think that a tcp send buffer of more than 10M is useful */ -#define DRBD_SNDBUF_SIZE_MIN 0U -#define DRBD_SNDBUF_SIZE_MAX (10U<<20) -#define DRBD_SNDBUF_SIZE_DEF 0U -#define DRBD_SNDBUF_SIZE_SCALE '1' - -#define DRBD_RCVBUF_SIZE_MIN 0U -#define DRBD_RCVBUF_SIZE_MAX (10U<<20) -#define DRBD_RCVBUF_SIZE_DEF 0U -#define DRBD_RCVBUF_SIZE_SCALE '1' - - /* @4k PageSize -> 128kB - 512MB */ -#define DRBD_MAX_BUFFERS_MIN 32U -#define DRBD_MAX_BUFFERS_MAX 131072U -#define DRBD_MAX_BUFFERS_DEF 2048U -#define DRBD_MAX_BUFFERS_SCALE '1' - - /* @4k PageSize -> 4kB - 512MB */ -#define DRBD_UNPLUG_WATERMARK_MIN 1U -#define DRBD_UNPLUG_WATERMARK_MAX 131072U -#define DRBD_UNPLUG_WATERMARK_DEF (DRBD_MAX_BUFFERS_DEF/16) -#define DRBD_UNPLUG_WATERMARK_SCALE '1' - - /* 0 is disabled. - * 200 should be more than enough even for very short timeouts */ -#define DRBD_KO_COUNT_MIN 0U -#define DRBD_KO_COUNT_MAX 200U -#define DRBD_KO_COUNT_DEF 7U -#define DRBD_KO_COUNT_SCALE '1' -/* } */ - -/* syncer { */ - /* FIXME allow rate to be zero? */ -#define DRBD_RESYNC_RATE_MIN 1U -/* channel bonding 10 GbE, or other hardware */ -#define DRBD_RESYNC_RATE_MAX (4 << 20) -#define DRBD_RESYNC_RATE_DEF 250U -#define DRBD_RESYNC_RATE_SCALE 'k' /* kilobytes */ - -#define DRBD_AL_EXTENTS_MIN 67U - /* we use u16 as "slot number", (u16)~0 is "FREE". - * If you use >= 292 kB on-disk ring buffer, - * this is the maximum you can use: */ -#define DRBD_AL_EXTENTS_MAX 0xfffeU -#define DRBD_AL_EXTENTS_DEF 1237U -#define DRBD_AL_EXTENTS_SCALE '1' - -#define DRBD_MINOR_NUMBER_MIN -1 -#define DRBD_MINOR_NUMBER_MAX ((1 << 20) - 1) -#define DRBD_MINOR_NUMBER_DEF -1 -#define DRBD_MINOR_NUMBER_SCALE '1' - -/* } */ - -/* drbdsetup XY resize -d Z - * you are free to reduce the device size to nothing, if you want to. - * the upper limit with 64bit kernel, enough ram and flexible meta data - * is 1 PiB, currently. */ -/* DRBD_MAX_SECTORS */ -#define DRBD_DISK_SIZE_MIN 0LLU -#define DRBD_DISK_SIZE_MAX (1LLU * (2LLU << 40)) -#define DRBD_DISK_SIZE_DEF 0LLU /* = disabled = no user size... */ -#define DRBD_DISK_SIZE_SCALE 's' /* sectors */ - -#define DRBD_ON_IO_ERROR_DEF EP_DETACH -#define DRBD_FENCING_DEF FP_DONT_CARE -#define DRBD_AFTER_SB_0P_DEF ASB_DISCONNECT -#define DRBD_AFTER_SB_1P_DEF ASB_DISCONNECT -#define DRBD_AFTER_SB_2P_DEF ASB_DISCONNECT -#define DRBD_RR_CONFLICT_DEF ASB_DISCONNECT -#define DRBD_ON_NO_DATA_DEF OND_IO_ERROR -#define DRBD_ON_CONGESTION_DEF OC_BLOCK -#define DRBD_READ_BALANCING_DEF RB_PREFER_LOCAL - -#define DRBD_MAX_BIO_BVECS_MIN 0U -#define DRBD_MAX_BIO_BVECS_MAX 128U -#define DRBD_MAX_BIO_BVECS_DEF 0U -#define DRBD_MAX_BIO_BVECS_SCALE '1' - -#define DRBD_C_PLAN_AHEAD_MIN 0U -#define DRBD_C_PLAN_AHEAD_MAX 300U -#define DRBD_C_PLAN_AHEAD_DEF 20U -#define DRBD_C_PLAN_AHEAD_SCALE '1' - -#define DRBD_C_DELAY_TARGET_MIN 1U -#define DRBD_C_DELAY_TARGET_MAX 100U -#define DRBD_C_DELAY_TARGET_DEF 10U -#define DRBD_C_DELAY_TARGET_SCALE '1' - -#define DRBD_C_FILL_TARGET_MIN 0U -#define DRBD_C_FILL_TARGET_MAX (1U<<20) /* 500MByte in sec */ -#define DRBD_C_FILL_TARGET_DEF 100U /* Try to place 50KiB in socket send buffer during resync */ -#define DRBD_C_FILL_TARGET_SCALE 's' /* sectors */ - -#define DRBD_C_MAX_RATE_MIN 250U -#define DRBD_C_MAX_RATE_MAX (4U << 20) -#define DRBD_C_MAX_RATE_DEF 102400U -#define DRBD_C_MAX_RATE_SCALE 'k' /* kilobytes */ - -#define DRBD_C_MIN_RATE_MIN 0U -#define DRBD_C_MIN_RATE_MAX (4U << 20) -#define DRBD_C_MIN_RATE_DEF 250U -#define DRBD_C_MIN_RATE_SCALE 'k' /* kilobytes */ - -#define DRBD_CONG_FILL_MIN 0U -#define DRBD_CONG_FILL_MAX (10U<<21) /* 10GByte in sectors */ -#define DRBD_CONG_FILL_DEF 0U -#define DRBD_CONG_FILL_SCALE 's' /* sectors */ - -#define DRBD_CONG_EXTENTS_MIN DRBD_AL_EXTENTS_MIN -#define DRBD_CONG_EXTENTS_MAX DRBD_AL_EXTENTS_MAX -#define DRBD_CONG_EXTENTS_DEF DRBD_AL_EXTENTS_DEF -#define DRBD_CONG_EXTENTS_SCALE DRBD_AL_EXTENTS_SCALE - -#define DRBD_PROTOCOL_DEF DRBD_PROT_C - -#define DRBD_DISK_BARRIER_DEF 0U -#define DRBD_DISK_FLUSHES_DEF 1U -#define DRBD_DISK_DRAIN_DEF 1U -#define DRBD_MD_FLUSHES_DEF 1U -#define DRBD_TCP_CORK_DEF 1U -#define DRBD_AL_UPDATES_DEF 1U - -/* We used to ignore the discard_zeroes_data setting. - * To not change established (and expected) behaviour, - * by default assume that, for discard_zeroes_data=0, - * we can make that an effective discard_zeroes_data=1, - * if we only explicitly zero-out unaligned partial chunks. */ -#define DRBD_DISCARD_ZEROES_IF_ALIGNED_DEF 1U - -/* Some backends pretend to support WRITE SAME, - * but fail such requests when they are actually submitted. - * This is to tell DRBD to not even try. */ -#define DRBD_DISABLE_WRITE_SAME_DEF 0U - -#define DRBD_ALLOW_TWO_PRIMARIES_DEF 0U -#define DRBD_ALWAYS_ASBP_DEF 0U -#define DRBD_USE_RLE_DEF 1U -#define DRBD_CSUMS_AFTER_CRASH_ONLY_DEF 0U - -#define DRBD_AL_STRIPES_MIN 1U -#define DRBD_AL_STRIPES_MAX 1024U -#define DRBD_AL_STRIPES_DEF 1U -#define DRBD_AL_STRIPES_SCALE '1' - -#define DRBD_AL_STRIPE_SIZE_MIN 4U -#define DRBD_AL_STRIPE_SIZE_MAX 16777216U -#define DRBD_AL_STRIPE_SIZE_DEF 32U -#define DRBD_AL_STRIPE_SIZE_SCALE 'k' /* kilobytes */ - -#define DRBD_SOCKET_CHECK_TIMEO_MIN 0U -#define DRBD_SOCKET_CHECK_TIMEO_MAX DRBD_PING_TIMEO_MAX -#define DRBD_SOCKET_CHECK_TIMEO_DEF 0U -#define DRBD_SOCKET_CHECK_TIMEO_SCALE '1' - -#define DRBD_RS_DISCARD_GRANULARITY_MIN 0U -#define DRBD_RS_DISCARD_GRANULARITY_MAX (1U<<20) /* 1MiByte */ -#define DRBD_RS_DISCARD_GRANULARITY_DEF 0U /* disabled by default */ -#define DRBD_RS_DISCARD_GRANULARITY_SCALE '1' /* bytes */ - -#endif diff --git a/include/uapi/linux/drbd.h b/include/uapi/linux/drbd.h new file mode 100644 index 000000000000..7930a972d8a4 --- /dev/null +++ b/include/uapi/linux/drbd.h @@ -0,0 +1,432 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later WITH Linux-syscall-note */ +/* + drbd.h + Kernel module for 2.6.x Kernels + + This file is part of DRBD by Philipp Reisner and Lars Ellenberg. + + Copyright (C) 2001-2008, LINBIT Information Technologies GmbH. + Copyright (C) 2001-2008, Philipp Reisner . + Copyright (C) 2001-2008, Lars Ellenberg . + + +*/ +#ifndef DRBD_H +#define DRBD_H +#include + +#ifdef __KERNEL__ +#include +#include +#else +#include +#include +#include + +/* Although the Linux source code makes a difference between + generic endianness and the bitfields' endianness, there is no + architecture as of Linux-2.6.24-rc4 where the bitfields' endianness + does not match the generic endianness. */ + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define __LITTLE_ENDIAN_BITFIELD +#elif __BYTE_ORDER == __BIG_ENDIAN +#define __BIG_ENDIAN_BITFIELD +#else +# error "sorry, weird endianness on this box" +#endif + +#endif + +enum drbd_io_error_p { + EP_PASS_ON, /* FIXME should the better be named "Ignore"? */ + EP_CALL_HELPER, + EP_DETACH +}; + +enum drbd_fencing_p { + FP_NOT_AVAIL = -1, /* Not a policy */ + FP_DONT_CARE = 0, + FP_RESOURCE, + FP_STONITH +}; + +enum drbd_disconnect_p { + DP_RECONNECT, + DP_DROP_NET_CONF, + DP_FREEZE_IO +}; + +enum drbd_after_sb_p { + ASB_DISCONNECT, + ASB_DISCARD_YOUNGER_PRI, + ASB_DISCARD_OLDER_PRI, + ASB_DISCARD_ZERO_CHG, + ASB_DISCARD_LEAST_CHG, + ASB_DISCARD_LOCAL, + ASB_DISCARD_REMOTE, + ASB_CONSENSUS, + ASB_DISCARD_SECONDARY, + ASB_CALL_HELPER, + ASB_VIOLENTLY +}; + +enum drbd_on_no_data { + OND_IO_ERROR, + OND_SUSPEND_IO +}; + +enum drbd_on_congestion { + OC_BLOCK, + OC_PULL_AHEAD, + OC_DISCONNECT, +}; + +enum drbd_read_balancing { + RB_PREFER_LOCAL, + RB_PREFER_REMOTE, + RB_ROUND_ROBIN, + RB_LEAST_PENDING, + RB_CONGESTED_REMOTE, + RB_32K_STRIPING, + RB_64K_STRIPING, + RB_128K_STRIPING, + RB_256K_STRIPING, + RB_512K_STRIPING, + RB_1M_STRIPING, +}; + +/* KEEP the order, do not delete or insert. Only append. */ +enum drbd_ret_code { + ERR_CODE_BASE = 100, + NO_ERROR = 101, + ERR_LOCAL_ADDR = 102, + ERR_PEER_ADDR = 103, + ERR_OPEN_DISK = 104, + ERR_OPEN_MD_DISK = 105, + ERR_DISK_NOT_BDEV = 107, + ERR_MD_NOT_BDEV = 108, + ERR_DISK_TOO_SMALL = 111, + ERR_MD_DISK_TOO_SMALL = 112, + ERR_BDCLAIM_DISK = 114, + ERR_BDCLAIM_MD_DISK = 115, + ERR_MD_IDX_INVALID = 116, + ERR_IO_MD_DISK = 118, + ERR_MD_INVALID = 119, + ERR_AUTH_ALG = 120, + ERR_AUTH_ALG_ND = 121, + ERR_NOMEM = 122, + ERR_DISCARD_IMPOSSIBLE = 123, + ERR_DISK_CONFIGURED = 124, + ERR_NET_CONFIGURED = 125, + ERR_MANDATORY_TAG = 126, + ERR_MINOR_INVALID = 127, + ERR_INTR = 129, /* EINTR */ + ERR_RESIZE_RESYNC = 130, + ERR_NO_PRIMARY = 131, + ERR_RESYNC_AFTER = 132, + ERR_RESYNC_AFTER_CYCLE = 133, + ERR_PAUSE_IS_SET = 134, + ERR_PAUSE_IS_CLEAR = 135, + ERR_PACKET_NR = 137, + ERR_NO_DISK = 138, + ERR_NOT_PROTO_C = 139, + ERR_NOMEM_BITMAP = 140, + ERR_INTEGRITY_ALG = 141, /* DRBD 8.2 only */ + ERR_INTEGRITY_ALG_ND = 142, /* DRBD 8.2 only */ + ERR_CPU_MASK_PARSE = 143, /* DRBD 8.2 only */ + ERR_CSUMS_ALG = 144, /* DRBD 8.2 only */ + ERR_CSUMS_ALG_ND = 145, /* DRBD 8.2 only */ + ERR_VERIFY_ALG = 146, /* DRBD 8.2 only */ + ERR_VERIFY_ALG_ND = 147, /* DRBD 8.2 only */ + ERR_CSUMS_RESYNC_RUNNING= 148, /* DRBD 8.2 only */ + ERR_VERIFY_RUNNING = 149, /* DRBD 8.2 only */ + ERR_DATA_NOT_CURRENT = 150, + ERR_CONNECTED = 151, /* DRBD 8.3 only */ + ERR_PERM = 152, + ERR_NEED_APV_93 = 153, + ERR_STONITH_AND_PROT_A = 154, + ERR_CONG_NOT_PROTO_A = 155, + ERR_PIC_AFTER_DEP = 156, + ERR_PIC_PEER_DEP = 157, + ERR_RES_NOT_KNOWN = 158, + ERR_RES_IN_USE = 159, + ERR_MINOR_CONFIGURED = 160, + ERR_MINOR_OR_VOLUME_EXISTS = 161, + ERR_INVALID_REQUEST = 162, + ERR_NEED_APV_100 = 163, + ERR_NEED_ALLOW_TWO_PRI = 164, + ERR_MD_UNCLEAN = 165, + ERR_MD_LAYOUT_CONNECTED = 166, + ERR_MD_LAYOUT_TOO_BIG = 167, + ERR_MD_LAYOUT_TOO_SMALL = 168, + ERR_MD_LAYOUT_NO_FIT = 169, + ERR_IMPLICIT_SHRINK = 170, + /* insert new ones above this line */ + AFTER_LAST_ERR_CODE +}; + +#define DRBD_PROT_A 1 +#define DRBD_PROT_B 2 +#define DRBD_PROT_C 3 + +enum drbd_role { + R_UNKNOWN = 0, + R_PRIMARY = 1, /* role */ + R_SECONDARY = 2, /* role */ + R_MASK = 3, +}; + +/* The order of these constants is important. + * The lower ones (=C_WF_REPORT_PARAMS ==> There is a socket + */ +enum drbd_conns { + C_STANDALONE, + C_DISCONNECTING, /* Temporal state on the way to StandAlone. */ + C_UNCONNECTED, /* >= C_UNCONNECTED -> inc_net() succeeds */ + + /* These temporal states are all used on the way + * from >= C_CONNECTED to Unconnected. + * The 'disconnect reason' states + * I do not allow to change between them. */ + C_TIMEOUT, + C_BROKEN_PIPE, + C_NETWORK_FAILURE, + C_PROTOCOL_ERROR, + C_TEAR_DOWN, + + C_WF_CONNECTION, + C_WF_REPORT_PARAMS, /* we have a socket */ + C_CONNECTED, /* we have introduced each other */ + C_STARTING_SYNC_S, /* starting full sync by admin request. */ + C_STARTING_SYNC_T, /* starting full sync by admin request. */ + C_WF_BITMAP_S, + C_WF_BITMAP_T, + C_WF_SYNC_UUID, + + /* All SyncStates are tested with this comparison + * xx >= C_SYNC_SOURCE && xx <= C_PAUSED_SYNC_T */ + C_SYNC_SOURCE, + C_SYNC_TARGET, + C_VERIFY_S, + C_VERIFY_T, + C_PAUSED_SYNC_S, + C_PAUSED_SYNC_T, + + C_AHEAD, + C_BEHIND, + + C_MASK = 31 +}; + +enum drbd_disk_state { + D_DISKLESS, + D_ATTACHING, /* In the process of reading the meta-data */ + D_FAILED, /* Becomes D_DISKLESS as soon as we told it the peer */ + /* when >= D_FAILED it is legal to access mdev->ldev */ + D_NEGOTIATING, /* Late attaching state, we need to talk to the peer */ + D_INCONSISTENT, + D_OUTDATED, + D_UNKNOWN, /* Only used for the peer, never for myself */ + D_CONSISTENT, /* Might be D_OUTDATED, might be D_UP_TO_DATE ... */ + D_UP_TO_DATE, /* Only this disk state allows applications' IO ! */ + D_MASK = 15 +}; + +union drbd_state { +/* According to gcc's docs is the ... + * The order of allocation of bit-fields within a unit (C90 6.5.2.1, C99 6.7.2.1). + * Determined by ABI. + * pointed out by Maxim Uvarov q + * even though we transmit as "cpu_to_be32(state)", + * the offsets of the bitfields still need to be swapped + * on different endianness. + */ + struct { +#if defined(__LITTLE_ENDIAN_BITFIELD) + unsigned role:2 ; /* 3/4 primary/secondary/unknown */ + unsigned peer:2 ; /* 3/4 primary/secondary/unknown */ + unsigned conn:5 ; /* 17/32 cstates */ + unsigned disk:4 ; /* 8/16 from D_DISKLESS to D_UP_TO_DATE */ + unsigned pdsk:4 ; /* 8/16 from D_DISKLESS to D_UP_TO_DATE */ + unsigned susp:1 ; /* 2/2 IO suspended no/yes (by user) */ + unsigned aftr_isp:1 ; /* isp .. imposed sync pause */ + unsigned peer_isp:1 ; + unsigned user_isp:1 ; + unsigned susp_nod:1 ; /* IO suspended because no data */ + unsigned susp_fen:1 ; /* IO suspended because fence peer handler runs*/ + unsigned _pad:9; /* 0 unused */ +#elif defined(__BIG_ENDIAN_BITFIELD) + unsigned _pad:9; + unsigned susp_fen:1 ; + unsigned susp_nod:1 ; + unsigned user_isp:1 ; + unsigned peer_isp:1 ; + unsigned aftr_isp:1 ; /* isp .. imposed sync pause */ + unsigned susp:1 ; /* 2/2 IO suspended no/yes */ + unsigned pdsk:4 ; /* 8/16 from D_DISKLESS to D_UP_TO_DATE */ + unsigned disk:4 ; /* 8/16 from D_DISKLESS to D_UP_TO_DATE */ + unsigned conn:5 ; /* 17/32 cstates */ + unsigned peer:2 ; /* 3/4 primary/secondary/unknown */ + unsigned role:2 ; /* 3/4 primary/secondary/unknown */ +#else +# error "this endianness is not supported" +#endif + }; + unsigned int i; +}; + +enum drbd_state_rv { + SS_CW_NO_NEED = 4, + SS_CW_SUCCESS = 3, + SS_NOTHING_TO_DO = 2, + SS_SUCCESS = 1, + SS_UNKNOWN_ERROR = 0, /* Used to sleep longer in _drbd_request_state */ + SS_TWO_PRIMARIES = -1, + SS_NO_UP_TO_DATE_DISK = -2, + SS_NO_LOCAL_DISK = -4, + SS_NO_REMOTE_DISK = -5, + SS_CONNECTED_OUTDATES = -6, + SS_PRIMARY_NOP = -7, + SS_RESYNC_RUNNING = -8, + SS_ALREADY_STANDALONE = -9, + SS_CW_FAILED_BY_PEER = -10, + SS_IS_DISKLESS = -11, + SS_DEVICE_IN_USE = -12, + SS_NO_NET_CONFIG = -13, + SS_NO_VERIFY_ALG = -14, /* drbd-8.2 only */ + SS_NEED_CONNECTION = -15, /* drbd-8.2 only */ + SS_LOWER_THAN_OUTDATED = -16, + SS_NOT_SUPPORTED = -17, /* drbd-8.2 only */ + SS_IN_TRANSIENT_STATE = -18, /* Retry after the next state change */ + SS_CONCURRENT_ST_CHG = -19, /* Concurrent cluster side state change! */ + SS_O_VOL_PEER_PRI = -20, + SS_OUTDATE_WO_CONN = -21, + SS_AFTER_LAST_ERROR = -22, /* Keep this at bottom */ +}; + +#define SHARED_SECRET_MAX 64 + +#define MDF_CONSISTENT (1 << 0) +#define MDF_PRIMARY_IND (1 << 1) +#define MDF_CONNECTED_IND (1 << 2) +#define MDF_FULL_SYNC (1 << 3) +#define MDF_WAS_UP_TO_DATE (1 << 4) +#define MDF_PEER_OUT_DATED (1 << 5) +#define MDF_CRASHED_PRIMARY (1 << 6) +#define MDF_AL_CLEAN (1 << 7) +#define MDF_AL_DISABLED (1 << 8) + +#define MAX_PEERS 32 + +enum drbd_uuid_index { + UI_CURRENT, + UI_BITMAP, + UI_HISTORY_START, + UI_HISTORY_END, + UI_SIZE, /* nl-packet: number of dirty bits */ + UI_FLAGS, /* nl-packet: flags */ + UI_EXTENDED_SIZE /* Everything. */ +}; + +#define HISTORY_UUIDS MAX_PEERS + +enum drbd_timeout_flag { + UT_DEFAULT = 0, + UT_DEGRADED = 1, + UT_PEER_OUTDATED = 2, +}; + +enum drbd_notification_type { + NOTIFY_EXISTS, + NOTIFY_CREATE, + NOTIFY_CHANGE, + NOTIFY_DESTROY, + NOTIFY_CALL, + NOTIFY_RESPONSE, + + NOTIFY_CONTINUES = 0x8000, + NOTIFY_FLAGS = NOTIFY_CONTINUES, +}; + +enum drbd_peer_state { + P_INCONSISTENT = 3, + P_OUTDATED = 4, + P_DOWN = 5, + P_PRIMARY = 6, + P_FENCING = 7, +}; + +#define UUID_JUST_CREATED ((__u64)4) + +enum write_ordering_e { + WO_NONE, + WO_DRAIN_IO, + WO_BDEV_FLUSH, + WO_BIO_BARRIER +}; + +/* magic numbers used in meta data and network packets */ +#define DRBD_MAGIC 0x83740267 +#define DRBD_MAGIC_BIG 0x835a +#define DRBD_MAGIC_100 0x8620ec20 + +#define DRBD_MD_MAGIC_07 (DRBD_MAGIC+3) +#define DRBD_MD_MAGIC_08 (DRBD_MAGIC+4) +#define DRBD_MD_MAGIC_84_UNCLEAN (DRBD_MAGIC+5) + + +/* how I came up with this magic? + * base64 decode "actlog==" ;) */ +#define DRBD_AL_MAGIC 0x69cb65a2 + +/* these are of type "int" */ +#define DRBD_MD_INDEX_INTERNAL -1 +#define DRBD_MD_INDEX_FLEX_EXT -2 +#define DRBD_MD_INDEX_FLEX_INT -3 + +#define DRBD_CPU_MASK_SIZE 32 + +/** + * struct drbd_genlmsghdr - DRBD specific header used in NETLINK_GENERIC requests + * @minor: + * For admin requests (user -> kernel): which minor device to operate on. + * For (unicast) replies or informational (broadcast) messages + * (kernel -> user): which minor device the information is about. + * If we do not operate on minors, but on connections or resources, + * the minor value shall be (~0), and the attribute DRBD_NLA_CFG_CONTEXT + * is used instead. + * @flags: possible operation modifiers (relevant only for user->kernel): + * DRBD_GENL_F_SET_DEFAULTS + * @volume: + * When creating a new minor (adding it to a resource), the resource needs + * to know which volume number within the resource this is supposed to be. + * The volume number corresponds to the same volume number on the remote side, + * whereas the minor number on the remote side may be different + * (union with flags). + * @ret_code: kernel->userland unicast cfg reply return code (union with flags); + */ +struct drbd_genlmsghdr { + __u32 minor; + union { + __u32 flags; + __s32 ret_code; + }; +}; + +/* To be used in drbd_genlmsghdr.flags */ +enum { + DRBD_GENL_F_SET_DEFAULTS = 1, +}; + +enum drbd_state_info_bcast_reason { + SIB_GET_STATUS_REPLY = 1, + SIB_STATE_CHANGE = 2, + SIB_HELPER_PRE = 3, + SIB_HELPER_POST = 4, + SIB_SYNC_PROGRESS = 5, +}; + +#endif diff --git a/include/uapi/linux/drbd_limits.h b/include/uapi/linux/drbd_limits.h new file mode 100644 index 000000000000..a72a102d1ca7 --- /dev/null +++ b/include/uapi/linux/drbd_limits.h @@ -0,0 +1,251 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + drbd_limits.h + This file is part of DRBD by Philipp Reisner and Lars Ellenberg. +*/ + +/* + * Our current limitations. + * Some of them are hard limits, + * some of them are arbitrary range limits, that make it easier to provide + * feedback about nonsense settings for certain configurable values. + */ + +#ifndef DRBD_LIMITS_H +#define DRBD_LIMITS_H 1 + +#define DEBUG_RANGE_CHECK 0 + +#define DRBD_MINOR_COUNT_MIN 1U +#define DRBD_MINOR_COUNT_MAX 255U +#define DRBD_MINOR_COUNT_DEF 32U +#define DRBD_MINOR_COUNT_SCALE '1' + +#define DRBD_VOLUME_MAX 65534U + +#define DRBD_DIALOG_REFRESH_MIN 0U +#define DRBD_DIALOG_REFRESH_MAX 600U +#define DRBD_DIALOG_REFRESH_SCALE '1' + +/* valid port number */ +#define DRBD_PORT_MIN 1U +#define DRBD_PORT_MAX 0xffffU +#define DRBD_PORT_SCALE '1' + +/* startup { */ + /* if you want more than 3.4 days, disable */ +#define DRBD_WFC_TIMEOUT_MIN 0U +#define DRBD_WFC_TIMEOUT_MAX 300000U +#define DRBD_WFC_TIMEOUT_DEF 0U +#define DRBD_WFC_TIMEOUT_SCALE '1' + +#define DRBD_DEGR_WFC_TIMEOUT_MIN 0U +#define DRBD_DEGR_WFC_TIMEOUT_MAX 300000U +#define DRBD_DEGR_WFC_TIMEOUT_DEF 0U +#define DRBD_DEGR_WFC_TIMEOUT_SCALE '1' + +#define DRBD_OUTDATED_WFC_TIMEOUT_MIN 0U +#define DRBD_OUTDATED_WFC_TIMEOUT_MAX 300000U +#define DRBD_OUTDATED_WFC_TIMEOUT_DEF 0U +#define DRBD_OUTDATED_WFC_TIMEOUT_SCALE '1' +/* }*/ + +/* net { */ + /* timeout, unit centi seconds + * more than one minute timeout is not useful */ +#define DRBD_TIMEOUT_MIN 1U +#define DRBD_TIMEOUT_MAX 600U +#define DRBD_TIMEOUT_DEF 60U /* 6 seconds */ +#define DRBD_TIMEOUT_SCALE '1' + + /* If backing disk takes longer than disk_timeout, mark the disk as failed */ +#define DRBD_DISK_TIMEOUT_MIN 0U /* 0 = disabled */ +#define DRBD_DISK_TIMEOUT_MAX 6000U /* 10 Minutes */ +#define DRBD_DISK_TIMEOUT_DEF 0U /* disabled */ +#define DRBD_DISK_TIMEOUT_SCALE '1' + + /* active connection retries when C_WF_CONNECTION */ +#define DRBD_CONNECT_INT_MIN 1U +#define DRBD_CONNECT_INT_MAX 120U +#define DRBD_CONNECT_INT_DEF 10U /* seconds */ +#define DRBD_CONNECT_INT_SCALE '1' + + /* keep-alive probes when idle */ +#define DRBD_PING_INT_MIN 1U +#define DRBD_PING_INT_MAX 120U +#define DRBD_PING_INT_DEF 10U +#define DRBD_PING_INT_SCALE '1' + + /* timeout for the ping packets.*/ +#define DRBD_PING_TIMEO_MIN 1U +#define DRBD_PING_TIMEO_MAX 300U +#define DRBD_PING_TIMEO_DEF 5U +#define DRBD_PING_TIMEO_SCALE '1' + + /* max number of write requests between write barriers */ +#define DRBD_MAX_EPOCH_SIZE_MIN 1U +#define DRBD_MAX_EPOCH_SIZE_MAX 20000U +#define DRBD_MAX_EPOCH_SIZE_DEF 2048U +#define DRBD_MAX_EPOCH_SIZE_SCALE '1' + + /* I don't think that a tcp send buffer of more than 10M is useful */ +#define DRBD_SNDBUF_SIZE_MIN 0U +#define DRBD_SNDBUF_SIZE_MAX (10U<<20) +#define DRBD_SNDBUF_SIZE_DEF 0U +#define DRBD_SNDBUF_SIZE_SCALE '1' + +#define DRBD_RCVBUF_SIZE_MIN 0U +#define DRBD_RCVBUF_SIZE_MAX (10U<<20) +#define DRBD_RCVBUF_SIZE_DEF 0U +#define DRBD_RCVBUF_SIZE_SCALE '1' + + /* @4k PageSize -> 128kB - 512MB */ +#define DRBD_MAX_BUFFERS_MIN 32U +#define DRBD_MAX_BUFFERS_MAX 131072U +#define DRBD_MAX_BUFFERS_DEF 2048U +#define DRBD_MAX_BUFFERS_SCALE '1' + + /* @4k PageSize -> 4kB - 512MB */ +#define DRBD_UNPLUG_WATERMARK_MIN 1U +#define DRBD_UNPLUG_WATERMARK_MAX 131072U +#define DRBD_UNPLUG_WATERMARK_DEF (DRBD_MAX_BUFFERS_DEF/16) +#define DRBD_UNPLUG_WATERMARK_SCALE '1' + + /* 0 is disabled. + * 200 should be more than enough even for very short timeouts */ +#define DRBD_KO_COUNT_MIN 0U +#define DRBD_KO_COUNT_MAX 200U +#define DRBD_KO_COUNT_DEF 7U +#define DRBD_KO_COUNT_SCALE '1' +/* } */ + +/* syncer { */ + /* FIXME allow rate to be zero? */ +#define DRBD_RESYNC_RATE_MIN 1U +/* channel bonding 10 GbE, or other hardware */ +#define DRBD_RESYNC_RATE_MAX (4 << 20) +#define DRBD_RESYNC_RATE_DEF 250U +#define DRBD_RESYNC_RATE_SCALE 'k' /* kilobytes */ + +#define DRBD_AL_EXTENTS_MIN 67U + /* we use u16 as "slot number", (u16)~0 is "FREE". + * If you use >= 292 kB on-disk ring buffer, + * this is the maximum you can use: */ +#define DRBD_AL_EXTENTS_MAX 0xfffeU +#define DRBD_AL_EXTENTS_DEF 1237U +#define DRBD_AL_EXTENTS_SCALE '1' + +#define DRBD_MINOR_NUMBER_MIN -1 +#define DRBD_MINOR_NUMBER_MAX ((1 << 20) - 1) +#define DRBD_MINOR_NUMBER_DEF -1 +#define DRBD_MINOR_NUMBER_SCALE '1' + +/* } */ + +/* drbdsetup XY resize -d Z + * you are free to reduce the device size to nothing, if you want to. + * the upper limit with 64bit kernel, enough ram and flexible meta data + * is 1 PiB, currently. */ +/* DRBD_MAX_SECTORS */ +#define DRBD_DISK_SIZE_MIN 0LLU +#define DRBD_DISK_SIZE_MAX (1LLU * (2LLU << 40)) +#define DRBD_DISK_SIZE_DEF 0LLU /* = disabled = no user size... */ +#define DRBD_DISK_SIZE_SCALE 's' /* sectors */ + +#define DRBD_ON_IO_ERROR_DEF EP_DETACH +#define DRBD_FENCING_DEF FP_DONT_CARE +#define DRBD_AFTER_SB_0P_DEF ASB_DISCONNECT +#define DRBD_AFTER_SB_1P_DEF ASB_DISCONNECT +#define DRBD_AFTER_SB_2P_DEF ASB_DISCONNECT +#define DRBD_RR_CONFLICT_DEF ASB_DISCONNECT +#define DRBD_ON_NO_DATA_DEF OND_IO_ERROR +#define DRBD_ON_CONGESTION_DEF OC_BLOCK +#define DRBD_READ_BALANCING_DEF RB_PREFER_LOCAL + +#define DRBD_MAX_BIO_BVECS_MIN 0U +#define DRBD_MAX_BIO_BVECS_MAX 128U +#define DRBD_MAX_BIO_BVECS_DEF 0U +#define DRBD_MAX_BIO_BVECS_SCALE '1' + +#define DRBD_C_PLAN_AHEAD_MIN 0U +#define DRBD_C_PLAN_AHEAD_MAX 300U +#define DRBD_C_PLAN_AHEAD_DEF 20U +#define DRBD_C_PLAN_AHEAD_SCALE '1' + +#define DRBD_C_DELAY_TARGET_MIN 1U +#define DRBD_C_DELAY_TARGET_MAX 100U +#define DRBD_C_DELAY_TARGET_DEF 10U +#define DRBD_C_DELAY_TARGET_SCALE '1' + +#define DRBD_C_FILL_TARGET_MIN 0U +#define DRBD_C_FILL_TARGET_MAX (1U<<20) /* 500MByte in sec */ +#define DRBD_C_FILL_TARGET_DEF 100U /* Try to place 50KiB in socket send buffer during resync */ +#define DRBD_C_FILL_TARGET_SCALE 's' /* sectors */ + +#define DRBD_C_MAX_RATE_MIN 250U +#define DRBD_C_MAX_RATE_MAX (4U << 20) +#define DRBD_C_MAX_RATE_DEF 102400U +#define DRBD_C_MAX_RATE_SCALE 'k' /* kilobytes */ + +#define DRBD_C_MIN_RATE_MIN 0U +#define DRBD_C_MIN_RATE_MAX (4U << 20) +#define DRBD_C_MIN_RATE_DEF 250U +#define DRBD_C_MIN_RATE_SCALE 'k' /* kilobytes */ + +#define DRBD_CONG_FILL_MIN 0U +#define DRBD_CONG_FILL_MAX (10U<<21) /* 10GByte in sectors */ +#define DRBD_CONG_FILL_DEF 0U +#define DRBD_CONG_FILL_SCALE 's' /* sectors */ + +#define DRBD_CONG_EXTENTS_MIN DRBD_AL_EXTENTS_MIN +#define DRBD_CONG_EXTENTS_MAX DRBD_AL_EXTENTS_MAX +#define DRBD_CONG_EXTENTS_DEF DRBD_AL_EXTENTS_DEF +#define DRBD_CONG_EXTENTS_SCALE DRBD_AL_EXTENTS_SCALE + +#define DRBD_PROTOCOL_DEF DRBD_PROT_C + +#define DRBD_DISK_BARRIER_DEF 0U +#define DRBD_DISK_FLUSHES_DEF 1U +#define DRBD_DISK_DRAIN_DEF 1U +#define DRBD_MD_FLUSHES_DEF 1U +#define DRBD_TCP_CORK_DEF 1U +#define DRBD_AL_UPDATES_DEF 1U + +/* We used to ignore the discard_zeroes_data setting. + * To not change established (and expected) behaviour, + * by default assume that, for discard_zeroes_data=0, + * we can make that an effective discard_zeroes_data=1, + * if we only explicitly zero-out unaligned partial chunks. */ +#define DRBD_DISCARD_ZEROES_IF_ALIGNED_DEF 1U + +/* Some backends pretend to support WRITE SAME, + * but fail such requests when they are actually submitted. + * This is to tell DRBD to not even try. */ +#define DRBD_DISABLE_WRITE_SAME_DEF 0U + +#define DRBD_ALLOW_TWO_PRIMARIES_DEF 0U +#define DRBD_ALWAYS_ASBP_DEF 0U +#define DRBD_USE_RLE_DEF 1U +#define DRBD_CSUMS_AFTER_CRASH_ONLY_DEF 0U + +#define DRBD_AL_STRIPES_MIN 1U +#define DRBD_AL_STRIPES_MAX 1024U +#define DRBD_AL_STRIPES_DEF 1U +#define DRBD_AL_STRIPES_SCALE '1' + +#define DRBD_AL_STRIPE_SIZE_MIN 4U +#define DRBD_AL_STRIPE_SIZE_MAX 16777216U +#define DRBD_AL_STRIPE_SIZE_DEF 32U +#define DRBD_AL_STRIPE_SIZE_SCALE 'k' /* kilobytes */ + +#define DRBD_SOCKET_CHECK_TIMEO_MIN 0U +#define DRBD_SOCKET_CHECK_TIMEO_MAX DRBD_PING_TIMEO_MAX +#define DRBD_SOCKET_CHECK_TIMEO_DEF 0U +#define DRBD_SOCKET_CHECK_TIMEO_SCALE '1' + +#define DRBD_RS_DISCARD_GRANULARITY_MIN 0U +#define DRBD_RS_DISCARD_GRANULARITY_MAX (1U<<20) /* 1MiByte */ +#define DRBD_RS_DISCARD_GRANULARITY_DEF 0U /* disabled by default */ +#define DRBD_RS_DISCARD_GRANULARITY_SCALE '1' /* bytes */ + +#endif -- cgit v1.2.3 From 8098eeb693c4cc4e774c62fbd4875197cb5578ce Mon Sep 17 00:00:00 2001 From: Christoph Böhmwalder Date: Wed, 6 May 2026 14:45:41 +0200 Subject: drbd: replace genl_magic with explicit netlink serialization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the genl_magic multi-include macro system with explicit serialization and parsing. The *_gen files were initially produced from a YNL spec via a customized ynl-gen-c, but the DRBD netlink family is effectively frozen, so the generator is kept unmodified. All new functionality will land in a separate, properly-designed family. Carry the resulting code as ordinary in-tree source rather than landing the spec and generator changes that produced it. The bulk of the changes are mechanical renames to fit the YNL naming conventions: - Handler functions: drbd_adm_* -> drbd_nl_*_doit/dumpit - GENL_MAGIC_VERSION -> DRBD_FAMILY_VERSION - GENL_MAGIC_FAMILY_HDRSZ -> sizeof(struct drbd_genlmsghdr) - drbd_genl_family -> drbd_nl_family - Attribute IDs: T_* -> DRBD_A_* Remove the nested_attr_tb static global buffer and move to a per-call allocation approach: each deserialization manages its own nested attribute table. This will be needed anyway when we eventually move to parallel_ops, and it's actually simpler this way, so make the move now. Replace the functionality of the "sensitive" flag: this was only used by a single field (shared_secret); open-code redaction logic for that locally. Also replace the "invariant" flag: this only had a couple of users, and those basically never change. Hard code the check directly inline. The genl_family struct itself is defined manually in drbd_nl.c. Also replace a couple of drbd-specific wrappers (nla_put_u64_0pad, drbd_nla_find_nested) with standard kernel functions while we're at it. Finally, completely remove the genl_magic system; DRBD was its only user. Signed-off-by: Christoph Böhmwalder Acked-by: Jakub Kicinski Link: https://patch.msgid.link/20260506124541.1951772-3-christoph.boehmwalder@linbit.com Signed-off-by: Jens Axboe --- drivers/block/drbd/Makefile | 1 + drivers/block/drbd/drbd_debugfs.c | 2 +- drivers/block/drbd/drbd_int.h | 4 +- drivers/block/drbd/drbd_main.c | 6 +- drivers/block/drbd/drbd_nl.c | 416 +++--- drivers/block/drbd/drbd_nl_gen.c | 2606 +++++++++++++++++++++++++++++++++++++ drivers/block/drbd/drbd_nl_gen.h | 395 ++++++ drivers/block/drbd/drbd_proc.c | 2 +- include/linux/drbd_genl.h | 536 -------- include/linux/drbd_genl_api.h | 16 - include/linux/genl_magic_func.h | 413 ------ include/linux/genl_magic_struct.h | 272 ---- include/uapi/linux/drbd.h | 3 + include/uapi/linux/drbd_genl.h | 359 +++++ 14 files changed, 3609 insertions(+), 1422 deletions(-) create mode 100644 drivers/block/drbd/drbd_nl_gen.c create mode 100644 drivers/block/drbd/drbd_nl_gen.h delete mode 100644 include/linux/drbd_genl.h delete mode 100644 include/linux/drbd_genl_api.h delete mode 100644 include/linux/genl_magic_func.h delete mode 100644 include/linux/genl_magic_struct.h create mode 100644 include/uapi/linux/drbd_genl.h (limited to 'include') diff --git a/drivers/block/drbd/Makefile b/drivers/block/drbd/Makefile index 187eaf81f0f8..5faaa8a8e7f0 100644 --- a/drivers/block/drbd/Makefile +++ b/drivers/block/drbd/Makefile @@ -3,6 +3,7 @@ drbd-y := drbd_buildtag.o drbd_bitmap.o drbd_proc.o drbd-y += drbd_worker.o drbd_receiver.o drbd_req.o drbd_actlog.o drbd-y += drbd_main.o drbd_strings.o drbd_nl.o drbd-y += drbd_interval.o drbd_state.o +drbd-y += drbd_nl_gen.o drbd-$(CONFIG_DEBUG_FS) += drbd_debugfs.o obj-$(CONFIG_BLK_DEV_DRBD) += drbd.o diff --git a/drivers/block/drbd/drbd_debugfs.c b/drivers/block/drbd/drbd_debugfs.c index 12460b584bcb..371abcd7e880 100644 --- a/drivers/block/drbd/drbd_debugfs.c +++ b/drivers/block/drbd/drbd_debugfs.c @@ -844,7 +844,7 @@ static int drbd_version_show(struct seq_file *m, void *ignored) { seq_printf(m, "# %s\n", drbd_buildtag()); seq_printf(m, "VERSION=%s\n", REL_VERSION); - seq_printf(m, "API_VERSION=%u\n", GENL_MAGIC_VERSION); + seq_printf(m, "API_VERSION=%u\n", DRBD_FAMILY_VERSION); seq_printf(m, "PRO_VERSION_MIN=%u\n", PRO_VERSION_MIN); seq_printf(m, "PRO_VERSION_MAX=%u\n", PRO_VERSION_MAX); return 0; diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index f3d746a6d6fd..48b45c3142f7 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -32,14 +32,16 @@ #include #include #include -#include #include #include "drbd_config.h" +#include "drbd_nl_gen.h" #include "drbd_strings.h" #include "drbd_state.h" #include "drbd_protocol.h" #include "drbd_polymorph_printk.h" +extern struct genl_family drbd_nl_family; + /* shared module parameters, defined in drbd_main.c */ #ifdef CONFIG_DRBD_FAULT_INJECTION extern int drbd_enable_faults; diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index b1a721dd0496..a2a841c89201 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -2324,7 +2324,7 @@ static void drbd_cleanup(void) if (retry.wq) destroy_workqueue(retry.wq); - drbd_genl_unregister(); + genl_unregister_family(&drbd_nl_family); idr_for_each_entry(&drbd_devices, device, i) drbd_delete_device(device); @@ -2846,7 +2846,7 @@ static int __init drbd_init(void) mutex_init(&resources_mutex); INIT_LIST_HEAD(&drbd_resources); - err = drbd_genl_register(); + err = genl_register_family(&drbd_nl_family); if (err) { pr_err("unable to register generic netlink family\n"); goto fail; @@ -2876,7 +2876,7 @@ static int __init drbd_init(void) pr_info("initialized. " "Version: " REL_VERSION " (api:%d/proto:%d-%d)\n", - GENL_MAGIC_VERSION, PRO_VERSION_MIN, PRO_VERSION_MAX); + DRBD_FAMILY_VERSION, PRO_VERSION_MIN, PRO_VERSION_MAX); pr_info("%s\n", drbd_buildtag()); pr_info("registered as block device major %d\n", DRBD_MAJOR); return 0; /* Success! */ diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index c2ac555473e7..f9ffcd67607b 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -31,59 +31,13 @@ #include -/* .doit */ -// int drbd_adm_create_resource(struct sk_buff *skb, struct genl_info *info); -// int drbd_adm_delete_resource(struct sk_buff *skb, struct genl_info *info); - -int drbd_adm_new_minor(struct sk_buff *skb, struct genl_info *info); -int drbd_adm_del_minor(struct sk_buff *skb, struct genl_info *info); - -int drbd_adm_new_resource(struct sk_buff *skb, struct genl_info *info); -int drbd_adm_del_resource(struct sk_buff *skb, struct genl_info *info); -int drbd_adm_down(struct sk_buff *skb, struct genl_info *info); - -int drbd_adm_set_role(struct sk_buff *skb, struct genl_info *info); -int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info); -int drbd_adm_disk_opts(struct sk_buff *skb, struct genl_info *info); -int drbd_adm_detach(struct sk_buff *skb, struct genl_info *info); -int drbd_adm_connect(struct sk_buff *skb, struct genl_info *info); -int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info); -int drbd_adm_resize(struct sk_buff *skb, struct genl_info *info); -int drbd_adm_start_ov(struct sk_buff *skb, struct genl_info *info); -int drbd_adm_new_c_uuid(struct sk_buff *skb, struct genl_info *info); -int drbd_adm_disconnect(struct sk_buff *skb, struct genl_info *info); -int drbd_adm_invalidate(struct sk_buff *skb, struct genl_info *info); -int drbd_adm_invalidate_peer(struct sk_buff *skb, struct genl_info *info); -int drbd_adm_pause_sync(struct sk_buff *skb, struct genl_info *info); -int drbd_adm_resume_sync(struct sk_buff *skb, struct genl_info *info); -int drbd_adm_suspend_io(struct sk_buff *skb, struct genl_info *info); -int drbd_adm_resume_io(struct sk_buff *skb, struct genl_info *info); -int drbd_adm_outdate(struct sk_buff *skb, struct genl_info *info); -int drbd_adm_resource_opts(struct sk_buff *skb, struct genl_info *info); -int drbd_adm_get_status(struct sk_buff *skb, struct genl_info *info); -int drbd_adm_get_timeout_type(struct sk_buff *skb, struct genl_info *info); -/* .dumpit */ -int drbd_adm_get_status_all(struct sk_buff *skb, struct netlink_callback *cb); -int drbd_adm_dump_resources(struct sk_buff *skb, struct netlink_callback *cb); -int drbd_adm_dump_devices(struct sk_buff *skb, struct netlink_callback *cb); -int drbd_adm_dump_devices_done(struct netlink_callback *cb); -int drbd_adm_dump_connections(struct sk_buff *skb, struct netlink_callback *cb); -int drbd_adm_dump_connections_done(struct netlink_callback *cb); -int drbd_adm_dump_peer_devices(struct sk_buff *skb, struct netlink_callback *cb); -int drbd_adm_dump_peer_devices_done(struct netlink_callback *cb); -int drbd_adm_get_initial_state(struct sk_buff *skb, struct netlink_callback *cb); - -#include - -static int drbd_pre_doit(const struct genl_split_ops *ops, - struct sk_buff *skb, struct genl_info *info); -static void drbd_post_doit(const struct genl_split_ops *ops, - struct sk_buff *skb, struct genl_info *info); - -#define GENL_MAGIC_FAMILY_PRE_DOIT drbd_pre_doit -#define GENL_MAGIC_FAMILY_POST_DOIT drbd_post_doit - -#include +#include "drbd_nl_gen.h" + +static int drbd_genl_multicast_events(struct sk_buff *skb, gfp_t flags) +{ + return genlmsg_multicast(&drbd_nl_family, skb, 0, + DRBD_NLGRP_EVENTS, flags); +} static atomic_t drbd_genl_seq = ATOMIC_INIT(2); /* two. */ static atomic_t notify_genl_seq = ATOMIC_INIT(2); /* two. */ @@ -114,7 +68,7 @@ static int drbd_msg_put_info(struct sk_buff *skb, const char *info) if (!nla) return err; - err = nla_put_string(skb, T_info_text, info); + err = nla_put_string(skb, DRBD_A_DRBD_CFG_REPLY_INFO_TEXT, info); if (err) { nla_nest_cancel(skb, nla); return err; @@ -135,7 +89,7 @@ static int drbd_msg_sprintf_info(struct sk_buff *skb, const char *fmt, ...) if (!nla) return err; - txt = nla_reserve(skb, T_info_text, 256); + txt = nla_reserve(skb, DRBD_A_DRBD_CFG_REPLY_INFO_TEXT, 256); if (!txt) { nla_nest_cancel(skb, nla); return err; @@ -187,6 +141,15 @@ static const unsigned int drbd_genl_cmd_flags[] = { [DRBD_ADM_DOWN] = DRBD_ADM_NEED_RESOURCE, }; +/* Detect attempts to change invariant attributes in a _change_ handler. */ +#define has_invariant(ntb, attr) \ +({ \ + bool __found = !!(ntb)[attr]; \ + if (__found) \ + pr_info("must not change invariant attr: %s\n", #attr); \ + __found; \ +}) + /* * At this point, we still rely on the global genl_lock(). * If we want to avoid that, and allow "genl_family.parallel_ops", we may need @@ -210,7 +173,7 @@ static int drbd_adm_prepare(struct drbd_config_context *adm_ctx, } adm_ctx->reply_dh = genlmsg_put_reply(adm_ctx->reply_skb, - info, &drbd_genl_family, 0, cmd); + info, &drbd_nl_family, 0, cmd); /* put of a few bytes into a fresh skb of >= 4k will always succeed. * but anyways */ if (!adm_ctx->reply_dh) { @@ -223,9 +186,11 @@ static int drbd_adm_prepare(struct drbd_config_context *adm_ctx, adm_ctx->volume = VOLUME_UNSPECIFIED; if (info->attrs[DRBD_NLA_CFG_CONTEXT]) { + struct nlattr **ntb; struct nlattr *nla; - /* parse and validate only */ - err = drbd_cfg_context_from_attrs(NULL, info); + + /* parse and validate, get nested attribute table */ + err = drbd_cfg_context_ntb_from_attrs(&ntb, info); if (err) goto fail; @@ -234,18 +199,21 @@ static int drbd_adm_prepare(struct drbd_config_context *adm_ctx, err = nla_put_nohdr(adm_ctx->reply_skb, info->attrs[DRBD_NLA_CFG_CONTEXT]->nla_len, info->attrs[DRBD_NLA_CFG_CONTEXT]); - if (err) + if (err) { + kfree(ntb); goto fail; + } /* and assign stuff to the adm_ctx */ - nla = nested_attr_tb[T_ctx_volume]; + nla = ntb[DRBD_A_DRBD_CFG_CONTEXT_CTX_VOLUME]; if (nla) adm_ctx->volume = nla_get_u32(nla); - nla = nested_attr_tb[T_ctx_resource_name]; + nla = ntb[DRBD_A_DRBD_CFG_CONTEXT_CTX_RESOURCE_NAME]; if (nla) adm_ctx->resource_name = nla_data(nla); - adm_ctx->my_addr = nested_attr_tb[T_ctx_my_addr]; - adm_ctx->peer_addr = nested_attr_tb[T_ctx_peer_addr]; + adm_ctx->my_addr = ntb[DRBD_A_DRBD_CFG_CONTEXT_CTX_MY_ADDR]; + adm_ctx->peer_addr = ntb[DRBD_A_DRBD_CFG_CONTEXT_CTX_PEER_ADDR]; + kfree(ntb); if ((adm_ctx->my_addr && nla_len(adm_ctx->my_addr) > sizeof(adm_ctx->connection->my_addr)) || (adm_ctx->peer_addr && @@ -259,7 +227,7 @@ static int drbd_adm_prepare(struct drbd_config_context *adm_ctx, adm_ctx->device = minor_to_device(d_in->minor); /* We are protected by the global genl_lock(). - * But we may explicitly drop it/retake it in drbd_adm_set_role(), + * But we may explicitly drop it/retake it in drbd_nl_set_role(), * so make sure this object stays around. */ if (adm_ctx->device) kref_get(&adm_ctx->device->kref); @@ -334,8 +302,8 @@ fail: return err; } -static int drbd_pre_doit(const struct genl_split_ops *ops, - struct sk_buff *skb, struct genl_info *info) +int drbd_pre_doit(const struct genl_split_ops *ops, + struct sk_buff *skb, struct genl_info *info) { struct drbd_config_context *adm_ctx; u8 cmd = info->genlhdr->cmd; @@ -362,8 +330,8 @@ static int drbd_pre_doit(const struct genl_split_ops *ops, return 0; } -static void drbd_post_doit(const struct genl_split_ops *ops, - struct sk_buff *skb, struct genl_info *info) +void drbd_post_doit(const struct genl_split_ops *ops, + struct sk_buff *skb, struct genl_info *info) { struct drbd_config_context *adm_ctx = info->user_ptr[0]; @@ -828,7 +796,7 @@ static const char *from_attrs_err_to_txt(int err) "invalid attribute value"; } -int drbd_adm_set_role(struct sk_buff *skb, struct genl_info *info) +static int drbd_nl_set_role(struct sk_buff *skb, struct genl_info *info) { struct drbd_config_context *adm_ctx = info->user_ptr[0]; struct set_role_parms parms; @@ -868,6 +836,16 @@ out: return 0; } +int drbd_nl_primary_doit(struct sk_buff *skb, struct genl_info *info) +{ + return drbd_nl_set_role(skb, info); +} + +int drbd_nl_secondary_doit(struct sk_buff *skb, struct genl_info *info) +{ + return drbd_nl_set_role(skb, info); +} + /* Initializes the md.*_offset members, so we are able to find * the on disk meta data. * @@ -962,7 +940,7 @@ char *ppsize(char *buf, unsigned long long size) * peer may not initiate a resize. */ /* Note these are not to be confused with - * drbd_adm_suspend_io/drbd_adm_resume_io, + * drbd_nl_suspend_io_doit/drbd_nl_resume_io_doit, * which are (sub) state changes triggered by admin (drbdsetup), * and can be long lived. * This changes an device->flag, is triggered by drbd internals, @@ -1574,13 +1552,14 @@ out: return err; } -int drbd_adm_disk_opts(struct sk_buff *skb, struct genl_info *info) +int drbd_nl_chg_disk_opts_doit(struct sk_buff *skb, struct genl_info *info) { struct drbd_config_context *adm_ctx = info->user_ptr[0]; enum drbd_ret_code retcode; struct drbd_device *device; struct disk_conf *new_disk_conf, *old_disk_conf; struct fifo_buffer *old_plan = NULL, *new_plan = NULL; + struct nlattr **ntb; int err; unsigned int fifo_size; @@ -1612,13 +1591,29 @@ int drbd_adm_disk_opts(struct sk_buff *skb, struct genl_info *info) if (should_set_defaults(info)) set_disk_conf_defaults(new_disk_conf); - err = disk_conf_from_attrs_for_change(new_disk_conf, info); + err = disk_conf_from_attrs(new_disk_conf, info); if (err && err != -ENOMSG) { retcode = ERR_MANDATORY_TAG; drbd_msg_put_info(adm_ctx->reply_skb, from_attrs_err_to_txt(err)); goto fail_unlock; } + err = disk_conf_ntb_from_attrs(&ntb, info); + if (!err) { + if (has_invariant(ntb, DRBD_A_DISK_CONF_BACKING_DEV) || + has_invariant(ntb, DRBD_A_DISK_CONF_META_DEV) || + has_invariant(ntb, DRBD_A_DISK_CONF_META_DEV_IDX) || + has_invariant(ntb, DRBD_A_DISK_CONF_DISK_SIZE) || + has_invariant(ntb, DRBD_A_DISK_CONF_MAX_BIO_BVECS)) { + retcode = ERR_MANDATORY_TAG; + drbd_msg_put_info(adm_ctx->reply_skb, + "cannot change invariant setting"); + kfree(ntb); + goto fail_unlock; + } + kfree(ntb); + } + if (!expect(device, new_disk_conf->resync_rate >= 1)) new_disk_conf->resync_rate = 1; @@ -1796,7 +1791,7 @@ void drbd_backing_dev_free(struct drbd_device *device, struct drbd_backing_dev * kfree(ldev); } -int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info) +int drbd_nl_attach_doit(struct sk_buff *skb, struct genl_info *info) { struct drbd_config_context *adm_ctx = info->user_ptr[0]; struct drbd_device *device; @@ -2236,7 +2231,7 @@ static int adm_detach(struct drbd_device *device, int force) * Then we transition to D_DISKLESS, and wait for put_ldev() to return all * internal references as well. * Only then we have finally detached. */ -int drbd_adm_detach(struct sk_buff *skb, struct genl_info *info) +int drbd_nl_detach_doit(struct sk_buff *skb, struct genl_info *info) { struct drbd_config_context *adm_ctx = info->user_ptr[0]; enum drbd_ret_code retcode; @@ -2434,12 +2429,13 @@ static void free_crypto(struct crypto *crypto) crypto_free_shash(crypto->verify_tfm); } -int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info) +int drbd_nl_chg_net_opts_doit(struct sk_buff *skb, struct genl_info *info) { struct drbd_config_context *adm_ctx = info->user_ptr[0]; enum drbd_ret_code retcode; struct drbd_connection *connection; struct net_conf *old_net_conf, *new_net_conf = NULL; + struct nlattr **ntb; int err; int ovr; /* online verify running */ int rsr; /* re-sync running */ @@ -2476,13 +2472,26 @@ int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info) if (should_set_defaults(info)) set_net_conf_defaults(new_net_conf); - err = net_conf_from_attrs_for_change(new_net_conf, info); + err = net_conf_from_attrs(new_net_conf, info); if (err && err != -ENOMSG) { retcode = ERR_MANDATORY_TAG; drbd_msg_put_info(adm_ctx->reply_skb, from_attrs_err_to_txt(err)); goto fail; } + err = net_conf_ntb_from_attrs(&ntb, info); + if (!err) { + if (has_invariant(ntb, DRBD_A_NET_CONF_DISCARD_MY_DATA) || + has_invariant(ntb, DRBD_A_NET_CONF_TENTATIVE)) { + retcode = ERR_MANDATORY_TAG; + drbd_msg_put_info(adm_ctx->reply_skb, + "cannot change invariant setting"); + kfree(ntb); + goto fail; + } + kfree(ntb); + } + retcode = check_net_options(connection, new_net_conf); if (retcode != NO_ERROR) goto fail; @@ -2575,7 +2584,7 @@ static void peer_device_to_info(struct peer_device_info *info, info->peer_resync_susp_dependency = device->state.aftr_isp; } -int drbd_adm_connect(struct sk_buff *skb, struct genl_info *info) +int drbd_nl_connect_doit(struct sk_buff *skb, struct genl_info *info) { struct connection_info connection_info; enum drbd_notification_type flags; @@ -2790,7 +2799,7 @@ repeat: return rv; } -int drbd_adm_disconnect(struct sk_buff *skb, struct genl_info *info) +int drbd_nl_disconnect_doit(struct sk_buff *skb, struct genl_info *info) { struct drbd_config_context *adm_ctx = info->user_ptr[0]; struct disconnect_parms parms; @@ -2845,7 +2854,7 @@ void resync_after_online_grow(struct drbd_device *device) _drbd_request_state(device, NS(conn, C_WF_SYNC_UUID), CS_VERBOSE + CS_SERIALIZE); } -int drbd_adm_resize(struct sk_buff *skb, struct genl_info *info) +int drbd_nl_resize_doit(struct sk_buff *skb, struct genl_info *info) { struct drbd_config_context *adm_ctx = info->user_ptr[0]; struct disk_conf *old_disk_conf, *new_disk_conf = NULL; @@ -2981,7 +2990,7 @@ int drbd_adm_resize(struct sk_buff *skb, struct genl_info *info) goto fail; } -int drbd_adm_resource_opts(struct sk_buff *skb, struct genl_info *info) +int drbd_nl_resource_opts_doit(struct sk_buff *skb, struct genl_info *info) { struct drbd_config_context *adm_ctx = info->user_ptr[0]; enum drbd_ret_code retcode; @@ -3019,7 +3028,7 @@ fail: return 0; } -int drbd_adm_invalidate(struct sk_buff *skb, struct genl_info *info) +int drbd_nl_invalidate_doit(struct sk_buff *skb, struct genl_info *info) { struct drbd_config_context *adm_ctx = info->user_ptr[0]; struct drbd_device *device; @@ -3097,7 +3106,7 @@ static int drbd_bmio_set_susp_al(struct drbd_device *device, return rv; } -int drbd_adm_invalidate_peer(struct sk_buff *skb, struct genl_info *info) +int drbd_nl_inval_peer_doit(struct sk_buff *skb, struct genl_info *info) { struct drbd_config_context *adm_ctx = info->user_ptr[0]; int retcode; /* drbd_ret_code, drbd_state_rv */ @@ -3148,7 +3157,7 @@ out: return 0; } -int drbd_adm_pause_sync(struct sk_buff *skb, struct genl_info *info) +int drbd_nl_pause_sync_doit(struct sk_buff *skb, struct genl_info *info) { struct drbd_config_context *adm_ctx = info->user_ptr[0]; enum drbd_ret_code retcode; @@ -3168,7 +3177,7 @@ out: return 0; } -int drbd_adm_resume_sync(struct sk_buff *skb, struct genl_info *info) +int drbd_nl_resume_sync_doit(struct sk_buff *skb, struct genl_info *info) { struct drbd_config_context *adm_ctx = info->user_ptr[0]; union drbd_dev_state s; @@ -3196,12 +3205,12 @@ out: return 0; } -int drbd_adm_suspend_io(struct sk_buff *skb, struct genl_info *info) +int drbd_nl_suspend_io_doit(struct sk_buff *skb, struct genl_info *info) { return drbd_adm_simple_request_state(skb, info, NS(susp, 1)); } -int drbd_adm_resume_io(struct sk_buff *skb, struct genl_info *info) +int drbd_nl_resume_io_doit(struct sk_buff *skb, struct genl_info *info) { struct drbd_config_context *adm_ctx = info->user_ptr[0]; struct drbd_device *device; @@ -3257,7 +3266,7 @@ out: return 0; } -int drbd_adm_outdate(struct sk_buff *skb, struct genl_info *info) +int drbd_nl_outdate_doit(struct sk_buff *skb, struct genl_info *info) { return drbd_adm_simple_request_state(skb, info, NS(disk, D_OUTDATED)); } @@ -3272,16 +3281,20 @@ static int nla_put_drbd_cfg_context(struct sk_buff *skb, if (!nla) goto nla_put_failure; if (device && - nla_put_u32(skb, T_ctx_volume, device->vnr)) + nla_put_u32(skb, DRBD_A_DRBD_CFG_CONTEXT_CTX_VOLUME, device->vnr)) goto nla_put_failure; - if (nla_put_string(skb, T_ctx_resource_name, resource->name)) + if (nla_put_string(skb, DRBD_A_DRBD_CFG_CONTEXT_CTX_RESOURCE_NAME, resource->name)) goto nla_put_failure; if (connection) { if (connection->my_addr_len && - nla_put(skb, T_ctx_my_addr, connection->my_addr_len, &connection->my_addr)) + nla_put(skb, DRBD_A_DRBD_CFG_CONTEXT_CTX_MY_ADDR, + connection->my_addr_len, + &connection->my_addr)) goto nla_put_failure; if (connection->peer_addr_len && - nla_put(skb, T_ctx_peer_addr, connection->peer_addr_len, &connection->peer_addr)) + nla_put(skb, DRBD_A_DRBD_CFG_CONTEXT_CTX_PEER_ADDR, + connection->peer_addr_len, + &connection->peer_addr)) goto nla_put_failure; } nla_nest_end(skb, nla); @@ -3300,7 +3313,7 @@ nla_put_failure: */ static struct nlattr *find_cfg_context_attr(const struct nlmsghdr *nlh, int attr) { - const unsigned hdrlen = GENL_HDRLEN + GENL_MAGIC_FAMILY_HDRSZ; + const unsigned int hdrlen = GENL_HDRLEN + sizeof(struct drbd_genlmsghdr); struct nlattr *nla; nla = nla_find(nlmsg_attrdata(nlh, hdrlen), nlmsg_attrlen(nlh, hdrlen), @@ -3312,7 +3325,7 @@ static struct nlattr *find_cfg_context_attr(const struct nlmsghdr *nlh, int attr static void resource_to_info(struct resource_info *, struct drbd_resource *); -int drbd_adm_dump_resources(struct sk_buff *skb, struct netlink_callback *cb) +int drbd_nl_get_resources_dumpit(struct sk_buff *skb, struct netlink_callback *cb) { struct drbd_genlmsghdr *dh; struct drbd_resource *resource; @@ -3340,7 +3353,7 @@ found_resource: put_result: dh = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, &drbd_genl_family, + cb->nlh->nlmsg_seq, &drbd_nl_family, NLM_F_MULTI, DRBD_ADM_GET_RESOURCES); err = -ENOMEM; if (!dh) @@ -3350,15 +3363,15 @@ put_result: err = nla_put_drbd_cfg_context(skb, resource, NULL, NULL); if (err) goto out; - err = res_opts_to_skb(skb, &resource->res_opts, !capable(CAP_SYS_ADMIN)); + err = res_opts_to_skb(skb, &resource->res_opts); if (err) goto out; resource_to_info(&resource_info, resource); - err = resource_info_to_skb(skb, &resource_info, !capable(CAP_SYS_ADMIN)); + err = resource_info_to_skb(skb, &resource_info); if (err) goto out; resource_statistics.res_stat_write_ordering = resource->write_ordering; - err = resource_statistics_to_skb(skb, &resource_statistics, !capable(CAP_SYS_ADMIN)); + err = resource_statistics_to_skb(skb, &resource_statistics); if (err) goto out; cb->args[0] = (long)resource; @@ -3423,7 +3436,7 @@ int drbd_adm_dump_devices_done(struct netlink_callback *cb) { static void device_to_info(struct device_info *, struct drbd_device *); -int drbd_adm_dump_devices(struct sk_buff *skb, struct netlink_callback *cb) +int drbd_nl_get_devices_dumpit(struct sk_buff *skb, struct netlink_callback *cb) { struct nlattr *resource_filter; struct drbd_resource *resource; @@ -3436,7 +3449,8 @@ int drbd_adm_dump_devices(struct sk_buff *skb, struct netlink_callback *cb) resource = (struct drbd_resource *)cb->args[0]; if (!cb->args[0] && !cb->args[1]) { - resource_filter = find_cfg_context_attr(cb->nlh, T_ctx_resource_name); + resource_filter = find_cfg_context_attr(cb->nlh, + DRBD_A_DRBD_CFG_CONTEXT_CTX_RESOURCE_NAME); if (resource_filter) { retcode = ERR_RES_NOT_KNOWN; resource = drbd_find_resource(nla_data(resource_filter)); @@ -3465,7 +3479,7 @@ int drbd_adm_dump_devices(struct sk_buff *skb, struct netlink_callback *cb) put_result: dh = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, &drbd_genl_family, + cb->nlh->nlmsg_seq, &drbd_nl_family, NLM_F_MULTI, DRBD_ADM_GET_DEVICES); err = -ENOMEM; if (!dh) @@ -3481,18 +3495,18 @@ put_result: struct disk_conf *disk_conf = rcu_dereference(device->ldev->disk_conf); - err = disk_conf_to_skb(skb, disk_conf, !capable(CAP_SYS_ADMIN)); + err = disk_conf_to_skb(skb, disk_conf); put_ldev(device); if (err) goto out; } device_to_info(&device_info, device); - err = device_info_to_skb(skb, &device_info, !capable(CAP_SYS_ADMIN)); + err = device_info_to_skb(skb, &device_info); if (err) goto out; device_to_statistics(&device_statistics, device); - err = device_statistics_to_skb(skb, &device_statistics, !capable(CAP_SYS_ADMIN)); + err = device_statistics_to_skb(skb, &device_statistics); if (err) goto out; cb->args[1] = minor + 1; @@ -3514,7 +3528,7 @@ int drbd_adm_dump_connections_done(struct netlink_callback *cb) enum { SINGLE_RESOURCE, ITERATE_RESOURCES }; -int drbd_adm_dump_connections(struct sk_buff *skb, struct netlink_callback *cb) +int drbd_nl_get_connections_dumpit(struct sk_buff *skb, struct netlink_callback *cb) { struct nlattr *resource_filter; struct drbd_resource *resource = NULL, *next_resource; @@ -3527,7 +3541,8 @@ int drbd_adm_dump_connections(struct sk_buff *skb, struct netlink_callback *cb) rcu_read_lock(); resource = (struct drbd_resource *)cb->args[0]; if (!cb->args[0]) { - resource_filter = find_cfg_context_attr(cb->nlh, T_ctx_resource_name); + resource_filter = find_cfg_context_attr(cb->nlh, + DRBD_A_DRBD_CFG_CONTEXT_CTX_RESOURCE_NAME); if (resource_filter) { retcode = ERR_RES_NOT_KNOWN; resource = drbd_find_resource(nla_data(resource_filter)); @@ -3591,7 +3606,7 @@ found_resource: put_result: dh = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, &drbd_genl_family, + cb->nlh->nlmsg_seq, &drbd_nl_family, NLM_F_MULTI, DRBD_ADM_GET_CONNECTIONS); err = -ENOMEM; if (!dh) @@ -3606,16 +3621,16 @@ put_result: goto out; net_conf = rcu_dereference(connection->net_conf); if (net_conf) { - err = net_conf_to_skb(skb, net_conf, !capable(CAP_SYS_ADMIN)); + err = net_conf_to_skb(skb, net_conf); if (err) goto out; } connection_to_info(&connection_info, connection); - err = connection_info_to_skb(skb, &connection_info, !capable(CAP_SYS_ADMIN)); + err = connection_info_to_skb(skb, &connection_info); if (err) goto out; connection_statistics.conn_congested = test_bit(NET_CONGESTED, &connection->flags); - err = connection_statistics_to_skb(skb, &connection_statistics, !capable(CAP_SYS_ADMIN)); + err = connection_statistics_to_skb(skb, &connection_statistics); if (err) goto out; cb->args[2] = (long)connection; @@ -3676,7 +3691,7 @@ int drbd_adm_dump_peer_devices_done(struct netlink_callback *cb) return put_resource_in_arg0(cb, 9); } -int drbd_adm_dump_peer_devices(struct sk_buff *skb, struct netlink_callback *cb) +int drbd_nl_get_peer_devices_dumpit(struct sk_buff *skb, struct netlink_callback *cb) { struct nlattr *resource_filter; struct drbd_resource *resource; @@ -3688,7 +3703,8 @@ int drbd_adm_dump_peer_devices(struct sk_buff *skb, struct netlink_callback *cb) resource = (struct drbd_resource *)cb->args[0]; if (!cb->args[0] && !cb->args[1]) { - resource_filter = find_cfg_context_attr(cb->nlh, T_ctx_resource_name); + resource_filter = find_cfg_context_attr(cb->nlh, + DRBD_A_DRBD_CFG_CONTEXT_CTX_RESOURCE_NAME); if (resource_filter) { retcode = ERR_RES_NOT_KNOWN; resource = drbd_find_resource(nla_data(resource_filter)); @@ -3735,7 +3751,7 @@ found_peer_device: put_result: dh = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, &drbd_genl_family, + cb->nlh->nlmsg_seq, &drbd_nl_family, NLM_F_MULTI, DRBD_ADM_GET_PEER_DEVICES); err = -ENOMEM; if (!dh) @@ -3751,11 +3767,11 @@ put_result: if (err) goto out; peer_device_to_info(&peer_device_info, peer_device); - err = peer_device_info_to_skb(skb, &peer_device_info, !capable(CAP_SYS_ADMIN)); + err = peer_device_info_to_skb(skb, &peer_device_info); if (err) goto out; peer_device_to_statistics(&peer_device_statistics, peer_device); - err = peer_device_statistics_to_skb(skb, &peer_device_statistics, !capable(CAP_SYS_ADMIN)); + err = peer_device_statistics_to_skb(skb, &peer_device_statistics); if (err) goto out; cb->args[1] = minor; @@ -3795,11 +3811,11 @@ static int nla_put_status_info(struct sk_buff *skb, struct drbd_device *device, /* If sib != NULL, this is drbd_bcast_event, which anyone can listen * to. So we better exclude_sensitive information. * - * If sib == NULL, this is drbd_adm_get_status, executed synchronously + * If sib == NULL, this is drbd_nl_get_status_doit, executed synchronously * in the context of the requesting user process. Exclude sensitive * information, unless current has superuser. * - * NOTE: for drbd_adm_get_status_all(), this is a netlink dump, and + * NOTE: for drbd_nl_get_status_dumpit(), this is a netlink dump, and * relies on the current implementation of netlink_dump(), which * executes the dump callback successively from netlink_recvmsg(), * always in the context of the receiving process */ @@ -3812,7 +3828,7 @@ static int nla_put_status_info(struct sk_buff *skb, struct drbd_device *device, if (nla_put_drbd_cfg_context(skb, resource, the_only_connection(resource), device)) goto nla_put_failure; - if (res_opts_to_skb(skb, &device->resource->res_opts, exclude_sensitive)) + if (res_opts_to_skb(skb, &device->resource->res_opts)) goto nla_put_failure; rcu_read_lock(); @@ -3820,14 +3836,24 @@ static int nla_put_status_info(struct sk_buff *skb, struct drbd_device *device, struct disk_conf *disk_conf; disk_conf = rcu_dereference(device->ldev->disk_conf); - err = disk_conf_to_skb(skb, disk_conf, exclude_sensitive); + err = disk_conf_to_skb(skb, disk_conf); } if (!err) { struct net_conf *nc; nc = rcu_dereference(first_peer_device(device)->connection->net_conf); - if (nc) - err = net_conf_to_skb(skb, nc, exclude_sensitive); + if (nc) { + if (exclude_sensitive) { + struct net_conf nc_clean = *nc; + + memset(nc_clean.shared_secret, 0, + sizeof(nc_clean.shared_secret)); + nc_clean.shared_secret_len = 0; + err = net_conf_to_skb(skb, &nc_clean); + } else { + err = net_conf_to_skb(skb, nc); + } + } } rcu_read_unlock(); if (err) @@ -3836,42 +3862,57 @@ static int nla_put_status_info(struct sk_buff *skb, struct drbd_device *device, nla = nla_nest_start_noflag(skb, DRBD_NLA_STATE_INFO); if (!nla) goto nla_put_failure; - if (nla_put_u32(skb, T_sib_reason, sib ? sib->sib_reason : SIB_GET_STATUS_REPLY) || - nla_put_u32(skb, T_current_state, device->state.i) || - nla_put_u64_0pad(skb, T_ed_uuid, device->ed_uuid) || - nla_put_u64_0pad(skb, T_capacity, get_capacity(device->vdisk)) || - nla_put_u64_0pad(skb, T_send_cnt, device->send_cnt) || - nla_put_u64_0pad(skb, T_recv_cnt, device->recv_cnt) || - nla_put_u64_0pad(skb, T_read_cnt, device->read_cnt) || - nla_put_u64_0pad(skb, T_writ_cnt, device->writ_cnt) || - nla_put_u64_0pad(skb, T_al_writ_cnt, device->al_writ_cnt) || - nla_put_u64_0pad(skb, T_bm_writ_cnt, device->bm_writ_cnt) || - nla_put_u32(skb, T_ap_bio_cnt, atomic_read(&device->ap_bio_cnt)) || - nla_put_u32(skb, T_ap_pending_cnt, atomic_read(&device->ap_pending_cnt)) || - nla_put_u32(skb, T_rs_pending_cnt, atomic_read(&device->rs_pending_cnt))) + if (nla_put_u32(skb, DRBD_A_STATE_INFO_SIB_REASON, + sib ? sib->sib_reason : SIB_GET_STATUS_REPLY) || + nla_put_u32(skb, DRBD_A_STATE_INFO_CURRENT_STATE, + device->state.i) || + nla_put_u64_64bit(skb, DRBD_A_STATE_INFO_ED_UUID, + device->ed_uuid, 0) || + nla_put_u64_64bit(skb, DRBD_A_STATE_INFO_CAPACITY, + get_capacity(device->vdisk), 0) || + nla_put_u64_64bit(skb, DRBD_A_STATE_INFO_SEND_CNT, + device->send_cnt, 0) || + nla_put_u64_64bit(skb, DRBD_A_STATE_INFO_RECV_CNT, + device->recv_cnt, 0) || + nla_put_u64_64bit(skb, DRBD_A_STATE_INFO_READ_CNT, + device->read_cnt, 0) || + nla_put_u64_64bit(skb, DRBD_A_STATE_INFO_WRIT_CNT, + device->writ_cnt, 0) || + nla_put_u64_64bit(skb, DRBD_A_STATE_INFO_AL_WRIT_CNT, + device->al_writ_cnt, 0) || + nla_put_u64_64bit(skb, DRBD_A_STATE_INFO_BM_WRIT_CNT, + device->bm_writ_cnt, 0) || + nla_put_u32(skb, DRBD_A_STATE_INFO_AP_BIO_CNT, + atomic_read(&device->ap_bio_cnt)) || + nla_put_u32(skb, DRBD_A_STATE_INFO_AP_PENDING_CNT, + atomic_read(&device->ap_pending_cnt)) || + nla_put_u32(skb, DRBD_A_STATE_INFO_RS_PENDING_CNT, + atomic_read(&device->rs_pending_cnt))) goto nla_put_failure; if (got_ldev) { int err; spin_lock_irq(&device->ldev->md.uuid_lock); - err = nla_put(skb, T_uuids, sizeof(si->uuids), device->ldev->md.uuid); + err = nla_put(skb, DRBD_A_STATE_INFO_UUIDS, + sizeof(si->uuids), + device->ldev->md.uuid); spin_unlock_irq(&device->ldev->md.uuid_lock); if (err) goto nla_put_failure; - if (nla_put_u32(skb, T_disk_flags, device->ldev->md.flags) || - nla_put_u64_0pad(skb, T_bits_total, drbd_bm_bits(device)) || - nla_put_u64_0pad(skb, T_bits_oos, - drbd_bm_total_weight(device))) + if (nla_put_u32(skb, DRBD_A_STATE_INFO_DISK_FLAGS, device->ldev->md.flags) || + nla_put_u64_64bit(skb, DRBD_A_STATE_INFO_BITS_TOTAL, drbd_bm_bits(device), 0) || + nla_put_u64_64bit(skb, DRBD_A_STATE_INFO_BITS_OOS, + drbd_bm_total_weight(device), 0)) goto nla_put_failure; if (C_SYNC_SOURCE <= device->state.conn && C_PAUSED_SYNC_T >= device->state.conn) { - if (nla_put_u64_0pad(skb, T_bits_rs_total, - device->rs_total) || - nla_put_u64_0pad(skb, T_bits_rs_failed, - device->rs_failed)) + if (nla_put_u64_64bit(skb, DRBD_A_STATE_INFO_BITS_RS_TOTAL, + device->rs_total, 0) || + nla_put_u64_64bit(skb, DRBD_A_STATE_INFO_BITS_RS_FAILED, + device->rs_failed, 0)) goto nla_put_failure; } } @@ -3882,17 +3923,17 @@ static int nla_put_status_info(struct sk_buff *skb, struct drbd_device *device, case SIB_GET_STATUS_REPLY: break; case SIB_STATE_CHANGE: - if (nla_put_u32(skb, T_prev_state, sib->os.i) || - nla_put_u32(skb, T_new_state, sib->ns.i)) + if (nla_put_u32(skb, DRBD_A_STATE_INFO_PREV_STATE, sib->os.i) || + nla_put_u32(skb, DRBD_A_STATE_INFO_NEW_STATE, sib->ns.i)) goto nla_put_failure; break; case SIB_HELPER_POST: - if (nla_put_u32(skb, T_helper_exit_code, + if (nla_put_u32(skb, DRBD_A_STATE_INFO_HELPER_EXIT_CODE, sib->helper_exit_code)) goto nla_put_failure; fallthrough; case SIB_HELPER_PRE: - if (nla_put_string(skb, T_helper, sib->helper_name)) + if (nla_put_string(skb, DRBD_A_STATE_INFO_HELPER, sib->helper_name)) goto nla_put_failure; break; } @@ -3907,7 +3948,7 @@ nla_put_failure: return err; } -int drbd_adm_get_status(struct sk_buff *skb, struct genl_info *info) +int drbd_nl_get_status_doit(struct sk_buff *skb, struct genl_info *info) { struct drbd_config_context *adm_ctx = info->user_ptr[0]; enum drbd_ret_code retcode; @@ -3997,7 +4038,7 @@ next_resource: } dh = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, &drbd_genl_family, + cb->nlh->nlmsg_seq, &drbd_nl_family, NLM_F_MULTI, DRBD_ADM_GET_STATUS); if (!dh) goto out; @@ -4017,7 +4058,7 @@ next_resource: struct net_conf *nc; nc = rcu_dereference(connection->net_conf); - if (nc && net_conf_to_skb(skb, nc, 1) != 0) + if (nc && net_conf_to_skb(skb, nc) != 0) goto cancel; } goto done; @@ -4059,9 +4100,9 @@ out: * * Once things are setup properly, we call into get_one_status(). */ -int drbd_adm_get_status_all(struct sk_buff *skb, struct netlink_callback *cb) +int drbd_nl_get_status_dumpit(struct sk_buff *skb, struct netlink_callback *cb) { - const unsigned hdrlen = GENL_HDRLEN + GENL_MAGIC_FAMILY_HDRSZ; + const unsigned int hdrlen = GENL_HDRLEN + sizeof(struct drbd_genlmsghdr); struct nlattr *nla; const char *resource_name; struct drbd_resource *resource; @@ -4084,7 +4125,7 @@ int drbd_adm_get_status_all(struct sk_buff *skb, struct netlink_callback *cb) /* No explicit context given. Dump all. */ if (!nla) goto dump; - nla = nla_find_nested(nla, T_ctx_resource_name); + nla = nla_find_nested(nla, DRBD_A_DRBD_CFG_CONTEXT_CTX_RESOURCE_NAME); /* context given, but no name present? */ if (!nla) return -EINVAL; @@ -4107,7 +4148,7 @@ dump: return get_one_status(skb, cb); } -int drbd_adm_get_timeout_type(struct sk_buff *skb, struct genl_info *info) +int drbd_nl_get_timeout_type_doit(struct sk_buff *skb, struct genl_info *info) { struct drbd_config_context *adm_ctx = info->user_ptr[0]; enum drbd_ret_code retcode; @@ -4125,7 +4166,7 @@ int drbd_adm_get_timeout_type(struct sk_buff *skb, struct genl_info *info) test_bit(USE_DEGR_WFC_T, &adm_ctx->device->flags) ? UT_DEGRADED : UT_DEFAULT; - err = timeout_parms_to_priv_skb(adm_ctx->reply_skb, &tp); + err = timeout_parms_to_skb(adm_ctx->reply_skb, &tp); if (err) { nlmsg_free(adm_ctx->reply_skb); adm_ctx->reply_skb = NULL; @@ -4136,7 +4177,7 @@ out: return 0; } -int drbd_adm_start_ov(struct sk_buff *skb, struct genl_info *info) +int drbd_nl_start_ov_doit(struct sk_buff *skb, struct genl_info *info) { struct drbd_config_context *adm_ctx = info->user_ptr[0]; struct drbd_device *device; @@ -4182,7 +4223,7 @@ out: } -int drbd_adm_new_c_uuid(struct sk_buff *skb, struct genl_info *info) +int drbd_nl_new_c_uuid_doit(struct sk_buff *skb, struct genl_info *info) { struct drbd_config_context *adm_ctx = info->user_ptr[0]; struct drbd_device *device; @@ -4285,7 +4326,7 @@ static void resource_to_info(struct resource_info *info, info->res_susp_fen = resource->susp_fen; } -int drbd_adm_new_resource(struct sk_buff *skb, struct genl_info *info) +int drbd_nl_new_resource_doit(struct sk_buff *skb, struct genl_info *info) { struct drbd_connection *connection; struct drbd_config_context *adm_ctx = info->user_ptr[0]; @@ -4348,7 +4389,7 @@ static void device_to_info(struct device_info *info, } -int drbd_adm_new_minor(struct sk_buff *skb, struct genl_info *info) +int drbd_nl_new_minor_doit(struct sk_buff *skb, struct genl_info *info) { struct drbd_config_context *adm_ctx = info->user_ptr[0]; struct drbd_genlmsghdr *dh = genl_info_userhdr(info); @@ -4455,7 +4496,7 @@ static enum drbd_ret_code adm_del_minor(struct drbd_device *device) return ERR_MINOR_CONFIGURED; } -int drbd_adm_del_minor(struct sk_buff *skb, struct genl_info *info) +int drbd_nl_del_minor_doit(struct sk_buff *skb, struct genl_info *info) { struct drbd_config_context *adm_ctx = info->user_ptr[0]; enum drbd_ret_code retcode; @@ -4504,7 +4545,7 @@ static int adm_del_resource(struct drbd_resource *resource) return NO_ERROR; } -int drbd_adm_down(struct sk_buff *skb, struct genl_info *info) +int drbd_nl_down_doit(struct sk_buff *skb, struct genl_info *info) { struct drbd_config_context *adm_ctx = info->user_ptr[0]; struct drbd_resource *resource; @@ -4567,7 +4608,7 @@ finish: return 0; } -int drbd_adm_del_resource(struct sk_buff *skb, struct genl_info *info) +int drbd_nl_del_resource_doit(struct sk_buff *skb, struct genl_info *info) { struct drbd_config_context *adm_ctx = info->user_ptr[0]; struct drbd_resource *resource; @@ -4601,7 +4642,7 @@ void drbd_bcast_event(struct drbd_device *device, const struct sib_info *sib) goto failed; err = -EMSGSIZE; - d_out = genlmsg_put(msg, 0, seq, &drbd_genl_family, 0, DRBD_EVENT); + d_out = genlmsg_put(msg, 0, seq, &drbd_nl_family, 0, DRBD_ADM_EVENT); if (!d_out) /* cannot happen, but anyways. */ goto nla_put_failure; d_out->minor = device_to_minor(device); @@ -4632,7 +4673,7 @@ static int nla_put_notification_header(struct sk_buff *msg, .nh_type = type, }; - return drbd_notification_header_to_skb(msg, &nh, true); + return drbd_notification_header_to_skb(msg, &nh); } int notify_resource_state(struct sk_buff *skb, @@ -4656,7 +4697,7 @@ int notify_resource_state(struct sk_buff *skb, } err = -EMSGSIZE; - dh = genlmsg_put(skb, 0, seq, &drbd_genl_family, 0, DRBD_RESOURCE_STATE); + dh = genlmsg_put(skb, 0, seq, &drbd_nl_family, 0, DRBD_ADM_RESOURCE_STATE); if (!dh) goto nla_put_failure; dh->minor = -1U; @@ -4664,10 +4705,10 @@ int notify_resource_state(struct sk_buff *skb, if (nla_put_drbd_cfg_context(skb, resource, NULL, NULL) || nla_put_notification_header(skb, type) || ((type & ~NOTIFY_FLAGS) != NOTIFY_DESTROY && - resource_info_to_skb(skb, resource_info, true))) + resource_info_to_skb(skb, resource_info))) goto nla_put_failure; resource_statistics.res_stat_write_ordering = resource->write_ordering; - err = resource_statistics_to_skb(skb, &resource_statistics, !capable(CAP_SYS_ADMIN)); + err = resource_statistics_to_skb(skb, &resource_statistics); if (err) goto nla_put_failure; genlmsg_end(skb, dh); @@ -4708,7 +4749,7 @@ int notify_device_state(struct sk_buff *skb, } err = -EMSGSIZE; - dh = genlmsg_put(skb, 0, seq, &drbd_genl_family, 0, DRBD_DEVICE_STATE); + dh = genlmsg_put(skb, 0, seq, &drbd_nl_family, 0, DRBD_ADM_DEVICE_STATE); if (!dh) goto nla_put_failure; dh->minor = device->minor; @@ -4716,10 +4757,10 @@ int notify_device_state(struct sk_buff *skb, if (nla_put_drbd_cfg_context(skb, device->resource, NULL, device) || nla_put_notification_header(skb, type) || ((type & ~NOTIFY_FLAGS) != NOTIFY_DESTROY && - device_info_to_skb(skb, device_info, true))) + device_info_to_skb(skb, device_info))) goto nla_put_failure; device_to_statistics(&device_statistics, device); - device_statistics_to_skb(skb, &device_statistics, !capable(CAP_SYS_ADMIN)); + device_statistics_to_skb(skb, &device_statistics); genlmsg_end(skb, dh); if (multicast) { err = drbd_genl_multicast_events(skb, GFP_NOWAIT); @@ -4758,7 +4799,7 @@ int notify_connection_state(struct sk_buff *skb, } err = -EMSGSIZE; - dh = genlmsg_put(skb, 0, seq, &drbd_genl_family, 0, DRBD_CONNECTION_STATE); + dh = genlmsg_put(skb, 0, seq, &drbd_nl_family, 0, DRBD_ADM_CONNECTION_STATE); if (!dh) goto nla_put_failure; dh->minor = -1U; @@ -4766,10 +4807,10 @@ int notify_connection_state(struct sk_buff *skb, if (nla_put_drbd_cfg_context(skb, connection->resource, connection, NULL) || nla_put_notification_header(skb, type) || ((type & ~NOTIFY_FLAGS) != NOTIFY_DESTROY && - connection_info_to_skb(skb, connection_info, true))) + connection_info_to_skb(skb, connection_info))) goto nla_put_failure; connection_statistics.conn_congested = test_bit(NET_CONGESTED, &connection->flags); - connection_statistics_to_skb(skb, &connection_statistics, !capable(CAP_SYS_ADMIN)); + connection_statistics_to_skb(skb, &connection_statistics); genlmsg_end(skb, dh); if (multicast) { err = drbd_genl_multicast_events(skb, GFP_NOWAIT); @@ -4809,7 +4850,7 @@ int notify_peer_device_state(struct sk_buff *skb, } err = -EMSGSIZE; - dh = genlmsg_put(skb, 0, seq, &drbd_genl_family, 0, DRBD_PEER_DEVICE_STATE); + dh = genlmsg_put(skb, 0, seq, &drbd_nl_family, 0, DRBD_ADM_PEER_DEVICE_STATE); if (!dh) goto nla_put_failure; dh->minor = -1U; @@ -4817,10 +4858,10 @@ int notify_peer_device_state(struct sk_buff *skb, if (nla_put_drbd_cfg_context(skb, resource, peer_device->connection, peer_device->device) || nla_put_notification_header(skb, type) || ((type & ~NOTIFY_FLAGS) != NOTIFY_DESTROY && - peer_device_info_to_skb(skb, peer_device_info, true))) + peer_device_info_to_skb(skb, peer_device_info))) goto nla_put_failure; peer_device_to_statistics(&peer_device_statistics, peer_device); - peer_device_statistics_to_skb(skb, &peer_device_statistics, !capable(CAP_SYS_ADMIN)); + peer_device_statistics_to_skb(skb, &peer_device_statistics); genlmsg_end(skb, dh); if (multicast) { err = drbd_genl_multicast_events(skb, GFP_NOWAIT); @@ -4859,7 +4900,7 @@ void notify_helper(enum drbd_notification_type type, goto fail; err = -EMSGSIZE; - dh = genlmsg_put(skb, 0, seq, &drbd_genl_family, 0, DRBD_HELPER); + dh = genlmsg_put(skb, 0, seq, &drbd_nl_family, 0, DRBD_ADM_HELPER); if (!dh) goto fail; dh->minor = device ? device->minor : -1; @@ -4867,7 +4908,7 @@ void notify_helper(enum drbd_notification_type type, mutex_lock(¬ification_mutex); if (nla_put_drbd_cfg_context(skb, resource, connection, device) || nla_put_notification_header(skb, type) || - drbd_helper_info_to_skb(skb, &helper_info, true)) + drbd_helper_info_to_skb(skb, &helper_info)) goto unlock_fail; genlmsg_end(skb, dh); err = drbd_genl_multicast_events(skb, GFP_NOWAIT); @@ -4892,7 +4933,7 @@ static int notify_initial_state_done(struct sk_buff *skb, unsigned int seq) int err; err = -EMSGSIZE; - dh = genlmsg_put(skb, 0, seq, &drbd_genl_family, 0, DRBD_INITIAL_STATE_DONE); + dh = genlmsg_put(skb, 0, seq, &drbd_nl_family, 0, DRBD_ADM_INITIAL_STATE_DONE); if (!dh) goto nla_put_failure; dh->minor = -1U; @@ -4987,7 +5028,7 @@ out: return skb->len; } -int drbd_adm_get_initial_state(struct sk_buff *skb, struct netlink_callback *cb) +int drbd_nl_get_initial_state_dumpit(struct sk_buff *skb, struct netlink_callback *cb) { struct drbd_resource *resource; LIST_HEAD(head); @@ -5035,3 +5076,20 @@ int drbd_adm_get_initial_state(struct sk_buff *skb, struct netlink_callback *cb) cb->args[2] = cb->nlh->nlmsg_seq; return get_initial_state(skb, cb); } + +static const struct genl_multicast_group drbd_nl_mcgrps[] = { + [DRBD_NLGRP_EVENTS] = { .name = "events", }, +}; + +struct genl_family drbd_nl_family __ro_after_init = { + .name = "drbd", + .version = DRBD_FAMILY_VERSION, + .hdrsize = NLA_ALIGN(sizeof(struct drbd_genlmsghdr)), + .split_ops = drbd_nl_ops, + .n_split_ops = ARRAY_SIZE(drbd_nl_ops), + .mcgrps = drbd_nl_mcgrps, + .n_mcgrps = ARRAY_SIZE(drbd_nl_mcgrps), + .resv_start_op = 42, + .module = THIS_MODULE, + .netnsok = true, +}; diff --git a/drivers/block/drbd/drbd_nl_gen.c b/drivers/block/drbd/drbd_nl_gen.c new file mode 100644 index 000000000000..fb44b948cec8 --- /dev/null +++ b/drivers/block/drbd/drbd_nl_gen.c @@ -0,0 +1,2606 @@ +// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) + +#include +#include + +#include +#include +#include "drbd_nl_gen.h" + +#include +#include +#include + +/* Common nested types */ +const struct nla_policy drbd_connection_info_nl_policy[DRBD_A_CONNECTION_INFO_CONN_ROLE + 1] = { + [DRBD_A_CONNECTION_INFO_CONN_CONNECTION_STATE] = { .type = NLA_U32, }, + [DRBD_A_CONNECTION_INFO_CONN_ROLE] = { .type = NLA_U32, }, +}; + +const struct nla_policy drbd_connection_statistics_nl_policy[DRBD_A_CONNECTION_STATISTICS_CONN_CONGESTED + 1] = { + [DRBD_A_CONNECTION_STATISTICS_CONN_CONGESTED] = { .type = NLA_U8, }, +}; + +const struct nla_policy drbd_detach_parms_nl_policy[DRBD_A_DETACH_PARMS_FORCE_DETACH + 1] = { + [DRBD_A_DETACH_PARMS_FORCE_DETACH] = { .type = NLA_U8, }, +}; + +const struct nla_policy drbd_device_info_nl_policy[DRBD_A_DEVICE_INFO_DEV_DISK_STATE + 1] = { + [DRBD_A_DEVICE_INFO_DEV_DISK_STATE] = { .type = NLA_U32, }, +}; + +const struct nla_policy drbd_device_statistics_nl_policy[DRBD_A_DEVICE_STATISTICS_HISTORY_UUIDS + 1] = { + [DRBD_A_DEVICE_STATISTICS_DEV_SIZE] = { .type = NLA_U64, }, + [DRBD_A_DEVICE_STATISTICS_DEV_READ] = { .type = NLA_U64, }, + [DRBD_A_DEVICE_STATISTICS_DEV_WRITE] = { .type = NLA_U64, }, + [DRBD_A_DEVICE_STATISTICS_DEV_AL_WRITES] = { .type = NLA_U64, }, + [DRBD_A_DEVICE_STATISTICS_DEV_BM_WRITES] = { .type = NLA_U64, }, + [DRBD_A_DEVICE_STATISTICS_DEV_UPPER_PENDING] = { .type = NLA_U32, }, + [DRBD_A_DEVICE_STATISTICS_DEV_LOWER_PENDING] = { .type = NLA_U32, }, + [DRBD_A_DEVICE_STATISTICS_DEV_UPPER_BLOCKED] = { .type = NLA_U8, }, + [DRBD_A_DEVICE_STATISTICS_DEV_LOWER_BLOCKED] = { .type = NLA_U8, }, + [DRBD_A_DEVICE_STATISTICS_DEV_AL_SUSPENDED] = { .type = NLA_U8, }, + [DRBD_A_DEVICE_STATISTICS_DEV_EXPOSED_DATA_UUID] = { .type = NLA_U64, }, + [DRBD_A_DEVICE_STATISTICS_DEV_CURRENT_UUID] = { .type = NLA_U64, }, + [DRBD_A_DEVICE_STATISTICS_DEV_DISK_FLAGS] = { .type = NLA_U32, }, + [DRBD_A_DEVICE_STATISTICS_HISTORY_UUIDS] = NLA_POLICY_MAX_LEN(DRBD_NL_HISTORY_UUIDS_SIZE), +}; + +const struct nla_policy drbd_disconnect_parms_nl_policy[DRBD_A_DISCONNECT_PARMS_FORCE_DISCONNECT + 1] = { + [DRBD_A_DISCONNECT_PARMS_FORCE_DISCONNECT] = { .type = NLA_U8, }, +}; + +const struct nla_policy drbd_disk_conf_nl_policy[DRBD_A_DISK_CONF_DISABLE_WRITE_SAME + 1] = { + [DRBD_A_DISK_CONF_BACKING_DEV] = { .type = NLA_NUL_STRING, .len = 128, }, + [DRBD_A_DISK_CONF_META_DEV] = { .type = NLA_NUL_STRING, .len = 128, }, + [DRBD_A_DISK_CONF_META_DEV_IDX] = { .type = NLA_U32, }, + [DRBD_A_DISK_CONF_DISK_SIZE] = { .type = NLA_U64, }, + [DRBD_A_DISK_CONF_MAX_BIO_BVECS] = { .type = NLA_U32, }, + [DRBD_A_DISK_CONF_ON_IO_ERROR] = { .type = NLA_U32, }, + [DRBD_A_DISK_CONF_FENCING] = { .type = NLA_U32, }, + [DRBD_A_DISK_CONF_RESYNC_RATE] = { .type = NLA_U32, }, + [DRBD_A_DISK_CONF_RESYNC_AFTER] = { .type = NLA_U32, }, + [DRBD_A_DISK_CONF_AL_EXTENTS] = { .type = NLA_U32, }, + [DRBD_A_DISK_CONF_C_PLAN_AHEAD] = { .type = NLA_U32, }, + [DRBD_A_DISK_CONF_C_DELAY_TARGET] = { .type = NLA_U32, }, + [DRBD_A_DISK_CONF_C_FILL_TARGET] = { .type = NLA_U32, }, + [DRBD_A_DISK_CONF_C_MAX_RATE] = { .type = NLA_U32, }, + [DRBD_A_DISK_CONF_C_MIN_RATE] = { .type = NLA_U32, }, + [DRBD_A_DISK_CONF_DISK_BARRIER] = { .type = NLA_U8, }, + [DRBD_A_DISK_CONF_DISK_FLUSHES] = { .type = NLA_U8, }, + [DRBD_A_DISK_CONF_DISK_DRAIN] = { .type = NLA_U8, }, + [DRBD_A_DISK_CONF_MD_FLUSHES] = { .type = NLA_U8, }, + [DRBD_A_DISK_CONF_DISK_TIMEOUT] = { .type = NLA_U32, }, + [DRBD_A_DISK_CONF_READ_BALANCING] = { .type = NLA_U32, }, + [DRBD_A_DISK_CONF_AL_UPDATES] = { .type = NLA_U8, }, + [DRBD_A_DISK_CONF_DISCARD_ZEROES_IF_ALIGNED] = { .type = NLA_U8, }, + [DRBD_A_DISK_CONF_RS_DISCARD_GRANULARITY] = { .type = NLA_U32, }, + [DRBD_A_DISK_CONF_DISABLE_WRITE_SAME] = { .type = NLA_U8, }, +}; + +const struct nla_policy drbd_drbd_cfg_context_nl_policy[DRBD_A_DRBD_CFG_CONTEXT_CTX_PEER_ADDR + 1] = { + [DRBD_A_DRBD_CFG_CONTEXT_CTX_VOLUME] = { .type = NLA_U32, }, + [DRBD_A_DRBD_CFG_CONTEXT_CTX_RESOURCE_NAME] = { .type = NLA_NUL_STRING, .len = 128, }, + [DRBD_A_DRBD_CFG_CONTEXT_CTX_MY_ADDR] = NLA_POLICY_MAX_LEN(128), + [DRBD_A_DRBD_CFG_CONTEXT_CTX_PEER_ADDR] = NLA_POLICY_MAX_LEN(128), +}; + +const struct nla_policy drbd_net_conf_nl_policy[DRBD_A_NET_CONF_SOCK_CHECK_TIMEO + 1] = { + [DRBD_A_NET_CONF_SHARED_SECRET] = { .type = NLA_NUL_STRING, .len = SHARED_SECRET_MAX, }, + [DRBD_A_NET_CONF_CRAM_HMAC_ALG] = { .type = NLA_NUL_STRING, .len = SHARED_SECRET_MAX, }, + [DRBD_A_NET_CONF_INTEGRITY_ALG] = { .type = NLA_NUL_STRING, .len = SHARED_SECRET_MAX, }, + [DRBD_A_NET_CONF_VERIFY_ALG] = { .type = NLA_NUL_STRING, .len = SHARED_SECRET_MAX, }, + [DRBD_A_NET_CONF_CSUMS_ALG] = { .type = NLA_NUL_STRING, .len = SHARED_SECRET_MAX, }, + [DRBD_A_NET_CONF_WIRE_PROTOCOL] = { .type = NLA_U32, }, + [DRBD_A_NET_CONF_CONNECT_INT] = { .type = NLA_U32, }, + [DRBD_A_NET_CONF_TIMEOUT] = { .type = NLA_U32, }, + [DRBD_A_NET_CONF_PING_INT] = { .type = NLA_U32, }, + [DRBD_A_NET_CONF_PING_TIMEO] = { .type = NLA_U32, }, + [DRBD_A_NET_CONF_SNDBUF_SIZE] = { .type = NLA_U32, }, + [DRBD_A_NET_CONF_RCVBUF_SIZE] = { .type = NLA_U32, }, + [DRBD_A_NET_CONF_KO_COUNT] = { .type = NLA_U32, }, + [DRBD_A_NET_CONF_MAX_BUFFERS] = { .type = NLA_U32, }, + [DRBD_A_NET_CONF_MAX_EPOCH_SIZE] = { .type = NLA_U32, }, + [DRBD_A_NET_CONF_UNPLUG_WATERMARK] = { .type = NLA_U32, }, + [DRBD_A_NET_CONF_AFTER_SB_0P] = { .type = NLA_U32, }, + [DRBD_A_NET_CONF_AFTER_SB_1P] = { .type = NLA_U32, }, + [DRBD_A_NET_CONF_AFTER_SB_2P] = { .type = NLA_U32, }, + [DRBD_A_NET_CONF_RR_CONFLICT] = { .type = NLA_U32, }, + [DRBD_A_NET_CONF_ON_CONGESTION] = { .type = NLA_U32, }, + [DRBD_A_NET_CONF_CONG_FILL] = { .type = NLA_U32, }, + [DRBD_A_NET_CONF_CONG_EXTENTS] = { .type = NLA_U32, }, + [DRBD_A_NET_CONF_TWO_PRIMARIES] = { .type = NLA_U8, }, + [DRBD_A_NET_CONF_DISCARD_MY_DATA] = { .type = NLA_U8, }, + [DRBD_A_NET_CONF_TCP_CORK] = { .type = NLA_U8, }, + [DRBD_A_NET_CONF_ALWAYS_ASBP] = { .type = NLA_U8, }, + [DRBD_A_NET_CONF_TENTATIVE] = { .type = NLA_U8, }, + [DRBD_A_NET_CONF_USE_RLE] = { .type = NLA_U8, }, + [DRBD_A_NET_CONF_CSUMS_AFTER_CRASH_ONLY] = { .type = NLA_U8, }, + [DRBD_A_NET_CONF_SOCK_CHECK_TIMEO] = { .type = NLA_U32, }, +}; + +const struct nla_policy drbd_new_c_uuid_parms_nl_policy[DRBD_A_NEW_C_UUID_PARMS_CLEAR_BM + 1] = { + [DRBD_A_NEW_C_UUID_PARMS_CLEAR_BM] = { .type = NLA_U8, }, +}; + +const struct nla_policy drbd_peer_device_info_nl_policy[DRBD_A_PEER_DEVICE_INFO_PEER_RESYNC_SUSP_DEPENDENCY + 1] = { + [DRBD_A_PEER_DEVICE_INFO_PEER_REPL_STATE] = { .type = NLA_U32, }, + [DRBD_A_PEER_DEVICE_INFO_PEER_DISK_STATE] = { .type = NLA_U32, }, + [DRBD_A_PEER_DEVICE_INFO_PEER_RESYNC_SUSP_USER] = { .type = NLA_U32, }, + [DRBD_A_PEER_DEVICE_INFO_PEER_RESYNC_SUSP_PEER] = { .type = NLA_U32, }, + [DRBD_A_PEER_DEVICE_INFO_PEER_RESYNC_SUSP_DEPENDENCY] = { .type = NLA_U32, }, +}; + +const struct nla_policy drbd_peer_device_statistics_nl_policy[DRBD_A_PEER_DEVICE_STATISTICS_PEER_DEV_FLAGS + 1] = { + [DRBD_A_PEER_DEVICE_STATISTICS_PEER_DEV_RECEIVED] = { .type = NLA_U64, }, + [DRBD_A_PEER_DEVICE_STATISTICS_PEER_DEV_SENT] = { .type = NLA_U64, }, + [DRBD_A_PEER_DEVICE_STATISTICS_PEER_DEV_PENDING] = { .type = NLA_U32, }, + [DRBD_A_PEER_DEVICE_STATISTICS_PEER_DEV_UNACKED] = { .type = NLA_U32, }, + [DRBD_A_PEER_DEVICE_STATISTICS_PEER_DEV_OUT_OF_SYNC] = { .type = NLA_U64, }, + [DRBD_A_PEER_DEVICE_STATISTICS_PEER_DEV_RESYNC_FAILED] = { .type = NLA_U64, }, + [DRBD_A_PEER_DEVICE_STATISTICS_PEER_DEV_BITMAP_UUID] = { .type = NLA_U64, }, + [DRBD_A_PEER_DEVICE_STATISTICS_PEER_DEV_FLAGS] = { .type = NLA_U32, }, +}; + +const struct nla_policy drbd_res_opts_nl_policy[DRBD_A_RES_OPTS_ON_NO_DATA + 1] = { + [DRBD_A_RES_OPTS_CPU_MASK] = { .type = NLA_NUL_STRING, .len = DRBD_CPU_MASK_SIZE, }, + [DRBD_A_RES_OPTS_ON_NO_DATA] = { .type = NLA_U32, }, +}; + +const struct nla_policy drbd_resize_parms_nl_policy[DRBD_A_RESIZE_PARMS_AL_STRIPE_SIZE + 1] = { + [DRBD_A_RESIZE_PARMS_RESIZE_SIZE] = { .type = NLA_U64, }, + [DRBD_A_RESIZE_PARMS_RESIZE_FORCE] = { .type = NLA_U8, }, + [DRBD_A_RESIZE_PARMS_NO_RESYNC] = { .type = NLA_U8, }, + [DRBD_A_RESIZE_PARMS_AL_STRIPES] = { .type = NLA_U32, }, + [DRBD_A_RESIZE_PARMS_AL_STRIPE_SIZE] = { .type = NLA_U32, }, +}; + +const struct nla_policy drbd_resource_info_nl_policy[DRBD_A_RESOURCE_INFO_RES_SUSP_FEN + 1] = { + [DRBD_A_RESOURCE_INFO_RES_ROLE] = { .type = NLA_U32, }, + [DRBD_A_RESOURCE_INFO_RES_SUSP] = { .type = NLA_U8, }, + [DRBD_A_RESOURCE_INFO_RES_SUSP_NOD] = { .type = NLA_U8, }, + [DRBD_A_RESOURCE_INFO_RES_SUSP_FEN] = { .type = NLA_U8, }, +}; + +const struct nla_policy drbd_resource_statistics_nl_policy[DRBD_A_RESOURCE_STATISTICS_RES_STAT_WRITE_ORDERING + 1] = { + [DRBD_A_RESOURCE_STATISTICS_RES_STAT_WRITE_ORDERING] = { .type = NLA_U32, }, +}; + +const struct nla_policy drbd_set_role_parms_nl_policy[DRBD_A_SET_ROLE_PARMS_ASSUME_UPTODATE + 1] = { + [DRBD_A_SET_ROLE_PARMS_ASSUME_UPTODATE] = { .type = NLA_U8, }, +}; + +const struct nla_policy drbd_start_ov_parms_nl_policy[DRBD_A_START_OV_PARMS_OV_STOP_SECTOR + 1] = { + [DRBD_A_START_OV_PARMS_OV_START_SECTOR] = { .type = NLA_U64, }, + [DRBD_A_START_OV_PARMS_OV_STOP_SECTOR] = { .type = NLA_U64, }, +}; + +/* DRBD_ADM_GET_STATUS - do */ +static const struct nla_policy drbd_get_status_do_nl_policy[DRBD_NLA_CFG_CONTEXT + 1] = { + [DRBD_NLA_CFG_CONTEXT] = NLA_POLICY_NESTED(drbd_drbd_cfg_context_nl_policy), +}; + +/* DRBD_ADM_GET_STATUS - dump */ +static const struct nla_policy drbd_get_status_dump_nl_policy[DRBD_NLA_CFG_CONTEXT + 1] = { + [DRBD_NLA_CFG_CONTEXT] = NLA_POLICY_NESTED(drbd_drbd_cfg_context_nl_policy), +}; + +/* DRBD_ADM_NEW_MINOR - do */ +static const struct nla_policy drbd_new_minor_nl_policy[DRBD_NLA_CFG_CONTEXT + 1] = { + [DRBD_NLA_CFG_CONTEXT] = NLA_POLICY_NESTED(drbd_drbd_cfg_context_nl_policy), +}; + +/* DRBD_ADM_DEL_MINOR - do */ +static const struct nla_policy drbd_del_minor_nl_policy[DRBD_NLA_CFG_CONTEXT + 1] = { + [DRBD_NLA_CFG_CONTEXT] = NLA_POLICY_NESTED(drbd_drbd_cfg_context_nl_policy), +}; + +/* DRBD_ADM_NEW_RESOURCE - do */ +static const struct nla_policy drbd_new_resource_nl_policy[DRBD_NLA_RESOURCE_OPTS + 1] = { + [DRBD_NLA_CFG_CONTEXT] = NLA_POLICY_NESTED(drbd_drbd_cfg_context_nl_policy), + [DRBD_NLA_RESOURCE_OPTS] = NLA_POLICY_NESTED(drbd_res_opts_nl_policy), +}; + +/* DRBD_ADM_DEL_RESOURCE - do */ +static const struct nla_policy drbd_del_resource_nl_policy[DRBD_NLA_CFG_CONTEXT + 1] = { + [DRBD_NLA_CFG_CONTEXT] = NLA_POLICY_NESTED(drbd_drbd_cfg_context_nl_policy), +}; + +/* DRBD_ADM_RESOURCE_OPTS - do */ +static const struct nla_policy drbd_resource_opts_nl_policy[DRBD_NLA_RESOURCE_OPTS + 1] = { + [DRBD_NLA_CFG_CONTEXT] = NLA_POLICY_NESTED(drbd_drbd_cfg_context_nl_policy), + [DRBD_NLA_RESOURCE_OPTS] = NLA_POLICY_NESTED(drbd_res_opts_nl_policy), +}; + +/* DRBD_ADM_CONNECT - do */ +static const struct nla_policy drbd_connect_nl_policy[DRBD_NLA_NET_CONF + 1] = { + [DRBD_NLA_CFG_CONTEXT] = NLA_POLICY_NESTED(drbd_drbd_cfg_context_nl_policy), + [DRBD_NLA_NET_CONF] = NLA_POLICY_NESTED(drbd_net_conf_nl_policy), +}; + +/* DRBD_ADM_DISCONNECT - do */ +static const struct nla_policy drbd_disconnect_nl_policy[DRBD_NLA_DISCONNECT_PARMS + 1] = { + [DRBD_NLA_CFG_CONTEXT] = NLA_POLICY_NESTED(drbd_drbd_cfg_context_nl_policy), + [DRBD_NLA_DISCONNECT_PARMS] = NLA_POLICY_NESTED(drbd_disconnect_parms_nl_policy), +}; + +/* DRBD_ADM_ATTACH - do */ +static const struct nla_policy drbd_attach_nl_policy[DRBD_NLA_DISK_CONF + 1] = { + [DRBD_NLA_CFG_CONTEXT] = NLA_POLICY_NESTED(drbd_drbd_cfg_context_nl_policy), + [DRBD_NLA_DISK_CONF] = NLA_POLICY_NESTED(drbd_disk_conf_nl_policy), +}; + +/* DRBD_ADM_RESIZE - do */ +static const struct nla_policy drbd_resize_nl_policy[DRBD_NLA_RESIZE_PARMS + 1] = { + [DRBD_NLA_CFG_CONTEXT] = NLA_POLICY_NESTED(drbd_drbd_cfg_context_nl_policy), + [DRBD_NLA_RESIZE_PARMS] = NLA_POLICY_NESTED(drbd_resize_parms_nl_policy), +}; + +/* DRBD_ADM_PRIMARY - do */ +static const struct nla_policy drbd_primary_nl_policy[DRBD_NLA_SET_ROLE_PARMS + 1] = { + [DRBD_NLA_CFG_CONTEXT] = NLA_POLICY_NESTED(drbd_drbd_cfg_context_nl_policy), + [DRBD_NLA_SET_ROLE_PARMS] = NLA_POLICY_NESTED(drbd_set_role_parms_nl_policy), +}; + +/* DRBD_ADM_SECONDARY - do */ +static const struct nla_policy drbd_secondary_nl_policy[DRBD_NLA_SET_ROLE_PARMS + 1] = { + [DRBD_NLA_CFG_CONTEXT] = NLA_POLICY_NESTED(drbd_drbd_cfg_context_nl_policy), + [DRBD_NLA_SET_ROLE_PARMS] = NLA_POLICY_NESTED(drbd_set_role_parms_nl_policy), +}; + +/* DRBD_ADM_NEW_C_UUID - do */ +static const struct nla_policy drbd_new_c_uuid_nl_policy[DRBD_NLA_NEW_C_UUID_PARMS + 1] = { + [DRBD_NLA_CFG_CONTEXT] = NLA_POLICY_NESTED(drbd_drbd_cfg_context_nl_policy), + [DRBD_NLA_NEW_C_UUID_PARMS] = NLA_POLICY_NESTED(drbd_new_c_uuid_parms_nl_policy), +}; + +/* DRBD_ADM_START_OV - do */ +static const struct nla_policy drbd_start_ov_nl_policy[DRBD_NLA_START_OV_PARMS + 1] = { + [DRBD_NLA_START_OV_PARMS] = NLA_POLICY_NESTED(drbd_start_ov_parms_nl_policy), +}; + +/* DRBD_ADM_DETACH - do */ +static const struct nla_policy drbd_detach_nl_policy[DRBD_NLA_DETACH_PARMS + 1] = { + [DRBD_NLA_CFG_CONTEXT] = NLA_POLICY_NESTED(drbd_drbd_cfg_context_nl_policy), + [DRBD_NLA_DETACH_PARMS] = NLA_POLICY_NESTED(drbd_detach_parms_nl_policy), +}; + +/* DRBD_ADM_INVALIDATE - do */ +static const struct nla_policy drbd_invalidate_nl_policy[DRBD_NLA_CFG_CONTEXT + 1] = { + [DRBD_NLA_CFG_CONTEXT] = NLA_POLICY_NESTED(drbd_drbd_cfg_context_nl_policy), +}; + +/* DRBD_ADM_INVAL_PEER - do */ +static const struct nla_policy drbd_inval_peer_nl_policy[DRBD_NLA_CFG_CONTEXT + 1] = { + [DRBD_NLA_CFG_CONTEXT] = NLA_POLICY_NESTED(drbd_drbd_cfg_context_nl_policy), +}; + +/* DRBD_ADM_PAUSE_SYNC - do */ +static const struct nla_policy drbd_pause_sync_nl_policy[DRBD_NLA_CFG_CONTEXT + 1] = { + [DRBD_NLA_CFG_CONTEXT] = NLA_POLICY_NESTED(drbd_drbd_cfg_context_nl_policy), +}; + +/* DRBD_ADM_RESUME_SYNC - do */ +static const struct nla_policy drbd_resume_sync_nl_policy[DRBD_NLA_CFG_CONTEXT + 1] = { + [DRBD_NLA_CFG_CONTEXT] = NLA_POLICY_NESTED(drbd_drbd_cfg_context_nl_policy), +}; + +/* DRBD_ADM_SUSPEND_IO - do */ +static const struct nla_policy drbd_suspend_io_nl_policy[DRBD_NLA_CFG_CONTEXT + 1] = { + [DRBD_NLA_CFG_CONTEXT] = NLA_POLICY_NESTED(drbd_drbd_cfg_context_nl_policy), +}; + +/* DRBD_ADM_RESUME_IO - do */ +static const struct nla_policy drbd_resume_io_nl_policy[DRBD_NLA_CFG_CONTEXT + 1] = { + [DRBD_NLA_CFG_CONTEXT] = NLA_POLICY_NESTED(drbd_drbd_cfg_context_nl_policy), +}; + +/* DRBD_ADM_OUTDATE - do */ +static const struct nla_policy drbd_outdate_nl_policy[DRBD_NLA_CFG_CONTEXT + 1] = { + [DRBD_NLA_CFG_CONTEXT] = NLA_POLICY_NESTED(drbd_drbd_cfg_context_nl_policy), +}; + +/* DRBD_ADM_GET_TIMEOUT_TYPE - do */ +static const struct nla_policy drbd_get_timeout_type_nl_policy[DRBD_NLA_CFG_CONTEXT + 1] = { + [DRBD_NLA_CFG_CONTEXT] = NLA_POLICY_NESTED(drbd_drbd_cfg_context_nl_policy), +}; + +/* DRBD_ADM_DOWN - do */ +static const struct nla_policy drbd_down_nl_policy[DRBD_NLA_CFG_CONTEXT + 1] = { + [DRBD_NLA_CFG_CONTEXT] = NLA_POLICY_NESTED(drbd_drbd_cfg_context_nl_policy), +}; + +/* DRBD_ADM_CHG_DISK_OPTS - do */ +static const struct nla_policy drbd_chg_disk_opts_nl_policy[DRBD_NLA_DISK_CONF + 1] = { + [DRBD_NLA_CFG_CONTEXT] = NLA_POLICY_NESTED(drbd_drbd_cfg_context_nl_policy), + [DRBD_NLA_DISK_CONF] = NLA_POLICY_NESTED(drbd_disk_conf_nl_policy), +}; + +/* DRBD_ADM_CHG_NET_OPTS - do */ +static const struct nla_policy drbd_chg_net_opts_nl_policy[DRBD_NLA_NET_CONF + 1] = { + [DRBD_NLA_CFG_CONTEXT] = NLA_POLICY_NESTED(drbd_drbd_cfg_context_nl_policy), + [DRBD_NLA_NET_CONF] = NLA_POLICY_NESTED(drbd_net_conf_nl_policy), +}; + +/* DRBD_ADM_GET_RESOURCES - dump */ +static const struct nla_policy drbd_get_resources_nl_policy[DRBD_NLA_RESOURCE_STATISTICS + 1] = { + [DRBD_NLA_CFG_CONTEXT] = NLA_POLICY_NESTED(drbd_drbd_cfg_context_nl_policy), + [DRBD_NLA_RESOURCE_INFO] = NLA_POLICY_NESTED(drbd_resource_info_nl_policy), + [DRBD_NLA_RESOURCE_STATISTICS] = NLA_POLICY_NESTED(drbd_resource_statistics_nl_policy), +}; + +/* DRBD_ADM_GET_DEVICES - dump */ +static const struct nla_policy drbd_get_devices_nl_policy[DRBD_NLA_DEVICE_STATISTICS + 1] = { + [DRBD_NLA_CFG_CONTEXT] = NLA_POLICY_NESTED(drbd_drbd_cfg_context_nl_policy), + [DRBD_NLA_DEVICE_INFO] = NLA_POLICY_NESTED(drbd_device_info_nl_policy), + [DRBD_NLA_DEVICE_STATISTICS] = NLA_POLICY_NESTED(drbd_device_statistics_nl_policy), +}; + +/* DRBD_ADM_GET_CONNECTIONS - dump */ +static const struct nla_policy drbd_get_connections_nl_policy[DRBD_NLA_CONNECTION_STATISTICS + 1] = { + [DRBD_NLA_CFG_CONTEXT] = NLA_POLICY_NESTED(drbd_drbd_cfg_context_nl_policy), + [DRBD_NLA_CONNECTION_INFO] = NLA_POLICY_NESTED(drbd_connection_info_nl_policy), + [DRBD_NLA_CONNECTION_STATISTICS] = NLA_POLICY_NESTED(drbd_connection_statistics_nl_policy), +}; + +/* DRBD_ADM_GET_PEER_DEVICES - dump */ +static const struct nla_policy drbd_get_peer_devices_nl_policy[DRBD_NLA_PEER_DEVICE_STATISTICS + 1] = { + [DRBD_NLA_CFG_CONTEXT] = NLA_POLICY_NESTED(drbd_drbd_cfg_context_nl_policy), + [DRBD_NLA_PEER_DEVICE_INFO] = NLA_POLICY_NESTED(drbd_peer_device_info_nl_policy), + [DRBD_NLA_PEER_DEVICE_STATISTICS] = NLA_POLICY_NESTED(drbd_peer_device_statistics_nl_policy), +}; + +/* DRBD_ADM_GET_INITIAL_STATE - dump */ +static const struct nla_policy drbd_get_initial_state_nl_policy[DRBD_NLA_CFG_CONTEXT + 1] = { + [DRBD_NLA_CFG_CONTEXT] = NLA_POLICY_NESTED(drbd_drbd_cfg_context_nl_policy), +}; + +/* Ops table for drbd */ +const struct genl_split_ops drbd_nl_ops[32] = { + { + .cmd = DRBD_ADM_GET_STATUS, + .pre_doit = drbd_pre_doit, + .doit = drbd_nl_get_status_doit, + .post_doit = drbd_post_doit, + .policy = drbd_get_status_do_nl_policy, + .maxattr = DRBD_NLA_CFG_CONTEXT, + .flags = GENL_CMD_CAP_DO, + }, + { + .cmd = DRBD_ADM_GET_STATUS, + .dumpit = drbd_nl_get_status_dumpit, + .policy = drbd_get_status_dump_nl_policy, + .maxattr = DRBD_NLA_CFG_CONTEXT, + .flags = GENL_CMD_CAP_DUMP, + }, + { + .cmd = DRBD_ADM_NEW_MINOR, + .pre_doit = drbd_pre_doit, + .doit = drbd_nl_new_minor_doit, + .post_doit = drbd_post_doit, + .policy = drbd_new_minor_nl_policy, + .maxattr = DRBD_NLA_CFG_CONTEXT, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DRBD_ADM_DEL_MINOR, + .pre_doit = drbd_pre_doit, + .doit = drbd_nl_del_minor_doit, + .post_doit = drbd_post_doit, + .policy = drbd_del_minor_nl_policy, + .maxattr = DRBD_NLA_CFG_CONTEXT, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DRBD_ADM_NEW_RESOURCE, + .pre_doit = drbd_pre_doit, + .doit = drbd_nl_new_resource_doit, + .post_doit = drbd_post_doit, + .policy = drbd_new_resource_nl_policy, + .maxattr = DRBD_NLA_RESOURCE_OPTS, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DRBD_ADM_DEL_RESOURCE, + .pre_doit = drbd_pre_doit, + .doit = drbd_nl_del_resource_doit, + .post_doit = drbd_post_doit, + .policy = drbd_del_resource_nl_policy, + .maxattr = DRBD_NLA_CFG_CONTEXT, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DRBD_ADM_RESOURCE_OPTS, + .pre_doit = drbd_pre_doit, + .doit = drbd_nl_resource_opts_doit, + .post_doit = drbd_post_doit, + .policy = drbd_resource_opts_nl_policy, + .maxattr = DRBD_NLA_RESOURCE_OPTS, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DRBD_ADM_CONNECT, + .pre_doit = drbd_pre_doit, + .doit = drbd_nl_connect_doit, + .post_doit = drbd_post_doit, + .policy = drbd_connect_nl_policy, + .maxattr = DRBD_NLA_NET_CONF, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DRBD_ADM_DISCONNECT, + .pre_doit = drbd_pre_doit, + .doit = drbd_nl_disconnect_doit, + .post_doit = drbd_post_doit, + .policy = drbd_disconnect_nl_policy, + .maxattr = DRBD_NLA_DISCONNECT_PARMS, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DRBD_ADM_ATTACH, + .pre_doit = drbd_pre_doit, + .doit = drbd_nl_attach_doit, + .post_doit = drbd_post_doit, + .policy = drbd_attach_nl_policy, + .maxattr = DRBD_NLA_DISK_CONF, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DRBD_ADM_RESIZE, + .pre_doit = drbd_pre_doit, + .doit = drbd_nl_resize_doit, + .post_doit = drbd_post_doit, + .policy = drbd_resize_nl_policy, + .maxattr = DRBD_NLA_RESIZE_PARMS, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DRBD_ADM_PRIMARY, + .pre_doit = drbd_pre_doit, + .doit = drbd_nl_primary_doit, + .post_doit = drbd_post_doit, + .policy = drbd_primary_nl_policy, + .maxattr = DRBD_NLA_SET_ROLE_PARMS, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DRBD_ADM_SECONDARY, + .pre_doit = drbd_pre_doit, + .doit = drbd_nl_secondary_doit, + .post_doit = drbd_post_doit, + .policy = drbd_secondary_nl_policy, + .maxattr = DRBD_NLA_SET_ROLE_PARMS, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DRBD_ADM_NEW_C_UUID, + .pre_doit = drbd_pre_doit, + .doit = drbd_nl_new_c_uuid_doit, + .post_doit = drbd_post_doit, + .policy = drbd_new_c_uuid_nl_policy, + .maxattr = DRBD_NLA_NEW_C_UUID_PARMS, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DRBD_ADM_START_OV, + .pre_doit = drbd_pre_doit, + .doit = drbd_nl_start_ov_doit, + .post_doit = drbd_post_doit, + .policy = drbd_start_ov_nl_policy, + .maxattr = DRBD_NLA_START_OV_PARMS, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DRBD_ADM_DETACH, + .pre_doit = drbd_pre_doit, + .doit = drbd_nl_detach_doit, + .post_doit = drbd_post_doit, + .policy = drbd_detach_nl_policy, + .maxattr = DRBD_NLA_DETACH_PARMS, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DRBD_ADM_INVALIDATE, + .pre_doit = drbd_pre_doit, + .doit = drbd_nl_invalidate_doit, + .post_doit = drbd_post_doit, + .policy = drbd_invalidate_nl_policy, + .maxattr = DRBD_NLA_CFG_CONTEXT, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DRBD_ADM_INVAL_PEER, + .pre_doit = drbd_pre_doit, + .doit = drbd_nl_inval_peer_doit, + .post_doit = drbd_post_doit, + .policy = drbd_inval_peer_nl_policy, + .maxattr = DRBD_NLA_CFG_CONTEXT, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DRBD_ADM_PAUSE_SYNC, + .pre_doit = drbd_pre_doit, + .doit = drbd_nl_pause_sync_doit, + .post_doit = drbd_post_doit, + .policy = drbd_pause_sync_nl_policy, + .maxattr = DRBD_NLA_CFG_CONTEXT, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DRBD_ADM_RESUME_SYNC, + .pre_doit = drbd_pre_doit, + .doit = drbd_nl_resume_sync_doit, + .post_doit = drbd_post_doit, + .policy = drbd_resume_sync_nl_policy, + .maxattr = DRBD_NLA_CFG_CONTEXT, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DRBD_ADM_SUSPEND_IO, + .pre_doit = drbd_pre_doit, + .doit = drbd_nl_suspend_io_doit, + .post_doit = drbd_post_doit, + .policy = drbd_suspend_io_nl_policy, + .maxattr = DRBD_NLA_CFG_CONTEXT, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DRBD_ADM_RESUME_IO, + .pre_doit = drbd_pre_doit, + .doit = drbd_nl_resume_io_doit, + .post_doit = drbd_post_doit, + .policy = drbd_resume_io_nl_policy, + .maxattr = DRBD_NLA_CFG_CONTEXT, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DRBD_ADM_OUTDATE, + .pre_doit = drbd_pre_doit, + .doit = drbd_nl_outdate_doit, + .post_doit = drbd_post_doit, + .policy = drbd_outdate_nl_policy, + .maxattr = DRBD_NLA_CFG_CONTEXT, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DRBD_ADM_GET_TIMEOUT_TYPE, + .pre_doit = drbd_pre_doit, + .doit = drbd_nl_get_timeout_type_doit, + .post_doit = drbd_post_doit, + .policy = drbd_get_timeout_type_nl_policy, + .maxattr = DRBD_NLA_CFG_CONTEXT, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DRBD_ADM_DOWN, + .pre_doit = drbd_pre_doit, + .doit = drbd_nl_down_doit, + .post_doit = drbd_post_doit, + .policy = drbd_down_nl_policy, + .maxattr = DRBD_NLA_CFG_CONTEXT, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DRBD_ADM_CHG_DISK_OPTS, + .pre_doit = drbd_pre_doit, + .doit = drbd_nl_chg_disk_opts_doit, + .post_doit = drbd_post_doit, + .policy = drbd_chg_disk_opts_nl_policy, + .maxattr = DRBD_NLA_DISK_CONF, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DRBD_ADM_CHG_NET_OPTS, + .pre_doit = drbd_pre_doit, + .doit = drbd_nl_chg_net_opts_doit, + .post_doit = drbd_post_doit, + .policy = drbd_chg_net_opts_nl_policy, + .maxattr = DRBD_NLA_NET_CONF, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DRBD_ADM_GET_RESOURCES, + .dumpit = drbd_nl_get_resources_dumpit, + .policy = drbd_get_resources_nl_policy, + .maxattr = DRBD_NLA_RESOURCE_STATISTICS, + .flags = GENL_CMD_CAP_DUMP, + }, + { + .cmd = DRBD_ADM_GET_DEVICES, + .dumpit = drbd_nl_get_devices_dumpit, + .done = drbd_adm_dump_devices_done, + .policy = drbd_get_devices_nl_policy, + .maxattr = DRBD_NLA_DEVICE_STATISTICS, + .flags = GENL_CMD_CAP_DUMP, + }, + { + .cmd = DRBD_ADM_GET_CONNECTIONS, + .dumpit = drbd_nl_get_connections_dumpit, + .done = drbd_adm_dump_connections_done, + .policy = drbd_get_connections_nl_policy, + .maxattr = DRBD_NLA_CONNECTION_STATISTICS, + .flags = GENL_CMD_CAP_DUMP, + }, + { + .cmd = DRBD_ADM_GET_PEER_DEVICES, + .dumpit = drbd_nl_get_peer_devices_dumpit, + .done = drbd_adm_dump_peer_devices_done, + .policy = drbd_get_peer_devices_nl_policy, + .maxattr = DRBD_NLA_PEER_DEVICE_STATISTICS, + .flags = GENL_CMD_CAP_DUMP, + }, + { + .cmd = DRBD_ADM_GET_INITIAL_STATE, + .dumpit = drbd_nl_get_initial_state_dumpit, + .policy = drbd_get_initial_state_nl_policy, + .maxattr = DRBD_NLA_CFG_CONTEXT, + .flags = GENL_CMD_CAP_DUMP, + }, +}; + +static const struct genl_multicast_group drbd_nl_mcgrps[] = { + [DRBD_NLGRP_EVENTS] = { "events", }, +}; + +static int __drbd_cfg_context_from_attrs(struct drbd_cfg_context *s, + struct nlattr ***ret_nested_attribute_table, + struct genl_info *info) +{ + const int maxtype = DRBD_A_DRBD_CFG_CONTEXT_CTX_PEER_ADDR; + struct nlattr *tla = info->attrs[DRBD_NLA_CFG_CONTEXT]; + struct nlattr **ntb; + struct nlattr *nla; + int err = 0; + + if (ret_nested_attribute_table) + *ret_nested_attribute_table = NULL; + if (!tla) + return -ENOMSG; + ntb = kcalloc(DRBD_A_DRBD_CFG_CONTEXT_CTX_PEER_ADDR + 1, sizeof(*ntb), GFP_KERNEL); + if (!ntb) + return -ENOMEM; + err = nla_parse_nested_deprecated(ntb, maxtype, tla, drbd_drbd_cfg_context_nl_policy, NULL); + if (err) + goto out; + + nla = ntb[DRBD_A_DRBD_CFG_CONTEXT_CTX_VOLUME]; + if (nla && s) + s->ctx_volume = nla_get_u32(nla); + + nla = ntb[DRBD_A_DRBD_CFG_CONTEXT_CTX_RESOURCE_NAME]; + if (nla && s) + s->ctx_resource_name_len = nla_strscpy(s->ctx_resource_name, nla, 128); + + nla = ntb[DRBD_A_DRBD_CFG_CONTEXT_CTX_MY_ADDR]; + if (nla && s) + s->ctx_my_addr_len = nla_memcpy(s->ctx_my_addr, nla, 128); + + nla = ntb[DRBD_A_DRBD_CFG_CONTEXT_CTX_PEER_ADDR]; + if (nla && s) + s->ctx_peer_addr_len = nla_memcpy(s->ctx_peer_addr, nla, 128); + +out: + if (ret_nested_attribute_table && (!err || err == -ENOMSG)) + *ret_nested_attribute_table = ntb; + else + kfree(ntb); + return err; +} + +int drbd_cfg_context_from_attrs(struct drbd_cfg_context *s, + struct genl_info *info) +{ + return __drbd_cfg_context_from_attrs(s, NULL, info); +} + +int drbd_cfg_context_ntb_from_attrs( + struct nlattr ***ret_nested_attribute_table, + struct genl_info *info) +{ + return __drbd_cfg_context_from_attrs(NULL, ret_nested_attribute_table, info); +} + +static int __disk_conf_from_attrs(struct disk_conf *s, + struct nlattr ***ret_nested_attribute_table, + struct genl_info *info) +{ + const int maxtype = DRBD_A_DISK_CONF_DISABLE_WRITE_SAME; + struct nlattr *tla = info->attrs[DRBD_NLA_DISK_CONF]; + struct nlattr **ntb; + struct nlattr *nla; + int err = 0; + + if (ret_nested_attribute_table) + *ret_nested_attribute_table = NULL; + if (!tla) + return -ENOMSG; + ntb = kcalloc(DRBD_A_DISK_CONF_DISABLE_WRITE_SAME + 1, sizeof(*ntb), GFP_KERNEL); + if (!ntb) + return -ENOMEM; + err = nla_parse_nested_deprecated(ntb, maxtype, tla, drbd_disk_conf_nl_policy, NULL); + if (err) + goto out; + + nla = ntb[DRBD_A_DISK_CONF_BACKING_DEV]; + if (nla) { + if (s) + s->backing_dev_len = nla_strscpy(s->backing_dev, nla, 128); + } else { + pr_info("<< missing required attr: backing_dev\n"); + err = -ENOMSG; + } + + nla = ntb[DRBD_A_DISK_CONF_META_DEV]; + if (nla) { + if (s) + s->meta_dev_len = nla_strscpy(s->meta_dev, nla, 128); + } else { + pr_info("<< missing required attr: meta_dev\n"); + err = -ENOMSG; + } + + nla = ntb[DRBD_A_DISK_CONF_META_DEV_IDX]; + if (nla) { + if (s) + s->meta_dev_idx = nla_get_s32(nla); + } else { + pr_info("<< missing required attr: meta_dev_idx\n"); + err = -ENOMSG; + } + + nla = ntb[DRBD_A_DISK_CONF_DISK_SIZE]; + if (nla && s) + s->disk_size = nla_get_u64(nla); + + nla = ntb[DRBD_A_DISK_CONF_MAX_BIO_BVECS]; + if (nla && s) + s->max_bio_bvecs = nla_get_u32(nla); + + nla = ntb[DRBD_A_DISK_CONF_ON_IO_ERROR]; + if (nla && s) + s->on_io_error = nla_get_u32(nla); + + nla = ntb[DRBD_A_DISK_CONF_FENCING]; + if (nla && s) + s->fencing = nla_get_u32(nla); + + nla = ntb[DRBD_A_DISK_CONF_RESYNC_RATE]; + if (nla && s) + s->resync_rate = nla_get_u32(nla); + + nla = ntb[DRBD_A_DISK_CONF_RESYNC_AFTER]; + if (nla && s) + s->resync_after = nla_get_s32(nla); + + nla = ntb[DRBD_A_DISK_CONF_AL_EXTENTS]; + if (nla && s) + s->al_extents = nla_get_u32(nla); + + nla = ntb[DRBD_A_DISK_CONF_C_PLAN_AHEAD]; + if (nla && s) + s->c_plan_ahead = nla_get_u32(nla); + + nla = ntb[DRBD_A_DISK_CONF_C_DELAY_TARGET]; + if (nla && s) + s->c_delay_target = nla_get_u32(nla); + + nla = ntb[DRBD_A_DISK_CONF_C_FILL_TARGET]; + if (nla && s) + s->c_fill_target = nla_get_u32(nla); + + nla = ntb[DRBD_A_DISK_CONF_C_MAX_RATE]; + if (nla && s) + s->c_max_rate = nla_get_u32(nla); + + nla = ntb[DRBD_A_DISK_CONF_C_MIN_RATE]; + if (nla && s) + s->c_min_rate = nla_get_u32(nla); + + nla = ntb[DRBD_A_DISK_CONF_DISK_BARRIER]; + if (nla && s) + s->disk_barrier = nla_get_u8(nla); + + nla = ntb[DRBD_A_DISK_CONF_DISK_FLUSHES]; + if (nla && s) + s->disk_flushes = nla_get_u8(nla); + + nla = ntb[DRBD_A_DISK_CONF_DISK_DRAIN]; + if (nla && s) + s->disk_drain = nla_get_u8(nla); + + nla = ntb[DRBD_A_DISK_CONF_MD_FLUSHES]; + if (nla && s) + s->md_flushes = nla_get_u8(nla); + + nla = ntb[DRBD_A_DISK_CONF_DISK_TIMEOUT]; + if (nla && s) + s->disk_timeout = nla_get_u32(nla); + + nla = ntb[DRBD_A_DISK_CONF_READ_BALANCING]; + if (nla && s) + s->read_balancing = nla_get_u32(nla); + + nla = ntb[DRBD_A_DISK_CONF_AL_UPDATES]; + if (nla && s) + s->al_updates = nla_get_u8(nla); + + nla = ntb[DRBD_A_DISK_CONF_DISCARD_ZEROES_IF_ALIGNED]; + if (nla && s) + s->discard_zeroes_if_aligned = nla_get_u8(nla); + + nla = ntb[DRBD_A_DISK_CONF_RS_DISCARD_GRANULARITY]; + if (nla && s) + s->rs_discard_granularity = nla_get_u32(nla); + + nla = ntb[DRBD_A_DISK_CONF_DISABLE_WRITE_SAME]; + if (nla && s) + s->disable_write_same = nla_get_u8(nla); + +out: + if (ret_nested_attribute_table && (!err || err == -ENOMSG)) + *ret_nested_attribute_table = ntb; + else + kfree(ntb); + return err; +} + +int disk_conf_from_attrs(struct disk_conf *s, + struct genl_info *info) +{ + return __disk_conf_from_attrs(s, NULL, info); +} + +int disk_conf_ntb_from_attrs( + struct nlattr ***ret_nested_attribute_table, + struct genl_info *info) +{ + return __disk_conf_from_attrs(NULL, ret_nested_attribute_table, info); +} + +static int __res_opts_from_attrs(struct res_opts *s, + struct nlattr ***ret_nested_attribute_table, + struct genl_info *info) +{ + const int maxtype = DRBD_A_RES_OPTS_ON_NO_DATA; + struct nlattr *tla = info->attrs[DRBD_NLA_RESOURCE_OPTS]; + struct nlattr **ntb; + struct nlattr *nla; + int err = 0; + + if (ret_nested_attribute_table) + *ret_nested_attribute_table = NULL; + if (!tla) + return -ENOMSG; + ntb = kcalloc(DRBD_A_RES_OPTS_ON_NO_DATA + 1, sizeof(*ntb), GFP_KERNEL); + if (!ntb) + return -ENOMEM; + err = nla_parse_nested_deprecated(ntb, maxtype, tla, drbd_res_opts_nl_policy, NULL); + if (err) + goto out; + + nla = ntb[DRBD_A_RES_OPTS_CPU_MASK]; + if (nla && s) + s->cpu_mask_len = nla_strscpy(s->cpu_mask, nla, DRBD_CPU_MASK_SIZE); + + nla = ntb[DRBD_A_RES_OPTS_ON_NO_DATA]; + if (nla && s) + s->on_no_data = nla_get_u32(nla); + +out: + if (ret_nested_attribute_table && (!err || err == -ENOMSG)) + *ret_nested_attribute_table = ntb; + else + kfree(ntb); + return err; +} + +int res_opts_from_attrs(struct res_opts *s, + struct genl_info *info) +{ + return __res_opts_from_attrs(s, NULL, info); +} + +int res_opts_ntb_from_attrs( + struct nlattr ***ret_nested_attribute_table, + struct genl_info *info) +{ + return __res_opts_from_attrs(NULL, ret_nested_attribute_table, info); +} + +static int __net_conf_from_attrs(struct net_conf *s, + struct nlattr ***ret_nested_attribute_table, + struct genl_info *info) +{ + const int maxtype = DRBD_A_NET_CONF_SOCK_CHECK_TIMEO; + struct nlattr *tla = info->attrs[DRBD_NLA_NET_CONF]; + struct nlattr **ntb; + struct nlattr *nla; + int err = 0; + + if (ret_nested_attribute_table) + *ret_nested_attribute_table = NULL; + if (!tla) + return -ENOMSG; + ntb = kcalloc(DRBD_A_NET_CONF_SOCK_CHECK_TIMEO + 1, sizeof(*ntb), GFP_KERNEL); + if (!ntb) + return -ENOMEM; + err = nla_parse_nested_deprecated(ntb, maxtype, tla, drbd_net_conf_nl_policy, NULL); + if (err) + goto out; + + nla = ntb[DRBD_A_NET_CONF_SHARED_SECRET]; + if (nla && s) + s->shared_secret_len = nla_strscpy(s->shared_secret, nla, SHARED_SECRET_MAX); + + nla = ntb[DRBD_A_NET_CONF_CRAM_HMAC_ALG]; + if (nla && s) + s->cram_hmac_alg_len = nla_strscpy(s->cram_hmac_alg, nla, SHARED_SECRET_MAX); + + nla = ntb[DRBD_A_NET_CONF_INTEGRITY_ALG]; + if (nla && s) + s->integrity_alg_len = nla_strscpy(s->integrity_alg, nla, SHARED_SECRET_MAX); + + nla = ntb[DRBD_A_NET_CONF_VERIFY_ALG]; + if (nla && s) + s->verify_alg_len = nla_strscpy(s->verify_alg, nla, SHARED_SECRET_MAX); + + nla = ntb[DRBD_A_NET_CONF_CSUMS_ALG]; + if (nla && s) + s->csums_alg_len = nla_strscpy(s->csums_alg, nla, SHARED_SECRET_MAX); + + nla = ntb[DRBD_A_NET_CONF_WIRE_PROTOCOL]; + if (nla && s) + s->wire_protocol = nla_get_u32(nla); + + nla = ntb[DRBD_A_NET_CONF_CONNECT_INT]; + if (nla && s) + s->connect_int = nla_get_u32(nla); + + nla = ntb[DRBD_A_NET_CONF_TIMEOUT]; + if (nla && s) + s->timeout = nla_get_u32(nla); + + nla = ntb[DRBD_A_NET_CONF_PING_INT]; + if (nla && s) + s->ping_int = nla_get_u32(nla); + + nla = ntb[DRBD_A_NET_CONF_PING_TIMEO]; + if (nla && s) + s->ping_timeo = nla_get_u32(nla); + + nla = ntb[DRBD_A_NET_CONF_SNDBUF_SIZE]; + if (nla && s) + s->sndbuf_size = nla_get_u32(nla); + + nla = ntb[DRBD_A_NET_CONF_RCVBUF_SIZE]; + if (nla && s) + s->rcvbuf_size = nla_get_u32(nla); + + nla = ntb[DRBD_A_NET_CONF_KO_COUNT]; + if (nla && s) + s->ko_count = nla_get_u32(nla); + + nla = ntb[DRBD_A_NET_CONF_MAX_BUFFERS]; + if (nla && s) + s->max_buffers = nla_get_u32(nla); + + nla = ntb[DRBD_A_NET_CONF_MAX_EPOCH_SIZE]; + if (nla && s) + s->max_epoch_size = nla_get_u32(nla); + + nla = ntb[DRBD_A_NET_CONF_UNPLUG_WATERMARK]; + if (nla && s) + s->unplug_watermark = nla_get_u32(nla); + + nla = ntb[DRBD_A_NET_CONF_AFTER_SB_0P]; + if (nla && s) + s->after_sb_0p = nla_get_u32(nla); + + nla = ntb[DRBD_A_NET_CONF_AFTER_SB_1P]; + if (nla && s) + s->after_sb_1p = nla_get_u32(nla); + + nla = ntb[DRBD_A_NET_CONF_AFTER_SB_2P]; + if (nla && s) + s->after_sb_2p = nla_get_u32(nla); + + nla = ntb[DRBD_A_NET_CONF_RR_CONFLICT]; + if (nla && s) + s->rr_conflict = nla_get_u32(nla); + + nla = ntb[DRBD_A_NET_CONF_ON_CONGESTION]; + if (nla && s) + s->on_congestion = nla_get_u32(nla); + + nla = ntb[DRBD_A_NET_CONF_CONG_FILL]; + if (nla && s) + s->cong_fill = nla_get_u32(nla); + + nla = ntb[DRBD_A_NET_CONF_CONG_EXTENTS]; + if (nla && s) + s->cong_extents = nla_get_u32(nla); + + nla = ntb[DRBD_A_NET_CONF_TWO_PRIMARIES]; + if (nla && s) + s->two_primaries = nla_get_u8(nla); + + nla = ntb[DRBD_A_NET_CONF_DISCARD_MY_DATA]; + if (nla && s) + s->discard_my_data = nla_get_u8(nla); + + nla = ntb[DRBD_A_NET_CONF_TCP_CORK]; + if (nla && s) + s->tcp_cork = nla_get_u8(nla); + + nla = ntb[DRBD_A_NET_CONF_ALWAYS_ASBP]; + if (nla && s) + s->always_asbp = nla_get_u8(nla); + + nla = ntb[DRBD_A_NET_CONF_TENTATIVE]; + if (nla && s) + s->tentative = nla_get_u8(nla); + + nla = ntb[DRBD_A_NET_CONF_USE_RLE]; + if (nla && s) + s->use_rle = nla_get_u8(nla); + + nla = ntb[DRBD_A_NET_CONF_CSUMS_AFTER_CRASH_ONLY]; + if (nla && s) + s->csums_after_crash_only = nla_get_u8(nla); + + nla = ntb[DRBD_A_NET_CONF_SOCK_CHECK_TIMEO]; + if (nla && s) + s->sock_check_timeo = nla_get_u32(nla); + +out: + if (ret_nested_attribute_table && (!err || err == -ENOMSG)) + *ret_nested_attribute_table = ntb; + else + kfree(ntb); + return err; +} + +int net_conf_from_attrs(struct net_conf *s, + struct genl_info *info) +{ + return __net_conf_from_attrs(s, NULL, info); +} + +int net_conf_ntb_from_attrs( + struct nlattr ***ret_nested_attribute_table, + struct genl_info *info) +{ + return __net_conf_from_attrs(NULL, ret_nested_attribute_table, info); +} + +static int __set_role_parms_from_attrs(struct set_role_parms *s, + struct nlattr ***ret_nested_attribute_table, + struct genl_info *info) +{ + const int maxtype = DRBD_A_SET_ROLE_PARMS_ASSUME_UPTODATE; + struct nlattr *tla = info->attrs[DRBD_NLA_SET_ROLE_PARMS]; + struct nlattr **ntb; + struct nlattr *nla; + int err = 0; + + if (ret_nested_attribute_table) + *ret_nested_attribute_table = NULL; + if (!tla) + return -ENOMSG; + ntb = kcalloc(DRBD_A_SET_ROLE_PARMS_ASSUME_UPTODATE + 1, sizeof(*ntb), GFP_KERNEL); + if (!ntb) + return -ENOMEM; + err = nla_parse_nested_deprecated(ntb, maxtype, tla, drbd_set_role_parms_nl_policy, NULL); + if (err) + goto out; + + nla = ntb[DRBD_A_SET_ROLE_PARMS_ASSUME_UPTODATE]; + if (nla && s) + s->assume_uptodate = nla_get_u8(nla); + +out: + if (ret_nested_attribute_table && (!err || err == -ENOMSG)) + *ret_nested_attribute_table = ntb; + else + kfree(ntb); + return err; +} + +int set_role_parms_from_attrs(struct set_role_parms *s, + struct genl_info *info) +{ + return __set_role_parms_from_attrs(s, NULL, info); +} + +int set_role_parms_ntb_from_attrs( + struct nlattr ***ret_nested_attribute_table, + struct genl_info *info) +{ + return __set_role_parms_from_attrs(NULL, ret_nested_attribute_table, info); +} + +static int __resize_parms_from_attrs(struct resize_parms *s, + struct nlattr ***ret_nested_attribute_table, + struct genl_info *info) +{ + const int maxtype = DRBD_A_RESIZE_PARMS_AL_STRIPE_SIZE; + struct nlattr *tla = info->attrs[DRBD_NLA_RESIZE_PARMS]; + struct nlattr **ntb; + struct nlattr *nla; + int err = 0; + + if (ret_nested_attribute_table) + *ret_nested_attribute_table = NULL; + if (!tla) + return -ENOMSG; + ntb = kcalloc(DRBD_A_RESIZE_PARMS_AL_STRIPE_SIZE + 1, sizeof(*ntb), GFP_KERNEL); + if (!ntb) + return -ENOMEM; + err = nla_parse_nested_deprecated(ntb, maxtype, tla, drbd_resize_parms_nl_policy, NULL); + if (err) + goto out; + + nla = ntb[DRBD_A_RESIZE_PARMS_RESIZE_SIZE]; + if (nla && s) + s->resize_size = nla_get_u64(nla); + + nla = ntb[DRBD_A_RESIZE_PARMS_RESIZE_FORCE]; + if (nla && s) + s->resize_force = nla_get_u8(nla); + + nla = ntb[DRBD_A_RESIZE_PARMS_NO_RESYNC]; + if (nla && s) + s->no_resync = nla_get_u8(nla); + + nla = ntb[DRBD_A_RESIZE_PARMS_AL_STRIPES]; + if (nla && s) + s->al_stripes = nla_get_u32(nla); + + nla = ntb[DRBD_A_RESIZE_PARMS_AL_STRIPE_SIZE]; + if (nla && s) + s->al_stripe_size = nla_get_u32(nla); + +out: + if (ret_nested_attribute_table && (!err || err == -ENOMSG)) + *ret_nested_attribute_table = ntb; + else + kfree(ntb); + return err; +} + +int resize_parms_from_attrs(struct resize_parms *s, + struct genl_info *info) +{ + return __resize_parms_from_attrs(s, NULL, info); +} + +int resize_parms_ntb_from_attrs( + struct nlattr ***ret_nested_attribute_table, + struct genl_info *info) +{ + return __resize_parms_from_attrs(NULL, ret_nested_attribute_table, info); +} + +static int __start_ov_parms_from_attrs(struct start_ov_parms *s, + struct nlattr ***ret_nested_attribute_table, + struct genl_info *info) +{ + const int maxtype = DRBD_A_START_OV_PARMS_OV_STOP_SECTOR; + struct nlattr *tla = info->attrs[DRBD_NLA_START_OV_PARMS]; + struct nlattr **ntb; + struct nlattr *nla; + int err = 0; + + if (ret_nested_attribute_table) + *ret_nested_attribute_table = NULL; + if (!tla) + return -ENOMSG; + ntb = kcalloc(DRBD_A_START_OV_PARMS_OV_STOP_SECTOR + 1, sizeof(*ntb), GFP_KERNEL); + if (!ntb) + return -ENOMEM; + err = nla_parse_nested_deprecated(ntb, maxtype, tla, drbd_start_ov_parms_nl_policy, NULL); + if (err) + goto out; + + nla = ntb[DRBD_A_START_OV_PARMS_OV_START_SECTOR]; + if (nla && s) + s->ov_start_sector = nla_get_u64(nla); + + nla = ntb[DRBD_A_START_OV_PARMS_OV_STOP_SECTOR]; + if (nla && s) + s->ov_stop_sector = nla_get_u64(nla); + +out: + if (ret_nested_attribute_table && (!err || err == -ENOMSG)) + *ret_nested_attribute_table = ntb; + else + kfree(ntb); + return err; +} + +int start_ov_parms_from_attrs(struct start_ov_parms *s, + struct genl_info *info) +{ + return __start_ov_parms_from_attrs(s, NULL, info); +} + +int start_ov_parms_ntb_from_attrs( + struct nlattr ***ret_nested_attribute_table, + struct genl_info *info) +{ + return __start_ov_parms_from_attrs(NULL, ret_nested_attribute_table, info); +} + +static int __new_c_uuid_parms_from_attrs(struct new_c_uuid_parms *s, + struct nlattr ***ret_nested_attribute_table, + struct genl_info *info) +{ + const int maxtype = DRBD_A_NEW_C_UUID_PARMS_CLEAR_BM; + struct nlattr *tla = info->attrs[DRBD_NLA_NEW_C_UUID_PARMS]; + struct nlattr **ntb; + struct nlattr *nla; + int err = 0; + + if (ret_nested_attribute_table) + *ret_nested_attribute_table = NULL; + if (!tla) + return -ENOMSG; + ntb = kcalloc(DRBD_A_NEW_C_UUID_PARMS_CLEAR_BM + 1, sizeof(*ntb), GFP_KERNEL); + if (!ntb) + return -ENOMEM; + err = nla_parse_nested_deprecated(ntb, maxtype, tla, drbd_new_c_uuid_parms_nl_policy, NULL); + if (err) + goto out; + + nla = ntb[DRBD_A_NEW_C_UUID_PARMS_CLEAR_BM]; + if (nla && s) + s->clear_bm = nla_get_u8(nla); + +out: + if (ret_nested_attribute_table && (!err || err == -ENOMSG)) + *ret_nested_attribute_table = ntb; + else + kfree(ntb); + return err; +} + +int new_c_uuid_parms_from_attrs(struct new_c_uuid_parms *s, + struct genl_info *info) +{ + return __new_c_uuid_parms_from_attrs(s, NULL, info); +} + +int new_c_uuid_parms_ntb_from_attrs( + struct nlattr ***ret_nested_attribute_table, + struct genl_info *info) +{ + return __new_c_uuid_parms_from_attrs(NULL, ret_nested_attribute_table, info); +} + +static int __disconnect_parms_from_attrs(struct disconnect_parms *s, + struct nlattr ***ret_nested_attribute_table, + struct genl_info *info) +{ + const int maxtype = DRBD_A_DISCONNECT_PARMS_FORCE_DISCONNECT; + struct nlattr *tla = info->attrs[DRBD_NLA_DISCONNECT_PARMS]; + struct nlattr **ntb; + struct nlattr *nla; + int err = 0; + + if (ret_nested_attribute_table) + *ret_nested_attribute_table = NULL; + if (!tla) + return -ENOMSG; + ntb = kcalloc(DRBD_A_DISCONNECT_PARMS_FORCE_DISCONNECT + 1, sizeof(*ntb), GFP_KERNEL); + if (!ntb) + return -ENOMEM; + err = nla_parse_nested_deprecated(ntb, maxtype, tla, drbd_disconnect_parms_nl_policy, NULL); + if (err) + goto out; + + nla = ntb[DRBD_A_DISCONNECT_PARMS_FORCE_DISCONNECT]; + if (nla && s) + s->force_disconnect = nla_get_u8(nla); + +out: + if (ret_nested_attribute_table && (!err || err == -ENOMSG)) + *ret_nested_attribute_table = ntb; + else + kfree(ntb); + return err; +} + +int disconnect_parms_from_attrs(struct disconnect_parms *s, + struct genl_info *info) +{ + return __disconnect_parms_from_attrs(s, NULL, info); +} + +int disconnect_parms_ntb_from_attrs( + struct nlattr ***ret_nested_attribute_table, + struct genl_info *info) +{ + return __disconnect_parms_from_attrs(NULL, ret_nested_attribute_table, info); +} + +static int __detach_parms_from_attrs(struct detach_parms *s, + struct nlattr ***ret_nested_attribute_table, + struct genl_info *info) +{ + const int maxtype = DRBD_A_DETACH_PARMS_FORCE_DETACH; + struct nlattr *tla = info->attrs[DRBD_NLA_DETACH_PARMS]; + struct nlattr **ntb; + struct nlattr *nla; + int err = 0; + + if (ret_nested_attribute_table) + *ret_nested_attribute_table = NULL; + if (!tla) + return -ENOMSG; + ntb = kcalloc(DRBD_A_DETACH_PARMS_FORCE_DETACH + 1, sizeof(*ntb), GFP_KERNEL); + if (!ntb) + return -ENOMEM; + err = nla_parse_nested_deprecated(ntb, maxtype, tla, drbd_detach_parms_nl_policy, NULL); + if (err) + goto out; + + nla = ntb[DRBD_A_DETACH_PARMS_FORCE_DETACH]; + if (nla && s) + s->force_detach = nla_get_u8(nla); + +out: + if (ret_nested_attribute_table && (!err || err == -ENOMSG)) + *ret_nested_attribute_table = ntb; + else + kfree(ntb); + return err; +} + +int detach_parms_from_attrs(struct detach_parms *s, + struct genl_info *info) +{ + return __detach_parms_from_attrs(s, NULL, info); +} + +int detach_parms_ntb_from_attrs( + struct nlattr ***ret_nested_attribute_table, + struct genl_info *info) +{ + return __detach_parms_from_attrs(NULL, ret_nested_attribute_table, info); +} + +static int __resource_info_from_attrs(struct resource_info *s, + struct nlattr ***ret_nested_attribute_table, + struct genl_info *info) +{ + const int maxtype = DRBD_A_RESOURCE_INFO_RES_SUSP_FEN; + struct nlattr *tla = info->attrs[DRBD_NLA_RESOURCE_INFO]; + struct nlattr **ntb; + struct nlattr *nla; + int err = 0; + + if (ret_nested_attribute_table) + *ret_nested_attribute_table = NULL; + if (!tla) + return -ENOMSG; + ntb = kcalloc(DRBD_A_RESOURCE_INFO_RES_SUSP_FEN + 1, sizeof(*ntb), GFP_KERNEL); + if (!ntb) + return -ENOMEM; + err = nla_parse_nested_deprecated(ntb, maxtype, tla, drbd_resource_info_nl_policy, NULL); + if (err) + goto out; + + nla = ntb[DRBD_A_RESOURCE_INFO_RES_ROLE]; + if (nla && s) + s->res_role = nla_get_u32(nla); + + nla = ntb[DRBD_A_RESOURCE_INFO_RES_SUSP]; + if (nla && s) + s->res_susp = nla_get_u8(nla); + + nla = ntb[DRBD_A_RESOURCE_INFO_RES_SUSP_NOD]; + if (nla && s) + s->res_susp_nod = nla_get_u8(nla); + + nla = ntb[DRBD_A_RESOURCE_INFO_RES_SUSP_FEN]; + if (nla && s) + s->res_susp_fen = nla_get_u8(nla); + +out: + if (ret_nested_attribute_table && (!err || err == -ENOMSG)) + *ret_nested_attribute_table = ntb; + else + kfree(ntb); + return err; +} + +int resource_info_from_attrs(struct resource_info *s, + struct genl_info *info) +{ + return __resource_info_from_attrs(s, NULL, info); +} + +int resource_info_ntb_from_attrs( + struct nlattr ***ret_nested_attribute_table, + struct genl_info *info) +{ + return __resource_info_from_attrs(NULL, ret_nested_attribute_table, info); +} + +static int __device_info_from_attrs(struct device_info *s, + struct nlattr ***ret_nested_attribute_table, + struct genl_info *info) +{ + const int maxtype = DRBD_A_DEVICE_INFO_DEV_DISK_STATE; + struct nlattr *tla = info->attrs[DRBD_NLA_DEVICE_INFO]; + struct nlattr **ntb; + struct nlattr *nla; + int err = 0; + + if (ret_nested_attribute_table) + *ret_nested_attribute_table = NULL; + if (!tla) + return -ENOMSG; + ntb = kcalloc(DRBD_A_DEVICE_INFO_DEV_DISK_STATE + 1, sizeof(*ntb), GFP_KERNEL); + if (!ntb) + return -ENOMEM; + err = nla_parse_nested_deprecated(ntb, maxtype, tla, drbd_device_info_nl_policy, NULL); + if (err) + goto out; + + nla = ntb[DRBD_A_DEVICE_INFO_DEV_DISK_STATE]; + if (nla && s) + s->dev_disk_state = nla_get_u32(nla); + +out: + if (ret_nested_attribute_table && (!err || err == -ENOMSG)) + *ret_nested_attribute_table = ntb; + else + kfree(ntb); + return err; +} + +int device_info_from_attrs(struct device_info *s, + struct genl_info *info) +{ + return __device_info_from_attrs(s, NULL, info); +} + +int device_info_ntb_from_attrs( + struct nlattr ***ret_nested_attribute_table, + struct genl_info *info) +{ + return __device_info_from_attrs(NULL, ret_nested_attribute_table, info); +} + +static int __connection_info_from_attrs(struct connection_info *s, + struct nlattr ***ret_nested_attribute_table, + struct genl_info *info) +{ + const int maxtype = DRBD_A_CONNECTION_INFO_CONN_ROLE; + struct nlattr *tla = info->attrs[DRBD_NLA_CONNECTION_INFO]; + struct nlattr **ntb; + struct nlattr *nla; + int err = 0; + + if (ret_nested_attribute_table) + *ret_nested_attribute_table = NULL; + if (!tla) + return -ENOMSG; + ntb = kcalloc(DRBD_A_CONNECTION_INFO_CONN_ROLE + 1, sizeof(*ntb), GFP_KERNEL); + if (!ntb) + return -ENOMEM; + err = nla_parse_nested_deprecated(ntb, maxtype, tla, drbd_connection_info_nl_policy, NULL); + if (err) + goto out; + + nla = ntb[DRBD_A_CONNECTION_INFO_CONN_CONNECTION_STATE]; + if (nla && s) + s->conn_connection_state = nla_get_u32(nla); + + nla = ntb[DRBD_A_CONNECTION_INFO_CONN_ROLE]; + if (nla && s) + s->conn_role = nla_get_u32(nla); + +out: + if (ret_nested_attribute_table && (!err || err == -ENOMSG)) + *ret_nested_attribute_table = ntb; + else + kfree(ntb); + return err; +} + +int connection_info_from_attrs(struct connection_info *s, + struct genl_info *info) +{ + return __connection_info_from_attrs(s, NULL, info); +} + +int connection_info_ntb_from_attrs( + struct nlattr ***ret_nested_attribute_table, + struct genl_info *info) +{ + return __connection_info_from_attrs(NULL, ret_nested_attribute_table, info); +} + +static int __peer_device_info_from_attrs(struct peer_device_info *s, + struct nlattr ***ret_nested_attribute_table, + struct genl_info *info) +{ + const int maxtype = DRBD_A_PEER_DEVICE_INFO_PEER_RESYNC_SUSP_DEPENDENCY; + struct nlattr *tla = info->attrs[DRBD_NLA_PEER_DEVICE_INFO]; + struct nlattr **ntb; + struct nlattr *nla; + int err = 0; + + if (ret_nested_attribute_table) + *ret_nested_attribute_table = NULL; + if (!tla) + return -ENOMSG; + ntb = kcalloc(DRBD_A_PEER_DEVICE_INFO_PEER_RESYNC_SUSP_DEPENDENCY + 1, sizeof(*ntb), GFP_KERNEL); + if (!ntb) + return -ENOMEM; + err = nla_parse_nested_deprecated(ntb, maxtype, tla, drbd_peer_device_info_nl_policy, NULL); + if (err) + goto out; + + nla = ntb[DRBD_A_PEER_DEVICE_INFO_PEER_REPL_STATE]; + if (nla && s) + s->peer_repl_state = nla_get_u32(nla); + + nla = ntb[DRBD_A_PEER_DEVICE_INFO_PEER_DISK_STATE]; + if (nla && s) + s->peer_disk_state = nla_get_u32(nla); + + nla = ntb[DRBD_A_PEER_DEVICE_INFO_PEER_RESYNC_SUSP_USER]; + if (nla && s) + s->peer_resync_susp_user = nla_get_u32(nla); + + nla = ntb[DRBD_A_PEER_DEVICE_INFO_PEER_RESYNC_SUSP_PEER]; + if (nla && s) + s->peer_resync_susp_peer = nla_get_u32(nla); + + nla = ntb[DRBD_A_PEER_DEVICE_INFO_PEER_RESYNC_SUSP_DEPENDENCY]; + if (nla && s) + s->peer_resync_susp_dependency = nla_get_u32(nla); + +out: + if (ret_nested_attribute_table && (!err || err == -ENOMSG)) + *ret_nested_attribute_table = ntb; + else + kfree(ntb); + return err; +} + +int peer_device_info_from_attrs(struct peer_device_info *s, + struct genl_info *info) +{ + return __peer_device_info_from_attrs(s, NULL, info); +} + +int peer_device_info_ntb_from_attrs( + struct nlattr ***ret_nested_attribute_table, + struct genl_info *info) +{ + return __peer_device_info_from_attrs(NULL, ret_nested_attribute_table, info); +} + +static int __resource_statistics_from_attrs(struct resource_statistics *s, + struct nlattr ***ret_nested_attribute_table, + struct genl_info *info) +{ + const int maxtype = DRBD_A_RESOURCE_STATISTICS_RES_STAT_WRITE_ORDERING; + struct nlattr *tla = info->attrs[DRBD_NLA_RESOURCE_STATISTICS]; + struct nlattr **ntb; + struct nlattr *nla; + int err = 0; + + if (ret_nested_attribute_table) + *ret_nested_attribute_table = NULL; + if (!tla) + return -ENOMSG; + ntb = kcalloc(DRBD_A_RESOURCE_STATISTICS_RES_STAT_WRITE_ORDERING + 1, sizeof(*ntb), GFP_KERNEL); + if (!ntb) + return -ENOMEM; + err = nla_parse_nested_deprecated(ntb, maxtype, tla, drbd_resource_statistics_nl_policy, NULL); + if (err) + goto out; + + nla = ntb[DRBD_A_RESOURCE_STATISTICS_RES_STAT_WRITE_ORDERING]; + if (nla && s) + s->res_stat_write_ordering = nla_get_u32(nla); + +out: + if (ret_nested_attribute_table && (!err || err == -ENOMSG)) + *ret_nested_attribute_table = ntb; + else + kfree(ntb); + return err; +} + +int resource_statistics_from_attrs(struct resource_statistics *s, + struct genl_info *info) +{ + return __resource_statistics_from_attrs(s, NULL, info); +} + +int resource_statistics_ntb_from_attrs( + struct nlattr ***ret_nested_attribute_table, + struct genl_info *info) +{ + return __resource_statistics_from_attrs(NULL, ret_nested_attribute_table, info); +} + +static int __device_statistics_from_attrs(struct device_statistics *s, + struct nlattr ***ret_nested_attribute_table, + struct genl_info *info) +{ + const int maxtype = DRBD_A_DEVICE_STATISTICS_HISTORY_UUIDS; + struct nlattr *tla = info->attrs[DRBD_NLA_DEVICE_STATISTICS]; + struct nlattr **ntb; + struct nlattr *nla; + int err = 0; + + if (ret_nested_attribute_table) + *ret_nested_attribute_table = NULL; + if (!tla) + return -ENOMSG; + ntb = kcalloc(DRBD_A_DEVICE_STATISTICS_HISTORY_UUIDS + 1, sizeof(*ntb), GFP_KERNEL); + if (!ntb) + return -ENOMEM; + err = nla_parse_nested_deprecated(ntb, maxtype, tla, drbd_device_statistics_nl_policy, NULL); + if (err) + goto out; + + nla = ntb[DRBD_A_DEVICE_STATISTICS_DEV_SIZE]; + if (nla && s) + s->dev_size = nla_get_u64(nla); + + nla = ntb[DRBD_A_DEVICE_STATISTICS_DEV_READ]; + if (nla && s) + s->dev_read = nla_get_u64(nla); + + nla = ntb[DRBD_A_DEVICE_STATISTICS_DEV_WRITE]; + if (nla && s) + s->dev_write = nla_get_u64(nla); + + nla = ntb[DRBD_A_DEVICE_STATISTICS_DEV_AL_WRITES]; + if (nla && s) + s->dev_al_writes = nla_get_u64(nla); + + nla = ntb[DRBD_A_DEVICE_STATISTICS_DEV_BM_WRITES]; + if (nla && s) + s->dev_bm_writes = nla_get_u64(nla); + + nla = ntb[DRBD_A_DEVICE_STATISTICS_DEV_UPPER_PENDING]; + if (nla && s) + s->dev_upper_pending = nla_get_u32(nla); + + nla = ntb[DRBD_A_DEVICE_STATISTICS_DEV_LOWER_PENDING]; + if (nla && s) + s->dev_lower_pending = nla_get_u32(nla); + + nla = ntb[DRBD_A_DEVICE_STATISTICS_DEV_UPPER_BLOCKED]; + if (nla && s) + s->dev_upper_blocked = nla_get_u8(nla); + + nla = ntb[DRBD_A_DEVICE_STATISTICS_DEV_LOWER_BLOCKED]; + if (nla && s) + s->dev_lower_blocked = nla_get_u8(nla); + + nla = ntb[DRBD_A_DEVICE_STATISTICS_DEV_AL_SUSPENDED]; + if (nla && s) + s->dev_al_suspended = nla_get_u8(nla); + + nla = ntb[DRBD_A_DEVICE_STATISTICS_DEV_EXPOSED_DATA_UUID]; + if (nla && s) + s->dev_exposed_data_uuid = nla_get_u64(nla); + + nla = ntb[DRBD_A_DEVICE_STATISTICS_DEV_CURRENT_UUID]; + if (nla && s) + s->dev_current_uuid = nla_get_u64(nla); + + nla = ntb[DRBD_A_DEVICE_STATISTICS_DEV_DISK_FLAGS]; + if (nla && s) + s->dev_disk_flags = nla_get_u32(nla); + + nla = ntb[DRBD_A_DEVICE_STATISTICS_HISTORY_UUIDS]; + if (nla && s) + s->history_uuids_len = nla_memcpy(s->history_uuids, nla, DRBD_NL_HISTORY_UUIDS_SIZE); + +out: + if (ret_nested_attribute_table && (!err || err == -ENOMSG)) + *ret_nested_attribute_table = ntb; + else + kfree(ntb); + return err; +} + +int device_statistics_from_attrs(struct device_statistics *s, + struct genl_info *info) +{ + return __device_statistics_from_attrs(s, NULL, info); +} + +int device_statistics_ntb_from_attrs( + struct nlattr ***ret_nested_attribute_table, + struct genl_info *info) +{ + return __device_statistics_from_attrs(NULL, ret_nested_attribute_table, info); +} + +static int __connection_statistics_from_attrs(struct connection_statistics *s, + struct nlattr ***ret_nested_attribute_table, + struct genl_info *info) +{ + const int maxtype = DRBD_A_CONNECTION_STATISTICS_CONN_CONGESTED; + struct nlattr *tla = info->attrs[DRBD_NLA_CONNECTION_STATISTICS]; + struct nlattr **ntb; + struct nlattr *nla; + int err = 0; + + if (ret_nested_attribute_table) + *ret_nested_attribute_table = NULL; + if (!tla) + return -ENOMSG; + ntb = kcalloc(DRBD_A_CONNECTION_STATISTICS_CONN_CONGESTED + 1, sizeof(*ntb), GFP_KERNEL); + if (!ntb) + return -ENOMEM; + err = nla_parse_nested_deprecated(ntb, maxtype, tla, drbd_connection_statistics_nl_policy, NULL); + if (err) + goto out; + + nla = ntb[DRBD_A_CONNECTION_STATISTICS_CONN_CONGESTED]; + if (nla && s) + s->conn_congested = nla_get_u8(nla); + +out: + if (ret_nested_attribute_table && (!err || err == -ENOMSG)) + *ret_nested_attribute_table = ntb; + else + kfree(ntb); + return err; +} + +int connection_statistics_from_attrs(struct connection_statistics *s, + struct genl_info *info) +{ + return __connection_statistics_from_attrs(s, NULL, info); +} + +int connection_statistics_ntb_from_attrs( + struct nlattr ***ret_nested_attribute_table, + struct genl_info *info) +{ + return __connection_statistics_from_attrs(NULL, ret_nested_attribute_table, info); +} + +static int __peer_device_statistics_from_attrs(struct peer_device_statistics *s, + struct nlattr ***ret_nested_attribute_table, + struct genl_info *info) +{ + const int maxtype = DRBD_A_PEER_DEVICE_STATISTICS_PEER_DEV_FLAGS; + struct nlattr *tla = info->attrs[DRBD_NLA_PEER_DEVICE_STATISTICS]; + struct nlattr **ntb; + struct nlattr *nla; + int err = 0; + + if (ret_nested_attribute_table) + *ret_nested_attribute_table = NULL; + if (!tla) + return -ENOMSG; + ntb = kcalloc(DRBD_A_PEER_DEVICE_STATISTICS_PEER_DEV_FLAGS + 1, sizeof(*ntb), GFP_KERNEL); + if (!ntb) + return -ENOMEM; + err = nla_parse_nested_deprecated(ntb, maxtype, tla, drbd_peer_device_statistics_nl_policy, NULL); + if (err) + goto out; + + nla = ntb[DRBD_A_PEER_DEVICE_STATISTICS_PEER_DEV_RECEIVED]; + if (nla && s) + s->peer_dev_received = nla_get_u64(nla); + + nla = ntb[DRBD_A_PEER_DEVICE_STATISTICS_PEER_DEV_SENT]; + if (nla && s) + s->peer_dev_sent = nla_get_u64(nla); + + nla = ntb[DRBD_A_PEER_DEVICE_STATISTICS_PEER_DEV_PENDING]; + if (nla && s) + s->peer_dev_pending = nla_get_u32(nla); + + nla = ntb[DRBD_A_PEER_DEVICE_STATISTICS_PEER_DEV_UNACKED]; + if (nla && s) + s->peer_dev_unacked = nla_get_u32(nla); + + nla = ntb[DRBD_A_PEER_DEVICE_STATISTICS_PEER_DEV_OUT_OF_SYNC]; + if (nla && s) + s->peer_dev_out_of_sync = nla_get_u64(nla); + + nla = ntb[DRBD_A_PEER_DEVICE_STATISTICS_PEER_DEV_RESYNC_FAILED]; + if (nla && s) + s->peer_dev_resync_failed = nla_get_u64(nla); + + nla = ntb[DRBD_A_PEER_DEVICE_STATISTICS_PEER_DEV_BITMAP_UUID]; + if (nla && s) + s->peer_dev_bitmap_uuid = nla_get_u64(nla); + + nla = ntb[DRBD_A_PEER_DEVICE_STATISTICS_PEER_DEV_FLAGS]; + if (nla && s) + s->peer_dev_flags = nla_get_u32(nla); + +out: + if (ret_nested_attribute_table && (!err || err == -ENOMSG)) + *ret_nested_attribute_table = ntb; + else + kfree(ntb); + return err; +} + +int peer_device_statistics_from_attrs(struct peer_device_statistics *s, + struct genl_info *info) +{ + return __peer_device_statistics_from_attrs(s, NULL, info); +} + +int peer_device_statistics_ntb_from_attrs( + struct nlattr ***ret_nested_attribute_table, + struct genl_info *info) +{ + return __peer_device_statistics_from_attrs(NULL, ret_nested_attribute_table, info); +} + +int drbd_cfg_reply_to_skb(struct sk_buff *skb, struct drbd_cfg_reply *s) +{ + struct nlattr *tla = nla_nest_start(skb, DRBD_NLA_CFG_REPLY); + + if (!tla) + goto nla_put_failure; + + if (nla_put(skb, DRBD_A_DRBD_CFG_REPLY_INFO_TEXT, min_t(int, 0, + s->info_text_len + (s->info_text_len < 0)), s->info_text)) + goto nla_put_failure; + + nla_nest_end(skb, tla); + return 0; + +nla_put_failure: + if (tla) + nla_nest_cancel(skb, tla); + return -EMSGSIZE; +} + +int drbd_cfg_context_to_skb(struct sk_buff *skb, struct drbd_cfg_context *s) +{ + struct nlattr *tla = nla_nest_start(skb, DRBD_NLA_CFG_CONTEXT); + + if (!tla) + goto nla_put_failure; + + if (nla_put_u32(skb, DRBD_A_DRBD_CFG_CONTEXT_CTX_VOLUME, s->ctx_volume)) + goto nla_put_failure; + if (nla_put(skb, DRBD_A_DRBD_CFG_CONTEXT_CTX_RESOURCE_NAME, min_t(int, 128, + s->ctx_resource_name_len + (s->ctx_resource_name_len < 128)), s->ctx_resource_name)) + goto nla_put_failure; + if (nla_put(skb, DRBD_A_DRBD_CFG_CONTEXT_CTX_MY_ADDR, min_t(int, 128, + s->ctx_my_addr_len), s->ctx_my_addr)) + goto nla_put_failure; + if (nla_put(skb, DRBD_A_DRBD_CFG_CONTEXT_CTX_PEER_ADDR, min_t(int, 128, + s->ctx_peer_addr_len), s->ctx_peer_addr)) + goto nla_put_failure; + + nla_nest_end(skb, tla); + return 0; + +nla_put_failure: + if (tla) + nla_nest_cancel(skb, tla); + return -EMSGSIZE; +} + +int disk_conf_to_skb(struct sk_buff *skb, struct disk_conf *s) +{ + struct nlattr *tla = nla_nest_start(skb, DRBD_NLA_DISK_CONF); + + if (!tla) + goto nla_put_failure; + + if (nla_put(skb, DRBD_A_DISK_CONF_BACKING_DEV, min_t(int, 128, + s->backing_dev_len + (s->backing_dev_len < 128)), s->backing_dev)) + goto nla_put_failure; + if (nla_put(skb, DRBD_A_DISK_CONF_META_DEV, min_t(int, 128, + s->meta_dev_len + (s->meta_dev_len < 128)), s->meta_dev)) + goto nla_put_failure; + if (nla_put_s32(skb, DRBD_A_DISK_CONF_META_DEV_IDX, s->meta_dev_idx)) + goto nla_put_failure; + if (nla_put_u64_64bit(skb, DRBD_A_DISK_CONF_DISK_SIZE, s->disk_size, 0)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_DISK_CONF_MAX_BIO_BVECS, s->max_bio_bvecs)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_DISK_CONF_ON_IO_ERROR, s->on_io_error)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_DISK_CONF_FENCING, s->fencing)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_DISK_CONF_RESYNC_RATE, s->resync_rate)) + goto nla_put_failure; + if (nla_put_s32(skb, DRBD_A_DISK_CONF_RESYNC_AFTER, s->resync_after)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_DISK_CONF_AL_EXTENTS, s->al_extents)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_DISK_CONF_C_PLAN_AHEAD, s->c_plan_ahead)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_DISK_CONF_C_DELAY_TARGET, s->c_delay_target)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_DISK_CONF_C_FILL_TARGET, s->c_fill_target)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_DISK_CONF_C_MAX_RATE, s->c_max_rate)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_DISK_CONF_C_MIN_RATE, s->c_min_rate)) + goto nla_put_failure; + if (nla_put_u8(skb, DRBD_A_DISK_CONF_DISK_BARRIER, s->disk_barrier)) + goto nla_put_failure; + if (nla_put_u8(skb, DRBD_A_DISK_CONF_DISK_FLUSHES, s->disk_flushes)) + goto nla_put_failure; + if (nla_put_u8(skb, DRBD_A_DISK_CONF_DISK_DRAIN, s->disk_drain)) + goto nla_put_failure; + if (nla_put_u8(skb, DRBD_A_DISK_CONF_MD_FLUSHES, s->md_flushes)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_DISK_CONF_DISK_TIMEOUT, s->disk_timeout)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_DISK_CONF_READ_BALANCING, s->read_balancing)) + goto nla_put_failure; + if (nla_put_u8(skb, DRBD_A_DISK_CONF_AL_UPDATES, s->al_updates)) + goto nla_put_failure; + if (nla_put_u8(skb, DRBD_A_DISK_CONF_DISCARD_ZEROES_IF_ALIGNED, s->discard_zeroes_if_aligned)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_DISK_CONF_RS_DISCARD_GRANULARITY, s->rs_discard_granularity)) + goto nla_put_failure; + if (nla_put_u8(skb, DRBD_A_DISK_CONF_DISABLE_WRITE_SAME, s->disable_write_same)) + goto nla_put_failure; + + nla_nest_end(skb, tla); + return 0; + +nla_put_failure: + if (tla) + nla_nest_cancel(skb, tla); + return -EMSGSIZE; +} + +int res_opts_to_skb(struct sk_buff *skb, struct res_opts *s) +{ + struct nlattr *tla = nla_nest_start(skb, DRBD_NLA_RESOURCE_OPTS); + + if (!tla) + goto nla_put_failure; + + if (nla_put(skb, DRBD_A_RES_OPTS_CPU_MASK, min_t(int, DRBD_CPU_MASK_SIZE, + s->cpu_mask_len + (s->cpu_mask_len < DRBD_CPU_MASK_SIZE)), s->cpu_mask)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_RES_OPTS_ON_NO_DATA, s->on_no_data)) + goto nla_put_failure; + + nla_nest_end(skb, tla); + return 0; + +nla_put_failure: + if (tla) + nla_nest_cancel(skb, tla); + return -EMSGSIZE; +} + +int net_conf_to_skb(struct sk_buff *skb, struct net_conf *s) +{ + struct nlattr *tla = nla_nest_start(skb, DRBD_NLA_NET_CONF); + + if (!tla) + goto nla_put_failure; + + if (nla_put(skb, DRBD_A_NET_CONF_SHARED_SECRET, min_t(int, SHARED_SECRET_MAX, + s->shared_secret_len + (s->shared_secret_len < SHARED_SECRET_MAX)), s->shared_secret)) + goto nla_put_failure; + if (nla_put(skb, DRBD_A_NET_CONF_CRAM_HMAC_ALG, min_t(int, SHARED_SECRET_MAX, + s->cram_hmac_alg_len + (s->cram_hmac_alg_len < SHARED_SECRET_MAX)), s->cram_hmac_alg)) + goto nla_put_failure; + if (nla_put(skb, DRBD_A_NET_CONF_INTEGRITY_ALG, min_t(int, SHARED_SECRET_MAX, + s->integrity_alg_len + (s->integrity_alg_len < SHARED_SECRET_MAX)), s->integrity_alg)) + goto nla_put_failure; + if (nla_put(skb, DRBD_A_NET_CONF_VERIFY_ALG, min_t(int, SHARED_SECRET_MAX, + s->verify_alg_len + (s->verify_alg_len < SHARED_SECRET_MAX)), s->verify_alg)) + goto nla_put_failure; + if (nla_put(skb, DRBD_A_NET_CONF_CSUMS_ALG, min_t(int, SHARED_SECRET_MAX, + s->csums_alg_len + (s->csums_alg_len < SHARED_SECRET_MAX)), s->csums_alg)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_NET_CONF_WIRE_PROTOCOL, s->wire_protocol)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_NET_CONF_CONNECT_INT, s->connect_int)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_NET_CONF_TIMEOUT, s->timeout)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_NET_CONF_PING_INT, s->ping_int)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_NET_CONF_PING_TIMEO, s->ping_timeo)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_NET_CONF_SNDBUF_SIZE, s->sndbuf_size)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_NET_CONF_RCVBUF_SIZE, s->rcvbuf_size)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_NET_CONF_KO_COUNT, s->ko_count)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_NET_CONF_MAX_BUFFERS, s->max_buffers)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_NET_CONF_MAX_EPOCH_SIZE, s->max_epoch_size)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_NET_CONF_UNPLUG_WATERMARK, s->unplug_watermark)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_NET_CONF_AFTER_SB_0P, s->after_sb_0p)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_NET_CONF_AFTER_SB_1P, s->after_sb_1p)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_NET_CONF_AFTER_SB_2P, s->after_sb_2p)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_NET_CONF_RR_CONFLICT, s->rr_conflict)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_NET_CONF_ON_CONGESTION, s->on_congestion)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_NET_CONF_CONG_FILL, s->cong_fill)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_NET_CONF_CONG_EXTENTS, s->cong_extents)) + goto nla_put_failure; + if (nla_put_u8(skb, DRBD_A_NET_CONF_TWO_PRIMARIES, s->two_primaries)) + goto nla_put_failure; + if (nla_put_u8(skb, DRBD_A_NET_CONF_DISCARD_MY_DATA, s->discard_my_data)) + goto nla_put_failure; + if (nla_put_u8(skb, DRBD_A_NET_CONF_TCP_CORK, s->tcp_cork)) + goto nla_put_failure; + if (nla_put_u8(skb, DRBD_A_NET_CONF_ALWAYS_ASBP, s->always_asbp)) + goto nla_put_failure; + if (nla_put_u8(skb, DRBD_A_NET_CONF_TENTATIVE, s->tentative)) + goto nla_put_failure; + if (nla_put_u8(skb, DRBD_A_NET_CONF_USE_RLE, s->use_rle)) + goto nla_put_failure; + if (nla_put_u8(skb, DRBD_A_NET_CONF_CSUMS_AFTER_CRASH_ONLY, s->csums_after_crash_only)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_NET_CONF_SOCK_CHECK_TIMEO, s->sock_check_timeo)) + goto nla_put_failure; + + nla_nest_end(skb, tla); + return 0; + +nla_put_failure: + if (tla) + nla_nest_cancel(skb, tla); + return -EMSGSIZE; +} + +int set_role_parms_to_skb(struct sk_buff *skb, struct set_role_parms *s) +{ + struct nlattr *tla = nla_nest_start(skb, DRBD_NLA_SET_ROLE_PARMS); + + if (!tla) + goto nla_put_failure; + + if (nla_put_u8(skb, DRBD_A_SET_ROLE_PARMS_ASSUME_UPTODATE, s->assume_uptodate)) + goto nla_put_failure; + + nla_nest_end(skb, tla); + return 0; + +nla_put_failure: + if (tla) + nla_nest_cancel(skb, tla); + return -EMSGSIZE; +} + +int resize_parms_to_skb(struct sk_buff *skb, struct resize_parms *s) +{ + struct nlattr *tla = nla_nest_start(skb, DRBD_NLA_RESIZE_PARMS); + + if (!tla) + goto nla_put_failure; + + if (nla_put_u64_64bit(skb, DRBD_A_RESIZE_PARMS_RESIZE_SIZE, s->resize_size, 0)) + goto nla_put_failure; + if (nla_put_u8(skb, DRBD_A_RESIZE_PARMS_RESIZE_FORCE, s->resize_force)) + goto nla_put_failure; + if (nla_put_u8(skb, DRBD_A_RESIZE_PARMS_NO_RESYNC, s->no_resync)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_RESIZE_PARMS_AL_STRIPES, s->al_stripes)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_RESIZE_PARMS_AL_STRIPE_SIZE, s->al_stripe_size)) + goto nla_put_failure; + + nla_nest_end(skb, tla); + return 0; + +nla_put_failure: + if (tla) + nla_nest_cancel(skb, tla); + return -EMSGSIZE; +} + +int state_info_to_skb(struct sk_buff *skb, struct state_info *s) +{ + struct nlattr *tla = nla_nest_start(skb, DRBD_NLA_STATE_INFO); + + if (!tla) + goto nla_put_failure; + + if (nla_put_u32(skb, DRBD_A_STATE_INFO_SIB_REASON, s->sib_reason)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_STATE_INFO_CURRENT_STATE, s->current_state)) + goto nla_put_failure; + if (nla_put_u64_64bit(skb, DRBD_A_STATE_INFO_CAPACITY, s->capacity, 0)) + goto nla_put_failure; + if (nla_put_u64_64bit(skb, DRBD_A_STATE_INFO_ED_UUID, s->ed_uuid, 0)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_STATE_INFO_PREV_STATE, s->prev_state)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_STATE_INFO_NEW_STATE, s->new_state)) + goto nla_put_failure; + if (nla_put(skb, DRBD_A_STATE_INFO_UUIDS, min_t(int, DRBD_NL_UUIDS_SIZE, + s->uuids_len), s->uuids)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_STATE_INFO_DISK_FLAGS, s->disk_flags)) + goto nla_put_failure; + if (nla_put_u64_64bit(skb, DRBD_A_STATE_INFO_BITS_TOTAL, s->bits_total, 0)) + goto nla_put_failure; + if (nla_put_u64_64bit(skb, DRBD_A_STATE_INFO_BITS_OOS, s->bits_oos, 0)) + goto nla_put_failure; + if (nla_put_u64_64bit(skb, DRBD_A_STATE_INFO_BITS_RS_TOTAL, s->bits_rs_total, 0)) + goto nla_put_failure; + if (nla_put_u64_64bit(skb, DRBD_A_STATE_INFO_BITS_RS_FAILED, s->bits_rs_failed, 0)) + goto nla_put_failure; + if (nla_put(skb, DRBD_A_STATE_INFO_HELPER, min_t(int, 32, + s->helper_len + (s->helper_len < 32)), s->helper)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_STATE_INFO_HELPER_EXIT_CODE, s->helper_exit_code)) + goto nla_put_failure; + if (nla_put_u64_64bit(skb, DRBD_A_STATE_INFO_SEND_CNT, s->send_cnt, 0)) + goto nla_put_failure; + if (nla_put_u64_64bit(skb, DRBD_A_STATE_INFO_RECV_CNT, s->recv_cnt, 0)) + goto nla_put_failure; + if (nla_put_u64_64bit(skb, DRBD_A_STATE_INFO_READ_CNT, s->read_cnt, 0)) + goto nla_put_failure; + if (nla_put_u64_64bit(skb, DRBD_A_STATE_INFO_WRIT_CNT, s->writ_cnt, 0)) + goto nla_put_failure; + if (nla_put_u64_64bit(skb, DRBD_A_STATE_INFO_AL_WRIT_CNT, s->al_writ_cnt, 0)) + goto nla_put_failure; + if (nla_put_u64_64bit(skb, DRBD_A_STATE_INFO_BM_WRIT_CNT, s->bm_writ_cnt, 0)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_STATE_INFO_AP_BIO_CNT, s->ap_bio_cnt)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_STATE_INFO_AP_PENDING_CNT, s->ap_pending_cnt)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_STATE_INFO_RS_PENDING_CNT, s->rs_pending_cnt)) + goto nla_put_failure; + + nla_nest_end(skb, tla); + return 0; + +nla_put_failure: + if (tla) + nla_nest_cancel(skb, tla); + return -EMSGSIZE; +} + +int start_ov_parms_to_skb(struct sk_buff *skb, struct start_ov_parms *s) +{ + struct nlattr *tla = nla_nest_start(skb, DRBD_NLA_START_OV_PARMS); + + if (!tla) + goto nla_put_failure; + + if (nla_put_u64_64bit(skb, DRBD_A_START_OV_PARMS_OV_START_SECTOR, s->ov_start_sector, 0)) + goto nla_put_failure; + if (nla_put_u64_64bit(skb, DRBD_A_START_OV_PARMS_OV_STOP_SECTOR, s->ov_stop_sector, 0)) + goto nla_put_failure; + + nla_nest_end(skb, tla); + return 0; + +nla_put_failure: + if (tla) + nla_nest_cancel(skb, tla); + return -EMSGSIZE; +} + +int new_c_uuid_parms_to_skb(struct sk_buff *skb, struct new_c_uuid_parms *s) +{ + struct nlattr *tla = nla_nest_start(skb, DRBD_NLA_NEW_C_UUID_PARMS); + + if (!tla) + goto nla_put_failure; + + if (nla_put_u8(skb, DRBD_A_NEW_C_UUID_PARMS_CLEAR_BM, s->clear_bm)) + goto nla_put_failure; + + nla_nest_end(skb, tla); + return 0; + +nla_put_failure: + if (tla) + nla_nest_cancel(skb, tla); + return -EMSGSIZE; +} + +int timeout_parms_to_skb(struct sk_buff *skb, struct timeout_parms *s) +{ + struct nlattr *tla = nla_nest_start(skb, DRBD_NLA_TIMEOUT_PARMS); + + if (!tla) + goto nla_put_failure; + + if (nla_put_u32(skb, DRBD_A_TIMEOUT_PARMS_TIMEOUT_TYPE, s->timeout_type)) + goto nla_put_failure; + + nla_nest_end(skb, tla); + return 0; + +nla_put_failure: + if (tla) + nla_nest_cancel(skb, tla); + return -EMSGSIZE; +} + +int disconnect_parms_to_skb(struct sk_buff *skb, struct disconnect_parms *s) +{ + struct nlattr *tla = nla_nest_start(skb, DRBD_NLA_DISCONNECT_PARMS); + + if (!tla) + goto nla_put_failure; + + if (nla_put_u8(skb, DRBD_A_DISCONNECT_PARMS_FORCE_DISCONNECT, s->force_disconnect)) + goto nla_put_failure; + + nla_nest_end(skb, tla); + return 0; + +nla_put_failure: + if (tla) + nla_nest_cancel(skb, tla); + return -EMSGSIZE; +} + +int detach_parms_to_skb(struct sk_buff *skb, struct detach_parms *s) +{ + struct nlattr *tla = nla_nest_start(skb, DRBD_NLA_DETACH_PARMS); + + if (!tla) + goto nla_put_failure; + + if (nla_put_u8(skb, DRBD_A_DETACH_PARMS_FORCE_DETACH, s->force_detach)) + goto nla_put_failure; + + nla_nest_end(skb, tla); + return 0; + +nla_put_failure: + if (tla) + nla_nest_cancel(skb, tla); + return -EMSGSIZE; +} + +int resource_info_to_skb(struct sk_buff *skb, struct resource_info *s) +{ + struct nlattr *tla = nla_nest_start(skb, DRBD_NLA_RESOURCE_INFO); + + if (!tla) + goto nla_put_failure; + + if (nla_put_u32(skb, DRBD_A_RESOURCE_INFO_RES_ROLE, s->res_role)) + goto nla_put_failure; + if (nla_put_u8(skb, DRBD_A_RESOURCE_INFO_RES_SUSP, s->res_susp)) + goto nla_put_failure; + if (nla_put_u8(skb, DRBD_A_RESOURCE_INFO_RES_SUSP_NOD, s->res_susp_nod)) + goto nla_put_failure; + if (nla_put_u8(skb, DRBD_A_RESOURCE_INFO_RES_SUSP_FEN, s->res_susp_fen)) + goto nla_put_failure; + + nla_nest_end(skb, tla); + return 0; + +nla_put_failure: + if (tla) + nla_nest_cancel(skb, tla); + return -EMSGSIZE; +} + +int device_info_to_skb(struct sk_buff *skb, struct device_info *s) +{ + struct nlattr *tla = nla_nest_start(skb, DRBD_NLA_DEVICE_INFO); + + if (!tla) + goto nla_put_failure; + + if (nla_put_u32(skb, DRBD_A_DEVICE_INFO_DEV_DISK_STATE, s->dev_disk_state)) + goto nla_put_failure; + + nla_nest_end(skb, tla); + return 0; + +nla_put_failure: + if (tla) + nla_nest_cancel(skb, tla); + return -EMSGSIZE; +} + +int connection_info_to_skb(struct sk_buff *skb, struct connection_info *s) +{ + struct nlattr *tla = nla_nest_start(skb, DRBD_NLA_CONNECTION_INFO); + + if (!tla) + goto nla_put_failure; + + if (nla_put_u32(skb, DRBD_A_CONNECTION_INFO_CONN_CONNECTION_STATE, s->conn_connection_state)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_CONNECTION_INFO_CONN_ROLE, s->conn_role)) + goto nla_put_failure; + + nla_nest_end(skb, tla); + return 0; + +nla_put_failure: + if (tla) + nla_nest_cancel(skb, tla); + return -EMSGSIZE; +} + +int peer_device_info_to_skb(struct sk_buff *skb, struct peer_device_info *s) +{ + struct nlattr *tla = nla_nest_start(skb, DRBD_NLA_PEER_DEVICE_INFO); + + if (!tla) + goto nla_put_failure; + + if (nla_put_u32(skb, DRBD_A_PEER_DEVICE_INFO_PEER_REPL_STATE, s->peer_repl_state)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_PEER_DEVICE_INFO_PEER_DISK_STATE, s->peer_disk_state)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_PEER_DEVICE_INFO_PEER_RESYNC_SUSP_USER, s->peer_resync_susp_user)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_PEER_DEVICE_INFO_PEER_RESYNC_SUSP_PEER, s->peer_resync_susp_peer)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_PEER_DEVICE_INFO_PEER_RESYNC_SUSP_DEPENDENCY, s->peer_resync_susp_dependency)) + goto nla_put_failure; + + nla_nest_end(skb, tla); + return 0; + +nla_put_failure: + if (tla) + nla_nest_cancel(skb, tla); + return -EMSGSIZE; +} + +int resource_statistics_to_skb(struct sk_buff *skb, struct resource_statistics *s) +{ + struct nlattr *tla = nla_nest_start(skb, DRBD_NLA_RESOURCE_STATISTICS); + + if (!tla) + goto nla_put_failure; + + if (nla_put_u32(skb, DRBD_A_RESOURCE_STATISTICS_RES_STAT_WRITE_ORDERING, s->res_stat_write_ordering)) + goto nla_put_failure; + + nla_nest_end(skb, tla); + return 0; + +nla_put_failure: + if (tla) + nla_nest_cancel(skb, tla); + return -EMSGSIZE; +} + +int device_statistics_to_skb(struct sk_buff *skb, struct device_statistics *s) +{ + struct nlattr *tla = nla_nest_start(skb, DRBD_NLA_DEVICE_STATISTICS); + + if (!tla) + goto nla_put_failure; + + if (nla_put_u64_64bit(skb, DRBD_A_DEVICE_STATISTICS_DEV_SIZE, s->dev_size, 0)) + goto nla_put_failure; + if (nla_put_u64_64bit(skb, DRBD_A_DEVICE_STATISTICS_DEV_READ, s->dev_read, 0)) + goto nla_put_failure; + if (nla_put_u64_64bit(skb, DRBD_A_DEVICE_STATISTICS_DEV_WRITE, s->dev_write, 0)) + goto nla_put_failure; + if (nla_put_u64_64bit(skb, DRBD_A_DEVICE_STATISTICS_DEV_AL_WRITES, s->dev_al_writes, 0)) + goto nla_put_failure; + if (nla_put_u64_64bit(skb, DRBD_A_DEVICE_STATISTICS_DEV_BM_WRITES, s->dev_bm_writes, 0)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_DEVICE_STATISTICS_DEV_UPPER_PENDING, s->dev_upper_pending)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_DEVICE_STATISTICS_DEV_LOWER_PENDING, s->dev_lower_pending)) + goto nla_put_failure; + if (nla_put_u8(skb, DRBD_A_DEVICE_STATISTICS_DEV_UPPER_BLOCKED, s->dev_upper_blocked)) + goto nla_put_failure; + if (nla_put_u8(skb, DRBD_A_DEVICE_STATISTICS_DEV_LOWER_BLOCKED, s->dev_lower_blocked)) + goto nla_put_failure; + if (nla_put_u8(skb, DRBD_A_DEVICE_STATISTICS_DEV_AL_SUSPENDED, s->dev_al_suspended)) + goto nla_put_failure; + if (nla_put_u64_64bit(skb, DRBD_A_DEVICE_STATISTICS_DEV_EXPOSED_DATA_UUID, s->dev_exposed_data_uuid, 0)) + goto nla_put_failure; + if (nla_put_u64_64bit(skb, DRBD_A_DEVICE_STATISTICS_DEV_CURRENT_UUID, s->dev_current_uuid, 0)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_DEVICE_STATISTICS_DEV_DISK_FLAGS, s->dev_disk_flags)) + goto nla_put_failure; + if (nla_put(skb, DRBD_A_DEVICE_STATISTICS_HISTORY_UUIDS, min_t(int, DRBD_NL_HISTORY_UUIDS_SIZE, + s->history_uuids_len), s->history_uuids)) + goto nla_put_failure; + + nla_nest_end(skb, tla); + return 0; + +nla_put_failure: + if (tla) + nla_nest_cancel(skb, tla); + return -EMSGSIZE; +} + +int connection_statistics_to_skb(struct sk_buff *skb, struct connection_statistics *s) +{ + struct nlattr *tla = nla_nest_start(skb, DRBD_NLA_CONNECTION_STATISTICS); + + if (!tla) + goto nla_put_failure; + + if (nla_put_u8(skb, DRBD_A_CONNECTION_STATISTICS_CONN_CONGESTED, s->conn_congested)) + goto nla_put_failure; + + nla_nest_end(skb, tla); + return 0; + +nla_put_failure: + if (tla) + nla_nest_cancel(skb, tla); + return -EMSGSIZE; +} + +int peer_device_statistics_to_skb(struct sk_buff *skb, struct peer_device_statistics *s) +{ + struct nlattr *tla = nla_nest_start(skb, DRBD_NLA_PEER_DEVICE_STATISTICS); + + if (!tla) + goto nla_put_failure; + + if (nla_put_u64_64bit(skb, DRBD_A_PEER_DEVICE_STATISTICS_PEER_DEV_RECEIVED, s->peer_dev_received, 0)) + goto nla_put_failure; + if (nla_put_u64_64bit(skb, DRBD_A_PEER_DEVICE_STATISTICS_PEER_DEV_SENT, s->peer_dev_sent, 0)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_PEER_DEVICE_STATISTICS_PEER_DEV_PENDING, s->peer_dev_pending)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_PEER_DEVICE_STATISTICS_PEER_DEV_UNACKED, s->peer_dev_unacked)) + goto nla_put_failure; + if (nla_put_u64_64bit(skb, DRBD_A_PEER_DEVICE_STATISTICS_PEER_DEV_OUT_OF_SYNC, s->peer_dev_out_of_sync, 0)) + goto nla_put_failure; + if (nla_put_u64_64bit(skb, DRBD_A_PEER_DEVICE_STATISTICS_PEER_DEV_RESYNC_FAILED, s->peer_dev_resync_failed, 0)) + goto nla_put_failure; + if (nla_put_u64_64bit(skb, DRBD_A_PEER_DEVICE_STATISTICS_PEER_DEV_BITMAP_UUID, s->peer_dev_bitmap_uuid, 0)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_PEER_DEVICE_STATISTICS_PEER_DEV_FLAGS, s->peer_dev_flags)) + goto nla_put_failure; + + nla_nest_end(skb, tla); + return 0; + +nla_put_failure: + if (tla) + nla_nest_cancel(skb, tla); + return -EMSGSIZE; +} + +int drbd_notification_header_to_skb(struct sk_buff *skb, struct drbd_notification_header *s) +{ + struct nlattr *tla = nla_nest_start(skb, DRBD_NLA_NOTIFICATION_HEADER); + + if (!tla) + goto nla_put_failure; + + if (nla_put_u32(skb, DRBD_A_DRBD_NOTIFICATION_HEADER_NH_TYPE, s->nh_type)) + goto nla_put_failure; + + nla_nest_end(skb, tla); + return 0; + +nla_put_failure: + if (tla) + nla_nest_cancel(skb, tla); + return -EMSGSIZE; +} + +int drbd_helper_info_to_skb(struct sk_buff *skb, struct drbd_helper_info *s) +{ + struct nlattr *tla = nla_nest_start(skb, DRBD_NLA_HELPER); + + if (!tla) + goto nla_put_failure; + + if (nla_put(skb, DRBD_A_DRBD_HELPER_INFO_HELPER_NAME, min_t(int, 32, + s->helper_name_len + (s->helper_name_len < 32)), s->helper_name)) + goto nla_put_failure; + if (nla_put_u32(skb, DRBD_A_DRBD_HELPER_INFO_HELPER_STATUS, s->helper_status)) + goto nla_put_failure; + + nla_nest_end(skb, tla); + return 0; + +nla_put_failure: + if (tla) + nla_nest_cancel(skb, tla); + return -EMSGSIZE; +} + +void set_disk_conf_defaults(struct disk_conf *x) +{ + x->on_io_error = DRBD_ON_IO_ERROR_DEF; + x->fencing = DRBD_FENCING_DEF; + x->resync_rate = DRBD_RESYNC_RATE_DEF; + x->resync_after = DRBD_MINOR_NUMBER_DEF; + x->al_extents = DRBD_AL_EXTENTS_DEF; + x->c_plan_ahead = DRBD_C_PLAN_AHEAD_DEF; + x->c_delay_target = DRBD_C_DELAY_TARGET_DEF; + x->c_fill_target = DRBD_C_FILL_TARGET_DEF; + x->c_max_rate = DRBD_C_MAX_RATE_DEF; + x->c_min_rate = DRBD_C_MIN_RATE_DEF; + x->disk_barrier = DRBD_DISK_BARRIER_DEF; + x->disk_flushes = DRBD_DISK_FLUSHES_DEF; + x->disk_drain = DRBD_DISK_DRAIN_DEF; + x->md_flushes = DRBD_MD_FLUSHES_DEF; + x->disk_timeout = DRBD_DISK_TIMEOUT_DEF; + x->read_balancing = DRBD_READ_BALANCING_DEF; + x->al_updates = DRBD_AL_UPDATES_DEF; + x->discard_zeroes_if_aligned = DRBD_DISCARD_ZEROES_IF_ALIGNED_DEF; + x->rs_discard_granularity = DRBD_RS_DISCARD_GRANULARITY_DEF; + x->disable_write_same = DRBD_DISABLE_WRITE_SAME_DEF; +} + +void set_res_opts_defaults(struct res_opts *x) +{ + memset(x->cpu_mask, 0, sizeof(x->cpu_mask)); + x->cpu_mask_len = 0; + x->on_no_data = DRBD_ON_NO_DATA_DEF; +} + +void set_net_conf_defaults(struct net_conf *x) +{ + memset(x->shared_secret, 0, sizeof(x->shared_secret)); + x->shared_secret_len = 0; + memset(x->cram_hmac_alg, 0, sizeof(x->cram_hmac_alg)); + x->cram_hmac_alg_len = 0; + memset(x->integrity_alg, 0, sizeof(x->integrity_alg)); + x->integrity_alg_len = 0; + memset(x->verify_alg, 0, sizeof(x->verify_alg)); + x->verify_alg_len = 0; + memset(x->csums_alg, 0, sizeof(x->csums_alg)); + x->csums_alg_len = 0; + x->wire_protocol = DRBD_PROTOCOL_DEF; + x->connect_int = DRBD_CONNECT_INT_DEF; + x->timeout = DRBD_TIMEOUT_DEF; + x->ping_int = DRBD_PING_INT_DEF; + x->ping_timeo = DRBD_PING_TIMEO_DEF; + x->sndbuf_size = DRBD_SNDBUF_SIZE_DEF; + x->rcvbuf_size = DRBD_RCVBUF_SIZE_DEF; + x->ko_count = DRBD_KO_COUNT_DEF; + x->max_buffers = DRBD_MAX_BUFFERS_DEF; + x->max_epoch_size = DRBD_MAX_EPOCH_SIZE_DEF; + x->unplug_watermark = DRBD_UNPLUG_WATERMARK_DEF; + x->after_sb_0p = DRBD_AFTER_SB_0P_DEF; + x->after_sb_1p = DRBD_AFTER_SB_1P_DEF; + x->after_sb_2p = DRBD_AFTER_SB_2P_DEF; + x->rr_conflict = DRBD_RR_CONFLICT_DEF; + x->on_congestion = DRBD_ON_CONGESTION_DEF; + x->cong_fill = DRBD_CONG_FILL_DEF; + x->cong_extents = DRBD_CONG_EXTENTS_DEF; + x->two_primaries = DRBD_ALLOW_TWO_PRIMARIES_DEF; + x->tcp_cork = DRBD_TCP_CORK_DEF; + x->always_asbp = DRBD_ALWAYS_ASBP_DEF; + x->use_rle = DRBD_USE_RLE_DEF; + x->csums_after_crash_only = DRBD_CSUMS_AFTER_CRASH_ONLY_DEF; + x->sock_check_timeo = DRBD_SOCKET_CHECK_TIMEO_DEF; +} + +void set_resize_parms_defaults(struct resize_parms *x) +{ + x->al_stripes = DRBD_AL_STRIPES_DEF; + x->al_stripe_size = DRBD_AL_STRIPE_SIZE_DEF; +} diff --git a/drivers/block/drbd/drbd_nl_gen.h b/drivers/block/drbd/drbd_nl_gen.h new file mode 100644 index 000000000000..f2140dd1ac4e --- /dev/null +++ b/drivers/block/drbd/drbd_nl_gen.h @@ -0,0 +1,395 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ + +#ifndef _LINUX_DRBD_GEN_H +#define _LINUX_DRBD_GEN_H + +#include +#include + +#include +#include +#include + +/* Common nested types */ +extern const struct nla_policy drbd_connection_info_nl_policy[DRBD_A_CONNECTION_INFO_CONN_ROLE + 1]; +extern const struct nla_policy drbd_connection_statistics_nl_policy[DRBD_A_CONNECTION_STATISTICS_CONN_CONGESTED + 1]; +extern const struct nla_policy drbd_detach_parms_nl_policy[DRBD_A_DETACH_PARMS_FORCE_DETACH + 1]; +extern const struct nla_policy drbd_device_info_nl_policy[DRBD_A_DEVICE_INFO_DEV_DISK_STATE + 1]; +extern const struct nla_policy drbd_device_statistics_nl_policy[DRBD_A_DEVICE_STATISTICS_HISTORY_UUIDS + 1]; +extern const struct nla_policy drbd_disconnect_parms_nl_policy[DRBD_A_DISCONNECT_PARMS_FORCE_DISCONNECT + 1]; +extern const struct nla_policy drbd_disk_conf_nl_policy[DRBD_A_DISK_CONF_DISABLE_WRITE_SAME + 1]; +extern const struct nla_policy drbd_drbd_cfg_context_nl_policy[DRBD_A_DRBD_CFG_CONTEXT_CTX_PEER_ADDR + 1]; +extern const struct nla_policy drbd_net_conf_nl_policy[DRBD_A_NET_CONF_SOCK_CHECK_TIMEO + 1]; +extern const struct nla_policy drbd_new_c_uuid_parms_nl_policy[DRBD_A_NEW_C_UUID_PARMS_CLEAR_BM + 1]; +extern const struct nla_policy drbd_peer_device_info_nl_policy[DRBD_A_PEER_DEVICE_INFO_PEER_RESYNC_SUSP_DEPENDENCY + 1]; +extern const struct nla_policy drbd_peer_device_statistics_nl_policy[DRBD_A_PEER_DEVICE_STATISTICS_PEER_DEV_FLAGS + 1]; +extern const struct nla_policy drbd_res_opts_nl_policy[DRBD_A_RES_OPTS_ON_NO_DATA + 1]; +extern const struct nla_policy drbd_resize_parms_nl_policy[DRBD_A_RESIZE_PARMS_AL_STRIPE_SIZE + 1]; +extern const struct nla_policy drbd_resource_info_nl_policy[DRBD_A_RESOURCE_INFO_RES_SUSP_FEN + 1]; +extern const struct nla_policy drbd_resource_statistics_nl_policy[DRBD_A_RESOURCE_STATISTICS_RES_STAT_WRITE_ORDERING + 1]; +extern const struct nla_policy drbd_set_role_parms_nl_policy[DRBD_A_SET_ROLE_PARMS_ASSUME_UPTODATE + 1]; +extern const struct nla_policy drbd_start_ov_parms_nl_policy[DRBD_A_START_OV_PARMS_OV_STOP_SECTOR + 1]; + +/* Ops table for drbd */ +extern const struct genl_split_ops drbd_nl_ops[32]; + +int drbd_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb, + struct genl_info *info); +void +drbd_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb, + struct genl_info *info); +int drbd_adm_dump_devices_done(struct netlink_callback *cb); +int drbd_adm_dump_connections_done(struct netlink_callback *cb); +int drbd_adm_dump_peer_devices_done(struct netlink_callback *cb); + +int drbd_nl_get_status_doit(struct sk_buff *skb, struct genl_info *info); +int drbd_nl_get_status_dumpit(struct sk_buff *skb, struct netlink_callback *cb); +int drbd_nl_new_minor_doit(struct sk_buff *skb, struct genl_info *info); +int drbd_nl_del_minor_doit(struct sk_buff *skb, struct genl_info *info); +int drbd_nl_new_resource_doit(struct sk_buff *skb, struct genl_info *info); +int drbd_nl_del_resource_doit(struct sk_buff *skb, struct genl_info *info); +int drbd_nl_resource_opts_doit(struct sk_buff *skb, struct genl_info *info); +int drbd_nl_connect_doit(struct sk_buff *skb, struct genl_info *info); +int drbd_nl_disconnect_doit(struct sk_buff *skb, struct genl_info *info); +int drbd_nl_attach_doit(struct sk_buff *skb, struct genl_info *info); +int drbd_nl_resize_doit(struct sk_buff *skb, struct genl_info *info); +int drbd_nl_primary_doit(struct sk_buff *skb, struct genl_info *info); +int drbd_nl_secondary_doit(struct sk_buff *skb, struct genl_info *info); +int drbd_nl_new_c_uuid_doit(struct sk_buff *skb, struct genl_info *info); +int drbd_nl_start_ov_doit(struct sk_buff *skb, struct genl_info *info); +int drbd_nl_detach_doit(struct sk_buff *skb, struct genl_info *info); +int drbd_nl_invalidate_doit(struct sk_buff *skb, struct genl_info *info); +int drbd_nl_inval_peer_doit(struct sk_buff *skb, struct genl_info *info); +int drbd_nl_pause_sync_doit(struct sk_buff *skb, struct genl_info *info); +int drbd_nl_resume_sync_doit(struct sk_buff *skb, struct genl_info *info); +int drbd_nl_suspend_io_doit(struct sk_buff *skb, struct genl_info *info); +int drbd_nl_resume_io_doit(struct sk_buff *skb, struct genl_info *info); +int drbd_nl_outdate_doit(struct sk_buff *skb, struct genl_info *info); +int drbd_nl_get_timeout_type_doit(struct sk_buff *skb, struct genl_info *info); +int drbd_nl_down_doit(struct sk_buff *skb, struct genl_info *info); +int drbd_nl_chg_disk_opts_doit(struct sk_buff *skb, struct genl_info *info); +int drbd_nl_chg_net_opts_doit(struct sk_buff *skb, struct genl_info *info); +int drbd_nl_get_resources_dumpit(struct sk_buff *skb, + struct netlink_callback *cb); +int drbd_nl_get_devices_dumpit(struct sk_buff *skb, + struct netlink_callback *cb); +int drbd_nl_get_connections_dumpit(struct sk_buff *skb, + struct netlink_callback *cb); +int drbd_nl_get_peer_devices_dumpit(struct sk_buff *skb, + struct netlink_callback *cb); +int drbd_nl_get_initial_state_dumpit(struct sk_buff *skb, + struct netlink_callback *cb); + +enum { + DRBD_NLGRP_EVENTS, +}; + +struct drbd_cfg_reply { + char info_text[0]; + __u32 info_text_len; +}; + +struct drbd_cfg_context { + __u32 ctx_volume; + char ctx_resource_name[128]; + __u32 ctx_resource_name_len; + char ctx_my_addr[128]; + __u32 ctx_my_addr_len; + char ctx_peer_addr[128]; + __u32 ctx_peer_addr_len; +}; + +struct disk_conf { + char backing_dev[128]; + __u32 backing_dev_len; + char meta_dev[128]; + __u32 meta_dev_len; + __s32 meta_dev_idx; + __u64 disk_size; + __u32 max_bio_bvecs; + __u32 on_io_error; + __u32 fencing; + __u32 resync_rate; + __s32 resync_after; + __u32 al_extents; + __u32 c_plan_ahead; + __u32 c_delay_target; + __u32 c_fill_target; + __u32 c_max_rate; + __u32 c_min_rate; + unsigned char disk_barrier; + unsigned char disk_flushes; + unsigned char disk_drain; + unsigned char md_flushes; + __u32 disk_timeout; + __u32 read_balancing; + unsigned char al_updates; + unsigned char discard_zeroes_if_aligned; + __u32 rs_discard_granularity; + unsigned char disable_write_same; +}; + +struct res_opts { + char cpu_mask[DRBD_CPU_MASK_SIZE]; + __u32 cpu_mask_len; + __u32 on_no_data; +}; + +struct net_conf { + char shared_secret[SHARED_SECRET_MAX]; + __u32 shared_secret_len; + char cram_hmac_alg[SHARED_SECRET_MAX]; + __u32 cram_hmac_alg_len; + char integrity_alg[SHARED_SECRET_MAX]; + __u32 integrity_alg_len; + char verify_alg[SHARED_SECRET_MAX]; + __u32 verify_alg_len; + char csums_alg[SHARED_SECRET_MAX]; + __u32 csums_alg_len; + __u32 wire_protocol; + __u32 connect_int; + __u32 timeout; + __u32 ping_int; + __u32 ping_timeo; + __u32 sndbuf_size; + __u32 rcvbuf_size; + __u32 ko_count; + __u32 max_buffers; + __u32 max_epoch_size; + __u32 unplug_watermark; + __u32 after_sb_0p; + __u32 after_sb_1p; + __u32 after_sb_2p; + __u32 rr_conflict; + __u32 on_congestion; + __u32 cong_fill; + __u32 cong_extents; + unsigned char two_primaries; + unsigned char discard_my_data; + unsigned char tcp_cork; + unsigned char always_asbp; + unsigned char tentative; + unsigned char use_rle; + unsigned char csums_after_crash_only; + __u32 sock_check_timeo; +}; + +struct set_role_parms { + unsigned char assume_uptodate; +}; + +struct resize_parms { + __u64 resize_size; + unsigned char resize_force; + unsigned char no_resync; + __u32 al_stripes; + __u32 al_stripe_size; +}; + +struct state_info { + __u32 sib_reason; + __u32 current_state; + __u64 capacity; + __u64 ed_uuid; + __u32 prev_state; + __u32 new_state; + char uuids[DRBD_NL_UUIDS_SIZE]; + __u32 uuids_len; + __u32 disk_flags; + __u64 bits_total; + __u64 bits_oos; + __u64 bits_rs_total; + __u64 bits_rs_failed; + char helper[32]; + __u32 helper_len; + __u32 helper_exit_code; + __u64 send_cnt; + __u64 recv_cnt; + __u64 read_cnt; + __u64 writ_cnt; + __u64 al_writ_cnt; + __u64 bm_writ_cnt; + __u32 ap_bio_cnt; + __u32 ap_pending_cnt; + __u32 rs_pending_cnt; +}; + +struct start_ov_parms { + __u64 ov_start_sector; + __u64 ov_stop_sector; +}; + +struct new_c_uuid_parms { + unsigned char clear_bm; +}; + +struct timeout_parms { + __u32 timeout_type; +}; + +struct disconnect_parms { + unsigned char force_disconnect; +}; + +struct detach_parms { + unsigned char force_detach; +}; + +struct resource_info { + __u32 res_role; + unsigned char res_susp; + unsigned char res_susp_nod; + unsigned char res_susp_fen; +}; + +struct device_info { + __u32 dev_disk_state; +}; + +struct connection_info { + __u32 conn_connection_state; + __u32 conn_role; +}; + +struct peer_device_info { + __u32 peer_repl_state; + __u32 peer_disk_state; + __u32 peer_resync_susp_user; + __u32 peer_resync_susp_peer; + __u32 peer_resync_susp_dependency; +}; + +struct resource_statistics { + __u32 res_stat_write_ordering; +}; + +struct device_statistics { + __u64 dev_size; + __u64 dev_read; + __u64 dev_write; + __u64 dev_al_writes; + __u64 dev_bm_writes; + __u32 dev_upper_pending; + __u32 dev_lower_pending; + unsigned char dev_upper_blocked; + unsigned char dev_lower_blocked; + unsigned char dev_al_suspended; + __u64 dev_exposed_data_uuid; + __u64 dev_current_uuid; + __u32 dev_disk_flags; + char history_uuids[DRBD_NL_HISTORY_UUIDS_SIZE]; + __u32 history_uuids_len; +}; + +struct connection_statistics { + unsigned char conn_congested; +}; + +struct peer_device_statistics { + __u64 peer_dev_received; + __u64 peer_dev_sent; + __u32 peer_dev_pending; + __u32 peer_dev_unacked; + __u64 peer_dev_out_of_sync; + __u64 peer_dev_resync_failed; + __u64 peer_dev_bitmap_uuid; + __u32 peer_dev_flags; +}; + +struct drbd_notification_header { + __u32 nh_type; +}; + +struct drbd_helper_info { + char helper_name[32]; + __u32 helper_name_len; + __u32 helper_status; +}; + +int drbd_cfg_reply_to_skb(struct sk_buff *skb, struct drbd_cfg_reply *s); + +int drbd_cfg_context_from_attrs(struct drbd_cfg_context *s, struct genl_info *info); +int drbd_cfg_context_ntb_from_attrs(struct nlattr ***ret_nested_attribute_table, struct genl_info *info); +int drbd_cfg_context_to_skb(struct sk_buff *skb, struct drbd_cfg_context *s); + +int disk_conf_from_attrs(struct disk_conf *s, struct genl_info *info); +int disk_conf_ntb_from_attrs(struct nlattr ***ret_nested_attribute_table, struct genl_info *info); +int disk_conf_to_skb(struct sk_buff *skb, struct disk_conf *s); +void set_disk_conf_defaults(struct disk_conf *x); + +int res_opts_from_attrs(struct res_opts *s, struct genl_info *info); +int res_opts_ntb_from_attrs(struct nlattr ***ret_nested_attribute_table, struct genl_info *info); +int res_opts_to_skb(struct sk_buff *skb, struct res_opts *s); +void set_res_opts_defaults(struct res_opts *x); + +int net_conf_from_attrs(struct net_conf *s, struct genl_info *info); +int net_conf_ntb_from_attrs(struct nlattr ***ret_nested_attribute_table, struct genl_info *info); +int net_conf_to_skb(struct sk_buff *skb, struct net_conf *s); +void set_net_conf_defaults(struct net_conf *x); + +int set_role_parms_from_attrs(struct set_role_parms *s, struct genl_info *info); +int set_role_parms_ntb_from_attrs(struct nlattr ***ret_nested_attribute_table, struct genl_info *info); +int set_role_parms_to_skb(struct sk_buff *skb, struct set_role_parms *s); + +int resize_parms_from_attrs(struct resize_parms *s, struct genl_info *info); +int resize_parms_ntb_from_attrs(struct nlattr ***ret_nested_attribute_table, struct genl_info *info); +int resize_parms_to_skb(struct sk_buff *skb, struct resize_parms *s); +void set_resize_parms_defaults(struct resize_parms *x); + +int state_info_to_skb(struct sk_buff *skb, struct state_info *s); + +int start_ov_parms_from_attrs(struct start_ov_parms *s, struct genl_info *info); +int start_ov_parms_ntb_from_attrs(struct nlattr ***ret_nested_attribute_table, struct genl_info *info); +int start_ov_parms_to_skb(struct sk_buff *skb, struct start_ov_parms *s); + +int new_c_uuid_parms_from_attrs(struct new_c_uuid_parms *s, struct genl_info *info); +int new_c_uuid_parms_ntb_from_attrs(struct nlattr ***ret_nested_attribute_table, struct genl_info *info); +int new_c_uuid_parms_to_skb(struct sk_buff *skb, struct new_c_uuid_parms *s); + +int timeout_parms_to_skb(struct sk_buff *skb, struct timeout_parms *s); + +int disconnect_parms_from_attrs(struct disconnect_parms *s, struct genl_info *info); +int disconnect_parms_ntb_from_attrs(struct nlattr ***ret_nested_attribute_table, struct genl_info *info); +int disconnect_parms_to_skb(struct sk_buff *skb, struct disconnect_parms *s); + +int detach_parms_from_attrs(struct detach_parms *s, struct genl_info *info); +int detach_parms_ntb_from_attrs(struct nlattr ***ret_nested_attribute_table, struct genl_info *info); +int detach_parms_to_skb(struct sk_buff *skb, struct detach_parms *s); + +int resource_info_from_attrs(struct resource_info *s, struct genl_info *info); +int resource_info_ntb_from_attrs(struct nlattr ***ret_nested_attribute_table, struct genl_info *info); +int resource_info_to_skb(struct sk_buff *skb, struct resource_info *s); + +int device_info_from_attrs(struct device_info *s, struct genl_info *info); +int device_info_ntb_from_attrs(struct nlattr ***ret_nested_attribute_table, struct genl_info *info); +int device_info_to_skb(struct sk_buff *skb, struct device_info *s); + +int connection_info_from_attrs(struct connection_info *s, struct genl_info *info); +int connection_info_ntb_from_attrs(struct nlattr ***ret_nested_attribute_table, struct genl_info *info); +int connection_info_to_skb(struct sk_buff *skb, struct connection_info *s); + +int peer_device_info_from_attrs(struct peer_device_info *s, struct genl_info *info); +int peer_device_info_ntb_from_attrs(struct nlattr ***ret_nested_attribute_table, struct genl_info *info); +int peer_device_info_to_skb(struct sk_buff *skb, struct peer_device_info *s); + +int resource_statistics_from_attrs(struct resource_statistics *s, struct genl_info *info); +int resource_statistics_ntb_from_attrs(struct nlattr ***ret_nested_attribute_table, struct genl_info *info); +int resource_statistics_to_skb(struct sk_buff *skb, struct resource_statistics *s); + +int device_statistics_from_attrs(struct device_statistics *s, struct genl_info *info); +int device_statistics_ntb_from_attrs(struct nlattr ***ret_nested_attribute_table, struct genl_info *info); +int device_statistics_to_skb(struct sk_buff *skb, struct device_statistics *s); + +int connection_statistics_from_attrs(struct connection_statistics *s, struct genl_info *info); +int connection_statistics_ntb_from_attrs(struct nlattr ***ret_nested_attribute_table, struct genl_info *info); +int connection_statistics_to_skb(struct sk_buff *skb, struct connection_statistics *s); + +int peer_device_statistics_from_attrs(struct peer_device_statistics *s, struct genl_info *info); +int peer_device_statistics_ntb_from_attrs(struct nlattr ***ret_nested_attribute_table, struct genl_info *info); +int peer_device_statistics_to_skb(struct sk_buff *skb, struct peer_device_statistics *s); + +int drbd_notification_header_to_skb(struct sk_buff *skb, struct drbd_notification_header *s); + +int drbd_helper_info_to_skb(struct sk_buff *skb, struct drbd_helper_info *s); + +#endif /* _LINUX_DRBD_GEN_H */ diff --git a/drivers/block/drbd/drbd_proc.c b/drivers/block/drbd/drbd_proc.c index 1d0feafceadc..6d0c12c10260 100644 --- a/drivers/block/drbd/drbd_proc.c +++ b/drivers/block/drbd/drbd_proc.c @@ -228,7 +228,7 @@ int drbd_seq_show(struct seq_file *seq, void *v) }; seq_printf(seq, "version: " REL_VERSION " (api:%d/proto:%d-%d)\n%s\n", - GENL_MAGIC_VERSION, PRO_VERSION_MIN, PRO_VERSION_MAX, drbd_buildtag()); + DRBD_FAMILY_VERSION, PRO_VERSION_MIN, PRO_VERSION_MAX, drbd_buildtag()); /* cs .. connection state diff --git a/include/linux/drbd_genl.h b/include/linux/drbd_genl.h deleted file mode 100644 index f53c534aba0c..000000000000 --- a/include/linux/drbd_genl.h +++ /dev/null @@ -1,536 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * General overview: - * full generic netlink message: - * |nlmsghdr|genlmsghdr| - * - * payload: - * |optional fixed size family header| - * - * sequence of netlink attributes: - * I chose to have all "top level" attributes NLA_NESTED, - * corresponding to some real struct. - * So we have a sequence of |tla, len| - * - * nested nla sequence: - * may be empty, or contain a sequence of netlink attributes - * representing the struct fields. - * - * The tag number of any field (regardless of containing struct) - * will be available as T_ ## field_name, - * so you cannot have the same field name in two differnt structs. - * - * The tag numbers themselves are per struct, though, - * so should always begin at 1 (not 0, that is the special "NLA_UNSPEC" type, - * which we won't use here). - * The tag numbers are used as index in the respective nla_policy array. - * - * GENL_struct(tag_name, tag_number, struct name, struct fields) - struct and policy - * genl_magic_struct.h - * generates the struct declaration, - * generates an entry in the tla enum, - * genl_magic_func.h - * generates an entry in the static tla policy - * with .type = NLA_NESTED - * generates the static _nl_policy definition, - * and static conversion functions - * - * genl_magic_func.h - * - * GENL_mc_group(group) - * genl_magic_struct.h - * does nothing - * genl_magic_func.h - * defines and registers the mcast group, - * and provides a send helper - * - * GENL_notification(op_name, op_num, mcast_group, tla list) - * These are notifications to userspace. - * - * genl_magic_struct.h - * generates an entry in the genl_ops enum, - * genl_magic_func.h - * does nothing - * - * mcast group: the name of the mcast group this notification should be - * expected on - * tla list: the list of expected top level attributes, - * for documentation and sanity checking. - * - * GENL_op(op_name, op_num, flags and handler, tla list) - "genl operations" - * These are requests from userspace. - * - * _op and _notification share the same "number space", - * op_nr will be assigned to "genlmsghdr->cmd" - * - * genl_magic_struct.h - * generates an entry in the genl_ops enum, - * genl_magic_func.h - * generates an entry in the static genl_ops array, - * and static register/unregister functions to - * genl_register_family(). - * - * flags and handler: - * GENL_op_init( .doit = x, .dumpit = y, .flags = something) - * GENL_doit(x) => .dumpit = NULL, .flags = GENL_ADMIN_PERM - * tla list: the list of expected top level attributes, - * for documentation and sanity checking. - */ - -/* - * STRUCTS - */ - -/* this is sent kernel -> userland on various error conditions, and contains - * informational textual info, which is supposedly human readable. - * The computer relevant return code is in the drbd_genlmsghdr. - */ -GENL_struct(DRBD_NLA_CFG_REPLY, 1, drbd_cfg_reply, - /* "arbitrary" size strings, nla_policy.len = 0 */ - __str_field(1, 0, info_text, 0) -) - -/* Configuration requests typically need a context to operate on. - * Possible keys are device minor (fits in the drbd_genlmsghdr), - * the replication link (aka connection) name, - * and/or the replication group (aka resource) name, - * and the volume id within the resource. */ -GENL_struct(DRBD_NLA_CFG_CONTEXT, 2, drbd_cfg_context, - __u32_field(1, 0, ctx_volume) - __str_field(2, 0, ctx_resource_name, 128) - __bin_field(3, 0, ctx_my_addr, 128) - __bin_field(4, 0, ctx_peer_addr, 128) -) - -GENL_struct(DRBD_NLA_DISK_CONF, 3, disk_conf, - __str_field(1, DRBD_F_REQUIRED | DRBD_F_INVARIANT, backing_dev, 128) - __str_field(2, DRBD_F_REQUIRED | DRBD_F_INVARIANT, meta_dev, 128) - __s32_field(3, DRBD_F_REQUIRED | DRBD_F_INVARIANT, meta_dev_idx) - - /* use the resize command to try and change the disk_size */ - __u64_field(4, DRBD_F_INVARIANT, disk_size) - /* we could change the max_bio_bvecs, - * but it won't propagate through the stack */ - __u32_field(5, DRBD_F_INVARIANT, max_bio_bvecs) - - __u32_field_def(6, 0, on_io_error, DRBD_ON_IO_ERROR_DEF) - __u32_field_def(7, 0, fencing, DRBD_FENCING_DEF) - - __u32_field_def(8, 0, resync_rate, DRBD_RESYNC_RATE_DEF) - __s32_field_def(9, 0, resync_after, DRBD_MINOR_NUMBER_DEF) - __u32_field_def(10, 0, al_extents, DRBD_AL_EXTENTS_DEF) - __u32_field_def(11, 0, c_plan_ahead, DRBD_C_PLAN_AHEAD_DEF) - __u32_field_def(12, 0, c_delay_target, DRBD_C_DELAY_TARGET_DEF) - __u32_field_def(13, 0, c_fill_target, DRBD_C_FILL_TARGET_DEF) - __u32_field_def(14, 0, c_max_rate, DRBD_C_MAX_RATE_DEF) - __u32_field_def(15, 0, c_min_rate, DRBD_C_MIN_RATE_DEF) - __u32_field_def(20, 0, disk_timeout, DRBD_DISK_TIMEOUT_DEF) - __u32_field_def(21, 0 /* OPTIONAL */, read_balancing, DRBD_READ_BALANCING_DEF) - __u32_field_def(25, 0 /* OPTIONAL */, rs_discard_granularity, DRBD_RS_DISCARD_GRANULARITY_DEF) - - __flg_field_def(16, 0, disk_barrier, DRBD_DISK_BARRIER_DEF) - __flg_field_def(17, 0, disk_flushes, DRBD_DISK_FLUSHES_DEF) - __flg_field_def(18, 0, disk_drain, DRBD_DISK_DRAIN_DEF) - __flg_field_def(19, 0, md_flushes, DRBD_MD_FLUSHES_DEF) - __flg_field_def(23, 0 /* OPTIONAL */, al_updates, DRBD_AL_UPDATES_DEF) - __flg_field_def(24, 0 /* OPTIONAL */, discard_zeroes_if_aligned, DRBD_DISCARD_ZEROES_IF_ALIGNED_DEF) - __flg_field_def(26, 0 /* OPTIONAL */, disable_write_same, DRBD_DISABLE_WRITE_SAME_DEF) -) - -GENL_struct(DRBD_NLA_RESOURCE_OPTS, 4, res_opts, - __str_field_def(1, 0, cpu_mask, DRBD_CPU_MASK_SIZE) - __u32_field_def(2, 0, on_no_data, DRBD_ON_NO_DATA_DEF) -) - -GENL_struct(DRBD_NLA_NET_CONF, 5, net_conf, - __str_field_def(1, DRBD_F_SENSITIVE, - shared_secret, SHARED_SECRET_MAX) - __str_field_def(2, 0, cram_hmac_alg, SHARED_SECRET_MAX) - __str_field_def(3, 0, integrity_alg, SHARED_SECRET_MAX) - __str_field_def(4, 0, verify_alg, SHARED_SECRET_MAX) - __str_field_def(5, 0, csums_alg, SHARED_SECRET_MAX) - __u32_field_def(6, 0, wire_protocol, DRBD_PROTOCOL_DEF) - __u32_field_def(7, 0, connect_int, DRBD_CONNECT_INT_DEF) - __u32_field_def(8, 0, timeout, DRBD_TIMEOUT_DEF) - __u32_field_def(9, 0, ping_int, DRBD_PING_INT_DEF) - __u32_field_def(10, 0, ping_timeo, DRBD_PING_TIMEO_DEF) - __u32_field_def(11, 0, sndbuf_size, DRBD_SNDBUF_SIZE_DEF) - __u32_field_def(12, 0, rcvbuf_size, DRBD_RCVBUF_SIZE_DEF) - __u32_field_def(13, 0, ko_count, DRBD_KO_COUNT_DEF) - __u32_field_def(14, 0, max_buffers, DRBD_MAX_BUFFERS_DEF) - __u32_field_def(15, 0, max_epoch_size, DRBD_MAX_EPOCH_SIZE_DEF) - __u32_field_def(16, 0, unplug_watermark, DRBD_UNPLUG_WATERMARK_DEF) - __u32_field_def(17, 0, after_sb_0p, DRBD_AFTER_SB_0P_DEF) - __u32_field_def(18, 0, after_sb_1p, DRBD_AFTER_SB_1P_DEF) - __u32_field_def(19, 0, after_sb_2p, DRBD_AFTER_SB_2P_DEF) - __u32_field_def(20, 0, rr_conflict, DRBD_RR_CONFLICT_DEF) - __u32_field_def(21, 0, on_congestion, DRBD_ON_CONGESTION_DEF) - __u32_field_def(22, 0, cong_fill, DRBD_CONG_FILL_DEF) - __u32_field_def(23, 0, cong_extents, DRBD_CONG_EXTENTS_DEF) - __flg_field_def(24, 0, two_primaries, DRBD_ALLOW_TWO_PRIMARIES_DEF) - __flg_field(25, DRBD_F_INVARIANT, discard_my_data) - __flg_field_def(26, 0, tcp_cork, DRBD_TCP_CORK_DEF) - __flg_field_def(27, 0, always_asbp, DRBD_ALWAYS_ASBP_DEF) - __flg_field(28, DRBD_F_INVARIANT, tentative) - __flg_field_def(29, 0, use_rle, DRBD_USE_RLE_DEF) - /* 9: __u32_field_def(30, 0, fencing_policy, DRBD_FENCING_DEF) */ - /* 9: __str_field_def(31, 0, name, SHARED_SECRET_MAX) */ - /* 9: __u32_field(32, DRBD_F_REQUIRED | DRBD_F_INVARIANT, peer_node_id) */ - __flg_field_def(33, 0 /* OPTIONAL */, csums_after_crash_only, DRBD_CSUMS_AFTER_CRASH_ONLY_DEF) - __u32_field_def(34, 0 /* OPTIONAL */, sock_check_timeo, DRBD_SOCKET_CHECK_TIMEO_DEF) -) - -GENL_struct(DRBD_NLA_SET_ROLE_PARMS, 6, set_role_parms, - __flg_field(1, 0, assume_uptodate) -) - -GENL_struct(DRBD_NLA_RESIZE_PARMS, 7, resize_parms, - __u64_field(1, 0, resize_size) - __flg_field(2, 0, resize_force) - __flg_field(3, 0, no_resync) - __u32_field_def(4, 0 /* OPTIONAL */, al_stripes, DRBD_AL_STRIPES_DEF) - __u32_field_def(5, 0 /* OPTIONAL */, al_stripe_size, DRBD_AL_STRIPE_SIZE_DEF) -) - -GENL_struct(DRBD_NLA_STATE_INFO, 8, state_info, - /* the reason of the broadcast, - * if this is an event triggered broadcast. */ - __u32_field(1, 0, sib_reason) - __u32_field(2, DRBD_F_REQUIRED, current_state) - __u64_field(3, 0, capacity) - __u64_field(4, 0, ed_uuid) - - /* These are for broadcast from after state change work. - * prev_state and new_state are from the moment the state change took - * place, new_state is not neccessarily the same as current_state, - * there may have been more state changes since. Which will be - * broadcasted soon, in their respective after state change work. */ - __u32_field(5, 0, prev_state) - __u32_field(6, 0, new_state) - - /* if we have a local disk: */ - __bin_field(7, 0, uuids, (UI_SIZE*sizeof(__u64))) - __u32_field(8, 0, disk_flags) - __u64_field(9, 0, bits_total) - __u64_field(10, 0, bits_oos) - /* and in case resync or online verify is active */ - __u64_field(11, 0, bits_rs_total) - __u64_field(12, 0, bits_rs_failed) - - /* for pre and post notifications of helper execution */ - __str_field(13, 0, helper, 32) - __u32_field(14, 0, helper_exit_code) - - __u64_field(15, 0, send_cnt) - __u64_field(16, 0, recv_cnt) - __u64_field(17, 0, read_cnt) - __u64_field(18, 0, writ_cnt) - __u64_field(19, 0, al_writ_cnt) - __u64_field(20, 0, bm_writ_cnt) - __u32_field(21, 0, ap_bio_cnt) - __u32_field(22, 0, ap_pending_cnt) - __u32_field(23, 0, rs_pending_cnt) -) - -GENL_struct(DRBD_NLA_START_OV_PARMS, 9, start_ov_parms, - __u64_field(1, 0, ov_start_sector) - __u64_field(2, 0, ov_stop_sector) -) - -GENL_struct(DRBD_NLA_NEW_C_UUID_PARMS, 10, new_c_uuid_parms, - __flg_field(1, 0, clear_bm) -) - -GENL_struct(DRBD_NLA_TIMEOUT_PARMS, 11, timeout_parms, - __u32_field(1, DRBD_F_REQUIRED, timeout_type) -) - -GENL_struct(DRBD_NLA_DISCONNECT_PARMS, 12, disconnect_parms, - __flg_field(1, 0, force_disconnect) -) - -GENL_struct(DRBD_NLA_DETACH_PARMS, 13, detach_parms, - __flg_field(1, 0, force_detach) -) - -GENL_struct(DRBD_NLA_RESOURCE_INFO, 15, resource_info, - __u32_field(1, 0, res_role) - __flg_field(2, 0, res_susp) - __flg_field(3, 0, res_susp_nod) - __flg_field(4, 0, res_susp_fen) - /* __flg_field(5, 0, res_weak) */ -) - -GENL_struct(DRBD_NLA_DEVICE_INFO, 16, device_info, - __u32_field(1, 0, dev_disk_state) -) - -GENL_struct(DRBD_NLA_CONNECTION_INFO, 17, connection_info, - __u32_field(1, 0, conn_connection_state) - __u32_field(2, 0, conn_role) -) - -GENL_struct(DRBD_NLA_PEER_DEVICE_INFO, 18, peer_device_info, - __u32_field(1, 0, peer_repl_state) - __u32_field(2, 0, peer_disk_state) - __u32_field(3, 0, peer_resync_susp_user) - __u32_field(4, 0, peer_resync_susp_peer) - __u32_field(5, 0, peer_resync_susp_dependency) -) - -GENL_struct(DRBD_NLA_RESOURCE_STATISTICS, 19, resource_statistics, - __u32_field(1, 0, res_stat_write_ordering) -) - -GENL_struct(DRBD_NLA_DEVICE_STATISTICS, 20, device_statistics, - __u64_field(1, 0, dev_size) /* (sectors) */ - __u64_field(2, 0, dev_read) /* (sectors) */ - __u64_field(3, 0, dev_write) /* (sectors) */ - __u64_field(4, 0, dev_al_writes) /* activity log writes (count) */ - __u64_field(5, 0, dev_bm_writes) /* bitmap writes (count) */ - __u32_field(6, 0, dev_upper_pending) /* application requests in progress */ - __u32_field(7, 0, dev_lower_pending) /* backing device requests in progress */ - __flg_field(8, 0, dev_upper_blocked) - __flg_field(9, 0, dev_lower_blocked) - __flg_field(10, 0, dev_al_suspended) /* activity log suspended */ - __u64_field(11, 0, dev_exposed_data_uuid) - __u64_field(12, 0, dev_current_uuid) - __u32_field(13, 0, dev_disk_flags) - __bin_field(14, 0, history_uuids, HISTORY_UUIDS * sizeof(__u64)) -) - -GENL_struct(DRBD_NLA_CONNECTION_STATISTICS, 21, connection_statistics, - __flg_field(1, 0, conn_congested) -) - -GENL_struct(DRBD_NLA_PEER_DEVICE_STATISTICS, 22, peer_device_statistics, - __u64_field(1, 0, peer_dev_received) /* sectors */ - __u64_field(2, 0, peer_dev_sent) /* sectors */ - __u32_field(3, 0, peer_dev_pending) /* number of requests */ - __u32_field(4, 0, peer_dev_unacked) /* number of requests */ - __u64_field(5, 0, peer_dev_out_of_sync) /* sectors */ - __u64_field(6, 0, peer_dev_resync_failed) /* sectors */ - __u64_field(7, 0, peer_dev_bitmap_uuid) - __u32_field(9, 0, peer_dev_flags) -) - -GENL_struct(DRBD_NLA_NOTIFICATION_HEADER, 23, drbd_notification_header, - __u32_field(1, 0, nh_type) -) - -GENL_struct(DRBD_NLA_HELPER, 24, drbd_helper_info, - __str_field(1, 0, helper_name, 32) - __u32_field(2, 0, helper_status) -) - -/* - * Notifications and commands (genlmsghdr->cmd) - */ -GENL_mc_group(events) - - /* kernel -> userspace announcement of changes */ -GENL_notification( - DRBD_EVENT, 1, events, - GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) - GENL_tla_expected(DRBD_NLA_STATE_INFO, DRBD_F_REQUIRED) - GENL_tla_expected(DRBD_NLA_NET_CONF, 0) - GENL_tla_expected(DRBD_NLA_DISK_CONF, 0) - GENL_tla_expected(DRBD_NLA_SYNCER_CONF, 0) -) - - /* query kernel for specific or all info */ -GENL_op( - DRBD_ADM_GET_STATUS, 2, - GENL_op_init( - .doit = drbd_adm_get_status, - .dumpit = drbd_adm_get_status_all, - /* anyone may ask for the status, - * it is broadcasted anyways */ - ), - /* To select the object .doit. - * Or a subset of objects in .dumpit. */ - GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, 0) -) - - /* add DRBD minor devices as volumes to resources */ -GENL_op(DRBD_ADM_NEW_MINOR, 5, GENL_doit(drbd_adm_new_minor), - GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED)) -GENL_op(DRBD_ADM_DEL_MINOR, 6, GENL_doit(drbd_adm_del_minor), - GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED)) - - /* add or delete resources */ -GENL_op(DRBD_ADM_NEW_RESOURCE, 7, GENL_doit(drbd_adm_new_resource), - GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED)) -GENL_op(DRBD_ADM_DEL_RESOURCE, 8, GENL_doit(drbd_adm_del_resource), - GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED)) - -GENL_op(DRBD_ADM_RESOURCE_OPTS, 9, - GENL_doit(drbd_adm_resource_opts), - GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) - GENL_tla_expected(DRBD_NLA_RESOURCE_OPTS, 0) -) - -GENL_op( - DRBD_ADM_CONNECT, 10, - GENL_doit(drbd_adm_connect), - GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) - GENL_tla_expected(DRBD_NLA_NET_CONF, DRBD_F_REQUIRED) -) - -GENL_op( - DRBD_ADM_CHG_NET_OPTS, 29, - GENL_doit(drbd_adm_net_opts), - GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) - GENL_tla_expected(DRBD_NLA_NET_CONF, DRBD_F_REQUIRED) -) - -GENL_op(DRBD_ADM_DISCONNECT, 11, GENL_doit(drbd_adm_disconnect), - GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED)) - -GENL_op(DRBD_ADM_ATTACH, 12, - GENL_doit(drbd_adm_attach), - GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) - GENL_tla_expected(DRBD_NLA_DISK_CONF, DRBD_F_REQUIRED) -) - -GENL_op(DRBD_ADM_CHG_DISK_OPTS, 28, - GENL_doit(drbd_adm_disk_opts), - GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) - GENL_tla_expected(DRBD_NLA_DISK_OPTS, DRBD_F_REQUIRED) -) - -GENL_op( - DRBD_ADM_RESIZE, 13, - GENL_doit(drbd_adm_resize), - GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) - GENL_tla_expected(DRBD_NLA_RESIZE_PARMS, 0) -) - -GENL_op( - DRBD_ADM_PRIMARY, 14, - GENL_doit(drbd_adm_set_role), - GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) - GENL_tla_expected(DRBD_NLA_SET_ROLE_PARMS, DRBD_F_REQUIRED) -) - -GENL_op( - DRBD_ADM_SECONDARY, 15, - GENL_doit(drbd_adm_set_role), - GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) - GENL_tla_expected(DRBD_NLA_SET_ROLE_PARMS, DRBD_F_REQUIRED) -) - -GENL_op( - DRBD_ADM_NEW_C_UUID, 16, - GENL_doit(drbd_adm_new_c_uuid), - GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) - GENL_tla_expected(DRBD_NLA_NEW_C_UUID_PARMS, 0) -) - -GENL_op( - DRBD_ADM_START_OV, 17, - GENL_doit(drbd_adm_start_ov), - GENL_tla_expected(DRBD_NLA_START_OV_PARMS, 0) -) - -GENL_op(DRBD_ADM_DETACH, 18, GENL_doit(drbd_adm_detach), - GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) - GENL_tla_expected(DRBD_NLA_DETACH_PARMS, 0)) - -GENL_op(DRBD_ADM_INVALIDATE, 19, GENL_doit(drbd_adm_invalidate), - GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED)) -GENL_op(DRBD_ADM_INVAL_PEER, 20, GENL_doit(drbd_adm_invalidate_peer), - GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED)) -GENL_op(DRBD_ADM_PAUSE_SYNC, 21, GENL_doit(drbd_adm_pause_sync), - GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED)) -GENL_op(DRBD_ADM_RESUME_SYNC, 22, GENL_doit(drbd_adm_resume_sync), - GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED)) -GENL_op(DRBD_ADM_SUSPEND_IO, 23, GENL_doit(drbd_adm_suspend_io), - GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED)) -GENL_op(DRBD_ADM_RESUME_IO, 24, GENL_doit(drbd_adm_resume_io), - GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED)) -GENL_op(DRBD_ADM_OUTDATE, 25, GENL_doit(drbd_adm_outdate), - GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED)) -GENL_op(DRBD_ADM_GET_TIMEOUT_TYPE, 26, GENL_doit(drbd_adm_get_timeout_type), - GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED)) -GENL_op(DRBD_ADM_DOWN, 27, GENL_doit(drbd_adm_down), - GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED)) - -GENL_op(DRBD_ADM_GET_RESOURCES, 30, - GENL_op_init( - .dumpit = drbd_adm_dump_resources, - ), - GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, 0) - GENL_tla_expected(DRBD_NLA_RESOURCE_INFO, 0) - GENL_tla_expected(DRBD_NLA_RESOURCE_STATISTICS, 0)) - -GENL_op(DRBD_ADM_GET_DEVICES, 31, - GENL_op_init( - .dumpit = drbd_adm_dump_devices, - .done = drbd_adm_dump_devices_done, - ), - GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, 0) - GENL_tla_expected(DRBD_NLA_DEVICE_INFO, 0) - GENL_tla_expected(DRBD_NLA_DEVICE_STATISTICS, 0)) - -GENL_op(DRBD_ADM_GET_CONNECTIONS, 32, - GENL_op_init( - .dumpit = drbd_adm_dump_connections, - .done = drbd_adm_dump_connections_done, - ), - GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, 0) - GENL_tla_expected(DRBD_NLA_CONNECTION_INFO, 0) - GENL_tla_expected(DRBD_NLA_CONNECTION_STATISTICS, 0)) - -GENL_op(DRBD_ADM_GET_PEER_DEVICES, 33, - GENL_op_init( - .dumpit = drbd_adm_dump_peer_devices, - .done = drbd_adm_dump_peer_devices_done, - ), - GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, 0) - GENL_tla_expected(DRBD_NLA_PEER_DEVICE_INFO, 0) - GENL_tla_expected(DRBD_NLA_PEER_DEVICE_STATISTICS, 0)) - -GENL_notification( - DRBD_RESOURCE_STATE, 34, events, - GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) - GENL_tla_expected(DRBD_NLA_NOTIFICATION_HEADER, DRBD_F_REQUIRED) - GENL_tla_expected(DRBD_NLA_RESOURCE_INFO, DRBD_F_REQUIRED) - GENL_tla_expected(DRBD_NLA_RESOURCE_STATISTICS, DRBD_F_REQUIRED)) - -GENL_notification( - DRBD_DEVICE_STATE, 35, events, - GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) - GENL_tla_expected(DRBD_NLA_NOTIFICATION_HEADER, DRBD_F_REQUIRED) - GENL_tla_expected(DRBD_NLA_DEVICE_INFO, DRBD_F_REQUIRED) - GENL_tla_expected(DRBD_NLA_DEVICE_STATISTICS, DRBD_F_REQUIRED)) - -GENL_notification( - DRBD_CONNECTION_STATE, 36, events, - GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) - GENL_tla_expected(DRBD_NLA_NOTIFICATION_HEADER, DRBD_F_REQUIRED) - GENL_tla_expected(DRBD_NLA_CONNECTION_INFO, DRBD_F_REQUIRED) - GENL_tla_expected(DRBD_NLA_CONNECTION_STATISTICS, DRBD_F_REQUIRED)) - -GENL_notification( - DRBD_PEER_DEVICE_STATE, 37, events, - GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) - GENL_tla_expected(DRBD_NLA_NOTIFICATION_HEADER, DRBD_F_REQUIRED) - GENL_tla_expected(DRBD_NLA_PEER_DEVICE_INFO, DRBD_F_REQUIRED) - GENL_tla_expected(DRBD_NLA_PEER_DEVICE_STATISTICS, DRBD_F_REQUIRED)) - -GENL_op( - DRBD_ADM_GET_INITIAL_STATE, 38, - GENL_op_init( - .dumpit = drbd_adm_get_initial_state, - ), - GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, 0)) - -GENL_notification( - DRBD_HELPER, 40, events, - GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED) - GENL_tla_expected(DRBD_NLA_HELPER, DRBD_F_REQUIRED)) - -GENL_notification( - DRBD_INITIAL_STATE_DONE, 41, events, - GENL_tla_expected(DRBD_NLA_NOTIFICATION_HEADER, DRBD_F_REQUIRED)) diff --git a/include/linux/drbd_genl_api.h b/include/linux/drbd_genl_api.h deleted file mode 100644 index 19d263924852..000000000000 --- a/include/linux/drbd_genl_api.h +++ /dev/null @@ -1,16 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef DRBD_GENL_STRUCT_H -#define DRBD_GENL_STRUCT_H - -/* hack around predefined gcc/cpp "linux=1", - * we cannot possibly include <1/drbd_genl.h> */ -#undef linux - -#include -#define GENL_MAGIC_VERSION 1 -#define GENL_MAGIC_FAMILY drbd -#define GENL_MAGIC_FAMILY_HDRSZ sizeof(struct drbd_genlmsghdr) -#define GENL_MAGIC_INCLUDE_FILE -#include - -#endif diff --git a/include/linux/genl_magic_func.h b/include/linux/genl_magic_func.h deleted file mode 100644 index a7d36c9ea924..000000000000 --- a/include/linux/genl_magic_func.h +++ /dev/null @@ -1,413 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef GENL_MAGIC_FUNC_H -#define GENL_MAGIC_FUNC_H - -#include -#include -#include - -/* - * Magic: declare tla policy {{{1 - * Magic: declare nested policies - * {{{2 - */ -#undef GENL_mc_group -#define GENL_mc_group(group) - -#undef GENL_notification -#define GENL_notification(op_name, op_num, mcast_group, tla_list) - -#undef GENL_op -#define GENL_op(op_name, op_num, handler, tla_list) - -#undef GENL_struct -#define GENL_struct(tag_name, tag_number, s_name, s_fields) \ - [tag_name] = { .type = NLA_NESTED }, - -static struct nla_policy CONCATENATE(GENL_MAGIC_FAMILY, _tla_nl_policy)[] = { -#include GENL_MAGIC_INCLUDE_FILE -}; - -#undef GENL_struct -#define GENL_struct(tag_name, tag_number, s_name, s_fields) \ -static struct nla_policy s_name ## _nl_policy[] __read_mostly = \ -{ s_fields }; - -#undef __field -#define __field(attr_nr, attr_flag, name, nla_type, _type, __get, \ - __put, __is_signed) \ - [attr_nr] = { .type = nla_type }, - -#undef __array -#define __array(attr_nr, attr_flag, name, nla_type, _type, maxlen, \ - __get, __put, __is_signed) \ - [attr_nr] = { .type = nla_type, \ - .len = maxlen - (nla_type == NLA_NUL_STRING) }, - -#include GENL_MAGIC_INCLUDE_FILE - -#ifndef __KERNEL__ -#ifndef pr_info -#define pr_info(args...) fprintf(stderr, args); -#endif -#endif - -#ifdef GENL_MAGIC_DEBUG -static void dprint_field(const char *dir, int nla_type, - const char *name, void *valp) -{ - __u64 val = valp ? *(__u32 *)valp : 1; - switch (nla_type) { - case NLA_U8: val = (__u8)val; - case NLA_U16: val = (__u16)val; - case NLA_U32: val = (__u32)val; - pr_info("%s attr %s: %d 0x%08x\n", dir, - name, (int)val, (unsigned)val); - break; - case NLA_U64: - val = *(__u64*)valp; - pr_info("%s attr %s: %lld 0x%08llx\n", dir, - name, (long long)val, (unsigned long long)val); - break; - case NLA_FLAG: - if (val) - pr_info("%s attr %s: set\n", dir, name); - break; - } -} - -static void dprint_array(const char *dir, int nla_type, - const char *name, const char *val, unsigned len) -{ - switch (nla_type) { - case NLA_NUL_STRING: - if (len && val[len-1] == '\0') - len--; - pr_info("%s attr %s: [len:%u] '%s'\n", dir, name, len, val); - break; - default: - /* we can always show 4 byte, - * thats what nlattr are aligned to. */ - pr_info("%s attr %s: [len:%u] %02x%02x%02x%02x ...\n", - dir, name, len, val[0], val[1], val[2], val[3]); - } -} - -#define DPRINT_TLA(a, op, b) pr_info("%s %s %s\n", a, op, b); - -/* Name is a member field name of the struct s. - * If s is NULL (only parsing, no copy requested in *_from_attrs()), - * nla is supposed to point to the attribute containing the information - * corresponding to that struct member. */ -#define DPRINT_FIELD(dir, nla_type, name, s, nla) \ - do { \ - if (s) \ - dprint_field(dir, nla_type, #name, &s->name); \ - else if (nla) \ - dprint_field(dir, nla_type, #name, \ - (nla_type == NLA_FLAG) ? NULL \ - : nla_data(nla)); \ - } while (0) - -#define DPRINT_ARRAY(dir, nla_type, name, s, nla) \ - do { \ - if (s) \ - dprint_array(dir, nla_type, #name, \ - s->name, s->name ## _len); \ - else if (nla) \ - dprint_array(dir, nla_type, #name, \ - nla_data(nla), nla_len(nla)); \ - } while (0) -#else -#define DPRINT_TLA(a, op, b) do {} while (0) -#define DPRINT_FIELD(dir, nla_type, name, s, nla) do {} while (0) -#define DPRINT_ARRAY(dir, nla_type, name, s, nla) do {} while (0) -#endif - -/* - * Magic: provide conversion functions {{{1 - * populate struct from attribute table: - * {{{2 - */ - -/* processing of generic netlink messages is serialized. - * use one static buffer for parsing of nested attributes */ -static struct nlattr *nested_attr_tb[128]; - -#undef GENL_struct -#define GENL_struct(tag_name, tag_number, s_name, s_fields) \ -/* *_from_attrs functions are static, but potentially unused */ \ -static int __ ## s_name ## _from_attrs(struct s_name *s, \ - struct genl_info *info, bool exclude_invariants) \ -{ \ - const int maxtype = ARRAY_SIZE(s_name ## _nl_policy)-1; \ - struct nlattr *tla = info->attrs[tag_number]; \ - struct nlattr **ntb = nested_attr_tb; \ - struct nlattr *nla; \ - int err; \ - BUILD_BUG_ON(ARRAY_SIZE(s_name ## _nl_policy) > ARRAY_SIZE(nested_attr_tb)); \ - if (!tla) \ - return -ENOMSG; \ - DPRINT_TLA(#s_name, "<=-", #tag_name); \ - err = nla_parse_nested_deprecated(ntb, maxtype, tla, \ - s_name ## _nl_policy, NULL); \ - if (err) \ - return err; \ - \ - s_fields \ - return 0; \ -} __attribute__((unused)) \ -static int s_name ## _from_attrs(struct s_name *s, \ - struct genl_info *info) \ -{ \ - return __ ## s_name ## _from_attrs(s, info, false); \ -} __attribute__((unused)) \ -static int s_name ## _from_attrs_for_change(struct s_name *s, \ - struct genl_info *info) \ -{ \ - return __ ## s_name ## _from_attrs(s, info, true); \ -} __attribute__((unused)) \ - -#define __assign(attr_nr, attr_flag, name, nla_type, type, assignment...) \ - nla = ntb[attr_nr]; \ - if (nla) { \ - if (exclude_invariants && !!((attr_flag) & DRBD_F_INVARIANT)) { \ - pr_info("<< must not change invariant attr: %s\n", #name); \ - return -EEXIST; \ - } \ - assignment; \ - } else if (exclude_invariants && !!((attr_flag) & DRBD_F_INVARIANT)) { \ - /* attribute missing from payload, */ \ - /* which was expected */ \ - } else if ((attr_flag) & DRBD_F_REQUIRED) { \ - pr_info("<< missing attr: %s\n", #name); \ - return -ENOMSG; \ - } - -#undef __field -#define __field(attr_nr, attr_flag, name, nla_type, type, __get, __put, \ - __is_signed) \ - __assign(attr_nr, attr_flag, name, nla_type, type, \ - if (s) \ - s->name = __get(nla); \ - DPRINT_FIELD("<<", nla_type, name, s, nla)) - -/* validate_nla() already checked nla_len <= maxlen appropriately. */ -#undef __array -#define __array(attr_nr, attr_flag, name, nla_type, type, maxlen, \ - __get, __put, __is_signed) \ - __assign(attr_nr, attr_flag, name, nla_type, type, \ - if (s) \ - s->name ## _len = \ - __get(s->name, nla, maxlen); \ - DPRINT_ARRAY("<<", nla_type, name, s, nla)) - -#include GENL_MAGIC_INCLUDE_FILE - -#undef GENL_struct -#define GENL_struct(tag_name, tag_number, s_name, s_fields) - -/* - * Magic: define op number to op name mapping {{{1 - * {{{2 - */ -static const char *CONCATENATE(GENL_MAGIC_FAMILY, _genl_cmd_to_str)(__u8 cmd) -{ - switch (cmd) { -#undef GENL_op -#define GENL_op(op_name, op_num, handler, tla_list) \ - case op_num: return #op_name; -#include GENL_MAGIC_INCLUDE_FILE - default: - return "unknown"; - } -} - -#ifdef __KERNEL__ -#include -/* - * Magic: define genl_ops {{{1 - * {{{2 - */ - -#undef GENL_op -#define GENL_op(op_name, op_num, handler, tla_list) \ -{ \ - handler \ - .cmd = op_name, \ -}, - -#define ZZZ_genl_ops CONCATENATE(GENL_MAGIC_FAMILY, _genl_ops) -static struct genl_ops ZZZ_genl_ops[] __read_mostly = { -#include GENL_MAGIC_INCLUDE_FILE -}; - -#undef GENL_op -#define GENL_op(op_name, op_num, handler, tla_list) - -/* - * Define the genl_family, multicast groups, {{{1 - * and provide register/unregister functions. - * {{{2 - */ -#define ZZZ_genl_family CONCATENATE(GENL_MAGIC_FAMILY, _genl_family) -static struct genl_family ZZZ_genl_family; -/* - * Magic: define multicast groups - * Magic: define multicast group registration helper - */ -#define ZZZ_genl_mcgrps CONCATENATE(GENL_MAGIC_FAMILY, _genl_mcgrps) -static const struct genl_multicast_group ZZZ_genl_mcgrps[] = { -#undef GENL_mc_group -#define GENL_mc_group(group) { .name = #group, }, -#include GENL_MAGIC_INCLUDE_FILE -}; - -enum CONCATENATE(GENL_MAGIC_FAMILY, group_ids) { -#undef GENL_mc_group -#define GENL_mc_group(group) CONCATENATE(GENL_MAGIC_FAMILY, _group_ ## group), -#include GENL_MAGIC_INCLUDE_FILE -}; - -#undef GENL_mc_group -#define GENL_mc_group(group) \ -static int CONCATENATE(GENL_MAGIC_FAMILY, _genl_multicast_ ## group)( \ - struct sk_buff *skb, gfp_t flags) \ -{ \ - unsigned int group_id = \ - CONCATENATE(GENL_MAGIC_FAMILY, _group_ ## group); \ - return genlmsg_multicast(&ZZZ_genl_family, skb, 0, \ - group_id, flags); \ -} - -#include GENL_MAGIC_INCLUDE_FILE - -#undef GENL_mc_group -#define GENL_mc_group(group) - -static struct genl_family ZZZ_genl_family __ro_after_init = { - .name = __stringify(GENL_MAGIC_FAMILY), - .version = GENL_MAGIC_VERSION, -#ifdef GENL_MAGIC_FAMILY_HDRSZ - .hdrsize = NLA_ALIGN(GENL_MAGIC_FAMILY_HDRSZ), -#endif - .maxattr = ARRAY_SIZE(CONCATENATE(GENL_MAGIC_FAMILY, _tla_nl_policy))-1, - .policy = CONCATENATE(GENL_MAGIC_FAMILY, _tla_nl_policy), -#ifdef GENL_MAGIC_FAMILY_PRE_DOIT - .pre_doit = GENL_MAGIC_FAMILY_PRE_DOIT, - .post_doit = GENL_MAGIC_FAMILY_POST_DOIT, -#endif - .ops = ZZZ_genl_ops, - .n_ops = ARRAY_SIZE(ZZZ_genl_ops), - .mcgrps = ZZZ_genl_mcgrps, - .resv_start_op = 42, /* drbd is currently the only user */ - .n_mcgrps = ARRAY_SIZE(ZZZ_genl_mcgrps), - .module = THIS_MODULE, -}; - -int CONCATENATE(GENL_MAGIC_FAMILY, _genl_register)(void) -{ - return genl_register_family(&ZZZ_genl_family); -} - -void CONCATENATE(GENL_MAGIC_FAMILY, _genl_unregister)(void) -{ - genl_unregister_family(&ZZZ_genl_family); -} - -/* - * Magic: provide conversion functions {{{1 - * populate skb from struct. - * {{{2 - */ - -#undef GENL_op -#define GENL_op(op_name, op_num, handler, tla_list) - -#undef GENL_struct -#define GENL_struct(tag_name, tag_number, s_name, s_fields) \ -static int s_name ## _to_skb(struct sk_buff *skb, struct s_name *s, \ - const bool exclude_sensitive) \ -{ \ - struct nlattr *tla = nla_nest_start(skb, tag_number); \ - if (!tla) \ - goto nla_put_failure; \ - DPRINT_TLA(#s_name, "-=>", #tag_name); \ - s_fields \ - nla_nest_end(skb, tla); \ - return 0; \ - \ -nla_put_failure: \ - if (tla) \ - nla_nest_cancel(skb, tla); \ - return -EMSGSIZE; \ -} \ -static inline int s_name ## _to_priv_skb(struct sk_buff *skb, \ - struct s_name *s) \ -{ \ - return s_name ## _to_skb(skb, s, 0); \ -} \ -static inline int s_name ## _to_unpriv_skb(struct sk_buff *skb, \ - struct s_name *s) \ -{ \ - return s_name ## _to_skb(skb, s, 1); \ -} - - -#undef __field -#define __field(attr_nr, attr_flag, name, nla_type, type, __get, __put, \ - __is_signed) \ - if (!exclude_sensitive || !((attr_flag) & DRBD_F_SENSITIVE)) { \ - DPRINT_FIELD(">>", nla_type, name, s, NULL); \ - if (__put(skb, attr_nr, s->name)) \ - goto nla_put_failure; \ - } - -#undef __array -#define __array(attr_nr, attr_flag, name, nla_type, type, maxlen, \ - __get, __put, __is_signed) \ - if (!exclude_sensitive || !((attr_flag) & DRBD_F_SENSITIVE)) { \ - DPRINT_ARRAY(">>",nla_type, name, s, NULL); \ - if (__put(skb, attr_nr, min_t(int, maxlen, \ - s->name ## _len + (nla_type == NLA_NUL_STRING)),\ - s->name)) \ - goto nla_put_failure; \ - } - -#include GENL_MAGIC_INCLUDE_FILE - - -/* Functions for initializing structs to default values. */ - -#undef __field -#define __field(attr_nr, attr_flag, name, nla_type, type, __get, __put, \ - __is_signed) -#undef __array -#define __array(attr_nr, attr_flag, name, nla_type, type, maxlen, \ - __get, __put, __is_signed) -#undef __u32_field_def -#define __u32_field_def(attr_nr, attr_flag, name, default) \ - x->name = default; -#undef __s32_field_def -#define __s32_field_def(attr_nr, attr_flag, name, default) \ - x->name = default; -#undef __flg_field_def -#define __flg_field_def(attr_nr, attr_flag, name, default) \ - x->name = default; -#undef __str_field_def -#define __str_field_def(attr_nr, attr_flag, name, maxlen) \ - memset(x->name, 0, sizeof(x->name)); \ - x->name ## _len = 0; -#undef GENL_struct -#define GENL_struct(tag_name, tag_number, s_name, s_fields) \ -static void set_ ## s_name ## _defaults(struct s_name *x) __attribute__((unused)); \ -static void set_ ## s_name ## _defaults(struct s_name *x) { \ -s_fields \ -} - -#include GENL_MAGIC_INCLUDE_FILE - -#endif /* __KERNEL__ */ - -/* }}}1 */ -#endif /* GENL_MAGIC_FUNC_H */ diff --git a/include/linux/genl_magic_struct.h b/include/linux/genl_magic_struct.h deleted file mode 100644 index 2200cedd160a..000000000000 --- a/include/linux/genl_magic_struct.h +++ /dev/null @@ -1,272 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef GENL_MAGIC_STRUCT_H -#define GENL_MAGIC_STRUCT_H - -#ifndef GENL_MAGIC_FAMILY -# error "you need to define GENL_MAGIC_FAMILY before inclusion" -#endif - -#ifndef GENL_MAGIC_VERSION -# error "you need to define GENL_MAGIC_VERSION before inclusion" -#endif - -#ifndef GENL_MAGIC_INCLUDE_FILE -# error "you need to define GENL_MAGIC_INCLUDE_FILE before inclusion" -#endif - -#include -#include -#include - -extern int CONCATENATE(GENL_MAGIC_FAMILY, _genl_register)(void); -extern void CONCATENATE(GENL_MAGIC_FAMILY, _genl_unregister)(void); - -/* - * Extension of genl attribute validation policies {{{2 - */ - -/* - * Flags specific to drbd and not visible at the netlink layer, used in - * _from_attrs and _to_skb: - * - * @DRBD_F_REQUIRED: Attribute is required; a request without this attribute is - * invalid. - * - * @DRBD_F_SENSITIVE: Attribute includes sensitive information and must not be - * included in unpriviledged get requests or broadcasts. - * - * @DRBD_F_INVARIANT: Attribute is set when an object is initially created, but - * cannot subsequently be changed. - */ -#define DRBD_F_REQUIRED (1 << 0) -#define DRBD_F_SENSITIVE (1 << 1) -#define DRBD_F_INVARIANT (1 << 2) - - -/* }}}1 - * MAGIC - * multi-include macro expansion magic starts here - */ - -/* MAGIC helpers {{{2 */ - -static inline int nla_put_u64_0pad(struct sk_buff *skb, int attrtype, u64 value) -{ - return nla_put_64bit(skb, attrtype, sizeof(u64), &value, 0); -} - -/* possible field types */ -#define __flg_field(attr_nr, attr_flag, name) \ - __field(attr_nr, attr_flag, name, NLA_U8, char, \ - nla_get_u8, nla_put_u8, false) -#define __u8_field(attr_nr, attr_flag, name) \ - __field(attr_nr, attr_flag, name, NLA_U8, unsigned char, \ - nla_get_u8, nla_put_u8, false) -#define __u16_field(attr_nr, attr_flag, name) \ - __field(attr_nr, attr_flag, name, NLA_U16, __u16, \ - nla_get_u16, nla_put_u16, false) -#define __u32_field(attr_nr, attr_flag, name) \ - __field(attr_nr, attr_flag, name, NLA_U32, __u32, \ - nla_get_u32, nla_put_u32, false) -#define __s32_field(attr_nr, attr_flag, name) \ - __field(attr_nr, attr_flag, name, NLA_U32, __s32, \ - nla_get_u32, nla_put_u32, true) -#define __u64_field(attr_nr, attr_flag, name) \ - __field(attr_nr, attr_flag, name, NLA_U64, __u64, \ - nla_get_u64, nla_put_u64_0pad, false) -#define __str_field(attr_nr, attr_flag, name, maxlen) \ - __array(attr_nr, attr_flag, name, NLA_NUL_STRING, char, maxlen, \ - nla_strscpy, nla_put, false) -#define __bin_field(attr_nr, attr_flag, name, maxlen) \ - __array(attr_nr, attr_flag, name, NLA_BINARY, char, maxlen, \ - nla_memcpy, nla_put, false) - -/* fields with default values */ -#define __flg_field_def(attr_nr, attr_flag, name, default) \ - __flg_field(attr_nr, attr_flag, name) -#define __u32_field_def(attr_nr, attr_flag, name, default) \ - __u32_field(attr_nr, attr_flag, name) -#define __s32_field_def(attr_nr, attr_flag, name, default) \ - __s32_field(attr_nr, attr_flag, name) -#define __str_field_def(attr_nr, attr_flag, name, maxlen) \ - __str_field(attr_nr, attr_flag, name, maxlen) - -#define GENL_op_init(args...) args -#define GENL_doit(handler) \ - .doit = handler, \ - .flags = GENL_ADMIN_PERM, -#define GENL_dumpit(handler) \ - .dumpit = handler, \ - .flags = GENL_ADMIN_PERM, - -/* }}}1 - * Magic: define the enum symbols for genl_ops - * Magic: define the enum symbols for top level attributes - * Magic: define the enum symbols for nested attributes - * {{{2 - */ - -#undef GENL_struct -#define GENL_struct(tag_name, tag_number, s_name, s_fields) - -#undef GENL_mc_group -#define GENL_mc_group(group) - -#undef GENL_notification -#define GENL_notification(op_name, op_num, mcast_group, tla_list) \ - op_name = op_num, - -#undef GENL_op -#define GENL_op(op_name, op_num, handler, tla_list) \ - op_name = op_num, - -enum { -#include GENL_MAGIC_INCLUDE_FILE -}; - -#undef GENL_notification -#define GENL_notification(op_name, op_num, mcast_group, tla_list) - -#undef GENL_op -#define GENL_op(op_name, op_num, handler, attr_list) - -#undef GENL_struct -#define GENL_struct(tag_name, tag_number, s_name, s_fields) \ - tag_name = tag_number, - -enum { -#include GENL_MAGIC_INCLUDE_FILE -}; - -#undef GENL_struct -#define GENL_struct(tag_name, tag_number, s_name, s_fields) \ -enum { \ - s_fields \ -}; - -#undef __field -#define __field(attr_nr, attr_flag, name, nla_type, type, \ - __get, __put, __is_signed) \ - T_ ## name = (__u16)(attr_nr), - -#undef __array -#define __array(attr_nr, attr_flag, name, nla_type, type, \ - maxlen, __get, __put, __is_signed) \ - T_ ## name = (__u16)(attr_nr), - -#include GENL_MAGIC_INCLUDE_FILE - -/* }}}1 - * Magic: compile time assert unique numbers for operations - * Magic: -"- unique numbers for top level attributes - * Magic: -"- unique numbers for nested attributes - * {{{2 - */ - -#undef GENL_struct -#define GENL_struct(tag_name, tag_number, s_name, s_fields) - -#undef GENL_op -#define GENL_op(op_name, op_num, handler, attr_list) \ - case op_name: - -#undef GENL_notification -#define GENL_notification(op_name, op_num, mcast_group, tla_list) \ - case op_name: - -static inline void ct_assert_unique_operations(void) -{ - switch (0) { -#include GENL_MAGIC_INCLUDE_FILE - case 0: - ; - } -} - -#undef GENL_op -#define GENL_op(op_name, op_num, handler, attr_list) - -#undef GENL_notification -#define GENL_notification(op_name, op_num, mcast_group, tla_list) - -#undef GENL_struct -#define GENL_struct(tag_name, tag_number, s_name, s_fields) \ - case tag_number: - -static inline void ct_assert_unique_top_level_attributes(void) -{ - switch (0) { -#include GENL_MAGIC_INCLUDE_FILE - case 0: - ; - } -} - -#undef GENL_struct -#define GENL_struct(tag_name, tag_number, s_name, s_fields) \ -static inline void ct_assert_unique_ ## s_name ## _attributes(void) \ -{ \ - switch (0) { \ - s_fields \ - case 0: \ - ; \ - } \ -} - -#undef __field -#define __field(attr_nr, attr_flag, name, nla_type, type, __get, __put, \ - __is_signed) \ - case attr_nr: - -#undef __array -#define __array(attr_nr, attr_flag, name, nla_type, type, maxlen, \ - __get, __put, __is_signed) \ - case attr_nr: - -#include GENL_MAGIC_INCLUDE_FILE - -/* }}}1 - * Magic: declare structs - * struct { - * fields - * }; - * {{{2 - */ - -#undef GENL_struct -#define GENL_struct(tag_name, tag_number, s_name, s_fields) \ -struct s_name { s_fields }; - -#undef __field -#define __field(attr_nr, attr_flag, name, nla_type, type, __get, __put, \ - __is_signed) \ - type name; - -#undef __array -#define __array(attr_nr, attr_flag, name, nla_type, type, maxlen, \ - __get, __put, __is_signed) \ - type name[maxlen]; \ - __u32 name ## _len; - -#include GENL_MAGIC_INCLUDE_FILE - -#undef GENL_struct -#define GENL_struct(tag_name, tag_number, s_name, s_fields) \ -enum { \ - s_fields \ -}; - -#undef __field -#define __field(attr_nr, attr_flag, name, nla_type, type, __get, __put, \ - is_signed) \ - F_ ## name ## _IS_SIGNED = is_signed, - -#undef __array -#define __array(attr_nr, attr_flag, name, nla_type, type, maxlen, \ - __get, __put, is_signed) \ - F_ ## name ## _IS_SIGNED = is_signed, - -#include GENL_MAGIC_INCLUDE_FILE - -/* }}}1 */ -#endif /* GENL_MAGIC_STRUCT_H */ diff --git a/include/uapi/linux/drbd.h b/include/uapi/linux/drbd.h index 7930a972d8a4..5d4d677cf1ad 100644 --- a/include/uapi/linux/drbd.h +++ b/include/uapi/linux/drbd.h @@ -333,6 +333,9 @@ enum drbd_uuid_index { #define HISTORY_UUIDS MAX_PEERS +#define DRBD_NL_UUIDS_SIZE (UI_SIZE * sizeof(__u64)) +#define DRBD_NL_HISTORY_UUIDS_SIZE (HISTORY_UUIDS * sizeof(__u64)) + enum drbd_timeout_flag { UT_DEFAULT = 0, UT_DEGRADED = 1, diff --git a/include/uapi/linux/drbd_genl.h b/include/uapi/linux/drbd_genl.h new file mode 100644 index 000000000000..8b25f08d8a90 --- /dev/null +++ b/include/uapi/linux/drbd_genl.h @@ -0,0 +1,359 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ + +#ifndef _UAPI_LINUX_DRBD_GENL_H +#define _UAPI_LINUX_DRBD_GENL_H + +#define DRBD_FAMILY_NAME "drbd" +#define DRBD_FAMILY_VERSION 1 + +enum { + DRBD_NLA_CFG_REPLY = 1, + DRBD_NLA_CFG_CONTEXT, + DRBD_NLA_DISK_CONF, + DRBD_NLA_RESOURCE_OPTS, + DRBD_NLA_NET_CONF, + DRBD_NLA_SET_ROLE_PARMS, + DRBD_NLA_RESIZE_PARMS, + DRBD_NLA_STATE_INFO, + DRBD_NLA_START_OV_PARMS, + DRBD_NLA_NEW_C_UUID_PARMS, + DRBD_NLA_TIMEOUT_PARMS, + DRBD_NLA_DISCONNECT_PARMS, + DRBD_NLA_DETACH_PARMS, + DRBD_NLA_RESOURCE_INFO = 15, + DRBD_NLA_DEVICE_INFO, + DRBD_NLA_CONNECTION_INFO, + DRBD_NLA_PEER_DEVICE_INFO, + DRBD_NLA_RESOURCE_STATISTICS, + DRBD_NLA_DEVICE_STATISTICS, + DRBD_NLA_CONNECTION_STATISTICS, + DRBD_NLA_PEER_DEVICE_STATISTICS, + DRBD_NLA_NOTIFICATION_HEADER, + DRBD_NLA_HELPER, + + __DRBD_NLA_MAX, + DRBD_NLA_MAX = (__DRBD_NLA_MAX - 1) +}; + +enum { + DRBD_A_DRBD_CFG_REPLY_INFO_TEXT = 1, + + __DRBD_A_DRBD_CFG_REPLY_MAX, + DRBD_A_DRBD_CFG_REPLY_MAX = (__DRBD_A_DRBD_CFG_REPLY_MAX - 1) +}; + +enum { + DRBD_A_DRBD_CFG_CONTEXT_CTX_VOLUME = 1, + DRBD_A_DRBD_CFG_CONTEXT_CTX_RESOURCE_NAME, + DRBD_A_DRBD_CFG_CONTEXT_CTX_MY_ADDR, + DRBD_A_DRBD_CFG_CONTEXT_CTX_PEER_ADDR, + + __DRBD_A_DRBD_CFG_CONTEXT_MAX, + DRBD_A_DRBD_CFG_CONTEXT_MAX = (__DRBD_A_DRBD_CFG_CONTEXT_MAX - 1) +}; + +enum { + DRBD_A_DISK_CONF_BACKING_DEV = 1, + DRBD_A_DISK_CONF_META_DEV, + DRBD_A_DISK_CONF_META_DEV_IDX, + DRBD_A_DISK_CONF_DISK_SIZE, + DRBD_A_DISK_CONF_MAX_BIO_BVECS, + DRBD_A_DISK_CONF_ON_IO_ERROR, + DRBD_A_DISK_CONF_FENCING, + DRBD_A_DISK_CONF_RESYNC_RATE, + DRBD_A_DISK_CONF_RESYNC_AFTER, + DRBD_A_DISK_CONF_AL_EXTENTS, + DRBD_A_DISK_CONF_C_PLAN_AHEAD, + DRBD_A_DISK_CONF_C_DELAY_TARGET, + DRBD_A_DISK_CONF_C_FILL_TARGET, + DRBD_A_DISK_CONF_C_MAX_RATE, + DRBD_A_DISK_CONF_C_MIN_RATE, + DRBD_A_DISK_CONF_DISK_BARRIER, + DRBD_A_DISK_CONF_DISK_FLUSHES, + DRBD_A_DISK_CONF_DISK_DRAIN, + DRBD_A_DISK_CONF_MD_FLUSHES, + DRBD_A_DISK_CONF_DISK_TIMEOUT, + DRBD_A_DISK_CONF_READ_BALANCING, + DRBD_A_DISK_CONF_AL_UPDATES = 23, + DRBD_A_DISK_CONF_DISCARD_ZEROES_IF_ALIGNED, + DRBD_A_DISK_CONF_RS_DISCARD_GRANULARITY, + DRBD_A_DISK_CONF_DISABLE_WRITE_SAME, + + __DRBD_A_DISK_CONF_MAX, + DRBD_A_DISK_CONF_MAX = (__DRBD_A_DISK_CONF_MAX - 1) +}; + +enum { + DRBD_A_RES_OPTS_CPU_MASK = 1, + DRBD_A_RES_OPTS_ON_NO_DATA, + + __DRBD_A_RES_OPTS_MAX, + DRBD_A_RES_OPTS_MAX = (__DRBD_A_RES_OPTS_MAX - 1) +}; + +enum { + DRBD_A_NET_CONF_SHARED_SECRET = 1, + DRBD_A_NET_CONF_CRAM_HMAC_ALG, + DRBD_A_NET_CONF_INTEGRITY_ALG, + DRBD_A_NET_CONF_VERIFY_ALG, + DRBD_A_NET_CONF_CSUMS_ALG, + DRBD_A_NET_CONF_WIRE_PROTOCOL, + DRBD_A_NET_CONF_CONNECT_INT, + DRBD_A_NET_CONF_TIMEOUT, + DRBD_A_NET_CONF_PING_INT, + DRBD_A_NET_CONF_PING_TIMEO, + DRBD_A_NET_CONF_SNDBUF_SIZE, + DRBD_A_NET_CONF_RCVBUF_SIZE, + DRBD_A_NET_CONF_KO_COUNT, + DRBD_A_NET_CONF_MAX_BUFFERS, + DRBD_A_NET_CONF_MAX_EPOCH_SIZE, + DRBD_A_NET_CONF_UNPLUG_WATERMARK, + DRBD_A_NET_CONF_AFTER_SB_0P, + DRBD_A_NET_CONF_AFTER_SB_1P, + DRBD_A_NET_CONF_AFTER_SB_2P, + DRBD_A_NET_CONF_RR_CONFLICT, + DRBD_A_NET_CONF_ON_CONGESTION, + DRBD_A_NET_CONF_CONG_FILL, + DRBD_A_NET_CONF_CONG_EXTENTS, + DRBD_A_NET_CONF_TWO_PRIMARIES, + DRBD_A_NET_CONF_DISCARD_MY_DATA, + DRBD_A_NET_CONF_TCP_CORK, + DRBD_A_NET_CONF_ALWAYS_ASBP, + DRBD_A_NET_CONF_TENTATIVE, + DRBD_A_NET_CONF_USE_RLE, + DRBD_A_NET_CONF_CSUMS_AFTER_CRASH_ONLY = 33, + DRBD_A_NET_CONF_SOCK_CHECK_TIMEO, + + __DRBD_A_NET_CONF_MAX, + DRBD_A_NET_CONF_MAX = (__DRBD_A_NET_CONF_MAX - 1) +}; + +enum { + DRBD_A_SET_ROLE_PARMS_ASSUME_UPTODATE = 1, + + __DRBD_A_SET_ROLE_PARMS_MAX, + DRBD_A_SET_ROLE_PARMS_MAX = (__DRBD_A_SET_ROLE_PARMS_MAX - 1) +}; + +enum { + DRBD_A_RESIZE_PARMS_RESIZE_SIZE = 1, + DRBD_A_RESIZE_PARMS_RESIZE_FORCE, + DRBD_A_RESIZE_PARMS_NO_RESYNC, + DRBD_A_RESIZE_PARMS_AL_STRIPES, + DRBD_A_RESIZE_PARMS_AL_STRIPE_SIZE, + + __DRBD_A_RESIZE_PARMS_MAX, + DRBD_A_RESIZE_PARMS_MAX = (__DRBD_A_RESIZE_PARMS_MAX - 1) +}; + +enum { + DRBD_A_STATE_INFO_SIB_REASON = 1, + DRBD_A_STATE_INFO_CURRENT_STATE, + DRBD_A_STATE_INFO_CAPACITY, + DRBD_A_STATE_INFO_ED_UUID, + DRBD_A_STATE_INFO_PREV_STATE, + DRBD_A_STATE_INFO_NEW_STATE, + DRBD_A_STATE_INFO_UUIDS, + DRBD_A_STATE_INFO_DISK_FLAGS, + DRBD_A_STATE_INFO_BITS_TOTAL, + DRBD_A_STATE_INFO_BITS_OOS, + DRBD_A_STATE_INFO_BITS_RS_TOTAL, + DRBD_A_STATE_INFO_BITS_RS_FAILED, + DRBD_A_STATE_INFO_HELPER, + DRBD_A_STATE_INFO_HELPER_EXIT_CODE, + DRBD_A_STATE_INFO_SEND_CNT, + DRBD_A_STATE_INFO_RECV_CNT, + DRBD_A_STATE_INFO_READ_CNT, + DRBD_A_STATE_INFO_WRIT_CNT, + DRBD_A_STATE_INFO_AL_WRIT_CNT, + DRBD_A_STATE_INFO_BM_WRIT_CNT, + DRBD_A_STATE_INFO_AP_BIO_CNT, + DRBD_A_STATE_INFO_AP_PENDING_CNT, + DRBD_A_STATE_INFO_RS_PENDING_CNT, + + __DRBD_A_STATE_INFO_MAX, + DRBD_A_STATE_INFO_MAX = (__DRBD_A_STATE_INFO_MAX - 1) +}; + +enum { + DRBD_A_START_OV_PARMS_OV_START_SECTOR = 1, + DRBD_A_START_OV_PARMS_OV_STOP_SECTOR, + + __DRBD_A_START_OV_PARMS_MAX, + DRBD_A_START_OV_PARMS_MAX = (__DRBD_A_START_OV_PARMS_MAX - 1) +}; + +enum { + DRBD_A_NEW_C_UUID_PARMS_CLEAR_BM = 1, + + __DRBD_A_NEW_C_UUID_PARMS_MAX, + DRBD_A_NEW_C_UUID_PARMS_MAX = (__DRBD_A_NEW_C_UUID_PARMS_MAX - 1) +}; + +enum { + DRBD_A_TIMEOUT_PARMS_TIMEOUT_TYPE = 1, + + __DRBD_A_TIMEOUT_PARMS_MAX, + DRBD_A_TIMEOUT_PARMS_MAX = (__DRBD_A_TIMEOUT_PARMS_MAX - 1) +}; + +enum { + DRBD_A_DISCONNECT_PARMS_FORCE_DISCONNECT = 1, + + __DRBD_A_DISCONNECT_PARMS_MAX, + DRBD_A_DISCONNECT_PARMS_MAX = (__DRBD_A_DISCONNECT_PARMS_MAX - 1) +}; + +enum { + DRBD_A_DETACH_PARMS_FORCE_DETACH = 1, + + __DRBD_A_DETACH_PARMS_MAX, + DRBD_A_DETACH_PARMS_MAX = (__DRBD_A_DETACH_PARMS_MAX - 1) +}; + +enum { + DRBD_A_RESOURCE_INFO_RES_ROLE = 1, + DRBD_A_RESOURCE_INFO_RES_SUSP, + DRBD_A_RESOURCE_INFO_RES_SUSP_NOD, + DRBD_A_RESOURCE_INFO_RES_SUSP_FEN, + + __DRBD_A_RESOURCE_INFO_MAX, + DRBD_A_RESOURCE_INFO_MAX = (__DRBD_A_RESOURCE_INFO_MAX - 1) +}; + +enum { + DRBD_A_DEVICE_INFO_DEV_DISK_STATE = 1, + + __DRBD_A_DEVICE_INFO_MAX, + DRBD_A_DEVICE_INFO_MAX = (__DRBD_A_DEVICE_INFO_MAX - 1) +}; + +enum { + DRBD_A_CONNECTION_INFO_CONN_CONNECTION_STATE = 1, + DRBD_A_CONNECTION_INFO_CONN_ROLE, + + __DRBD_A_CONNECTION_INFO_MAX, + DRBD_A_CONNECTION_INFO_MAX = (__DRBD_A_CONNECTION_INFO_MAX - 1) +}; + +enum { + DRBD_A_PEER_DEVICE_INFO_PEER_REPL_STATE = 1, + DRBD_A_PEER_DEVICE_INFO_PEER_DISK_STATE, + DRBD_A_PEER_DEVICE_INFO_PEER_RESYNC_SUSP_USER, + DRBD_A_PEER_DEVICE_INFO_PEER_RESYNC_SUSP_PEER, + DRBD_A_PEER_DEVICE_INFO_PEER_RESYNC_SUSP_DEPENDENCY, + + __DRBD_A_PEER_DEVICE_INFO_MAX, + DRBD_A_PEER_DEVICE_INFO_MAX = (__DRBD_A_PEER_DEVICE_INFO_MAX - 1) +}; + +enum { + DRBD_A_RESOURCE_STATISTICS_RES_STAT_WRITE_ORDERING = 1, + + __DRBD_A_RESOURCE_STATISTICS_MAX, + DRBD_A_RESOURCE_STATISTICS_MAX = (__DRBD_A_RESOURCE_STATISTICS_MAX - 1) +}; + +enum { + DRBD_A_DEVICE_STATISTICS_DEV_SIZE = 1, + DRBD_A_DEVICE_STATISTICS_DEV_READ, + DRBD_A_DEVICE_STATISTICS_DEV_WRITE, + DRBD_A_DEVICE_STATISTICS_DEV_AL_WRITES, + DRBD_A_DEVICE_STATISTICS_DEV_BM_WRITES, + DRBD_A_DEVICE_STATISTICS_DEV_UPPER_PENDING, + DRBD_A_DEVICE_STATISTICS_DEV_LOWER_PENDING, + DRBD_A_DEVICE_STATISTICS_DEV_UPPER_BLOCKED, + DRBD_A_DEVICE_STATISTICS_DEV_LOWER_BLOCKED, + DRBD_A_DEVICE_STATISTICS_DEV_AL_SUSPENDED, + DRBD_A_DEVICE_STATISTICS_DEV_EXPOSED_DATA_UUID, + DRBD_A_DEVICE_STATISTICS_DEV_CURRENT_UUID, + DRBD_A_DEVICE_STATISTICS_DEV_DISK_FLAGS, + DRBD_A_DEVICE_STATISTICS_HISTORY_UUIDS, + + __DRBD_A_DEVICE_STATISTICS_MAX, + DRBD_A_DEVICE_STATISTICS_MAX = (__DRBD_A_DEVICE_STATISTICS_MAX - 1) +}; + +enum { + DRBD_A_CONNECTION_STATISTICS_CONN_CONGESTED = 1, + + __DRBD_A_CONNECTION_STATISTICS_MAX, + DRBD_A_CONNECTION_STATISTICS_MAX = (__DRBD_A_CONNECTION_STATISTICS_MAX - 1) +}; + +enum { + DRBD_A_PEER_DEVICE_STATISTICS_PEER_DEV_RECEIVED = 1, + DRBD_A_PEER_DEVICE_STATISTICS_PEER_DEV_SENT, + DRBD_A_PEER_DEVICE_STATISTICS_PEER_DEV_PENDING, + DRBD_A_PEER_DEVICE_STATISTICS_PEER_DEV_UNACKED, + DRBD_A_PEER_DEVICE_STATISTICS_PEER_DEV_OUT_OF_SYNC, + DRBD_A_PEER_DEVICE_STATISTICS_PEER_DEV_RESYNC_FAILED, + DRBD_A_PEER_DEVICE_STATISTICS_PEER_DEV_BITMAP_UUID, + DRBD_A_PEER_DEVICE_STATISTICS_PEER_DEV_FLAGS = 9, + + __DRBD_A_PEER_DEVICE_STATISTICS_MAX, + DRBD_A_PEER_DEVICE_STATISTICS_MAX = (__DRBD_A_PEER_DEVICE_STATISTICS_MAX - 1) +}; + +enum { + DRBD_A_DRBD_NOTIFICATION_HEADER_NH_TYPE = 1, + + __DRBD_A_DRBD_NOTIFICATION_HEADER_MAX, + DRBD_A_DRBD_NOTIFICATION_HEADER_MAX = (__DRBD_A_DRBD_NOTIFICATION_HEADER_MAX - 1) +}; + +enum { + DRBD_A_DRBD_HELPER_INFO_HELPER_NAME = 1, + DRBD_A_DRBD_HELPER_INFO_HELPER_STATUS, + + __DRBD_A_DRBD_HELPER_INFO_MAX, + DRBD_A_DRBD_HELPER_INFO_MAX = (__DRBD_A_DRBD_HELPER_INFO_MAX - 1) +}; + +enum { + DRBD_ADM_EVENT = 1, + DRBD_ADM_GET_STATUS, + DRBD_ADM_NEW_MINOR = 5, + DRBD_ADM_DEL_MINOR, + DRBD_ADM_NEW_RESOURCE, + DRBD_ADM_DEL_RESOURCE, + DRBD_ADM_RESOURCE_OPTS, + DRBD_ADM_CONNECT, + DRBD_ADM_DISCONNECT, + DRBD_ADM_ATTACH, + DRBD_ADM_RESIZE, + DRBD_ADM_PRIMARY, + DRBD_ADM_SECONDARY, + DRBD_ADM_NEW_C_UUID, + DRBD_ADM_START_OV, + DRBD_ADM_DETACH, + DRBD_ADM_INVALIDATE, + DRBD_ADM_INVAL_PEER, + DRBD_ADM_PAUSE_SYNC, + DRBD_ADM_RESUME_SYNC, + DRBD_ADM_SUSPEND_IO, + DRBD_ADM_RESUME_IO, + DRBD_ADM_OUTDATE, + DRBD_ADM_GET_TIMEOUT_TYPE, + DRBD_ADM_DOWN, + DRBD_ADM_CHG_DISK_OPTS, + DRBD_ADM_CHG_NET_OPTS, + DRBD_ADM_GET_RESOURCES, + DRBD_ADM_GET_DEVICES, + DRBD_ADM_GET_CONNECTIONS, + DRBD_ADM_GET_PEER_DEVICES, + DRBD_ADM_RESOURCE_STATE, + DRBD_ADM_DEVICE_STATE, + DRBD_ADM_CONNECTION_STATE, + DRBD_ADM_PEER_DEVICE_STATE, + DRBD_ADM_GET_INITIAL_STATE, + DRBD_ADM_HELPER = 40, + DRBD_ADM_INITIAL_STATE_DONE, + + __DRBD_ADM_MAX, + DRBD_ADM_MAX = (__DRBD_ADM_MAX - 1) +}; + +#define DRBD_MCGRP_EVENTS "events" + +#endif /* _UAPI_LINUX_DRBD_GENL_H */ -- cgit v1.2.3 From d5607f1fafd7eb72ed693b6a033d96221e870edd Mon Sep 17 00:00:00 2001 From: Christoph Böhmwalder Date: Wed, 13 May 2026 13:03:42 +0200 Subject: drbd: clean up UAPI headers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit b1798910fc7f ("drbd: move UAPI headers to include/uapi/linux/") broke compilation on targets without a hosted libc: ./usr/include/linux/drbd.h:18:10: fatal error: sys/types.h: No such file or directory The underlying issue is that there were some constructs left over in those headers that don't belong in uapi. Drop the __KERNEL__-gated split in drbd.h. The !__KERNEL__ branch pulls in , and for symbols that the header does not actually reference; they were carried over from when this lived in include/linux/. Replace and the entire #ifdef block with the standard UAPI combo + , which provides __u32/__u64/__s32 and __{LITTLE,BIG}_ENDIAN_BITFIELD in both kernel and userspace contexts. drbd_limits.h references some enum values and the DRBD_PROT_C define from drbd.h, but does not include it. Add the missing include while we're here. Drop the unprefixed DEBUG_RANGE_CHECK from drbd_limits.h. It has no in-kernel users and pollutes the userspace namespace. Switch the drbd.h and drbd_limits.h include guards to the _UAPI_LINUX_* convention already used by drbd_genl.h. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202605101346.V2wwJqv1-lkp@intel.com/ Fixes: b1798910fc7f ("drbd: move UAPI headers to include/uapi/linux/") Signed-off-by: Christoph Böhmwalder Link: https://patch.msgid.link/20260513110343.3170338-1-christoph.boehmwalder@linbit.com Signed-off-by: Jens Axboe --- include/uapi/linux/drbd.h | 28 +++------------------------- include/uapi/linux/drbd_limits.h | 8 ++++---- 2 files changed, 7 insertions(+), 29 deletions(-) (limited to 'include') diff --git a/include/uapi/linux/drbd.h b/include/uapi/linux/drbd.h index 5d4d677cf1ad..cf1ec3eb872f 100644 --- a/include/uapi/linux/drbd.h +++ b/include/uapi/linux/drbd.h @@ -11,32 +11,10 @@ */ -#ifndef DRBD_H -#define DRBD_H -#include - -#ifdef __KERNEL__ +#ifndef _UAPI_LINUX_DRBD_H +#define _UAPI_LINUX_DRBD_H #include #include -#else -#include -#include -#include - -/* Although the Linux source code makes a difference between - generic endianness and the bitfields' endianness, there is no - architecture as of Linux-2.6.24-rc4 where the bitfields' endianness - does not match the generic endianness. */ - -#if __BYTE_ORDER == __LITTLE_ENDIAN -#define __LITTLE_ENDIAN_BITFIELD -#elif __BYTE_ORDER == __BIG_ENDIAN -#define __BIG_ENDIAN_BITFIELD -#else -# error "sorry, weird endianness on this box" -#endif - -#endif enum drbd_io_error_p { EP_PASS_ON, /* FIXME should the better be named "Ignore"? */ @@ -432,4 +410,4 @@ enum drbd_state_info_bcast_reason { SIB_SYNC_PROGRESS = 5, }; -#endif +#endif /* _UAPI_LINUX_DRBD_H */ diff --git a/include/uapi/linux/drbd_limits.h b/include/uapi/linux/drbd_limits.h index a72a102d1ca7..acefe84bc602 100644 --- a/include/uapi/linux/drbd_limits.h +++ b/include/uapi/linux/drbd_limits.h @@ -11,10 +11,10 @@ * feedback about nonsense settings for certain configurable values. */ -#ifndef DRBD_LIMITS_H -#define DRBD_LIMITS_H 1 +#ifndef _UAPI_LINUX_DRBD_LIMITS_H +#define _UAPI_LINUX_DRBD_LIMITS_H -#define DEBUG_RANGE_CHECK 0 +#include #define DRBD_MINOR_COUNT_MIN 1U #define DRBD_MINOR_COUNT_MAX 255U @@ -248,4 +248,4 @@ #define DRBD_RS_DISCARD_GRANULARITY_DEF 0U /* disabled by default */ #define DRBD_RS_DISCARD_GRANULARITY_SCALE '1' /* bytes */ -#endif +#endif /* _UAPI_LINUX_DRBD_LIMITS_H */ -- cgit v1.2.3 From 64cf531f9900c011afe97a28c8ef464d551cec1b Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 15 May 2026 06:55:30 +0200 Subject: block: remove zero_fill_bio_iter Only used to implement zero_fill_bio, so directly implement that. Signed-off-by: Christoph Hellwig Link: https://patch.msgid.link/20260515045547.3790129-2-hch@lst.de Signed-off-by: Jens Axboe --- block/bio.c | 6 +++--- include/linux/bio.h | 7 +------ 2 files changed, 4 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/block/bio.c b/block/bio.c index b8972dba68a0..b990c453d72f 100644 --- a/block/bio.c +++ b/block/bio.c @@ -635,15 +635,15 @@ struct bio *bio_kmalloc(unsigned short nr_vecs, gfp_t gfp_mask) } EXPORT_SYMBOL(bio_kmalloc); -void zero_fill_bio_iter(struct bio *bio, struct bvec_iter start) +void zero_fill_bio(struct bio *bio) { struct bio_vec bv; struct bvec_iter iter; - __bio_for_each_segment(bv, bio, iter, start) + bio_for_each_segment(bv, bio, iter) memzero_bvec(&bv); } -EXPORT_SYMBOL(zero_fill_bio_iter); +EXPORT_SYMBOL(zero_fill_bio); /** * bio_truncate - truncate the bio to small size of @new_size diff --git a/include/linux/bio.h b/include/linux/bio.h index 97d747320b35..84643fc0fb08 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -482,13 +482,8 @@ extern void bio_copy_data_iter(struct bio *dst, struct bvec_iter *dst_iter, struct bio *src, struct bvec_iter *src_iter); extern void bio_copy_data(struct bio *dst, struct bio *src); extern void bio_free_pages(struct bio *bio); +void zero_fill_bio(struct bio *bio); void guard_bio_eod(struct bio *bio); -void zero_fill_bio_iter(struct bio *bio, struct bvec_iter iter); - -static inline void zero_fill_bio(struct bio *bio) -{ - zero_fill_bio_iter(bio, bio->bi_iter); -} static inline void bio_release_pages(struct bio *bio, bool mark_dirty) { -- cgit v1.2.3 From 8d57b5876d39679c81d479485422e88319f17418 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 15 May 2026 06:55:31 +0200 Subject: block: remove bio_copy_data_iter Only used by bio_copy_data, so implement that directly. Signed-off-by: Christoph Hellwig Link: https://patch.msgid.link/20260515045547.3790129-3-hch@lst.de Signed-off-by: Jens Axboe --- block/bio.c | 36 +++++++++++++++--------------------- include/linux/bio.h | 2 -- 2 files changed, 15 insertions(+), 23 deletions(-) (limited to 'include') diff --git a/block/bio.c b/block/bio.c index b990c453d72f..57d5a87b3e2f 100644 --- a/block/bio.c +++ b/block/bio.c @@ -1575,26 +1575,6 @@ void __bio_advance(struct bio *bio, unsigned bytes) } EXPORT_SYMBOL(__bio_advance); -void bio_copy_data_iter(struct bio *dst, struct bvec_iter *dst_iter, - struct bio *src, struct bvec_iter *src_iter) -{ - while (src_iter->bi_size && dst_iter->bi_size) { - struct bio_vec src_bv = bio_iter_iovec(src, *src_iter); - struct bio_vec dst_bv = bio_iter_iovec(dst, *dst_iter); - unsigned int bytes = min(src_bv.bv_len, dst_bv.bv_len); - void *src_buf = bvec_kmap_local(&src_bv); - void *dst_buf = bvec_kmap_local(&dst_bv); - - memcpy(dst_buf, src_buf, bytes); - - kunmap_local(dst_buf); - kunmap_local(src_buf); - - bio_advance_iter_single(src, src_iter, bytes); - bio_advance_iter_single(dst, dst_iter, bytes); - } -} -EXPORT_SYMBOL(bio_copy_data_iter); /** * bio_copy_data - copy contents of data buffers from one bio to another @@ -1609,7 +1589,21 @@ void bio_copy_data(struct bio *dst, struct bio *src) struct bvec_iter src_iter = src->bi_iter; struct bvec_iter dst_iter = dst->bi_iter; - bio_copy_data_iter(dst, &dst_iter, src, &src_iter); + while (src_iter.bi_size && dst_iter.bi_size) { + struct bio_vec src_bv = bio_iter_iovec(src, src_iter); + struct bio_vec dst_bv = bio_iter_iovec(dst, dst_iter); + unsigned int bytes = min(src_bv.bv_len, dst_bv.bv_len); + void *src_buf = bvec_kmap_local(&src_bv); + void *dst_buf = bvec_kmap_local(&dst_bv); + + memcpy(dst_buf, src_buf, bytes); + + kunmap_local(dst_buf); + kunmap_local(src_buf); + + bio_advance_iter_single(src, &src_iter, bytes); + bio_advance_iter_single(dst, &dst_iter, bytes); + } } EXPORT_SYMBOL(bio_copy_data); diff --git a/include/linux/bio.h b/include/linux/bio.h index 84643fc0fb08..85463981d0f5 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -478,8 +478,6 @@ extern void bio_check_pages_dirty(struct bio *bio); int bio_iov_iter_bounce(struct bio *bio, struct iov_iter *iter, size_t maxlen); void bio_iov_iter_unbounce(struct bio *bio, bool is_error, bool mark_dirty); -extern void bio_copy_data_iter(struct bio *dst, struct bvec_iter *dst_iter, - struct bio *src, struct bvec_iter *src_iter); extern void bio_copy_data(struct bio *dst, struct bio *src); extern void bio_free_pages(struct bio *bio); void zero_fill_bio(struct bio *bio); -- cgit v1.2.3 From 82aaa55a3162acaad10baced6f87126a4454a0d7 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 15 May 2026 06:55:33 +0200 Subject: block: unexport blk_status_to_str Only used in core block code, so unexport and move the prototype to blk.h. Signed-off-by: Christoph Hellwig Link: https://patch.msgid.link/20260515045547.3790129-5-hch@lst.de Signed-off-by: Jens Axboe --- block/blk-core.c | 1 - block/blk.h | 2 ++ include/linux/blkdev.h | 1 - 3 files changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/block/blk-core.c b/block/blk-core.c index d7de87e86994..22af5dec112b 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -197,7 +197,6 @@ const char *blk_status_to_str(blk_status_t status) return ""; return blk_errors[idx].name; } -EXPORT_SYMBOL_GPL(blk_status_to_str); /** * blk_sync_queue - cancel any pending callbacks on a queue diff --git a/block/blk.h b/block/blk.h index b998a7761faf..bf1a80493ff1 100644 --- a/block/blk.h +++ b/block/blk.h @@ -49,6 +49,8 @@ struct blk_flush_queue *blk_alloc_flush_queue(int node, int cmd_size, gfp_t flags); void blk_free_flush_queue(struct blk_flush_queue *q); +const char *blk_status_to_str(blk_status_t status); + bool __blk_mq_unfreeze_queue(struct request_queue *q, bool force_atomic); bool blk_queue_start_drain(struct request_queue *q); bool __blk_freeze_queue_start(struct request_queue *q, diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 890128cdea1c..17270a28c66d 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -1040,7 +1040,6 @@ extern const char *blk_op_str(enum req_op op); int blk_status_to_errno(blk_status_t status); blk_status_t errno_to_blk_status(int errno); -const char *blk_status_to_str(blk_status_t status); /* only poll the hardware once, don't continue until a completion was found */ #define BLK_POLL_ONESHOT (1 << 0) -- cgit v1.2.3 From 999722b34441b4ab65b7ca7fb16dd4b62fc3c354 Mon Sep 17 00:00:00 2001 From: Caleb Sander Mateos Date: Wed, 13 May 2026 15:18:45 -0600 Subject: blk-mq: introduce blk_rq_has_data() Add blk_rq_has_data(), an analogue of bio_has_data() for struct request. This skips one dereference relative to bio_has_data(rq->bio). Signed-off-by: Caleb Sander Mateos Reviewed-by: Ming Lei Link: https://patch.msgid.link/20260513211846.1956810-2-csander@purestorage.com Signed-off-by: Jens Axboe --- include/linux/blk-mq.h | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'include') diff --git a/include/linux/blk-mq.h b/include/linux/blk-mq.h index 18a2388ba581..4349aefdbc87 100644 --- a/include/linux/blk-mq.h +++ b/include/linux/blk-mq.h @@ -1104,6 +1104,7 @@ struct req_iterator { /* * blk_rq_pos() : the current sector * blk_rq_bytes() : bytes left in the entire request + * blk_rq_has_data() : whether the request carries data * blk_rq_cur_bytes() : bytes left in the current segment * blk_rq_sectors() : sectors left in the entire request * blk_rq_cur_sectors() : sectors left in the current segment @@ -1119,6 +1120,14 @@ static inline unsigned int blk_rq_bytes(const struct request *rq) return rq->__data_len; } +static inline bool blk_rq_has_data(const struct request *rq) +{ + return blk_rq_bytes(rq) && + req_op(rq) != REQ_OP_DISCARD && + req_op(rq) != REQ_OP_SECURE_ERASE && + req_op(rq) != REQ_OP_WRITE_ZEROES; +} + static inline int blk_rq_cur_bytes(const struct request *rq) { if (!rq->bio) -- cgit v1.2.3 From 4d94ec1bc12c4d9d6fe428e4cf2652e187058373 Mon Sep 17 00:00:00 2001 From: Aaron Tomlin Date: Sun, 24 May 2026 20:51:23 -0400 Subject: blk-mq: add tracepoint block_rq_tag_wait In high-performance storage environments, particularly when utilising RAID controllers with shared tag sets (BLK_MQ_F_TAG_HCTX_SHARED), severe latency spikes can occur when fast devices (SSDs) are starved of hardware tags when sharing the same blk_mq_tag_set. Currently, diagnosing this specific hardware queue contention is difficult. When a CPU thread exhausts the tag pool, blk_mq_get_tag() forces the current thread to block uninterruptible via io_schedule(). While this can be inferred via sched:sched_switch or dynamically traced by attaching a kprobe to blk_mq_mark_tag_wait(), there is no dedicated, out-of-the-box observability for this event. This patch introduces the block_rq_tag_wait tracepoint in the tag allocation slow-path. It triggers immediately before the task state is altered to TASK_UNINTERRUPTIBLE (ensuring safety for PREEMPT_RT locks). It exposes the exact hardware context (hctx) that is starved, the specific pool experiencing starvation (driver, software scheduler, or reserved), and the exact pool depth. This provides storage engineers with a zero-configuration, low-overhead mechanism to definitively identify shared-tag bottlenecks. For example, userspace can trivially replicate tag starvation counters using bpftrace: # bpftrace -e 'tracepoint:block:block_rq_tag_wait { @tag_waits[cpu] = count(); }' Attaching 1 probe... ^C @tag_waits[4]: 12 @tag_waits[12]: 87 Signed-off-by: Aaron Tomlin Link: https://patch.msgid.link/20260525005123.722277-1-atomlin@atomlin.com Signed-off-by: Jens Axboe --- block/blk-mq-tag.c | 6 +++++ include/trace/events/block.h | 59 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) (limited to 'include') diff --git a/block/blk-mq-tag.c b/block/blk-mq-tag.c index 33946cdb5716..35deee5bbc73 100644 --- a/block/blk-mq-tag.c +++ b/block/blk-mq-tag.c @@ -13,6 +13,7 @@ #include #include +#include #include "blk.h" #include "blk-mq.h" #include "blk-mq-sched.h" @@ -181,6 +182,11 @@ unsigned int blk_mq_get_tag(struct blk_mq_alloc_data *data) if (tag != BLK_MQ_NO_TAG) break; + /* Log the starvation event before altering task state */ + trace_block_rq_tag_wait(data->q, data->hctx, + data->rq_flags & RQF_SCHED_TAGS, + data->flags); + sbitmap_prepare_to_wait(bt, ws, &wait, TASK_UNINTERRUPTIBLE); tag = __blk_mq_get_tag(data, bt); diff --git a/include/trace/events/block.h b/include/trace/events/block.h index 6aa79e2d799c..9c97a16850b9 100644 --- a/include/trace/events/block.h +++ b/include/trace/events/block.h @@ -226,6 +226,65 @@ DECLARE_EVENT_CLASS(block_rq, IOPRIO_PRIO_LEVEL(__entry->ioprio), __entry->comm) ); +/** + * block_rq_tag_wait - triggered when a request is starved of a tag + * @q: request queue of the target device + * @hctx: hardware context of the request experiencing starvation + * @is_sched_tag: indicates whether the starved pool is the software scheduler + * @alloc_flags: allocation flags dictating the specific tag pool + * + * Called immediately before the submitting context is forced to block due + * to the exhaustion of available tags (i.e., physical hardware driver + * tags, software scheduler tags, or reserved tags). This trace point + * indicates that the context will be placed into an uninterruptible state + * via sbitmap_prepare_to_wait(). If a tag is not acquired in the final + * lockless retry, the context will yield the CPU via io_schedule() until + * an active request completes and relinquishes its assigned tag. + */ +TRACE_EVENT(block_rq_tag_wait, + + TP_PROTO(struct request_queue *q, struct blk_mq_hw_ctx *hctx, + bool is_sched_tag, unsigned int alloc_flags), + + TP_ARGS(q, hctx, is_sched_tag, alloc_flags), + + TP_STRUCT__entry( + __field( dev_t, dev ) + __field( u32, hctx_id ) + __field( u32, nr_tags ) + __field( bool, is_sched_tag ) + __field( bool, is_reserved ) + ), + + TP_fast_assign( + __entry->dev = q->disk ? disk_devt(q->disk) : 0; + __entry->hctx_id = hctx->queue_num; + __entry->is_sched_tag = is_sched_tag; + __entry->is_reserved = alloc_flags & BLK_MQ_REQ_RESERVED; + + if (__entry->is_reserved) { + __entry->nr_tags = is_sched_tag ? + hctx->sched_tags->nr_reserved_tags : + hctx->tags->nr_reserved_tags; + } else { + if (is_sched_tag) + __entry->nr_tags = hctx->sched_tags->nr_tags - + hctx->sched_tags->nr_reserved_tags; + else + __entry->nr_tags = hctx->tags->nr_tags - + hctx->tags->nr_reserved_tags; + } + + ), + + TP_printk("%d,%d hctx=%u starved on %s%s tags (depth=%u)", + MAJOR(__entry->dev), MINOR(__entry->dev), + __entry->hctx_id, + __entry->is_sched_tag ? "scheduler" : "hardware", + __entry->is_reserved ? " reserved" : "", + __entry->nr_tags) +); + /** * block_rq_insert - insert block operation request into queue * @rq: block IO operation request -- cgit v1.2.3 From b040a1a4523d99a935cb6566b1e2a753c84733cd Mon Sep 17 00:00:00 2001 From: Mateusz Nowicki Date: Sat, 23 May 2026 12:52:35 +0000 Subject: block: switch numa_node to int in blk_mq_hw_ctx and init_request numa_node in blk_mq_hw_ctx and the matching argument of blk_mq_ops::init_request can be NUMA_NO_NODE (-1). Declared as unsigned int, NUMA_NO_NODE becomes UINT_MAX and walks off nvme_dev::descriptor_pools[] on CONFIG_NUMA=n [1]. Switch the field and the callback prototype to int and update all in-tree init_request implementations. No functional change: cpu_to_node(), kmalloc_node() and blk_alloc_flush_queue() already take int. Link: https://lore.kernel.org/linux-nvme/20260522150628.399288-1-mateusz.nowicki@posteo.net/ [1] Link: https://lore.kernel.org/linux-nvme/20260309062840.2937858-2-iam@sung-woo.kim/ Suggested-by: Caleb Sander Mateos Suggested-by: Sung-woo Kim Signed-off-by: Mateusz Nowicki Reviewed-by: Christoph Hellwig Link: https://patch.msgid.link/20260523125210.272274-1-mateusz.nowicki@posteo.net Signed-off-by: Jens Axboe --- block/bsg-lib.c | 2 +- drivers/block/mtip32xx/mtip32xx.c | 2 +- drivers/block/nbd.c | 2 +- drivers/md/dm-rq.c | 2 +- drivers/mmc/core/queue.c | 2 +- drivers/mtd/ubi/block.c | 2 +- drivers/nvme/host/apple.c | 2 +- drivers/nvme/host/fc.c | 2 +- drivers/nvme/host/pci.c | 2 +- drivers/nvme/host/rdma.c | 2 +- drivers/nvme/host/tcp.c | 2 +- drivers/nvme/target/loop.c | 2 +- drivers/scsi/scsi_lib.c | 2 +- include/linux/blk-mq.h | 4 ++-- 14 files changed, 15 insertions(+), 15 deletions(-) (limited to 'include') diff --git a/block/bsg-lib.c b/block/bsg-lib.c index fdb4b290ca68..895db30a7033 100644 --- a/block/bsg-lib.c +++ b/block/bsg-lib.c @@ -299,7 +299,7 @@ out: /* called right after the request is allocated for the request_queue */ static int bsg_init_rq(struct blk_mq_tag_set *set, struct request *req, - unsigned int hctx_idx, unsigned int numa_node) + unsigned int hctx_idx, int numa_node) { struct bsg_job *job = blk_mq_rq_to_pdu(req); diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index 567192e371a8..8aedba9b5690 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c @@ -3340,7 +3340,7 @@ static void mtip_free_cmd(struct blk_mq_tag_set *set, struct request *rq, } static int mtip_init_cmd(struct blk_mq_tag_set *set, struct request *rq, - unsigned int hctx_idx, unsigned int numa_node) + unsigned int hctx_idx, int numa_node) { struct driver_data *dd = set->driver_data; struct mtip_cmd *cmd = blk_mq_rq_to_pdu(rq); diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index fe63f3c55d0d..e2fe9e3308fc 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -1888,7 +1888,7 @@ static void nbd_dbg_close(void) #endif static int nbd_init_request(struct blk_mq_tag_set *set, struct request *rq, - unsigned int hctx_idx, unsigned int numa_node) + unsigned int hctx_idx, int numa_node) { struct nbd_cmd *cmd = blk_mq_rq_to_pdu(rq); cmd->nbd = set->driver_data; diff --git a/drivers/md/dm-rq.c b/drivers/md/dm-rq.c index 9703b3ae364e..9a386254d836 100644 --- a/drivers/md/dm-rq.c +++ b/drivers/md/dm-rq.c @@ -462,7 +462,7 @@ static void dm_start_request(struct mapped_device *md, struct request *orig) } static int dm_mq_init_request(struct blk_mq_tag_set *set, struct request *rq, - unsigned int hctx_idx, unsigned int numa_node) + unsigned int hctx_idx, int numa_node) { struct mapped_device *md = set->driver_data; struct dm_rq_target_io *tio = blk_mq_rq_to_pdu(rq); diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c index 39fcb662c43f..cfa268925c26 100644 --- a/drivers/mmc/core/queue.c +++ b/drivers/mmc/core/queue.c @@ -208,7 +208,7 @@ static unsigned short mmc_get_max_segments(struct mmc_host *host) } static int mmc_mq_init_request(struct blk_mq_tag_set *set, struct request *req, - unsigned int hctx_idx, unsigned int numa_node) + unsigned int hctx_idx, int numa_node) { struct mmc_queue_req *mq_rq = req_to_mmc_queue_req(req); struct mmc_queue *mq = set->driver_data; diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c index 8880a783c3bc..29c0d6941a81 100644 --- a/drivers/mtd/ubi/block.c +++ b/drivers/mtd/ubi/block.c @@ -312,7 +312,7 @@ static blk_status_t ubiblock_queue_rq(struct blk_mq_hw_ctx *hctx, static int ubiblock_init_request(struct blk_mq_tag_set *set, struct request *req, unsigned int hctx_idx, - unsigned int numa_node) + int numa_node) { struct ubiblock_pdu *pdu = blk_mq_rq_to_pdu(req); diff --git a/drivers/nvme/host/apple.c b/drivers/nvme/host/apple.c index 423c9c628e7b..7fc6b9eacf2e 100644 --- a/drivers/nvme/host/apple.c +++ b/drivers/nvme/host/apple.c @@ -819,7 +819,7 @@ static int apple_nvme_init_hctx(struct blk_mq_hw_ctx *hctx, void *data, static int apple_nvme_init_request(struct blk_mq_tag_set *set, struct request *req, unsigned int hctx_idx, - unsigned int numa_node) + int numa_node) { struct apple_nvme_queue *q = set->driver_data; struct apple_nvme *anv = queue_to_apple_nvme(q); diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c index e4f4528fe2a2..1907da499ad2 100644 --- a/drivers/nvme/host/fc.c +++ b/drivers/nvme/host/fc.c @@ -2109,7 +2109,7 @@ out_on_error: static int nvme_fc_init_request(struct blk_mq_tag_set *set, struct request *rq, - unsigned int hctx_idx, unsigned int numa_node) + unsigned int hctx_idx, int numa_node) { struct nvme_fc_ctrl *ctrl = to_fc_ctrl(set->driver_data); struct nvme_fcp_op_w_sgl *op = blk_mq_rq_to_pdu(rq); diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index 9fd04cd7c5cb..24911e1252d5 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -660,7 +660,7 @@ static int nvme_init_hctx(struct blk_mq_hw_ctx *hctx, void *data, static int nvme_pci_init_request(struct blk_mq_tag_set *set, struct request *req, unsigned int hctx_idx, - unsigned int numa_node) + int numa_node) { struct nvme_iod *iod = blk_mq_rq_to_pdu(req); diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c index f77c960f7632..08459c65c3d5 100644 --- a/drivers/nvme/host/rdma.c +++ b/drivers/nvme/host/rdma.c @@ -292,7 +292,7 @@ static void nvme_rdma_exit_request(struct blk_mq_tag_set *set, static int nvme_rdma_init_request(struct blk_mq_tag_set *set, struct request *rq, unsigned int hctx_idx, - unsigned int numa_node) + int numa_node) { struct nvme_rdma_ctrl *ctrl = to_rdma_ctrl(set->driver_data); struct nvme_rdma_request *req = blk_mq_rq_to_pdu(rq); diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c index 15d36d6a728e..36b3ec50a9fd 100644 --- a/drivers/nvme/host/tcp.c +++ b/drivers/nvme/host/tcp.c @@ -548,7 +548,7 @@ static void nvme_tcp_exit_request(struct blk_mq_tag_set *set, static int nvme_tcp_init_request(struct blk_mq_tag_set *set, struct request *rq, unsigned int hctx_idx, - unsigned int numa_node) + int numa_node) { struct nvme_tcp_ctrl *ctrl = to_tcp_ctrl(set->driver_data); struct nvme_tcp_request *req = blk_mq_rq_to_pdu(rq); diff --git a/drivers/nvme/target/loop.c b/drivers/nvme/target/loop.c index d98d0cdc5d6f..ae00bcef2251 100644 --- a/drivers/nvme/target/loop.c +++ b/drivers/nvme/target/loop.c @@ -202,7 +202,7 @@ static int nvme_loop_init_iod(struct nvme_loop_ctrl *ctrl, static int nvme_loop_init_request(struct blk_mq_tag_set *set, struct request *req, unsigned int hctx_idx, - unsigned int numa_node) + int numa_node) { struct nvme_loop_ctrl *ctrl = to_loop_ctrl(set->driver_data); struct nvme_loop_iod *iod = blk_mq_rq_to_pdu(req); diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 6e8c7a42603e..67f789bd02e7 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1950,7 +1950,7 @@ out_put_budget: } static int scsi_mq_init_request(struct blk_mq_tag_set *set, struct request *rq, - unsigned int hctx_idx, unsigned int numa_node) + unsigned int hctx_idx, int numa_node) { struct Scsi_Host *shost = set->driver_data; struct scsi_cmnd *cmd = blk_mq_rq_to_pdu(rq); diff --git a/include/linux/blk-mq.h b/include/linux/blk-mq.h index 4349aefdbc87..24b4160aeaad 100644 --- a/include/linux/blk-mq.h +++ b/include/linux/blk-mq.h @@ -428,7 +428,7 @@ struct blk_mq_hw_ctx { struct blk_mq_tags *sched_tags; /** @numa_node: NUMA node the storage adapter has been connected to. */ - unsigned int numa_node; + int numa_node; /** @queue_num: Index of this hardware queue. */ unsigned int queue_num; @@ -653,7 +653,7 @@ struct blk_mq_ops { * flush request. */ int (*init_request)(struct blk_mq_tag_set *set, struct request *, - unsigned int, unsigned int); + unsigned int, int); /** * @exit_request: Ditto for exit/teardown. */ -- cgit v1.2.3 From a148d0a5af1ab60253994047403f9eb41ef709a4 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 18 May 2026 08:33:30 +0200 Subject: block: don't set BIO_QUIET for BLK_STS_AGAIN Commit abb30460bda2 ("block: mark bio_wouldblock_error() bio with BIO_QUIET") added this to suppress buffer_head warnings, but neither when this commit was added nor now any buffer_head using code actually ever sets REQ_NOWAIT which can lead to BLK_STS_AGAIN. Remove the special handling for now. If we ever plan to use REQ_NOWAIT for buffer_head based I/O we're better off handling BLK_STS_AGAIN in the completion handler as it actually needs to retry the I/O as well. Signed-off-by: Christoph Hellwig Reviewed-by: Damien Le Moal Reviewed-by: Jan Kara Link: https://patch.msgid.link/20260518063336.507369-3-hch@lst.de Signed-off-by: Jens Axboe --- include/linux/bio.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include') diff --git a/include/linux/bio.h b/include/linux/bio.h index 85463981d0f5..7597ae4dc52b 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -379,7 +379,6 @@ static inline void bio_io_error(struct bio *bio) static inline void bio_wouldblock_error(struct bio *bio) { - bio_set_flag(bio, BIO_QUIET); bio->bi_status = BLK_STS_AGAIN; bio_endio(bio); } -- cgit v1.2.3 From 353c85082a82fa6d78cbb3821749d5982ffed9f4 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 27 May 2026 17:06:46 +0200 Subject: block: mark biovec_init_pool static Signed-off-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Reviewed-by: Bart Van Assche Link: https://patch.msgid.link/20260527150646.2349405-1-hch@lst.de Signed-off-by: Jens Axboe --- block/bio.c | 2 +- include/linux/bio.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'include') diff --git a/block/bio.c b/block/bio.c index 2d880d1255fe..e9944dab0132 100644 --- a/block/bio.c +++ b/block/bio.c @@ -1873,7 +1873,7 @@ EXPORT_SYMBOL_GPL(bio_trim); * create memory pools for biovec's in a bio_set. * use the global biovec slabs created for general use. */ -int biovec_init_pool(mempool_t *pool, int pool_entries) +static int biovec_init_pool(mempool_t *pool, int pool_entries) { struct biovec_slab *bp = bvec_slabs + ARRAY_SIZE(bvec_slabs) - 1; diff --git a/include/linux/bio.h b/include/linux/bio.h index 7597ae4dc52b..e60d2f5bd3dc 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -347,7 +347,6 @@ enum { }; extern int bioset_init(struct bio_set *, unsigned int, unsigned int, int flags); extern void bioset_exit(struct bio_set *); -extern int biovec_init_pool(mempool_t *pool, int pool_entries); struct bio *bio_alloc_bioset(struct block_device *bdev, unsigned short nr_vecs, blk_opf_t opf, gfp_t gfp, struct bio_set *bs); -- cgit v1.2.3 From f6fe52a7b18675d76d7f7dae0c16f412a4e33f9a Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 27 May 2026 17:10:22 +0200 Subject: bvec: make the bvec_iter helpers inline functions The macros are impossible to follow due to the lack of visual type information and all the braces. Replace them with inline helpers to improve on that. Because the calling conventions are a bit problematic with a lot of passing structures by value, all the helpers are marked as __always_inline so that they are force inlined. Signed-off-by: Christoph Hellwig Reviewed-by: Bart Van Assche Reviewed-by: Caleb Sander Mateos Reviewed-by: Ming Lei Reviewed-by: Chaitanya Kulkarni Reviewed-by: Keith Busch Link: https://patch.msgid.link/20260527151043.2349900-4-hch@lst.de Signed-off-by: Jens Axboe --- include/linux/bvec.h | 101 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 64 insertions(+), 37 deletions(-) (limited to 'include') diff --git a/include/linux/bvec.h b/include/linux/bvec.h index d36dd476feda..f4c7ec282ac9 100644 --- a/include/linux/bvec.h +++ b/include/linux/bvec.h @@ -104,51 +104,78 @@ struct bvec_iter_all { unsigned done; }; -/* - * various member access, note that bio_data should of course not be used - * on highmem page vectors - */ -#define __bvec_iter_bvec(bvec, iter) (&(bvec)[(iter).bi_idx]) +static __always_inline const struct bio_vec * +__bvec_iter_bvec(const struct bio_vec *bvecs, const struct bvec_iter iter) +{ + return bvecs + iter.bi_idx; +} /* multi-page (mp_bvec) helpers */ -#define mp_bvec_iter_page(bvec, iter) \ - (__bvec_iter_bvec((bvec), (iter))->bv_page) +static __always_inline struct page * +mp_bvec_iter_page(const struct bio_vec *bvecs, const struct bvec_iter iter) +{ + return __bvec_iter_bvec(bvecs, iter)->bv_page; +} -#define mp_bvec_iter_len(bvec, iter) \ - min((iter).bi_size, \ - __bvec_iter_bvec((bvec), (iter))->bv_len - (iter).bi_bvec_done) +static __always_inline unsigned int +mp_bvec_iter_len(const struct bio_vec *bvecs, const struct bvec_iter iter) +{ + return min(__bvec_iter_bvec(bvecs, iter)->bv_len - iter.bi_bvec_done, + iter.bi_size); +} -#define mp_bvec_iter_offset(bvec, iter) \ - (__bvec_iter_bvec((bvec), (iter))->bv_offset + (iter).bi_bvec_done) +static __always_inline unsigned int +mp_bvec_iter_offset(const struct bio_vec *bvecs, const struct bvec_iter iter) +{ + return __bvec_iter_bvec(bvecs, iter)->bv_offset + iter.bi_bvec_done; +} -#define mp_bvec_iter_page_idx(bvec, iter) \ - (mp_bvec_iter_offset((bvec), (iter)) / PAGE_SIZE) +static __always_inline unsigned int +mp_bvec_iter_page_idx(const struct bio_vec *bvecs, const struct bvec_iter iter) +{ + return mp_bvec_iter_offset(bvecs, iter) / PAGE_SIZE; +} -#define mp_bvec_iter_bvec(bvec, iter) \ -((struct bio_vec) { \ - .bv_page = mp_bvec_iter_page((bvec), (iter)), \ - .bv_len = mp_bvec_iter_len((bvec), (iter)), \ - .bv_offset = mp_bvec_iter_offset((bvec), (iter)), \ -}) +static __always_inline struct bio_vec +mp_bvec_iter_bvec(const struct bio_vec *bvecs, const struct bvec_iter iter) +{ + return (struct bio_vec) { + .bv_page = mp_bvec_iter_page(bvecs, iter), + .bv_len = mp_bvec_iter_len(bvecs, iter), + .bv_offset = mp_bvec_iter_offset(bvecs, iter), + }; +} /* For building single-page bvec in flight */ - #define bvec_iter_offset(bvec, iter) \ - (mp_bvec_iter_offset((bvec), (iter)) % PAGE_SIZE) - -#define bvec_iter_len(bvec, iter) \ - min_t(unsigned, mp_bvec_iter_len((bvec), (iter)), \ - PAGE_SIZE - bvec_iter_offset((bvec), (iter))) - -#define bvec_iter_page(bvec, iter) \ - (mp_bvec_iter_page((bvec), (iter)) + \ - mp_bvec_iter_page_idx((bvec), (iter))) - -#define bvec_iter_bvec(bvec, iter) \ -((struct bio_vec) { \ - .bv_page = bvec_iter_page((bvec), (iter)), \ - .bv_len = bvec_iter_len((bvec), (iter)), \ - .bv_offset = bvec_iter_offset((bvec), (iter)), \ -}) +static __always_inline unsigned int +bvec_iter_offset(const struct bio_vec *bvecs, const struct bvec_iter iter) +{ + return mp_bvec_iter_offset(bvecs, iter) % PAGE_SIZE; +} + +static __always_inline unsigned int +bvec_iter_len(const struct bio_vec *bvecs, const struct bvec_iter iter) +{ + return min(mp_bvec_iter_len(bvecs, iter), + PAGE_SIZE - bvec_iter_offset(bvecs, iter)); +} + +static __always_inline struct page * +bvec_iter_page(const struct bio_vec *bvecs, const struct bvec_iter iter) +{ + return mp_bvec_iter_page(bvecs, iter) + + mp_bvec_iter_page_idx(bvecs, iter); +} + +static __always_inline struct bio_vec +bvec_iter_bvec(const struct bio_vec *bvecs, const struct bvec_iter iter) +{ + return (struct bio_vec) { + .bv_page = bvec_iter_page(bvecs, iter), + .bv_len = bvec_iter_len(bvecs, iter), + .bv_offset = bvec_iter_offset(bvecs, iter), + }; +} static inline bool bvec_iter_advance(const struct bio_vec *bv, struct bvec_iter *iter, unsigned bytes) -- cgit v1.2.3 From a7d8eaee7fafe2e2c58aef9579bdef778c144029 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 28 May 2026 10:46:13 +0200 Subject: block: add a bio_endio_status helper Add a helper that sets bi_status and call bio_endio() as that is a very common pattern and convert the core block code over to it. Signed-off-by: Christoph Hellwig Reviewed-by: Keith Busch Reviewed-by: Md Haris Iqbal Reviewed-by: Damien Le Moal Reviewed-by: Hannes Reinecke Link: https://patch.msgid.link/20260528084632.2505277-1-hch@lst.de Signed-off-by: Jens Axboe --- block/blk-core.c | 11 ++++------- block/blk-crypto-fallback.c | 9 +++------ block/blk-crypto.c | 3 +-- block/blk-merge.c | 6 ++---- block/blk-mq.c | 6 ++---- block/fops.c | 3 +-- include/linux/bio.h | 19 +++++++++++++++---- 7 files changed, 28 insertions(+), 29 deletions(-) (limited to 'include') diff --git a/block/blk-core.c b/block/blk-core.c index 22af5dec112b..b0f0a304ea0b 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -636,12 +636,10 @@ static void __submit_bio(struct bio *bio) struct gendisk *disk = bio->bi_bdev->bd_disk; if ((bio->bi_opf & REQ_POLLED) && - !(disk->queue->limits.features & BLK_FEAT_POLL)) { - bio->bi_status = BLK_STS_NOTSUPP; - bio_endio(bio); - } else { + !(disk->queue->limits.features & BLK_FEAT_POLL)) + bio_endio_status(bio, BLK_STS_NOTSUPP); + else disk->fops->submit_bio(bio); - } blk_queue_exit(disk->queue); } @@ -886,8 +884,7 @@ void submit_bio_noacct(struct bio *bio) not_supported: status = BLK_STS_NOTSUPP; end_io: - bio->bi_status = status; - bio_endio(bio); + bio_endio_status(bio, status); } EXPORT_SYMBOL(submit_bio_noacct); diff --git a/block/blk-crypto-fallback.c b/block/blk-crypto-fallback.c index 61f595410832..8b04d9205b8d 100644 --- a/block/blk-crypto-fallback.c +++ b/block/blk-crypto-fallback.c @@ -361,8 +361,7 @@ static void blk_crypto_fallback_encrypt_bio(struct bio *src_bio) status = blk_crypto_get_keyslot(blk_crypto_fallback_profile, bc->bc_key, &slot); if (status != BLK_STS_OK) { - src_bio->bi_status = status; - bio_endio(src_bio); + bio_endio_status(src_bio, status); return; } __blk_crypto_fallback_encrypt_bio(src_bio, @@ -437,8 +436,7 @@ static void blk_crypto_fallback_decrypt_bio(struct work_struct *work) } mempool_free(f_ctx, bio_fallback_crypt_ctx_pool); - bio->bi_status = status; - bio_endio(bio); + bio_endio_status(bio, status); } /** @@ -499,8 +497,7 @@ bool blk_crypto_fallback_bio_prep(struct bio *bio) if (!__blk_crypto_cfg_supported(blk_crypto_fallback_profile, &bc->bc_key->crypto_cfg)) { - bio->bi_status = BLK_STS_NOTSUPP; - bio_endio(bio); + bio_endio_status(bio, BLK_STS_NOTSUPP); return false; } diff --git a/block/blk-crypto.c b/block/blk-crypto.c index 856d3c5b1fa0..165c9d2cce07 100644 --- a/block/blk-crypto.c +++ b/block/blk-crypto.c @@ -267,8 +267,7 @@ bool __blk_crypto_submit_bio(struct bio *bio) if (!IS_ENABLED(CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK)) { pr_warn_once("%pg: crypto API fallback disabled; failing request.\n", bdev); - bio->bi_status = BLK_STS_NOTSUPP; - bio_endio(bio); + bio_endio_status(bio, BLK_STS_NOTSUPP); return false; } return blk_crypto_fallback_bio_prep(bio); diff --git a/block/blk-merge.c b/block/blk-merge.c index fcf09325b22e..7cc82a7a6f4e 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -122,8 +122,7 @@ struct bio *bio_submit_split_bioset(struct bio *bio, unsigned int split_sectors, struct bio *split = bio_split(bio, split_sectors, GFP_NOIO, bs); if (IS_ERR(split)) { - bio->bi_status = errno_to_blk_status(PTR_ERR(split)); - bio_endio(bio); + bio_endio_status(bio, errno_to_blk_status(PTR_ERR(split))); return NULL; } @@ -143,8 +142,7 @@ EXPORT_SYMBOL_GPL(bio_submit_split_bioset); static struct bio *bio_submit_split(struct bio *bio, int split_sectors) { if (unlikely(split_sectors < 0)) { - bio->bi_status = errno_to_blk_status(split_sectors); - bio_endio(bio); + bio_endio_status(bio, errno_to_blk_status(split_sectors)); return NULL; } diff --git a/block/blk-mq.c b/block/blk-mq.c index 4c5c16cce4f8..ade9d3a89743 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -3187,8 +3187,7 @@ void blk_mq_submit_bio(struct bio *bio) } if ((bio->bi_opf & REQ_POLLED) && !blk_mq_can_poll(q)) { - bio->bi_status = BLK_STS_NOTSUPP; - bio_endio(bio); + bio_endio_status(bio, BLK_STS_NOTSUPP); goto queue_exit; } @@ -3229,8 +3228,7 @@ new_request: ret = blk_crypto_rq_get_keyslot(rq); if (ret != BLK_STS_OK) { - bio->bi_status = ret; - bio_endio(bio); + bio_endio_status(bio, ret); blk_mq_free_request(rq); return; } diff --git a/block/fops.c b/block/fops.c index ffe7b2042f4e..15783a6180de 100644 --- a/block/fops.c +++ b/block/fops.c @@ -218,8 +218,7 @@ static ssize_t __blkdev_direct_IO(struct kiocb *iocb, struct iov_iter *iter, ret = blkdev_iov_iter_get_pages(bio, iter, bdev); if (unlikely(ret)) { - bio->bi_status = BLK_STS_IOERR; - bio_endio(bio); + bio_endio_status(bio, BLK_STS_IOERR); break; } if (iocb->ki_flags & IOCB_NOWAIT) { diff --git a/include/linux/bio.h b/include/linux/bio.h index e60d2f5bd3dc..97f993d4d914 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -370,16 +370,27 @@ void submit_bio(struct bio *bio); extern void bio_endio(struct bio *); -static inline void bio_io_error(struct bio *bio) +/** + * bio_endio_status - end I/O on a bio with a specific status + * @bio: bio + * @status: status to set + * + * Set @bio->bi_status to @status and call bio_endio(). + **/ +static inline void bio_endio_status(struct bio *bio, blk_status_t status) { - bio->bi_status = BLK_STS_IOERR; + bio->bi_status = status; bio_endio(bio); } +static inline void bio_io_error(struct bio *bio) +{ + bio_endio_status(bio, BLK_STS_IOERR); +} + static inline void bio_wouldblock_error(struct bio *bio) { - bio->bi_status = BLK_STS_AGAIN; - bio_endio(bio); + bio_endio_status(bio, BLK_STS_AGAIN); } /* -- cgit v1.2.3 From b7f40ab50190e2500c3c297d15e00040dca47feb Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Wed, 27 May 2026 18:00:40 -0700 Subject: block: export passthrough stats enabled A user can enable io accounting for passthrough requests, so export the helper that checks if the request should be tracked. This will enable stacking drivers to to report iostats for passthrough workloads. Since the stacking request_queue may not be the one providing the request, the API has to add a parameter for the caller to specify which one to check. Reviewed-by: Nilay Shroff Reviewed-by: Nitesh Shetty Signed-off-by: Keith Busch Reviewed-by: Christoph Hellwig Link: https://patch.msgid.link/20260528010041.1533124-2-kbusch@meta.com Signed-off-by: Jens Axboe --- block/blk-mq.c | 32 +------------------------------- include/linux/blk-mq.h | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 31 deletions(-) (limited to 'include') diff --git a/block/blk-mq.c b/block/blk-mq.c index ade9d3a89743..629e16003eb7 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -1088,43 +1088,13 @@ static inline void blk_account_io_done(struct request *req, u64 now) } } -static inline bool blk_rq_passthrough_stats(struct request *req) -{ - struct bio *bio = req->bio; - - if (!blk_queue_passthrough_stat(req->q)) - return false; - - /* Requests without a bio do not transfer data. */ - if (!bio) - return false; - - /* - * Stats are accumulated in the bdev, so must have one attached to a - * bio to track stats. Most drivers do not set the bdev for passthrough - * requests, but nvme is one that will set it. - */ - if (!bio->bi_bdev) - return false; - - /* - * We don't know what a passthrough command does, but we know the - * payload size and data direction. Ensuring the size is aligned to the - * block size filters out most commands with payloads that don't - * represent sector access. - */ - if (blk_rq_bytes(req) & (bdev_logical_block_size(bio->bi_bdev) - 1)) - return false; - return true; -} - static inline void blk_account_io_start(struct request *req) { trace_block_io_start(req); if (!blk_queue_io_stat(req->q)) return; - if (blk_rq_is_passthrough(req) && !blk_rq_passthrough_stats(req)) + if (blk_rq_is_passthrough(req) && !blk_rq_passthrough_stats(req, req->q)) return; req->rq_flags |= RQF_IO_STAT; diff --git a/include/linux/blk-mq.h b/include/linux/blk-mq.h index 24b4160aeaad..af878597afb8 100644 --- a/include/linux/blk-mq.h +++ b/include/linux/blk-mq.h @@ -1252,4 +1252,44 @@ static inline int blk_rq_map_sg(struct request *rq, struct scatterlist *sglist) } void blk_dump_rq_flags(struct request *, char *); +/** + * blk_rq_passthrough_stats - check if this request should account stats + * @rq: request to check + * @q: the queue accumulating the stats + * + * Note, @q does not necessarily need to be the request_queue that provides + * @rq. + * + * Return: true if stats should be accounted. + */ +static inline bool blk_rq_passthrough_stats(struct request *rq, + struct request_queue *q) +{ + struct bio *bio = rq->bio; + + if (!blk_queue_passthrough_stat(q)) + return false; + + /* Requests without a bio do not transfer data. */ + if (!bio) + return false; + + /* + * Stats are accumulated in the bdev, so must have one attached to a + * bio to track stats. Most drivers do not set the bdev for passthrough + * requests, but nvme is one that will set it. + */ + if (!bio->bi_bdev) + return false; + + /* + * We don't know what a passthrough command does, but we know the + * payload size and data direction. Ensuring the size is aligned to the + * block size filters out most commands with payloads that don't + * represent sector access. + */ + if (blk_rq_bytes(rq) & (bdev_logical_block_size(bio->bi_bdev) - 1)) + return false; + return true; +} #endif /* BLK_MQ_H */ -- cgit v1.2.3 From ca36c1aaee095d009d73f6623fb5e536ada80032 Mon Sep 17 00:00:00 2001 From: "Matthew Wilcox (Oracle)" Date: Thu, 28 May 2026 18:59:03 +0100 Subject: block: Add bvec_folio() This is a simple helper which replaces page_folio(bvec->bv_page). Minor improvement in readability, but the real motivation is to reduce the number of references to bvec->bv_page so that it can be changed with less work. Signed-off-by: Matthew Wilcox (Oracle) Cc: Leon Romanovsky Reviewed-by: Hannes Reinecke Reviewed-by: Christoph Hellwig Reviewed-by: William Kucharski Link: https://patch.msgid.link/20260528175905.1102280-2-willy@infradead.org Signed-off-by: Jens Axboe --- block/bio.c | 6 +++--- include/linux/bio.h | 2 +- include/linux/bvec.h | 15 +++++++++++++++ io_uring/rsrc.c | 2 +- mm/page_io.c | 4 ++-- 5 files changed, 22 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/block/bio.c b/block/bio.c index e9944dab0132..c3d0a00a27f1 100644 --- a/block/bio.c +++ b/block/bio.c @@ -1299,7 +1299,7 @@ static void bio_free_folios(struct bio *bio) int i; bio_for_each_bvec_all(bv, bio, i) { - struct folio *folio = page_folio(bv->bv_page); + struct folio *folio = bvec_folio(bv); if (!is_zero_folio(folio)) folio_put(folio); @@ -1406,7 +1406,7 @@ int bio_iov_iter_bounce(struct bio *bio, struct iov_iter *iter, size_t maxlen) static void bvec_unpin(struct bio_vec *bv, bool mark_dirty) { - struct folio *folio = page_folio(bv->bv_page); + struct folio *folio = bvec_folio(bv); size_t nr_pages = (bv->bv_offset + bv->bv_len - 1) / PAGE_SIZE - bv->bv_offset / PAGE_SIZE + 1; @@ -1440,7 +1440,7 @@ static void bio_iov_iter_unbounce_read(struct bio *bio, bool is_error, bvec_unpin(&bio->bi_io_vec[1 + i], mark_dirty); } - folio_put(page_folio(bio->bi_io_vec[0].bv_page)); + folio_put(bvec_folio(&bio->bi_io_vec[0])); } /** diff --git a/include/linux/bio.h b/include/linux/bio.h index 97f993d4d914..26ebfff93a16 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -283,7 +283,7 @@ static inline void bio_first_folio(struct folio_iter *fi, struct bio *bio, return; } - fi->folio = page_folio(bvec->bv_page); + fi->folio = bvec_folio(bvec); fi->offset = bvec->bv_offset + PAGE_SIZE * folio_page_idx(fi->folio, bvec->bv_page); fi->_seg_count = bvec->bv_len; diff --git a/include/linux/bvec.h b/include/linux/bvec.h index f4c7ec282ac9..c939f2b3be87 100644 --- a/include/linux/bvec.h +++ b/include/linux/bvec.h @@ -74,6 +74,21 @@ static inline void bvec_set_virt(struct bio_vec *bv, void *vaddr, bvec_set_page(bv, virt_to_page(vaddr), len, offset_in_page(vaddr)); } +/** + * bvec_folio - Return the first folio referenced by this bvec + * @bv: bvec to access + * + * A bvec can contain non-folio memory, so this should only be called by + * the creator of the bvec; drivers have no business looking at the owner + * of the memory. It may not even be the right interface for the caller + * to use as a bvec can span multiple folios. You may be better off using + * something like bio_for_each_folio_all() which iterates over all folios. + */ +static inline struct folio *bvec_folio(const struct bio_vec *bv) +{ + return page_folio(bv->bv_page); +} + struct bvec_iter { /* * Current device address in 512 byte sectors. Only updated by the bio diff --git a/io_uring/rsrc.c b/io_uring/rsrc.c index 650303626be6..5d792f70ec1e 100644 --- a/io_uring/rsrc.c +++ b/io_uring/rsrc.c @@ -102,7 +102,7 @@ static void io_release_ubuf(void *priv) unsigned int i; for (i = 0; i < imu->nr_bvecs; i++) { - struct folio *folio = page_folio(imu->bvec[i].bv_page); + struct folio *folio = bvec_folio(&imu->bvec[i]); unpin_user_folio(folio, 1); } diff --git a/mm/page_io.c b/mm/page_io.c index 70cea9e24d2f..a59b73f8bdd9 100644 --- a/mm/page_io.c +++ b/mm/page_io.c @@ -490,7 +490,7 @@ static void sio_read_complete(struct kiocb *iocb, long ret) if (ret == sio->len) { for (p = 0; p < sio->pages; p++) { - struct folio *folio = page_folio(sio->bvec[p].bv_page); + struct folio *folio = bvec_folio(&sio->bvec[p]); count_mthp_stat(folio_order(folio), MTHP_STAT_SWPIN); count_memcg_folio_events(folio, PSWPIN, folio_nr_pages(folio)); @@ -500,7 +500,7 @@ static void sio_read_complete(struct kiocb *iocb, long ret) count_vm_events(PSWPIN, sio->len >> PAGE_SHIFT); } else { for (p = 0; p < sio->pages; p++) { - struct folio *folio = page_folio(sio->bvec[p].bv_page); + struct folio *folio = bvec_folio(&sio->bvec[p]); folio_unlock(folio); } -- cgit v1.2.3 From 11ff85db51e05cf8cbeea36be1085fdacedeab55 Mon Sep 17 00:00:00 2001 From: "Matthew Wilcox (Oracle)" Date: Thu, 28 May 2026 18:59:04 +0100 Subject: block: Include bvec.h kernel-doc in the htmldocs People have gone to the trouble of writing this kernel-doc; the least we can do is publish it. Signed-off-by: Matthew Wilcox (Oracle) Reviewed-by: Hannes Reinecke Reviewed-by: Christoph Hellwig Reviewed-by: William Kucharski Link: https://patch.msgid.link/20260528175905.1102280-3-willy@infradead.org Signed-off-by: Jens Axboe --- Documentation/core-api/kernel-api.rst | 1 + include/linux/bvec.h | 2 ++ 2 files changed, 3 insertions(+) (limited to 'include') diff --git a/Documentation/core-api/kernel-api.rst b/Documentation/core-api/kernel-api.rst index e8211c4ca662..4c4a57c1c094 100644 --- a/Documentation/core-api/kernel-api.rst +++ b/Documentation/core-api/kernel-api.rst @@ -307,6 +307,7 @@ Accounting Framework Block Devices ============= +.. kernel-doc:: include/linux/bvec.h .. kernel-doc:: include/linux/bio.h .. kernel-doc:: block/blk-core.c :export: diff --git a/include/linux/bvec.h b/include/linux/bvec.h index c939f2b3be87..92837e2743f1 100644 --- a/include/linux/bvec.h +++ b/include/linux/bvec.h @@ -289,6 +289,7 @@ static inline void *bvec_kmap_local(struct bio_vec *bvec) /** * memcpy_from_bvec - copy data from a bvec + * @to: Kernel virtual address to copy to. * @bvec: bvec to copy from * * Must be called on single-page bvecs only. @@ -301,6 +302,7 @@ static inline void memcpy_from_bvec(char *to, struct bio_vec *bvec) /** * memcpy_to_bvec - copy data to a bvec * @bvec: bvec to copy to + * @from: Kernel virtual address to copy from. * * Must be called on single-page bvecs only. */ -- cgit v1.2.3 From 08d912bc44dab63f2637677712d2a0b86922389a Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 5 Jun 2026 11:00:54 -0700 Subject: block: Annotate the queue limits functions Let the thread-safety checker verify whether every start of a queue limits update is followed by a call to a function that finishes a queue limits update. Reviewed-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Signed-off-by: Bart Van Assche Reviewed-by: Chaitanya Kulkarni Link: https://patch.msgid.link/8f71062b6d0fcf2b80bc8cda701c453224755439.1780682325.git.bvanassche@acm.org Signed-off-by: Jens Axboe --- include/linux/blkdev.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 17270a28c66d..65efbd7fe1a3 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -1092,15 +1092,17 @@ static inline unsigned int blk_boundary_sectors_left(sector_t offset, */ static inline struct queue_limits queue_limits_start_update(struct request_queue *q) + __acquires(&q->limits_lock) { mutex_lock(&q->limits_lock); return q->limits; } int queue_limits_commit_update_frozen(struct request_queue *q, - struct queue_limits *lim); + struct queue_limits *lim) __releases(&q->limits_lock); int queue_limits_commit_update(struct request_queue *q, - struct queue_limits *lim); -int queue_limits_set(struct request_queue *q, struct queue_limits *lim); + struct queue_limits *lim) __releases(&q->limits_lock); +int queue_limits_set(struct request_queue *q, struct queue_limits *lim) + __must_not_hold(&q->limits_lock); int blk_validate_limits(struct queue_limits *lim); /** @@ -1112,6 +1114,7 @@ int blk_validate_limits(struct queue_limits *lim); * starting update. */ static inline void queue_limits_cancel_update(struct request_queue *q) + __releases(&q->limits_lock) { mutex_unlock(&q->limits_lock); } -- cgit v1.2.3 From 3033c86fa1a8bb31d0a13738fe8c5f9e5bbaf98a Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 5 Jun 2026 11:00:55 -0700 Subject: block/bdev: Annotate the blk_holder_ops callback functions The four callback functions in blk_holder_ops all release the bd_holder_lock. Annotate these functions accordingly. Reviewed-by: Hannes Reinecke Reviewed-by: Christoph Hellwig Signed-off-by: Bart Van Assche Reviewed-by: Chaitanya Kulkarni Link: https://patch.msgid.link/be51cf81110f691ebd5868ac2f15ceb847805bc8.1780682325.git.bvanassche@acm.org Signed-off-by: Jens Axboe --- include/linux/blkdev.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 65efbd7fe1a3..57e84d59a642 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -1746,22 +1746,26 @@ void blkdev_show(struct seq_file *seqf, off_t offset); #endif struct blk_holder_ops { - void (*mark_dead)(struct block_device *bdev, bool surprise); + void (*mark_dead)(struct block_device *bdev, bool surprise) + __releases(&bdev->bd_holder_lock); /* * Sync the file system mounted on the block device. */ - void (*sync)(struct block_device *bdev); + void (*sync)(struct block_device *bdev) + __releases(&bdev->bd_holder_lock); /* * Freeze the file system mounted on the block device. */ - int (*freeze)(struct block_device *bdev); + int (*freeze)(struct block_device *bdev) + __releases(&bdev->bd_holder_lock); /* * Thaw the file system mounted on the block device. */ - int (*thaw)(struct block_device *bdev); + int (*thaw)(struct block_device *bdev) + __releases(&bdev->bd_holder_lock); }; /* -- cgit v1.2.3 From e8dcf2d142bd720c8334233ad6cfdf00f0e76b7f Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 11 Jun 2026 16:06:47 +0200 Subject: block: add configurable error injection Add a new block error injection interface that allows to inject specific status code for specific ranges. Signed-off-by: Christoph Hellwig Reviewed-by: Damien Le Moal Reviewed-by: Hannes Reinecke Reviewed-by: Md Haris Iqbal Link: https://patch.msgid.link/20260611140703.2401204-5-hch@lst.de Signed-off-by: Jens Axboe --- Documentation/block/error-injection.rst | 59 ++++++ Documentation/block/index.rst | 1 + block/Kconfig | 8 + block/Makefile | 1 + block/blk-core.c | 4 + block/blk-sysfs.c | 5 + block/error-injection.c | 315 ++++++++++++++++++++++++++++++++ block/error-injection.h | 21 +++ block/genhd.c | 4 + include/linux/blkdev.h | 6 + 10 files changed, 424 insertions(+) create mode 100644 Documentation/block/error-injection.rst create mode 100644 block/error-injection.c create mode 100644 block/error-injection.h (limited to 'include') diff --git a/Documentation/block/error-injection.rst b/Documentation/block/error-injection.rst new file mode 100644 index 000000000000..81f31af82e65 --- /dev/null +++ b/Documentation/block/error-injection.rst @@ -0,0 +1,59 @@ +.. SPDX-License-Identifier: GPL-2.0 + +============================ +Configurable Error Injection +============================ + +Overview +-------- + +Configurable error injection allows injecting specific block layer status codes +for sector ranges of a block device. Errors can be injected unconditionally, or +with a given probability. + +To use configurable error injection, CONFIG_BLK_ERROR_INJECTION must be enabled. + +The only interface is the error_injection debugfs file, which is created for +each registered gendisk. Writes to this file are used to create or delete rules +and reads return a list of the current error injection sites. + +Options +------- + +The following options specify the operations: + +=================== ======================================================= +add add a new rule +removeall remove all existing rules +=================== ======================================================= + +The following options specify the details of the rule for the add operation: + +=================== ======================================================= +op= block layer operation this rule applies to. This uses + the XYZ for each REQ_OP_XYZ operation, e.g. READ, WRITE + or DISCARD. Mandatory. +status= Status to return. This uses XYZ for each BLK_STS_XYZ + code, e.g. IOERR or MEDIUM. Mandatory. +start= First block layer sector the rule applies to. + Optional, defaults to 0. +nr_sectors= Number of sectors this rule applies. + Optional, defaults to the remainder of the device. +chance= Only return a failure with a likelihood of 1/chance. + Optional, defaults to 1 (always). +=================== ======================================================= + +Example +------- + +Return BLK_STS_IOERR for one in 10 reads of sector 0 of /dev/nvme0n1: + + $ echo 'add,op=READ,start=0,status=IOERR,chance=10' > /sys/kernel/debug/block/nvme0n1/error_injection + +Return BLK_STS_MEDIUM for every write to /dev/nvme0n1: + + $ echo 'add,op=WRITE,start=0,status=MEDIUM' > /sys/kernel/debug/block/nvme0n1/error_injection + +Remove all rules for /dev/nvme0n1: + + $ echo 'removeall' > /sys/kernel/debug/block/nvme0n1/error_injection diff --git a/Documentation/block/index.rst b/Documentation/block/index.rst index 9fea696f9daa..bfa1bbd31ddf 100644 --- a/Documentation/block/index.rst +++ b/Documentation/block/index.rst @@ -22,3 +22,4 @@ Block switching-sched writeback_cache_control ublk + error-injection diff --git a/block/Kconfig b/block/Kconfig index 15027963472d..70e4a66d941f 100644 --- a/block/Kconfig +++ b/block/Kconfig @@ -221,6 +221,14 @@ config BLOCK_HOLDER_DEPRECATED config BLK_MQ_STACKING bool +config BLK_ERROR_INJECTION + bool "Enable block layer error injection" + select JUMP_LABEL if HAVE_ARCH_JUMP_LABEL + help + Enable inserting arbitrary block errors through a debugfs interface. + + See Documentation/block/error-injection.rst for details. + source "block/Kconfig.iosched" endif # BLOCK diff --git a/block/Makefile b/block/Makefile index 54130faacc21..e7bd320e3d69 100644 --- a/block/Makefile +++ b/block/Makefile @@ -13,6 +13,7 @@ obj-y := bdev.o fops.o bio.o elevator.o blk-core.o blk-sysfs.o \ genhd.o ioprio.o badblocks.o partitions/ blk-rq-qos.o \ disk-events.o blk-ia-ranges.o early-lookup.o +obj-$(CONFIG_BLK_ERROR_INJECTION) += error-injection.o obj-$(CONFIG_BLK_DEV_BSG_COMMON) += bsg.o obj-$(CONFIG_BLK_DEV_BSGLIB) += bsg-lib.o obj-$(CONFIG_BLK_CGROUP) += blk-cgroup.o diff --git a/block/blk-core.c b/block/blk-core.c index beaab7a71fba..73a41df98c9a 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -50,6 +50,7 @@ #include "blk-cgroup.h" #include "blk-throttle.h" #include "blk-ioprio.h" +#include "error-injection.h" struct dentry *blk_debugfs_root; @@ -767,6 +768,9 @@ static void __submit_bio_noacct_mq(struct bio *bio) void submit_bio_noacct_nocheck(struct bio *bio, bool split) { + if (unlikely(blk_error_inject(bio))) + return; + blk_cgroup_bio_start(bio); if (!bio_flagged(bio, BIO_TRACE_COMPLETION)) { diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c index f22c1f253eb3..520972676ab4 100644 --- a/block/blk-sysfs.c +++ b/block/blk-sysfs.c @@ -19,6 +19,7 @@ #include "blk-wbt.h" #include "blk-cgroup.h" #include "blk-throttle.h" +#include "error-injection.h" struct queue_sysfs_entry { struct attribute attr; @@ -933,6 +934,8 @@ static void blk_debugfs_remove(struct gendisk *disk) blk_debugfs_lock_nomemsave(q); blk_trace_shutdown(q); + if (IS_ENABLED(CONFIG_BLK_ERROR_INJECTION)) + blk_error_injection_exit(disk); debugfs_remove_recursive(q->debugfs_dir); q->debugfs_dir = NULL; q->sched_debugfs_dir = NULL; @@ -963,6 +966,8 @@ int blk_register_queue(struct gendisk *disk) memflags = blk_debugfs_lock(q); q->debugfs_dir = debugfs_create_dir(disk->disk_name, blk_debugfs_root); + if (IS_ENABLED(CONFIG_BLK_ERROR_INJECTION)) + blk_error_injection_init(disk); if (queue_is_mq(q)) blk_mq_debugfs_register(q); blk_debugfs_unlock(q, memflags); diff --git a/block/error-injection.c b/block/error-injection.c new file mode 100644 index 000000000000..d24c90e9a25f --- /dev/null +++ b/block/error-injection.c @@ -0,0 +1,315 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2026 Christoph Hellwig. + */ +#include +#include +#include +#include +#include "blk.h" +#include "error-injection.h" + +struct blk_error_inject { + struct list_head entry; + sector_t start; + sector_t end; + enum req_op op; + blk_status_t status; + + /* only inject every 1 / chance times */ + unsigned int chance; +}; + +DEFINE_STATIC_KEY_FALSE(blk_error_injection_enabled); + +bool __blk_error_inject(struct bio *bio) +{ + struct gendisk *disk = bio->bi_bdev->bd_disk; + struct blk_error_inject *inj; + + rcu_read_lock(); + list_for_each_entry_rcu(inj, &disk->error_injection_list, entry) { + if (bio_op(bio) != inj->op) + continue; + /* + * This never matches 0-sized bios like empty WRITEs with + * REQ_PREFLUSH or ZONE_RESET_ALL. While adding a special case + * for them would be trivial, that means any WRITE rule would + * trigger for flushes. So before we can make this work + * properly, we'll need to start using REQ_OP_FLUSH for pure + * flushes at the bio level like we already do in blk-mq. + */ + if (bio->bi_iter.bi_sector > inj->end || + bio_end_sector(bio) <= inj->start) + continue; + if (inj->chance > 1 && (get_random_u32() % inj->chance) != 0) + continue; + + pr_info_ratelimited("%pg: injecting %s error for %s at sector %llu:%u\n", + disk->part0, blk_status_to_str(inj->status), + blk_op_str(inj->op), bio->bi_iter.bi_sector, + bio_sectors(bio)); + bio->bi_status = inj->status; + rcu_read_unlock(); + bio_endio(bio); + return true; + } + rcu_read_unlock(); + return false; +} + +static int error_inject_add(struct gendisk *disk, enum req_op op, + sector_t start, u64 nr_sectors, blk_status_t status, + unsigned int chance) +{ + struct blk_error_inject *inj; + int error = -EINVAL; + + if (op == REQ_OP_LAST) + return -EINVAL; + if (status == BLK_STS_OK) + return -EINVAL; + + inj = kzalloc_obj(*inj); + if (!inj) + return -ENOMEM; + + if (nr_sectors) { + if (U64_MAX - nr_sectors < start) + goto out_free_inj; + inj->end = start + nr_sectors - 1; + } else { + inj->end = U64_MAX; + } + + inj->op = op; + inj->start = start; + inj->status = status; + inj->chance = chance; + + pr_debug_ratelimited("%pg: adding %s injection for %s at sector %llu:%llu\n", + disk->part0, blk_status_to_str(status), + blk_op_str(op), + start, nr_sectors); + + /* + * Add to the front of the list so that newer entries can partially + * override other entries. This also intentionally allows duplicate + * entries as there is no real reason to reject them. + */ + mutex_lock(&disk->error_injection_lock); + if (!disk_live(disk)) { + mutex_unlock(&disk->error_injection_lock); + error = -ENODEV; + goto out_free_inj; + } + if (list_empty(&disk->error_injection_list)) + static_branch_inc(&blk_error_injection_enabled); + list_add_rcu(&inj->entry, &disk->error_injection_list); + set_bit(GD_ERROR_INJECT, &disk->state); + mutex_unlock(&disk->error_injection_lock); + return 0; + +out_free_inj: + kfree(inj); + return error; +} + +static void error_inject_removeall(struct gendisk *disk) +{ + struct blk_error_inject *inj; + + mutex_lock(&disk->error_injection_lock); + clear_bit(GD_ERROR_INJECT, &disk->state); + while ((inj = list_first_entry_or_null(&disk->error_injection_list, + struct blk_error_inject, entry))) { + list_del_rcu(&inj->entry); + kfree_rcu_mightsleep(inj); + } + static_branch_dec(&blk_error_injection_enabled); + mutex_unlock(&disk->error_injection_lock); +} + +enum options { + Opt_add = (1u << 0), + Opt_removeall = (1u << 1), + + Opt_op = (1u << 16), + Opt_start = (1u << 17), + Opt_nr_sectors = (1u << 18), + Opt_status = (1u << 19), + Opt_chance = (1u << 20), + + Opt_invalid, +}; + +static const match_table_t opt_tokens = { + { Opt_add, "add", }, + { Opt_removeall, "removeall", }, + { Opt_op, "op=%s", }, + { Opt_start, "start=%u" }, + { Opt_nr_sectors, "nr_sectors=%u" }, + { Opt_status, "status=%s" }, + { Opt_chance, "chance=%u" }, + { Opt_invalid, NULL, }, +}; + +static int match_op(substring_t *args, enum req_op *op) +{ + const char *tag; + + tag = match_strdup(args); + if (!tag) + return -ENOMEM; + *op = str_to_blk_op(tag); + if (*op == REQ_OP_LAST) + pr_warn("invalid op '%s'\n", tag); + kfree(tag); + return 0; +} + +static int match_status(substring_t *args, blk_status_t *status) +{ + const char *tag; + + tag = match_strdup(args); + if (!tag) + return -ENOMEM; + *status = tag_to_blk_status(tag); + if (!*status) + pr_warn("invalid status '%s'\n", tag); + kfree(tag); + return 0; +} + +static ssize_t blk_error_injection_parse_options(struct gendisk *disk, + char *options) +{ + enum { Unset, Add, Removeall } action = Unset; + unsigned int option_mask = 0, chance = 1; + enum req_op op = REQ_OP_LAST; + u64 start = 0, nr_sectors = 0; + blk_status_t status = BLK_STS_OK; + substring_t args[MAX_OPT_ARGS]; + char *p; + + while ((p = strsep(&options, ",\n")) != NULL) { + int error = 0; + ssize_t token; + + if (!*p) + continue; + token = match_token(p, opt_tokens, args); + option_mask |= token; + switch (token) { + case Opt_add: + if (action != Unset) + return -EINVAL; + action = Add; + break; + case Opt_removeall: + if (action != Unset) + return -EINVAL; + action = Removeall; + break; + case Opt_op: + error = match_op(args, &op); + break; + case Opt_start: + error = match_u64(args, &start); + break; + case Opt_nr_sectors: + error = match_u64(args, &nr_sectors); + break; + case Opt_status: + error = match_status(args, &status); + break; + case Opt_chance: + error = match_uint(args, &chance); + if (!error && chance == 0) + error = -EINVAL; + break; + default: + pr_warn("unknown parameter or missing value '%s'\n", p); + error = -EINVAL; + } + if (error) + return error; + } + + switch (action) { + case Add: + return error_inject_add(disk, op, start, nr_sectors, status, + chance); + case Removeall: + if (option_mask & ~Opt_removeall) + return -EINVAL; + error_inject_removeall(disk); + return 0; + default: + return -EINVAL; + } +} + +static ssize_t blk_error_injection_write(struct file *file, + const char __user *ubuf, size_t count, loff_t *pos) +{ + struct gendisk *disk = file_inode(file)->i_private; + char *options; + int error; + + options = memdup_user_nul(ubuf, count); + if (IS_ERR(options)) + return PTR_ERR(options); + error = blk_error_injection_parse_options(disk, options); + kfree(options); + + if (error) + return error; + return count; +} + +static int blk_error_injection_show(struct seq_file *s, void *private) +{ + struct gendisk *disk = s->private; + struct blk_error_inject *inj; + + rcu_read_lock(); + list_for_each_entry_rcu(inj, &disk->error_injection_list, entry) { + seq_printf(s, "%llu:%llu status=%s,chance=%u", + inj->start, inj->end, + blk_status_to_tag(inj->status), inj->chance); + seq_putc(s, '\n'); + } + rcu_read_unlock(); + return 0; +} + +static int blk_error_injection_open(struct inode *inode, struct file *file) +{ + return single_open(file, blk_error_injection_show, inode->i_private); +} + +static int blk_error_injection_release(struct inode *inode, struct file *file) +{ + return single_release(inode, file); +} + +static const struct file_operations blk_error_injection_fops = { + .owner = THIS_MODULE, + .write = blk_error_injection_write, + .read = seq_read, + .open = blk_error_injection_open, + .release = blk_error_injection_release, +}; + +void blk_error_injection_init(struct gendisk *disk) +{ + debugfs_create_file("error_injection", 0600, disk->queue->debugfs_dir, + disk, &blk_error_injection_fops); +} + +void blk_error_injection_exit(struct gendisk *disk) +{ + error_inject_removeall(disk); +} diff --git a/block/error-injection.h b/block/error-injection.h new file mode 100644 index 000000000000..9821d773abab --- /dev/null +++ b/block/error-injection.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _BLK_ERROR_INJECTION_H +#define _BLK_ERROR_INJECTION_H 1 + +#include + +DECLARE_STATIC_KEY_FALSE(blk_error_injection_enabled); + +void blk_error_injection_init(struct gendisk *disk); +void blk_error_injection_exit(struct gendisk *disk); +bool __blk_error_inject(struct bio *bio); +static inline bool blk_error_inject(struct bio *bio) +{ + if (IS_ENABLED(CONFIG_BLK_ERROR_INJECTION) && + static_branch_unlikely(&blk_error_injection_enabled) && + test_bit(GD_ERROR_INJECT, &bio->bi_bdev->bd_disk->state)) + return __blk_error_inject(bio); + return false; +} + +#endif /* _BLK_ERROR_INJECTION_H */ diff --git a/block/genhd.c b/block/genhd.c index 7d6854fd28e9..f84b6a355b57 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -1485,6 +1485,10 @@ struct gendisk *__alloc_disk_node(struct request_queue *q, int node_id, lockdep_init_map(&disk->lockdep_map, "(bio completion)", lkclass, 0); #ifdef CONFIG_BLOCK_HOLDER_DEPRECATED INIT_LIST_HEAD(&disk->slave_bdevs); +#endif +#ifdef CONFIG_BLK_ERROR_INJECTION + mutex_init(&disk->error_injection_lock); + INIT_LIST_HEAD(&disk->error_injection_list); #endif mutex_init(&disk->rqos_state_mutex); kobject_init(&disk->queue_kobj, &blk_queue_ktype); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 57e84d59a642..5070851cf924 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -176,6 +176,7 @@ struct gendisk { #define GD_SUPPRESS_PART_SCAN 5 #define GD_OWNS_QUEUE 6 #define GD_ZONE_APPEND_USED 7 +#define GD_ERROR_INJECT 8 struct mutex open_mutex; /* open/close mutex */ unsigned open_partitions; /* number of open partitions */ @@ -227,6 +228,11 @@ struct gendisk { */ struct blk_independent_access_ranges *ia_ranges; +#ifdef CONFIG_BLK_ERROR_INJECTION + struct mutex error_injection_lock; + struct list_head error_injection_list; +#endif + struct mutex rqos_state_mutex; /* rqos state change mutex */ }; -- cgit v1.2.3