linux/drivers/block/drbd/drbd_nl.c

// SPDX-License-Identifier: GPL-2.0-only
/*
   drbd_nl.c

   This file is part of DRBD by Philipp Reisner and Lars Ellenberg.

   Copyright (C) 2001-2008, LINBIT Information Technologies GmbH.
   Copyright (C) 1999-2008, Philipp Reisner <[email protected]>.
   Copyright (C) 2002-2008, Lars Ellenberg <[email protected]>.


 */

#define pr_fmt(fmt)

#include <linux/module.h>
#include <linux/drbd.h>
#include <linux/in.h>
#include <linux/fs.h>
#include <linux/file.h>
#include <linux/slab.h>
#include <linux/blkpg.h>
#include <linux/cpumask.h>
#include "drbd_int.h"
#include "drbd_protocol.h"
#include "drbd_req.h"
#include "drbd_state_change.h"
#include <asm/unaligned.h>
#include <linux/drbd_limits.h>
#include <linux/kthread.h>

#include <net/genetlink.h>

/* .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 <linux/drbd_genl_api.h>
#include "drbd_nla.h"
#include <linux/genl_magic_func.h>

static atomic_t drbd_genl_seq =; /* two. */
static atomic_t notify_genl_seq =; /* two. */

DEFINE_MUTEX();

/* used bdev_open_by_path, to claim our meta data device(s) */
static char *drbd_m_holder =;

static void drbd_adm_send_reply(struct sk_buff *skb, struct genl_info *info)
{}

/* Used on a fresh "drbd_adm_prepare"d reply_skb, this cannot fail: The only
 * reason it could fail was no space in skb, and there are 4k available. */
static int drbd_msg_put_info(struct sk_buff *skb, const char *info)
{}

__printf(2, 3)
static int drbd_msg_sprintf_info(struct sk_buff *skb, const char *fmt, ...)
{}

/* This would be a good candidate for a "pre_doit" hook,
 * and per-family private info->pointers.
 * But we need to stay compatible with older kernels.
 * If it returns successfully, adm_ctx members are valid.
 *
 * 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
 * to add additional synchronization against object destruction/modification.
 */
#define DRBD_ADM_NEED_MINOR
#define DRBD_ADM_NEED_RESOURCE
#define DRBD_ADM_NEED_CONNECTION
static int drbd_adm_prepare(struct drbd_config_context *adm_ctx,
	struct sk_buff *skb, struct genl_info *info, unsigned flags)
{}

static int drbd_adm_finish(struct drbd_config_context *adm_ctx,
	struct genl_info *info, int retcode)
{}

static void setup_khelper_env(struct drbd_connection *connection, char **envp)
{}

int drbd_khelper(struct drbd_device *device, char *cmd)
{}

enum drbd_peer_state conn_khelper(struct drbd_connection *connection, char *cmd)
{}

static enum drbd_fencing_p highest_fencing_policy(struct drbd_connection *connection)
{}

static bool resource_is_supended(struct drbd_resource *resource)
{}

bool conn_try_outdate_peer(struct drbd_connection *connection)
{}

static int _try_outdate_peer_async(void *data)
{}

void conn_try_outdate_peer_async(struct drbd_connection *connection)
{}

enum drbd_state_rv
drbd_set_role(struct drbd_device *const device, enum drbd_role new_role, int force)
{}

static const char *from_attrs_err_to_txt(int err)
{}

int drbd_adm_set_role(struct sk_buff *skb, struct genl_info *info)
{}

/* Initializes the md.*_offset members, so we are able to find
 * the on disk meta data.
 *
 * We currently have two possible layouts:
 * external:
 *   |----------- md_size_sect ------------------|
 *   [ 4k superblock ][ activity log ][  Bitmap  ]
 *   | al_offset == 8 |
 *   | bm_offset = al_offset + X      |
 *  ==> bitmap sectors = md_size_sect - bm_offset
 *
 * internal:
 *            |----------- md_size_sect ------------------|
 * [data.....][  Bitmap  ][ activity log ][ 4k superblock ]
 *                        | al_offset < 0 |
 *            | bm_offset = al_offset - Y |
 *  ==> bitmap sectors = Y = al_offset - bm_offset
 *
 *  Activity log size used to be fixed 32kB,
 *  but is about to become configurable.
 */
static void drbd_md_set_sector_offsets(struct drbd_device *device,
				       struct drbd_backing_dev *bdev)
{}

/* input size is expected to be in KB */
char *ppsize(char *buf, unsigned long long size)
{}

/* there is still a theoretical deadlock when called from receiver
 * on an D_INCONSISTENT R_PRIMARY:
 *  remote READ does inc_ap_bio, receiver would need to receive answer
 *  packet from remote to dec_ap_bio again.
 *  receiver receive_sizes(), comes here,
 *  waits for ap_bio_cnt == 0. -> deadlock.
 * but this cannot happen, actually, because:
 *  R_PRIMARY D_INCONSISTENT, and peer's disk is unreachable
 *  (not connected, or bad/no disk on peer):
 *  see drbd_fail_request_early, ap_bio_cnt is zero.
 *  R_PRIMARY D_INCONSISTENT, and C_SYNC_TARGET:
 *  peer may not initiate a resize.
 */
/* Note these are not to be confused with
 * drbd_adm_suspend_io/drbd_adm_resume_io,
 * which are (sub) state changes triggered by admin (drbdsetup),
 * and can be long lived.
 * This changes an device->flag, is triggered by drbd internals,
 * and should be short-lived. */
/* It needs to be a counter, since multiple threads might
   independently suspend and resume IO. */
void drbd_suspend_io(struct drbd_device *device)
{}

void drbd_resume_io(struct drbd_device *device)
{}

/*
 * drbd_determine_dev_size() -  Sets the right device size obeying all constraints
 * @device:	DRBD device.
 *
 * Returns 0 on success, negative return values indicate errors.
 * You should call drbd_md_sync() after calling this function.
 */
enum determine_dev_size
drbd_determine_dev_size(struct drbd_device *device, enum dds_flags flags, struct resize_parms *rs) __must_hold(local)
{}

sector_t
drbd_new_dev_size(struct drbd_device *device, struct drbd_backing_dev *bdev,
		  sector_t u_size, int assume_peer_has_space)
{}

/*
 * drbd_check_al_size() - Ensures that the AL is of the right size
 * @device:	DRBD device.
 *
 * Returns -EBUSY if current al lru is still used, -ENOMEM when allocation
 * failed, and 0 on success. You should call drbd_md_sync() after you called
 * this function.
 */
static int drbd_check_al_size(struct drbd_device *device, struct disk_conf *dc)
{}

static unsigned int drbd_max_peer_bio_size(struct drbd_device *device)
{}

static unsigned int drbd_max_discard_sectors(struct drbd_connection *connection)
{}

static bool drbd_discard_supported(struct drbd_connection *connection,
		struct drbd_backing_dev *bdev)
{}

/* This is the workaround for "bio would need to, but cannot, be split" */
static unsigned int drbd_backing_dev_max_segments(struct drbd_device *device)
{}

void drbd_reconsider_queue_parameters(struct drbd_device *device,
		struct drbd_backing_dev *bdev, struct o_qlim *o)
{}

/* Starts the worker thread */
static void conn_reconfig_start(struct drbd_connection *connection)
{}

/* if still unconfigured, stops worker again. */
static void conn_reconfig_done(struct drbd_connection *connection)
{}

/* Make sure IO is suspended before calling this function(). */
static void drbd_suspend_al(struct drbd_device *device)
{}


static bool should_set_defaults(struct genl_info *info)
{}

static unsigned int drbd_al_extents_max(struct drbd_backing_dev *bdev)
{}

static bool write_ordering_changed(struct disk_conf *a, struct disk_conf *b)
{}

static void sanitize_disk_conf(struct drbd_device *device, struct disk_conf *disk_conf,
			       struct drbd_backing_dev *nbc)
{}

static int disk_opts_check_al_size(struct drbd_device *device, struct disk_conf *dc)
{}

int drbd_adm_disk_opts(struct sk_buff *skb, struct genl_info *info)
{}

static struct file *open_backing_dev(struct drbd_device *device,
		const char *bdev_path, void *claim_ptr, bool do_bd_link)
{}

static int open_backing_devices(struct drbd_device *device,
		struct disk_conf *new_disk_conf,
		struct drbd_backing_dev *nbc)
{}

static void close_backing_dev(struct drbd_device *device,
		struct file *bdev_file, bool do_bd_unlink)
{}

void drbd_backing_dev_free(struct drbd_device *device, struct drbd_backing_dev *ldev)
{}

int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
{}

static int adm_detach(struct drbd_device *device, int force)
{}

/* Detaching the disk is a process in multiple stages.  First we need to lock
 * out application IO, in-flight IO, IO stuck in drbd_al_begin_io.
 * 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)
{}

static bool conn_resync_running(struct drbd_connection *connection)
{}

static bool conn_ov_running(struct drbd_connection *connection)
{}

static enum drbd_ret_code
_check_net_options(struct drbd_connection *connection, struct net_conf *old_net_conf, struct net_conf *new_net_conf)
{}

static enum drbd_ret_code
check_net_options(struct drbd_connection *connection, struct net_conf *new_net_conf)
{}

struct crypto {};

static int
alloc_shash(struct crypto_shash **tfm, char *tfm_name, int err_alg)
{}

static enum drbd_ret_code
alloc_crypto(struct crypto *crypto, struct net_conf *new_net_conf)
{}

static void free_crypto(struct crypto *crypto)
{}

int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info)
{}

static void connection_to_info(struct connection_info *info,
			       struct drbd_connection *connection)
{}

static void peer_device_to_info(struct peer_device_info *info,
				struct drbd_peer_device *peer_device)
{}

int drbd_adm_connect(struct sk_buff *skb, struct genl_info *info)
{}

static enum drbd_state_rv conn_try_disconnect(struct drbd_connection *connection, bool force)
{}

int drbd_adm_disconnect(struct sk_buff *skb, struct genl_info *info)
{}

void resync_after_online_grow(struct drbd_device *device)
{}

int drbd_adm_resize(struct sk_buff *skb, struct genl_info *info)
{}

int drbd_adm_resource_opts(struct sk_buff *skb, struct genl_info *info)
{}

int drbd_adm_invalidate(struct sk_buff *skb, struct genl_info *info)
{}

static int drbd_adm_simple_request_state(struct sk_buff *skb, struct genl_info *info,
		union drbd_state mask, union drbd_state val)
{}

static int drbd_bmio_set_susp_al(struct drbd_device *device,
		struct drbd_peer_device *peer_device) __must_hold(local)
{}

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)
{}

static int nla_put_drbd_cfg_context(struct sk_buff *skb,
				    struct drbd_resource *resource,
				    struct drbd_connection *connection,
				    struct drbd_device *device)
{}

/*
 * The generic netlink dump callbacks are called outside the genl_lock(), so
 * they cannot use the simple attribute parsing code which uses global
 * attribute tables.
 */
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)
{}

static void device_to_statistics(struct device_statistics *s,
				 struct drbd_device *device)
{}

static int put_resource_in_arg0(struct netlink_callback *cb, int holder_nr)
{}

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_adm_dump_connections_done(struct netlink_callback *cb)
{}

enum {};

int drbd_adm_dump_connections(struct sk_buff *skb, struct netlink_callback *cb)
{}

enum mdf_peer_flag {};

static void peer_device_to_statistics(struct peer_device_statistics *s,
				      struct drbd_peer_device *peer_device)
{}

int drbd_adm_dump_peer_devices_done(struct netlink_callback *cb)
{}

int drbd_adm_dump_peer_devices(struct sk_buff *skb, struct netlink_callback *cb)
{}
/*
 * Return the connection of @resource if @resource has exactly one connection.
 */
static struct drbd_connection *the_only_connection(struct drbd_resource *resource)
{}

static int nla_put_status_info(struct sk_buff *skb, struct drbd_device *device,
		const struct sib_info *sib)
{}

int drbd_adm_get_status(struct sk_buff *skb, struct genl_info *info)
{}

static int get_one_status(struct sk_buff *skb, struct netlink_callback *cb)
{}

/*
 * Request status of all resources, or of all volumes within a single resource.
 *
 * This is a dump, as the answer may not fit in a single reply skb otherwise.
 * Which means we cannot use the family->attrbuf or other such members, because
 * dump is NOT protected by the genl_lock().  During dump, we only have access
 * to the incoming skb, and need to opencode "parsing" of the nlattr payload.
 *
 * 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_adm_get_timeout_type(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)
{}

static enum drbd_ret_code
drbd_check_resource_name(struct drbd_config_context *adm_ctx)
{}

static void resource_to_info(struct resource_info *info,
			     struct drbd_resource *resource)
{}

int drbd_adm_new_resource(struct sk_buff *skb, struct genl_info *info)
{}

static void device_to_info(struct device_info *info,
			   struct drbd_device *device)
{}


int drbd_adm_new_minor(struct sk_buff *skb, struct genl_info *info)
{}

static enum drbd_ret_code adm_del_minor(struct drbd_device *device)
{}

int drbd_adm_del_minor(struct sk_buff *skb, struct genl_info *info)
{}

static int adm_del_resource(struct drbd_resource *resource)
{}

int drbd_adm_down(struct sk_buff *skb, struct genl_info *info)
{}

int drbd_adm_del_resource(struct sk_buff *skb, struct genl_info *info)
{}

void drbd_bcast_event(struct drbd_device *device, const struct sib_info *sib)
{}

static int nla_put_notification_header(struct sk_buff *msg,
				       enum drbd_notification_type type)
{}

int notify_resource_state(struct sk_buff *skb,
			   unsigned int seq,
			   struct drbd_resource *resource,
			   struct resource_info *resource_info,
			   enum drbd_notification_type type)
{}

int notify_device_state(struct sk_buff *skb,
			 unsigned int seq,
			 struct drbd_device *device,
			 struct device_info *device_info,
			 enum drbd_notification_type type)
{}

int notify_connection_state(struct sk_buff *skb,
			     unsigned int seq,
			     struct drbd_connection *connection,
			     struct connection_info *connection_info,
			     enum drbd_notification_type type)
{}

int notify_peer_device_state(struct sk_buff *skb,
			      unsigned int seq,
			      struct drbd_peer_device *peer_device,
			      struct peer_device_info *peer_device_info,
			      enum drbd_notification_type type)
{}

void notify_helper(enum drbd_notification_type type,
		   struct drbd_device *device, struct drbd_connection *connection,
		   const char *name, int status)
{}

static int notify_initial_state_done(struct sk_buff *skb, unsigned int seq)
{}

static void free_state_changes(struct list_head *list)
{}

static unsigned int notifications_for_state_change(struct drbd_state_change *state_change)
{}

static int get_initial_state(struct sk_buff *skb, struct netlink_callback *cb)
{}

int drbd_adm_get_initial_state(struct sk_buff *skb, struct netlink_callback *cb)
{}