summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-06-16 13:02:47 +0530
committerLinus Torvalds <torvalds@linux-foundation.org>2026-06-16 13:02:47 +0530
commitba9c792c824fff732df85119011d399d9b6d9155 (patch)
treea6de1eda726e4e9156366b6fd960b81d09297aa3 /drivers
parent9b40ba14edcdf70240af8114092a76f75f070774 (diff)
parentc7c76f9232bd34835d821f14abdc5fafc17bc938 (diff)
downloadlinux-next-ba9c792c824fff732df85119011d399d9b6d9155.tar.gz
linux-next-ba9c792c824fff732df85119011d399d9b6d9155.zip
Merge tag 'for-7.2/block-20260615' of git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux
Pull block updates from Jens Axboe: - NVMe pull request via Keith: - Per-controller admin and IO timeout sysfs attributes, and letting the block layer set request timeouts (Maurizio, Maximilian) - Multipath passthrough iostats, and PCI P2PDMA enablement for multipath devices (Keith, Kiran) - A new diag sysfs attribute group exporting per-controller counters (retries, multipath failover, error counters, requeue and failure counts, reset and reconnect events) (Nilay) - FDP configuration validation and bounds check fixes (liuxixin) - Various nvmet fixes, including a pre-auth out-of-bounds read in the Discovery Get Log Page handler, auth payload bounds validation, and tcp error-path leak fixes (Bryam, Tianchu, Geliang) - nvme-tcp lockdep and workqueue fixes (Shin'ichiro, Kuniyuki, Eric) - Assorted other fixes and cleanups (John, Yao, Chao, Mateusz, Achkinazi, Wentao) - MD pull request via Yu Kuai: - raid1/raid10 fixes for a deadlock in the read error recovery path, error-path detection and bio accounting with cloned bios, and an nr_pending leak in the REQ_ATOMIC bad-block error path (Abd-Alrhman) - PCI P2PDMA propagation from member devices to the RAID device (Kiran) - dm-raid bio requeue fix, and various smaller fixes and cleanups (Benjamin, Chen, Li, Thorsten) - Enable Clang lock context analysis for the block layer, with the accompanying annotations across queue limits, the blk_holder_ops callbacks, crypto, cgroup, iocost, kyber and mq-deadline (Bart) - Block status code infrastructure work: a tagged status table, a str_to_blk_op() helper, a bio_endio_status() helper, and on top of that a new configurable block-layer error injection facility (Christoph) - DRBD netlink rework, replacing the genl_magic machinery with explicit netlink serialization and moving the DRBD UAPI headers to include/uapi/linux/ (Christoph Böhmwalder) - bvec improvements: a bvec_folio() helper and making the bvec_iter helpers proper inline functions (Willy, Christoph) - ublk cleanups and a canceling-flag fix for the disk-not-allocated case (Caleb, Ming) - Partition handling fixes: bound the AIX pp_count scan, fix an of_node refcount leak, and replace __get_free_page() with kmalloc() (Bryam, Wentao, Mike) - Convert numa_node to int in blk_mq_hw_ctx and ->init_request, and add WQ_PERCPU to the block workqueue users (Mateusz, Marco) - Block statistics and tracing: propagate in-flight to the whole disk on partition IO, export passthrough stats, and a new block_rq_tag_wait tracepoint (Tang, Keith, Aaron) - A round of removals, unexports and cleanups across bio, direct-io and the bvec helpers (Christoph) - Various driver fixes (mtip32xx use-after-free, rbd snap_count validation and strscpy conversion, nbd socket lockdep reclassify, virtio-blk zone report clamp, floppy) and a batch of MAINTAINERS email/list updates (Coly, Li, Yu, Christoph Böhmwalder) - Other little fixes and cleanups all over * tag 'for-7.2/block-20260615' of git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux: (117 commits) MAINTAINERS: Update Coly Li's email address block: check bio split for unaligned bvec nbd: Reclassify sockets to avoid lockdep circular dependency block: add configurable error injection block: add a str_to_blk_op helper block: add a "tag" for block status codes block: add a macro to initialize the status table floppy: Drop unused pnp driver data block: propagate in_flight to whole disk on partition I/O virtio-blk: clamp zone report to the report buffer capacity block: optimize I/O merge hot path with unlikely() hints drivers/block/rbd: Use strscpy() to copy strings into arrays partitions: aix: bound the pp_count scan to the ppe array block: Enable lock context analysis block/mq-deadline: Make the lock context annotations compatible with Clang block/Kyber: Make the lock context annotations compatible with Clang block/blk-mq-debugfs: Improve lock context annotations block/blk-iocost: Inline iocg_lock() and iocg_unlock() block/blk-iocost: Split ioc_rqos_throttle() block/crypto: Annotate the crypto functions ...
Diffstat (limited to 'drivers')
-rw-r--r--drivers/block/drbd/Makefile1
-rw-r--r--drivers/block/drbd/drbd_buildtag.c2
-rw-r--r--drivers/block/drbd/drbd_config.h16
-rw-r--r--drivers/block/drbd/drbd_debugfs.c2
-rw-r--r--drivers/block/drbd/drbd_int.h6
-rw-r--r--drivers/block/drbd/drbd_main.c6
-rw-r--r--drivers/block/drbd/drbd_nl.c416
-rw-r--r--drivers/block/drbd/drbd_nl_gen.c2606
-rw-r--r--drivers/block/drbd/drbd_nl_gen.h395
-rw-r--r--drivers/block/drbd/drbd_proc.c2
-rw-r--r--drivers/block/floppy.c4
-rw-r--r--drivers/block/loop.c24
-rw-r--r--drivers/block/mtip32xx/mtip32xx.c19
-rw-r--r--drivers/block/n64cart.c3
-rw-r--r--drivers/block/nbd.c39
-rw-r--r--drivers/block/rbd.c9
-rw-r--r--drivers/block/ublk_drv.c174
-rw-r--r--drivers/block/virtio_blk.c2
-rw-r--r--drivers/md/dm-raid.c6
-rw-r--r--drivers/md/dm-rq.c2
-rw-r--r--drivers/md/md.c32
-rw-r--r--drivers/md/md.h7
-rw-r--r--drivers/md/raid0.c4
-rw-r--r--drivers/md/raid1.c64
-rw-r--r--drivers/md/raid10.c30
-rw-r--r--drivers/md/raid5.c7
-rw-r--r--drivers/mmc/core/queue.c2
-rw-r--r--drivers/mtd/ubi/block.c2
-rw-r--r--drivers/nvme/host/apple.c4
-rw-r--r--drivers/nvme/host/core.c74
-rw-r--r--drivers/nvme/host/fc.c5
-rw-r--r--drivers/nvme/host/ioctl.c9
-rw-r--r--drivers/nvme/host/multipath.c144
-rw-r--r--drivers/nvme/host/nvme.h21
-rw-r--r--drivers/nvme/host/pci.c16
-rw-r--r--drivers/nvme/host/rdma.c6
-rw-r--r--drivers/nvme/host/sysfs.c311
-rw-r--r--drivers/nvme/host/tcp.c127
-rw-r--r--drivers/nvme/target/discovery.c23
-rw-r--r--drivers/nvme/target/fabrics-cmd-auth.c15
-rw-r--r--drivers/nvme/target/loop.c33
-rw-r--r--drivers/nvme/target/rdma.c6
-rw-r--r--drivers/nvme/target/tcp.c11
-rw-r--r--drivers/scsi/scsi_lib.c2
44 files changed, 4184 insertions, 505 deletions
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_buildtag.c b/drivers/block/drbd/drbd_buildtag.c
index cb1aa66d7d5d..cd0389488f63 100644
--- a/drivers/block/drbd/drbd_buildtag.c
+++ b/drivers/block/drbd/drbd_buildtag.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-#include <linux/drbd_config.h>
+#include "drbd_config.h"
#include <linux/module.h>
const char *drbd_buildtag(void)
diff --git a/drivers/block/drbd/drbd_config.h b/drivers/block/drbd/drbd_config.h
new file mode 100644
index 000000000000..d215365c6bb1
--- /dev/null
+++ b/drivers/block/drbd/drbd_config.h
@@ -0,0 +1,16 @@
+/* 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/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 f6d6276974ee..48b45c3142f7 100644
--- a/drivers/block/drbd/drbd_int.h
+++ b/drivers/block/drbd/drbd_int.h
@@ -32,14 +32,16 @@
#include <net/tcp.h>
#include <linux/lru_cache.h>
#include <linux/prefetch.h>
-#include <linux/drbd_genl_api.h>
#include <linux/drbd.h>
-#include <linux/drbd_config.h>
+#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 <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>
-
-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 <linux/genl_magic_func.h>
+#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(&notification_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 <net/netlink.h>
+#include <net/genetlink.h>
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include "drbd_nl_gen.h"
+
+#include <uapi/linux/drbd_genl.h>
+#include <linux/drbd.h>
+#include <linux/drbd_limits.h>
+
+/* 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 <net/netlink.h>
+#include <net/genetlink.h>
+
+#include <uapi/linux/drbd_genl.h>
+#include <linux/drbd.h>
+#include <linux/drbd_limits.h>
+
+/* 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/drivers/block/floppy.c b/drivers/block/floppy.c
index 0509746f8aed..dca495be0683 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -5012,8 +5012,8 @@ MODULE_LICENSE("GPL");
/* This doesn't actually get used other than for module information */
static const struct pnp_device_id floppy_pnpids[] = {
- {"PNP0700", 0},
- {}
+ { .id = "PNP0700" },
+ { }
};
MODULE_DEVICE_TABLE(pnp, floppy_pnpids);
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 0000913f7efc..310de0463beb 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -342,23 +342,19 @@ static int lo_rw_aio(struct loop_device *lo, struct loop_cmd *cmd,
{
struct iov_iter iter;
struct req_iterator rq_iter;
- struct bio_vec *bvec;
struct request *rq = blk_mq_rq_from_pdu(cmd);
- struct bio *bio = rq->bio;
struct file *file = lo->lo_backing_file;
- struct bio_vec tmp;
- unsigned int offset;
unsigned int nr_bvec;
int ret;
nr_bvec = blk_rq_nr_bvec(rq);
if (rq->bio != rq->biotail) {
+ struct bio_vec tmp, *bvec;
- bvec = kmalloc_objs(struct bio_vec, nr_bvec, GFP_NOIO);
- if (!bvec)
+ cmd->bvec = kmalloc_objs(*cmd->bvec, nr_bvec, GFP_NOIO);
+ if (!cmd->bvec)
return -EIO;
- cmd->bvec = bvec;
/*
* The bios of the request may be started from the middle of
@@ -366,26 +362,26 @@ static int lo_rw_aio(struct loop_device *lo, struct loop_cmd *cmd,
* copy bio->bi_iov_vec to new bvec. The rq_for_each_bvec
* API will take care of all details for us.
*/
+ bvec = cmd->bvec;
rq_for_each_bvec(tmp, rq, rq_iter) {
*bvec = tmp;
bvec++;
}
- bvec = cmd->bvec;
- offset = 0;
+ iov_iter_bvec(&iter, rw, cmd->bvec, nr_bvec, blk_rq_bytes(rq));
+ iter.iov_offset = 0;
} else {
/*
* Same here, this bio may be started from the middle of the
* 'bvec' because of bio splitting, so offset from the bvec
* must be passed to iov iterator
*/
- offset = bio->bi_iter.bi_bvec_done;
- bvec = __bvec_iter_bvec(bio->bi_io_vec, bio->bi_iter);
+ iov_iter_bvec(&iter, rw,
+ __bvec_iter_bvec(rq->bio->bi_io_vec, rq->bio->bi_iter),
+ nr_bvec, blk_rq_bytes(rq));
+ iter.iov_offset = rq->bio->bi_iter.bi_bvec_done;
}
atomic_set(&cmd->ref, 2);
- iov_iter_bvec(&iter, rw, bvec, nr_bvec, blk_rq_bytes(rq));
- iter.iov_offset = offset;
-
cmd->iocb.ki_pos = pos;
cmd->iocb.ki_filp = file;
cmd->iocb.ki_ioprio = req_get_ioprio(rq);
diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c
index 567192e371a8..f214a616386c 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);
@@ -3405,6 +3405,7 @@ static int mtip_block_initialize(struct driver_data *dd)
.max_segment_size = 0x400000,
};
int rv = 0, wait_for_rebuild = 0;
+ bool disk_added = false;
sector_t capacity;
unsigned int index = 0;
@@ -3438,6 +3439,7 @@ static int mtip_block_initialize(struct driver_data *dd)
dev_err(&dd->pdev->dev,
"Unable to allocate request queue\n");
rv = -ENOMEM;
+ dd->disk = NULL;
goto block_queue_alloc_init_error;
}
dd->queue = dd->disk->queue;
@@ -3496,6 +3498,7 @@ skip_create_disk:
rv = device_add_disk(&dd->pdev->dev, dd->disk, mtip_disk_attr_groups);
if (rv)
goto read_capacity_error;
+ disk_added = true;
if (dd->mtip_svc_handler) {
set_bit(MTIP_DDF_INIT_DONE_BIT, &dd->dd_flag);
@@ -3511,7 +3514,9 @@ start_service_thread:
dev_err(&dd->pdev->dev, "service thread failed to start\n");
dd->mtip_svc_handler = NULL;
rv = -EFAULT;
- goto kthread_run_error;
+ if (disk_added)
+ goto kthread_run_error;
+ goto read_capacity_error;
}
wake_up_process(dd->mtip_svc_handler);
if (wait_for_rebuild == MTIP_FTL_REBUILD_MAGIC)
@@ -3522,6 +3527,10 @@ start_service_thread:
kthread_run_error:
/* Delete our gendisk. This also removes the device from /dev */
del_gendisk(dd->disk);
+ mtip_hw_debugfs_exit(dd);
+ blk_mq_free_tag_set(&dd->tags);
+ mtip_hw_exit(dd);
+ return rv;
read_capacity_error:
init_hw_cmds_error:
mtip_hw_debugfs_exit(dd);
@@ -3529,6 +3538,7 @@ disk_index_error:
ida_free(&rssd_index_ida, index);
ida_get_error:
put_disk(dd->disk);
+ dd->disk = NULL;
block_queue_alloc_init_error:
blk_mq_free_tag_set(&dd->tags);
block_queue_alloc_tag_error:
@@ -3839,7 +3849,10 @@ msi_initialize_err:
}
iomap_err:
- kfree(dd);
+ if (dd->disk)
+ put_disk(dd->disk);
+ else
+ kfree(dd);
pci_set_drvdata(pdev, NULL);
return rv;
done:
diff --git a/drivers/block/n64cart.c b/drivers/block/n64cart.c
index b9fdeff31caf..328da73b6f2c 100644
--- a/drivers/block/n64cart.c
+++ b/drivers/block/n64cart.c
@@ -12,6 +12,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/string.h>
enum {
PI_DRAM_REG = 0,
@@ -145,7 +146,7 @@ static int __init n64cart_probe(struct platform_device *pdev)
disk->flags = GENHD_FL_NO_PART;
disk->fops = &n64cart_fops;
disk->private_data = &pdev->dev;
- strcpy(disk->disk_name, "n64cart");
+ strscpy(disk->disk_name, "n64cart");
set_capacity(disk, size >> SECTOR_SHIFT);
set_disk_ro(disk, 1);
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index fe63f3c55d0d..3a585a0c882a 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -1238,6 +1238,42 @@ static struct socket *nbd_get_socket(struct nbd_device *nbd, unsigned long fd,
return sock;
}
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+static struct lock_class_key nbd_key[3];
+static struct lock_class_key nbd_slock_key[3];
+
+static void nbd_reclassify_socket(struct socket *sock)
+{
+ struct sock *sk = sock->sk;
+
+ if (WARN_ON_ONCE(!sock_allow_reclassification(sk)))
+ return;
+
+ switch (sk->sk_family) {
+ case AF_INET:
+ sock_lock_init_class_and_name(sk, "slock-AF_INET-NBD",
+ &nbd_slock_key[0],
+ "sk_lock-AF_INET-NBD",
+ &nbd_key[0]);
+ break;
+ case AF_INET6:
+ sock_lock_init_class_and_name(sk, "slock-AF_INET6-NBD",
+ &nbd_slock_key[1],
+ "sk_lock-AF_INET6-NBD",
+ &nbd_key[1]);
+ break;
+ case AF_UNIX:
+ sock_lock_init_class_and_name(sk, "slock-AF_UNIX-NBD",
+ &nbd_slock_key[2],
+ "sk_lock-AF_UNIX-NBD",
+ &nbd_key[2]);
+ break;
+ }
+}
+#else
+static inline void nbd_reclassify_socket(struct socket *sock) {}
+#endif
+
static int nbd_add_socket(struct nbd_device *nbd, unsigned long arg,
bool netlink)
{
@@ -1254,6 +1290,7 @@ static int nbd_add_socket(struct nbd_device *nbd, unsigned long arg,
sock = nbd_get_socket(nbd, arg, &err);
if (!sock)
return err;
+ nbd_reclassify_socket(sock);
/*
* We need to make sure we don't get any errant requests while we're
@@ -1888,7 +1925,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/block/rbd.c b/drivers/block/rbd.c
index 6c1e7347e6a7..90c13de47cff 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -3672,7 +3672,7 @@ static void __rbd_lock(struct rbd_device *rbd_dev, const char *cookie)
struct rbd_client_id cid = rbd_get_cid(rbd_dev);
rbd_dev->lock_state = RBD_LOCK_STATE_LOCKED;
- strcpy(rbd_dev->lock_cookie, cookie);
+ strscpy(rbd_dev->lock_cookie, cookie);
rbd_set_owner_cid(rbd_dev, &cid);
queue_work(rbd_dev->task_wq, &rbd_dev->acquired_lock_work);
}
@@ -6082,12 +6082,9 @@ static int rbd_dev_v2_snap_context(struct rbd_device *rbd_dev,
/*
* Make sure the reported number of snapshot ids wouldn't go
- * beyond the end of our buffer. But before checking that,
- * make sure the computed size of the snapshot context we
- * allocate is representable in a size_t.
+ * beyond the end of our buffer.
*/
- if (snap_count > (SIZE_MAX - sizeof (struct ceph_snap_context))
- / sizeof (u64)) {
+ if (snap_count > RBD_MAX_SNAP_COUNT) {
ret = -EINVAL;
goto out;
}
diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
index 6c041eaebdb9..4f6d9e652187 100644
--- a/drivers/block/ublk_drv.c
+++ b/drivers/block/ublk_drv.c
@@ -359,7 +359,6 @@ static void ublk_buf_cleanup(struct ublk_device *ub);
static void ublk_abort_queue(struct ublk_device *ub, struct ublk_queue *ubq);
static inline struct request *__ublk_check_and_get_req(struct ublk_device *ub,
u16 q_id, u16 tag, struct ublk_io *io);
-static inline unsigned int ublk_req_build_flags(struct request *req);
static void ublk_batch_dispatch(struct ublk_queue *ubq,
const struct ublk_batch_io_data *data,
struct ublk_batch_fetch_cmd *fcmd);
@@ -471,6 +470,62 @@ static inline bool ublk_dev_support_integrity(const struct ublk_device *ub)
return ub->dev_info.flags & UBLK_F_INTEGRITY;
}
+static inline unsigned int ublk_req_build_flags(struct request *req)
+{
+ unsigned flags = 0;
+
+ if (req->cmd_flags & REQ_FAILFAST_DEV)
+ flags |= UBLK_IO_F_FAILFAST_DEV;
+
+ if (req->cmd_flags & REQ_FAILFAST_TRANSPORT)
+ flags |= UBLK_IO_F_FAILFAST_TRANSPORT;
+
+ if (req->cmd_flags & REQ_FAILFAST_DRIVER)
+ flags |= UBLK_IO_F_FAILFAST_DRIVER;
+
+ if (req->cmd_flags & REQ_META)
+ flags |= UBLK_IO_F_META;
+
+ if (req->cmd_flags & REQ_FUA)
+ flags |= UBLK_IO_F_FUA;
+
+ if (req->cmd_flags & REQ_NOUNMAP)
+ flags |= UBLK_IO_F_NOUNMAP;
+
+ if (req->cmd_flags & REQ_SWAP)
+ flags |= UBLK_IO_F_SWAP;
+
+ if (blk_integrity_rq(req))
+ flags |= UBLK_IO_F_INTEGRITY;
+
+ return flags;
+}
+
+static void ublk_init_iod(struct ublk_queue *ubq, struct request *req,
+ uint8_t ublk_op, uint32_t nr_sectors,
+ uint64_t start_sector)
+{
+ struct ublksrv_io_desc *iod = ublk_get_iod(ubq, req->tag);
+ struct ublk_io *io = &ubq->ios[req->tag];
+
+ iod->op_flags = ublk_op | ublk_req_build_flags(req);
+ iod->nr_sectors = nr_sectors;
+ iod->start_sector = start_sector;
+
+ /* Try shmem zero-copy match before setting addr */
+ if (ublk_support_shmem_zc(ubq) && blk_rq_has_data(req)) {
+ u32 buf_idx, buf_off;
+
+ if (ublk_try_buf_match(ubq->dev, req, &buf_idx, &buf_off)) {
+ iod->op_flags |= UBLK_IO_F_SHMEM_ZC;
+ iod->addr = ublk_shmem_zc_addr(buf_idx, buf_off);
+ return;
+ }
+ }
+
+ iod->addr = io->buf.addr;
+}
+
#ifdef CONFIG_BLK_DEV_ZONED
struct ublk_zoned_report_desc {
@@ -652,8 +707,6 @@ out:
static blk_status_t ublk_setup_iod_zoned(struct ublk_queue *ubq,
struct request *req)
{
- struct ublksrv_io_desc *iod = ublk_get_iod(ubq, req->tag);
- struct ublk_io *io = &ubq->ios[req->tag];
struct ublk_zoned_report_desc *desc;
u32 ublk_op;
@@ -683,9 +736,8 @@ static blk_status_t ublk_setup_iod_zoned(struct ublk_queue *ubq,
ublk_op = desc->operation;
switch (ublk_op) {
case UBLK_IO_OP_REPORT_ZONES:
- iod->op_flags = ublk_op | ublk_req_build_flags(req);
- iod->nr_zones = desc->nr_zones;
- iod->start_sector = desc->sector;
+ ublk_init_iod(ubq, req, ublk_op, desc->nr_zones,
+ desc->sector);
return BLK_STS_OK;
default:
return BLK_STS_IOERR;
@@ -697,11 +749,7 @@ static blk_status_t ublk_setup_iod_zoned(struct ublk_queue *ubq,
return BLK_STS_IOERR;
}
- iod->op_flags = ublk_op | ublk_req_build_flags(req);
- iod->nr_sectors = blk_rq_sectors(req);
- iod->start_sector = blk_rq_pos(req);
- iod->addr = io->buf.addr;
-
+ ublk_init_iod(ubq, req, ublk_op, blk_rq_sectors(req), blk_rq_pos(req));
return BLK_STS_OK;
}
@@ -1189,11 +1237,6 @@ static inline struct ublk_queue *ublk_get_queue(struct ublk_device *dev,
return dev->queues[qid];
}
-static inline bool ublk_rq_has_data(const struct request *rq)
-{
- return bio_has_data(rq->bio);
-}
-
static inline struct ublksrv_io_desc *
ublk_queue_cmd_buf(struct ublk_device *ub, int q_id)
{
@@ -1406,12 +1449,12 @@ static size_t ublk_copy_user_integrity(const struct request *req,
static inline bool ublk_need_map_req(const struct request *req)
{
- return ublk_rq_has_data(req) && req_op(req) == REQ_OP_WRITE;
+ return blk_rq_has_data(req) && req_op(req) == REQ_OP_WRITE;
}
static inline bool ublk_need_unmap_req(const struct request *req)
{
- return ublk_rq_has_data(req) &&
+ return blk_rq_has_data(req) &&
(req_op(req) == REQ_OP_READ || req_op(req) == REQ_OP_DRV_IN);
}
@@ -1460,41 +1503,8 @@ static unsigned int ublk_unmap_io(bool need_map,
return rq_bytes;
}
-static inline unsigned int ublk_req_build_flags(struct request *req)
-{
- unsigned flags = 0;
-
- if (req->cmd_flags & REQ_FAILFAST_DEV)
- flags |= UBLK_IO_F_FAILFAST_DEV;
-
- if (req->cmd_flags & REQ_FAILFAST_TRANSPORT)
- flags |= UBLK_IO_F_FAILFAST_TRANSPORT;
-
- if (req->cmd_flags & REQ_FAILFAST_DRIVER)
- flags |= UBLK_IO_F_FAILFAST_DRIVER;
-
- if (req->cmd_flags & REQ_META)
- flags |= UBLK_IO_F_META;
-
- if (req->cmd_flags & REQ_FUA)
- flags |= UBLK_IO_F_FUA;
-
- if (req->cmd_flags & REQ_NOUNMAP)
- flags |= UBLK_IO_F_NOUNMAP;
-
- if (req->cmd_flags & REQ_SWAP)
- flags |= UBLK_IO_F_SWAP;
-
- if (blk_integrity_rq(req))
- flags |= UBLK_IO_F_INTEGRITY;
-
- return flags;
-}
-
static blk_status_t ublk_setup_iod(struct ublk_queue *ubq, struct request *req)
{
- struct ublksrv_io_desc *iod = ublk_get_iod(ubq, req->tag);
- struct ublk_io *io = &ubq->ios[req->tag];
u32 ublk_op;
switch (req_op(req)) {
@@ -1519,25 +1529,7 @@ static blk_status_t ublk_setup_iod(struct ublk_queue *ubq, struct request *req)
return BLK_STS_IOERR;
}
- /* need to translate since kernel may change */
- iod->op_flags = ublk_op | ublk_req_build_flags(req);
- iod->nr_sectors = blk_rq_sectors(req);
- iod->start_sector = blk_rq_pos(req);
-
- /* Try shmem zero-copy match before setting addr */
- if (ublk_support_shmem_zc(ubq) && ublk_rq_has_data(req)) {
- u32 buf_idx, buf_off;
-
- if (ublk_try_buf_match(ubq->dev, req,
- &buf_idx, &buf_off)) {
- iod->op_flags |= UBLK_IO_F_SHMEM_ZC;
- iod->addr = ublk_shmem_zc_addr(buf_idx, buf_off);
- return BLK_STS_OK;
- }
- }
-
- iod->addr = io->buf.addr;
-
+ ublk_init_iod(ubq, req, ublk_op, blk_rq_sectors(req), blk_rq_pos(req));
return BLK_STS_OK;
}
@@ -1815,7 +1807,7 @@ static void ublk_dispatch_req(struct ublk_queue *ubq, struct request *req)
if (!ublk_start_io(ubq, req, io))
return;
- if (ublk_support_auto_buf_reg(ubq) && ublk_rq_has_data(req)) {
+ if (ublk_support_auto_buf_reg(ubq) && blk_rq_has_data(req)) {
ublk_auto_buf_dispatch(ubq, req, io, io->cmd, issue_flags);
} else {
ublk_init_req_ref(ubq, io);
@@ -1836,7 +1828,7 @@ static bool __ublk_batch_prep_dispatch(struct ublk_queue *ubq,
if (!ublk_start_io(ubq, req, io))
return false;
- if (ublk_support_auto_buf_reg(ubq) && ublk_rq_has_data(req)) {
+ if (ublk_support_auto_buf_reg(ubq) && blk_rq_has_data(req)) {
res = ublk_auto_buf_register(ubq, req, io, cmd,
data->issue_flags);
@@ -2735,23 +2727,27 @@ static void ublk_start_cancel(struct ublk_device *ub)
{
struct gendisk *disk = ublk_get_disk(ub);
- /* Our disk has been dead */
- if (!disk)
- return;
-
mutex_lock(&ub->cancel_mutex);
if (ub->canceling)
goto out;
- /*
- * Now we are serialized with ublk_queue_rq()
- *
- * Make sure that ubq->canceling is set when queue is frozen,
- * because ublk_queue_rq() has to rely on this flag for avoiding to
- * touch completed uring_cmd
- */
- blk_mq_quiesce_queue(disk->queue);
- ublk_set_canceling(ub, true);
- blk_mq_unquiesce_queue(disk->queue);
+
+ if (disk) {
+ /*
+ * Quiesce to serialize with ublk_queue_rq(), ensuring
+ * ubq->canceling is visible when the queue resumes.
+ */
+ blk_mq_quiesce_queue(disk->queue);
+ ublk_set_canceling(ub, true);
+ blk_mq_unquiesce_queue(disk->queue);
+ } else {
+ /*
+ * Disk not yet allocated by ublk_ctrl_start_dev(), so
+ * there is no request queue and ublk_queue_rq() cannot
+ * be running. Just set the flag; if start_dev proceeds
+ * later, new I/O will see canceling and be aborted.
+ */
+ ublk_set_canceling(ub, true);
+ }
out:
mutex_unlock(&ub->cancel_mutex);
ublk_put_disk(disk);
@@ -3227,7 +3223,7 @@ ublk_daemon_register_io_buf(struct io_uring_cmd *cmd,
return ublk_register_io_buf(cmd, ub, q_id, tag, io, index,
issue_flags);
- if (!ublk_dev_support_zero_copy(ub) || !ublk_rq_has_data(req))
+ if (!ublk_dev_support_zero_copy(ub) || !blk_rq_has_data(req))
return -EINVAL;
ret = io_buffer_register_bvec(cmd, req, ublk_io_release, index,
@@ -3510,7 +3506,7 @@ static inline struct request *__ublk_check_and_get_req(struct ublk_device *ub,
if (unlikely(!blk_mq_request_started(req) || req->tag != tag))
goto fail_put;
- if (!ublk_rq_has_data(req))
+ if (!blk_rq_has_data(req))
goto fail_put;
return req;
@@ -4085,7 +4081,7 @@ ublk_user_copy(struct kiocb *iocb, struct iov_iter *iter, int dir)
return -EINVAL;
req = io->req;
- if (!ublk_rq_has_data(req))
+ if (!blk_rq_has_data(req))
return -EINVAL;
} else {
req = __ublk_check_and_get_req(ub, q_id, tag, io);
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index b1c9a27fe00f..32bf3ba07a9d 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -689,6 +689,8 @@ static int virtblk_report_zones(struct gendisk *disk, sector_t sector,
nz = min_t(u64, virtio64_to_cpu(vblk->vdev, report->nr_zones),
nr_zones);
+ nz = min_t(u64, nz,
+ (buflen - sizeof(*report)) / sizeof(report->zones[0]));
if (!nz)
break;
diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c
index c5dc083c7244..8f5a5e1342a9 100644
--- a/drivers/md/dm-raid.c
+++ b/drivers/md/dm-raid.c
@@ -3831,6 +3831,7 @@ static void raid_presuspend(struct dm_target *ti)
* resume, raid_postsuspend() is too late.
*/
set_bit(RT_FLAG_RS_FROZEN, &rs->runtime_flags);
+ set_bit(MD_DM_SUSPENDING, &mddev->flags);
if (!reshape_interrupted(mddev))
return;
@@ -3847,13 +3848,16 @@ static void raid_presuspend(struct dm_target *ti)
static void raid_presuspend_undo(struct dm_target *ti)
{
struct raid_set *rs = ti->private;
+ struct mddev *mddev = &rs->md;
+ clear_bit(MD_DM_SUSPENDING, &mddev->flags);
clear_bit(RT_FLAG_RS_FROZEN, &rs->runtime_flags);
}
static void raid_postsuspend(struct dm_target *ti)
{
struct raid_set *rs = ti->private;
+ struct mddev *mddev = &rs->md;
if (!test_and_set_bit(RT_FLAG_RS_SUSPENDED, &rs->runtime_flags)) {
/*
@@ -3864,6 +3868,8 @@ static void raid_postsuspend(struct dm_target *ti)
mddev_suspend(&rs->md, false);
rs->md.ro = MD_RDONLY;
}
+ clear_bit(MD_DM_SUSPENDING, &mddev->flags);
+
}
static void attempt_restore_of_faulty_devices(struct raid_set *rs)
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/md/md.c b/drivers/md/md.c
index 8b568eee8743..096bb64e87bd 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -395,17 +395,24 @@ static bool is_suspended(struct mddev *mddev, struct bio *bio)
bool md_handle_request(struct mddev *mddev, struct bio *bio)
{
check_suspended:
- if (is_suspended(mddev, bio)) {
- /* Bail out if REQ_NOWAIT is set for the bio */
- if (bio->bi_opf & REQ_NOWAIT) {
- bio_wouldblock_error(bio);
- return true;
+ if (unlikely(md_cloned_bio(mddev, bio))) {
+ /*
+ * This bio is an MD cloned bio and already holds an
+ * active_io reference, so percpu_ref_get() is safe here.
+ */
+ percpu_ref_get(&mddev->active_io);
+ } else {
+ if (is_suspended(mddev, bio)) {
+ /* Bail out if REQ_NOWAIT is set for the bio */
+ if (bio->bi_opf & REQ_NOWAIT) {
+ bio_wouldblock_error(bio);
+ return true;
+ }
+ wait_event(mddev->sb_wait, !is_suspended(mddev, bio));
}
- wait_event(mddev->sb_wait, !is_suspended(mddev, bio));
+ if (!percpu_ref_tryget_live(&mddev->active_io))
+ goto check_suspended;
}
- if (!percpu_ref_tryget_live(&mddev->active_io))
- goto check_suspended;
-
if (!mddev->pers->make_request(mddev, bio)) {
percpu_ref_put(&mddev->active_io);
if (mddev_is_dm(mddev) && mddev->pers->prepare_suspend)
@@ -4414,9 +4421,10 @@ raid_disks_store(struct mddev *mddev, const char *buf, size_t len)
err = mddev_suspend_and_lock(mddev);
if (err)
return err;
- if (mddev->pers)
- err = update_raid_disks(mddev, n);
- else if (mddev->reshape_position != MaxSector) {
+ if (mddev->pers) {
+ if (n != mddev->raid_disks)
+ err = update_raid_disks(mddev, n);
+ } else if (mddev->reshape_position != MaxSector) {
struct md_rdev *rdev;
int olddisks = mddev->raid_disks - mddev->delta_disks;
diff --git a/drivers/md/md.h b/drivers/md/md.h
index 52c378086046..d8daf0f75cbb 100644
--- a/drivers/md/md.h
+++ b/drivers/md/md.h
@@ -346,6 +346,7 @@ struct md_cluster_operations;
* @MD_HAS_SUPERBLOCK: There is persistence sb in member disks.
* @MD_FAILLAST_DEV: Allow last rdev to be removed.
* @MD_SERIALIZE_POLICY: Enforce write IO is not reordered, just used by raid1.
+ * @MD_DM_SUSPENDING: This DM raid device is suspending.
*
* change UNSUPPORTED_MDDEV_FLAGS for each array type if new flag is added
*/
@@ -365,6 +366,7 @@ enum mddev_flags {
MD_HAS_SUPERBLOCK,
MD_FAILLAST_DEV,
MD_SERIALIZE_POLICY,
+ MD_DM_SUSPENDING,
};
enum mddev_sb_flags {
@@ -1042,6 +1044,11 @@ void mddev_update_io_opt(struct mddev *mddev, unsigned int nr_stripes);
extern const struct block_device_operations md_fops;
+static inline bool md_cloned_bio(struct mddev *mddev, struct bio *bio)
+{
+ return bio->bi_pool == &mddev->io_clone_set;
+}
+
/*
* MD devices can be used undeneath by DM, in which case ->gendisk is NULL.
*/
diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c
index 5e38a51e349a..2c000b3a5f49 100644
--- a/drivers/md/raid0.c
+++ b/drivers/md/raid0.c
@@ -14,6 +14,7 @@
#include <linux/seq_file.h>
#include <linux/module.h>
#include <linux/slab.h>
+#include <linux/string_choices.h>
#include <trace/events/block.h>
#include "md.h"
#include "raid0.h"
@@ -43,7 +44,7 @@ static void dump_zones(struct mddev *mddev)
int raid_disks = conf->strip_zone[0].nb_dev;
pr_debug("md: RAID0 configuration for %s - %d zone%s\n",
mdname(mddev),
- conf->nr_strip_zones, conf->nr_strip_zones==1?"":"s");
+ conf->nr_strip_zones, str_plural(conf->nr_strip_zones));
for (j = 0; j < conf->nr_strip_zones; j++) {
char line[200];
int len = 0;
@@ -392,6 +393,7 @@ static int raid0_set_limits(struct mddev *mddev)
lim.io_opt = lim.io_min * mddev->raid_disks;
lim.chunk_sectors = mddev->chunk_sectors;
lim.features |= BLK_FEAT_ATOMIC_WRITES;
+ lim.features |= BLK_FEAT_PCI_P2PDMA;
err = mddev_stack_rdev_limits(mddev, &lim, MDDEV_STACK_INTEGRITY);
if (err)
return err;
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 64d970e2ef50..5b9368bd9e70 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -1343,11 +1343,18 @@ static void raid1_read_request(struct mddev *mddev, struct bio *bio,
bool r1bio_existed = !!r1_bio;
/*
- * If r1_bio is set, we are blocking the raid1d thread
- * so there is a tiny risk of deadlock. So ask for
+ * An md cloned bio indicates we are in the error path.
+ * This is more reliable than checking r1_bio, which might
+ * be NULL even in the error path if a failed bio was split.
+ */
+ bool err_path = md_cloned_bio(mddev, bio);
+
+ /*
+ * If we are in the error path, we are blocking the raid1d
+ * thread so there is a tiny risk of deadlock. So ask for
* emergency memory if needed.
*/
- gfp_t gfp = r1_bio ? (GFP_NOIO | __GFP_HIGH) : GFP_NOIO;
+ gfp_t gfp = err_path ? (GFP_NOIO | __GFP_HIGH) : GFP_NOIO;
/*
* Still need barrier for READ in case that whole
@@ -1411,7 +1418,7 @@ static void raid1_read_request(struct mddev *mddev, struct bio *bio,
}
r1_bio->read_disk = rdisk;
- if (!r1bio_existed) {
+ if (likely(!md_cloned_bio(mddev, bio))) {
md_account_bio(mddev, &bio);
r1_bio->master_bio = bio;
}
@@ -1596,8 +1603,10 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
* complexity of supporting that is not worth
* the benefit.
*/
- if (bio->bi_opf & REQ_ATOMIC)
+ if (bio->bi_opf & REQ_ATOMIC) {
+ rdev_dec_pending(rdev, mddev);
goto err_handle;
+ }
good_sectors = first_bad - r1_bio->sector;
if (good_sectors < max_sectors)
@@ -2411,11 +2420,6 @@ static void fix_read_error(struct r1conf *conf, struct r1bio *r1_bio)
struct mddev *mddev = conf->mddev;
struct md_rdev *rdev = conf->mirrors[read_disk].rdev;
- if (exceed_read_errors(mddev, rdev)) {
- r1_bio->bios[r1_bio->read_disk] = IO_BLOCKED;
- return;
- }
-
while(sectors) {
int s = sectors;
int d = read_disk;
@@ -2627,35 +2631,36 @@ static void handle_write_finished(struct r1conf *conf, struct r1bio *r1_bio)
static void handle_read_error(struct r1conf *conf, struct r1bio *r1_bio)
{
+ struct md_rdev *rdev = conf->mirrors[r1_bio->read_disk].rdev;
+ struct bio *bio = r1_bio->bios[r1_bio->read_disk];
struct mddev *mddev = conf->mddev;
- struct bio *bio;
- struct md_rdev *rdev;
sector_t sector;
clear_bit(R1BIO_ReadError, &r1_bio->state);
- /* we got a read error. Maybe the drive is bad. Maybe just
- * the block and we can fix it.
- * We freeze all other IO, and try reading the block from
- * other devices. When we find one, we re-write
- * and check it that fixes the read error.
- * This is all done synchronously while the array is
- * frozen
- */
- bio = r1_bio->bios[r1_bio->read_disk];
bio_put(bio);
r1_bio->bios[r1_bio->read_disk] = NULL;
- rdev = conf->mirrors[r1_bio->read_disk].rdev;
- if (mddev->ro == 0
- && !test_bit(FailFast, &rdev->flags)) {
- freeze_array(conf, 1);
- fix_read_error(conf, r1_bio);
- unfreeze_array(conf);
- } else if (mddev->ro == 0 && test_bit(FailFast, &rdev->flags)) {
+ /*
+ * We got a read error. Maybe the drive is bad. Maybe just the block
+ * and we can fix it.
+ *
+ * If allowed, freeze all other IO, and try reading the block from other
+ * devices. If we find one, we re-write and check it that fixes the
+ * read error. This is all done synchronously while the array is
+ * frozen.
+ */
+ if (mddev->ro) {
+ r1_bio->bios[r1_bio->read_disk] = IO_BLOCKED;
+ } else if (test_bit(FailFast, &rdev->flags)) {
md_error(mddev, rdev);
} else {
- r1_bio->bios[r1_bio->read_disk] = IO_BLOCKED;
+ freeze_array(conf, 1);
+ if (exceed_read_errors(mddev, rdev))
+ r1_bio->bios[r1_bio->read_disk] = IO_BLOCKED;
+ else
+ fix_read_error(conf, r1_bio);
+ unfreeze_array(conf);
}
rdev_dec_pending(rdev, conf->mddev);
@@ -3208,6 +3213,7 @@ static int raid1_set_limits(struct mddev *mddev)
lim.max_hw_wzeroes_unmap_sectors = 0;
lim.logical_block_size = mddev->logical_block_size;
lim.features |= BLK_FEAT_ATOMIC_WRITES;
+ lim.features |= BLK_FEAT_PCI_P2PDMA;
err = mddev_stack_rdev_limits(mddev, &lim, MDDEV_STACK_INTEGRITY);
if (err)
return err;
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 39085e7dd6d2..cee5a253a281 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -1146,7 +1146,7 @@ static bool regular_request_wait(struct mddev *mddev, struct r10conf *conf,
}
static void raid10_read_request(struct mddev *mddev, struct bio *bio,
- struct r10bio *r10_bio, bool io_accounting)
+ struct r10bio *r10_bio)
{
struct r10conf *conf = mddev->private;
struct bio *read_bio;
@@ -1155,7 +1155,20 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio,
char b[BDEVNAME_SIZE];
int slot = r10_bio->read_slot;
struct md_rdev *err_rdev = NULL;
- gfp_t gfp = GFP_NOIO;
+
+ /*
+ * An md cloned bio indicates we are in the error path.
+ * This is more reliable than checking slot, which might
+ * be -1 even in the error path if a failed bio was split.
+ */
+ bool err_path = md_cloned_bio(mddev, bio);
+
+ /*
+ * If we are in the error path, we are blocking the raid10d
+ * thread so there is a tiny risk of deadlock. So ask for
+ * emergency memory if needed.
+ */
+ gfp_t gfp = err_path ? (GFP_NOIO | __GFP_HIGH) : GFP_NOIO;
if (slot >= 0 && r10_bio->devs[slot].rdev) {
/*
@@ -1166,11 +1179,6 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio,
* we lose the device name in error messages.
*/
int disk;
- /*
- * As we are blocking raid10, it is a little safer to
- * use __GFP_HIGH.
- */
- gfp = GFP_NOIO | __GFP_HIGH;
disk = r10_bio->devs[slot].devnum;
err_rdev = conf->mirrors[disk].rdev;
@@ -1218,7 +1226,7 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio,
}
slot = r10_bio->read_slot;
- if (io_accounting) {
+ if (likely(!md_cloned_bio(mddev, bio))) {
md_account_bio(mddev, &bio);
r10_bio->master_bio = bio;
}
@@ -1544,7 +1552,7 @@ static void __make_request(struct mddev *mddev, struct bio *bio, int sectors)
conf->geo.raid_disks);
if (bio_data_dir(bio) == READ)
- raid10_read_request(mddev, bio, r10_bio, true);
+ raid10_read_request(mddev, bio, r10_bio);
else
raid10_write_request(mddev, bio, r10_bio);
}
@@ -1727,6 +1735,7 @@ retry_discard:
r10_bio->mddev = mddev;
r10_bio->state = 0;
r10_bio->sectors = 0;
+ r10_bio->read_slot = -1;
memset(r10_bio->devs, 0, sizeof(r10_bio->devs[0]) * geo->raid_disks);
wait_blocked_dev(mddev, r10_bio);
@@ -2858,7 +2867,7 @@ static void handle_read_error(struct mddev *mddev, struct r10bio *r10_bio)
rdev_dec_pending(rdev, mddev);
r10_bio->state = 0;
- raid10_read_request(mddev, r10_bio->master_bio, r10_bio, false);
+ raid10_read_request(mddev, r10_bio->master_bio, r10_bio);
/*
* allow_barrier after re-submit to ensure no sync io
* can be issued while regular io pending.
@@ -3941,6 +3950,7 @@ static int raid10_set_queue_limits(struct mddev *mddev)
lim.chunk_sectors = mddev->chunk_sectors;
lim.io_opt = lim.io_min * raid10_nr_stripes(conf);
lim.features |= BLK_FEAT_ATOMIC_WRITES;
+ lim.features |= BLK_FEAT_PCI_P2PDMA;
err = mddev_stack_rdev_limits(mddev, &lim, MDDEV_STACK_INTEGRITY);
if (err)
return err;
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 0d76e82f4506..65ae7d8930fc 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -6042,8 +6042,11 @@ out_release:
raid5_release_stripe(sh);
out:
if (ret == STRIPE_SCHEDULE_AND_RETRY && reshape_interrupted(mddev)) {
- bi->bi_status = BLK_STS_RESOURCE;
- ret = STRIPE_WAIT_RESHAPE;
+ if (!mddev_is_dm(mddev) ||
+ test_bit(MD_DM_SUSPENDING, &mddev->flags)) {
+ bi->bi_status = BLK_STS_RESOURCE;
+ ret = STRIPE_WAIT_RESHAPE;
+ }
pr_err_ratelimited("dm-raid456: io across reshape position while reshape can't make progress");
}
return ret;
diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c
index c9028e4a7e56..5d187e063da8 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 c692fc73babf..f9327feb87d0 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);
@@ -858,7 +858,7 @@ static void apple_nvme_disable(struct apple_nvme *anv, bool shutdown)
* doing a safe shutdown.
*/
if (!dead && shutdown && freeze)
- nvme_wait_freeze_timeout(&anv->ctrl, NVME_IO_TIMEOUT);
+ nvme_wait_freeze_timeout(&anv->ctrl);
nvme_quiesce_io_queues(&anv->ctrl);
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index c3032d6ad6b1..3b7a8f7a3542 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -323,6 +323,7 @@ static void nvme_retry_req(struct request *req)
{
unsigned long delay = 0;
u16 crd;
+ struct nvme_ns *ns = req->q->queuedata;
/* The mask and shift result must be <= 3 */
crd = (nvme_req(req)->status & NVME_STATUS_CRD) >> 11;
@@ -330,6 +331,9 @@ static void nvme_retry_req(struct request *req)
delay = nvme_req(req)->ctrl->crdt[crd - 1] * 100;
nvme_req(req)->retries++;
+ if (ns)
+ atomic_long_inc(&ns->retries);
+
blk_mq_requeue_request(req, false);
blk_mq_delay_kick_requeue_list(req->q, delay);
}
@@ -434,11 +438,19 @@ static inline void nvme_end_req_zoned(struct request *req)
static inline void __nvme_end_req(struct request *req)
{
- if (unlikely(nvme_req(req)->status && !(req->rq_flags & RQF_QUIET))) {
+ struct nvme_ns *ns = req->q->queuedata;
+ struct nvme_request *nr = nvme_req(req);
+
+ if (unlikely(nr->status && !(req->rq_flags & RQF_QUIET))) {
if (blk_rq_is_passthrough(req))
nvme_log_err_passthru(req);
else
nvme_log_error(req);
+
+ if (ns)
+ atomic_long_inc(&ns->errors);
+ else
+ atomic_long_inc(&nr->ctrl->errors);
}
nvme_end_req_zoned(req);
nvme_trace_bio_complete(req);
@@ -584,6 +596,7 @@ bool nvme_change_ctrl_state(struct nvme_ctrl *ctrl,
case NVME_CTRL_NEW:
case NVME_CTRL_LIVE:
changed = true;
+ atomic_long_inc(&ctrl->nr_reset);
fallthrough;
default:
break;
@@ -729,10 +742,8 @@ void nvme_init_request(struct request *req, struct nvme_command *cmd)
struct nvme_ns *ns = req->q->disk->private_data;
logging_enabled = ns->head->passthru_err_log_enabled;
- req->timeout = NVME_IO_TIMEOUT;
} else { /* no queuedata implies admin queue */
logging_enabled = nr->ctrl->passthru_err_log_enabled;
- req->timeout = NVME_ADMIN_TIMEOUT;
}
if (!logging_enabled)
@@ -2263,7 +2274,7 @@ static int nvme_query_fdp_granularity(struct nvme_ctrl *ctrl,
}
n = le16_to_cpu(h->numfdpc) + 1;
- if (fdp_idx > n) {
+ if (fdp_idx >= n) {
dev_warn(ctrl->device, "FDP index:%d out of range:%d\n",
fdp_idx, n);
/* Proceed without registering FDP streams */
@@ -2275,14 +2286,16 @@ static int nvme_query_fdp_granularity(struct nvme_ctrl *ctrl,
desc = log;
end = log + size - sizeof(*h);
for (i = 0; i < fdp_idx; i++) {
- log += le16_to_cpu(desc->dsze);
- desc = log;
- if (log >= end) {
+ u16 dsze = le16_to_cpu(desc->dsze);
+
+ if (!dsze || log + dsze > end) {
dev_warn(ctrl->device,
- "FDP invalid config descriptor list\n");
+ "FDP invalid config descriptor at index %d\n", i);
ret = 0;
goto out;
}
+ log += dsze;
+ desc = log;
}
if (le32_to_cpu(desc->nrg) > 1) {
@@ -2409,12 +2422,22 @@ static int nvme_update_ns_info_block(struct nvme_ns *ns,
goto out;
}
+ if (id->lbaf[lbaf].ds < SECTOR_SHIFT ||
+ check_shl_overflow(le64_to_cpu(id->nsze),
+ id->lbaf[lbaf].ds - SECTOR_SHIFT,
+ &capacity)) {
+ dev_warn_once(ns->ctrl->device,
+ "invalid LBA data size %u, skipping namespace\n",
+ id->lbaf[lbaf].ds);
+ ret = -ENODEV;
+ goto out;
+ }
+
lim = queue_limits_start_update(ns->disk->queue);
memflags = blk_mq_freeze_queue(ns->disk->queue);
ns->head->lba_shift = id->lbaf[lbaf].ds;
ns->head->nuse = le64_to_cpu(id->nuse);
- capacity = nvme_lba_to_sect(ns->head, le64_to_cpu(id->nsze));
nvme_set_ctrl_limits(ns->ctrl, &lim, false);
nvme_configure_metadata(ns->ctrl, ns->head, id, nvm, info);
nvme_set_chunk_sectors(ns, id, &lim);
@@ -2483,6 +2506,14 @@ out:
return ret;
}
+static void nvme_stack_zone_resources(struct queue_limits *t,
+ const struct queue_limits *b)
+{
+ t->max_open_zones = min_not_zero(t->max_open_zones, b->max_open_zones);
+ t->max_active_zones =
+ min_not_zero(t->max_active_zones, b->max_active_zones);
+}
+
static int nvme_update_ns_info(struct nvme_ns *ns, struct nvme_ns_info *info)
{
bool unsupported = false;
@@ -2549,6 +2580,8 @@ static int nvme_update_ns_info(struct nvme_ns *ns, struct nvme_ns_info *info)
lim.io_opt = ns_lim->io_opt;
queue_limits_stack_bdev(&lim, ns->disk->part0, 0,
ns->head->disk->disk_name);
+ if (lim.features & BLK_FEAT_ZONED)
+ nvme_stack_zone_resources(&lim, ns_lim);
if (unsupported)
ns->head->disk->flags |= GENHD_FL_HIDDEN;
else
@@ -2559,7 +2592,7 @@ static int nvme_update_ns_info(struct nvme_ns *ns, struct nvme_ns_info *info)
set_capacity_and_notify(ns->head->disk, get_capacity(ns->disk));
set_disk_ro(ns->head->disk, nvme_ns_is_readonly(ns, info));
- nvme_mpath_revalidate_paths(ns);
+ nvme_mpath_revalidate_paths(ns->head);
blk_mq_unfreeze_queue(ns->head->disk->queue, memflags);
}
@@ -3926,7 +3959,7 @@ static struct nvme_ns_head *nvme_alloc_ns_head(struct nvme_ctrl *ctrl,
int ret = -ENOMEM;
#ifdef CONFIG_NVME_MULTIPATH
- size += num_possible_nodes() * sizeof(struct nvme_ns *);
+ size += nr_node_ids * sizeof(struct nvme_ns *);
#endif
head = kzalloc(size, GFP_KERNEL);
@@ -4209,6 +4242,7 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, struct nvme_ns_info *info)
mutex_unlock(&ctrl->namespaces_lock);
goto out_unlink_ns;
}
+ blk_queue_rq_timeout(ns->queue, ctrl->io_timeout);
nvme_ns_add_to_ctrl_list(ns);
mutex_unlock(&ctrl->namespaces_lock);
synchronize_srcu(&ctrl->srcu);
@@ -4894,12 +4928,7 @@ int nvme_alloc_admin_tag_set(struct nvme_ctrl *ctrl, struct blk_mq_tag_set *set,
if (ret)
return ret;
- /*
- * If a previous admin queue exists (e.g., from before a reset),
- * put it now before allocating a new one to avoid orphaning it.
- */
- if (ctrl->admin_q)
- blk_put_queue(ctrl->admin_q);
+ WARN_ON_ONCE(ctrl->admin_q);
ctrl->admin_q = blk_mq_alloc_queue(set, NULL, NULL);
if (IS_ERR(ctrl->admin_q)) {
@@ -4937,10 +4966,8 @@ void nvme_remove_admin_tag_set(struct nvme_ctrl *ctrl)
*/
nvme_stop_keep_alive(ctrl);
blk_mq_destroy_queue(ctrl->admin_q);
- if (ctrl->ops->flags & NVME_F_FABRICS) {
+ if (ctrl->fabrics_q)
blk_mq_destroy_queue(ctrl->fabrics_q);
- blk_put_queue(ctrl->fabrics_q);
- }
blk_mq_free_tag_set(ctrl->admin_tagset);
}
EXPORT_SYMBOL_GPL(nvme_remove_admin_tag_set);
@@ -5082,6 +5109,8 @@ static void nvme_free_ctrl(struct device *dev)
if (ctrl->admin_q)
blk_put_queue(ctrl->admin_q);
+ if (ctrl->fabrics_q)
+ blk_put_queue(ctrl->fabrics_q);
if (!subsys || ctrl->instance != subsys->instance)
ida_free(&nvme_instance_ida, ctrl->instance);
nvme_free_cels(ctrl);
@@ -5146,6 +5175,8 @@ int nvme_init_ctrl(struct nvme_ctrl *ctrl, struct device *dev,
memset(&ctrl->ka_cmd, 0, sizeof(ctrl->ka_cmd));
ctrl->ka_cmd.common.opcode = nvme_admin_keep_alive;
ctrl->ka_last_check_time = jiffies;
+ ctrl->admin_timeout = NVME_ADMIN_TIMEOUT;
+ ctrl->io_timeout = NVME_IO_TIMEOUT;
BUILD_BUG_ON(NVME_DSM_MAX_RANGES * sizeof(struct nvme_dsm_range) >
PAGE_SIZE);
@@ -5252,8 +5283,9 @@ void nvme_unfreeze(struct nvme_ctrl *ctrl)
}
EXPORT_SYMBOL_GPL(nvme_unfreeze);
-int nvme_wait_freeze_timeout(struct nvme_ctrl *ctrl, long timeout)
+int nvme_wait_freeze_timeout(struct nvme_ctrl *ctrl)
{
+ long timeout = ctrl->io_timeout;
struct nvme_ns *ns;
int srcu_idx;
diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c
index e4f4528fe2a2..2c9a6d3c9797 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);
@@ -3148,6 +3148,8 @@ nvme_fc_create_association(struct nvme_fc_ctrl *ctrl)
goto out_term_aen_ops;
}
+ /* accumulate reconnect attempts before resetting it to zero */
+ atomic_long_add(ctrl->ctrl.nr_reconnects, &ctrl->ctrl.acc_reconnects);
ctrl->ctrl.nr_reconnects = 0;
nvme_start_ctrl(&ctrl->ctrl);
@@ -3470,6 +3472,7 @@ nvme_fc_alloc_ctrl(struct device *dev, struct nvmf_ctrl_options *opts,
ctrl->ctrl.opts = opts;
ctrl->ctrl.nr_reconnects = 0;
+ atomic_long_set(&ctrl->ctrl.acc_reconnects, 0);
INIT_LIST_HEAD(&ctrl->ctrl_list);
ctrl->lport = lport;
ctrl->rport = rport;
diff --git a/drivers/nvme/host/ioctl.c b/drivers/nvme/host/ioctl.c
index 08889b20e5d8..664216eece4a 100644
--- a/drivers/nvme/host/ioctl.c
+++ b/drivers/nvme/host/ioctl.c
@@ -102,8 +102,17 @@ static struct request *nvme_alloc_user_request(struct request_queue *q,
struct nvme_command *cmd, blk_opf_t rq_flags,
blk_mq_req_flags_t blk_flags)
{
+ struct nvme_ns *ns = q->queuedata;
struct request *req;
+ /*
+ * The NVME_MPATH flag is set only for IO commands sent to a namespace
+ * with a multipath enabled head. The request is not eligible for
+ * failover as passthrough requests also append REQ_FAILFAST_DRIVER.
+ */
+ if (ns && nvme_ns_head_multipath(ns->head))
+ rq_flags |= REQ_NVME_MPATH;
+
req = blk_mq_alloc_request(q, nvme_req_op(cmd) | rq_flags, blk_flags);
if (IS_ERR(req))
return req;
diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c
index 263161cb8ac0..e033ede953cc 100644
--- a/drivers/nvme/host/multipath.c
+++ b/drivers/nvme/host/multipath.c
@@ -73,19 +73,29 @@ static const char *nvme_iopolicy_names[] = {
static int iopolicy = NVME_IOPOLICY_NUMA;
+static int nvme_iopolicy_parse(const char *str)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(nvme_iopolicy_names); i++) {
+ if (sysfs_streq(str, nvme_iopolicy_names[i]))
+ return i;
+ }
+ return -EINVAL;
+}
+
static int nvme_set_iopolicy(const char *val, const struct kernel_param *kp)
{
+ int policy;
+
if (!val)
return -EINVAL;
- if (!strncmp(val, "numa", 4))
- iopolicy = NVME_IOPOLICY_NUMA;
- else if (!strncmp(val, "round-robin", 11))
- iopolicy = NVME_IOPOLICY_RR;
- else if (!strncmp(val, "queue-depth", 11))
- iopolicy = NVME_IOPOLICY_QD;
- else
- return -EINVAL;
+ policy = nvme_iopolicy_parse(val);
+ if (policy < 0)
+ return policy;
+
+ iopolicy = policy;
return 0;
}
@@ -142,6 +152,7 @@ void nvme_failover_req(struct request *req)
struct bio *bio;
nvme_mpath_clear_current_path(ns);
+ atomic_long_inc(&ns->failover);
/*
* If we got back an ANA error, we know the controller is alive but not
@@ -175,9 +186,12 @@ void nvme_mpath_start_request(struct request *rq)
nvme_req(rq)->flags |= NVME_MPATH_CNT_ACTIVE;
}
- if (!blk_queue_io_stat(disk->queue) || blk_rq_is_passthrough(rq) ||
+ if (!blk_queue_io_stat(disk->queue) ||
(nvme_req(rq)->flags & NVME_MPATH_IO_STATS))
return;
+ if (blk_rq_is_passthrough(rq) &&
+ !blk_rq_passthrough_stats(rq, disk->queue))
+ return;
nvme_req(rq)->flags |= NVME_MPATH_IO_STATS;
nvme_req(rq)->start_time = bdev_start_io_acct(disk->part0, req_op(rq),
@@ -254,10 +268,10 @@ void nvme_mpath_clear_ctrl_paths(struct nvme_ctrl *ctrl)
srcu_read_unlock(&ctrl->srcu, srcu_idx);
}
-void nvme_mpath_revalidate_paths(struct nvme_ns *ns)
+void nvme_mpath_revalidate_paths(struct nvme_ns_head *head)
{
- struct nvme_ns_head *head = ns->head;
sector_t capacity = get_capacity(head->disk);
+ struct nvme_ns *ns;
int node;
int srcu_idx;
@@ -511,6 +525,12 @@ static void nvme_ns_head_submit_bio(struct bio *bio)
ns = nvme_find_path(head);
if (likely(ns)) {
bio_set_dev(bio, ns->disk->part0);
+ /*
+ * Use BIO_REMAPPED to skip bio_check_eod() when this bio
+ * enters submit_bio_noacct() for the per-path device. The EOD
+ * check already passed on the multipath head.
+ */
+ bio_set_flag(bio, BIO_REMAPPED);
bio->bi_opf |= REQ_NVME_MPATH;
trace_block_bio_remap(bio, disk_devt(ns->head->disk),
bio->bi_iter.bi_sector);
@@ -521,10 +541,12 @@ static void nvme_ns_head_submit_bio(struct bio *bio)
spin_lock_irq(&head->requeue_lock);
bio_list_add(&head->requeue_list, bio);
spin_unlock_irq(&head->requeue_lock);
+ atomic_long_inc(&head->io_requeue_no_usable_path_count);
} else {
dev_warn_ratelimited(dev, "no available path - failing I/O\n");
bio_io_error(bio);
+ atomic_long_inc(&head->io_fail_no_available_path_count);
}
srcu_read_unlock(&head->srcu, srcu_idx);
@@ -730,7 +752,7 @@ int nvme_mpath_alloc_disk(struct nvme_ctrl *ctrl, struct nvme_ns_head *head)
blk_set_stacking_limits(&lim);
lim.dma_alignment = 3;
lim.features |= BLK_FEAT_IO_STAT | BLK_FEAT_NOWAIT |
- BLK_FEAT_POLL | BLK_FEAT_ATOMIC_WRITES;
+ BLK_FEAT_POLL | BLK_FEAT_ATOMIC_WRITES | BLK_FEAT_PCI_P2PDMA;
if (head->ids.csi == NVME_CSI_ZNS)
lim.features |= BLK_FEAT_ZONED;
@@ -1039,16 +1061,14 @@ static ssize_t nvme_subsys_iopolicy_store(struct device *dev,
{
struct nvme_subsystem *subsys =
container_of(dev, struct nvme_subsystem, dev);
- int i;
+ int policy;
- for (i = 0; i < ARRAY_SIZE(nvme_iopolicy_names); i++) {
- if (sysfs_streq(buf, nvme_iopolicy_names[i])) {
- nvme_subsys_iopolicy_update(subsys, i);
- return count;
- }
- }
+ policy = nvme_iopolicy_parse(buf);
+ if (policy < 0)
+ return policy;
- return -EINVAL;
+ nvme_subsys_iopolicy_update(subsys, policy);
+ return count;
}
SUBSYS_ATTR_RW(iopolicy, S_IRUGO | S_IWUSR,
nvme_subsys_iopolicy_show, nvme_subsys_iopolicy_store);
@@ -1151,6 +1171,90 @@ static ssize_t delayed_removal_secs_store(struct device *dev,
DEVICE_ATTR_RW(delayed_removal_secs);
+static ssize_t multipath_failover_count_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct nvme_ns *ns = nvme_get_ns_from_dev(dev);
+
+ return sysfs_emit(buf, "%lu\n", atomic_long_read(&ns->failover));
+}
+
+static ssize_t multipath_failover_count_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ unsigned long failover;
+ int ret;
+ struct nvme_ns *ns = nvme_get_ns_from_dev(dev);
+
+ ret = kstrtoul(buf, 0, &failover);
+ if (ret)
+ return -EINVAL;
+
+ atomic_long_set(&ns->failover, failover);
+
+ return count;
+}
+
+DEVICE_ATTR_RW(multipath_failover_count);
+
+static ssize_t io_requeue_no_usable_path_count_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct gendisk *disk = dev_to_disk(dev);
+ struct nvme_ns_head *head = disk->private_data;
+
+ return sysfs_emit(buf, "%lu\n",
+ atomic_long_read(&head->io_requeue_no_usable_path_count));
+}
+
+static ssize_t io_requeue_no_usable_path_count_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int err;
+ unsigned long requeue_cnt;
+ struct gendisk *disk = dev_to_disk(dev);
+ struct nvme_ns_head *head = disk->private_data;
+
+ err = kstrtoul(buf, 0, &requeue_cnt);
+ if (err)
+ return -EINVAL;
+
+ atomic_long_set(&head->io_requeue_no_usable_path_count, requeue_cnt);
+
+ return count;
+}
+
+DEVICE_ATTR_RW(io_requeue_no_usable_path_count);
+
+static ssize_t io_fail_no_available_path_count_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct gendisk *disk = dev_to_disk(dev);
+ struct nvme_ns_head *head = disk->private_data;
+
+ return sysfs_emit(buf, "%lu\n",
+ atomic_long_read(&head->io_fail_no_available_path_count));
+}
+
+static ssize_t io_fail_no_available_path_count_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int err;
+ unsigned long fail_cnt;
+ struct gendisk *disk = dev_to_disk(dev);
+ struct nvme_ns_head *head = disk->private_data;
+
+ err = kstrtoul(buf, 0, &fail_cnt);
+ if (err)
+ return -EINVAL;
+
+ atomic_long_set(&head->io_fail_no_available_path_count, fail_cnt);
+
+ return count;
+}
+
+DEVICE_ATTR_RW(io_fail_no_available_path_count);
+
static int nvme_lookup_ana_group_desc(struct nvme_ctrl *ctrl,
struct nvme_ana_group_desc *desc, void *data)
{
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index ccd5e05dac98..b367c67dcb37 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -370,6 +370,8 @@ struct nvme_ctrl {
u16 mtfa;
u32 ctrl_config;
u32 queue_count;
+ u32 admin_timeout;
+ u32 io_timeout;
u64 cap;
u32 max_hw_sectors;
@@ -413,6 +415,8 @@ struct nvme_ctrl {
unsigned long ka_last_check_time;
struct work_struct fw_act_work;
unsigned long events;
+ atomic_long_t errors;
+ atomic_long_t nr_reset;
#ifdef CONFIG_NVME_MULTIPATH
/* asymmetric namespace access: */
@@ -454,6 +458,8 @@ struct nvme_ctrl {
u16 icdoff;
u16 maxcmd;
int nr_reconnects;
+ /* accumulate reconenct attempts, as nr_reconnects can reset to zero */
+ atomic_long_t acc_reconnects;
unsigned long flags;
struct nvmf_ctrl_options *opts;
@@ -563,6 +569,8 @@ struct nvme_ns_head {
unsigned long flags;
struct delayed_work remove_work;
unsigned int delayed_removal_secs;
+ atomic_long_t io_requeue_no_usable_path_count;
+ atomic_long_t io_fail_no_available_path_count;
#define NVME_NSHEAD_DISK_LIVE 0
#define NVME_NSHEAD_QUEUE_IF_NO_PATH 1
struct nvme_ns __rcu *current_path[];
@@ -589,7 +597,10 @@ struct nvme_ns {
#ifdef CONFIG_NVME_MULTIPATH
enum nvme_ana_state ana_state;
u32 ana_grpid;
+ atomic_long_t failover;
#endif
+ atomic_long_t retries;
+ atomic_long_t errors;
struct list_head siblings;
struct kref kref;
struct nvme_ns_head *head;
@@ -900,7 +911,7 @@ void nvme_sync_queues(struct nvme_ctrl *ctrl);
void nvme_sync_io_queues(struct nvme_ctrl *ctrl);
void nvme_unfreeze(struct nvme_ctrl *ctrl);
void nvme_wait_freeze(struct nvme_ctrl *ctrl);
-int nvme_wait_freeze_timeout(struct nvme_ctrl *ctrl, long timeout);
+int nvme_wait_freeze_timeout(struct nvme_ctrl *ctrl);
void nvme_start_freeze(struct nvme_ctrl *ctrl);
static inline enum req_op nvme_req_op(struct nvme_command *cmd)
@@ -1012,6 +1023,7 @@ extern const struct attribute_group nvme_ns_mpath_attr_group;
extern const struct pr_ops nvme_pr_ops;
extern const struct block_device_operations nvme_ns_head_ops;
extern const struct attribute_group nvme_dev_attrs_group;
+extern const struct attribute_group nvme_dev_diag_attrs_group;
extern const struct attribute_group *nvme_subsys_attrs_groups[];
extern const struct attribute_group *nvme_dev_attr_groups[];
extern const struct block_device_operations nvme_bdev_ops;
@@ -1041,7 +1053,7 @@ void nvme_mpath_update(struct nvme_ctrl *ctrl);
void nvme_mpath_uninit(struct nvme_ctrl *ctrl);
void nvme_mpath_stop(struct nvme_ctrl *ctrl);
bool nvme_mpath_clear_current_path(struct nvme_ns *ns);
-void nvme_mpath_revalidate_paths(struct nvme_ns *ns);
+void nvme_mpath_revalidate_paths(struct nvme_ns_head *head);
void nvme_mpath_clear_ctrl_paths(struct nvme_ctrl *ctrl);
void nvme_mpath_remove_disk(struct nvme_ns_head *head);
void nvme_mpath_start_request(struct request *rq);
@@ -1061,6 +1073,9 @@ extern struct device_attribute dev_attr_ana_state;
extern struct device_attribute dev_attr_queue_depth;
extern struct device_attribute dev_attr_numa_nodes;
extern struct device_attribute dev_attr_delayed_removal_secs;
+extern struct device_attribute dev_attr_multipath_failover_count;
+extern struct device_attribute dev_attr_io_requeue_no_usable_path_count;
+extern struct device_attribute dev_attr_io_fail_no_available_path_count;
extern struct device_attribute subsys_attr_iopolicy;
static inline bool nvme_disk_is_ns_head(struct gendisk *disk)
@@ -1106,7 +1121,7 @@ static inline bool nvme_mpath_clear_current_path(struct nvme_ns *ns)
{
return false;
}
-static inline void nvme_mpath_revalidate_paths(struct nvme_ns *ns)
+static inline void nvme_mpath_revalidate_paths(struct nvme_ns_head *head)
{
}
static inline void nvme_mpath_clear_ctrl_paths(struct nvme_ctrl *ctrl)
diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index b5f846200678..8438c904ec49 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -587,11 +587,16 @@ static bool nvme_dbbuf_update_and_check_event(u16 value, __le32 *dbbuf_db,
}
static struct nvme_descriptor_pools *
-nvme_setup_descriptor_pools(struct nvme_dev *dev, unsigned numa_node)
+nvme_setup_descriptor_pools(struct nvme_dev *dev, int numa_node)
{
- struct nvme_descriptor_pools *pools = &dev->descriptor_pools[numa_node];
+ struct nvme_descriptor_pools *pools;
size_t small_align = NVME_SMALL_POOL_SIZE;
+ if (numa_node == NUMA_NO_NODE)
+ numa_node = 0;
+
+ pools = &dev->descriptor_pools[numa_node];
+
if (pools->small)
return pools; /* already initialized */
@@ -660,7 +665,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);
@@ -2838,6 +2843,7 @@ static const struct attribute_group nvme_pci_dev_attrs_group = {
static const struct attribute_group *nvme_pci_dev_attr_groups[] = {
&nvme_dev_attrs_group,
&nvme_pci_dev_attrs_group,
+ &nvme_dev_diag_attrs_group,
NULL,
};
@@ -3122,7 +3128,7 @@ static bool __nvme_delete_io_queues(struct nvme_dev *dev, u8 opcode)
unsigned long timeout;
retry:
- timeout = NVME_ADMIN_TIMEOUT;
+ timeout = dev->ctrl.admin_timeout;
while (nr_queues > 0) {
if (nvme_delete_queue(&dev->queues[nr_queues], opcode))
break;
@@ -3304,7 +3310,7 @@ static void nvme_dev_disable(struct nvme_dev *dev, bool shutdown)
* if doing a safe shutdown.
*/
if (!dead && shutdown)
- nvme_wait_freeze_timeout(&dev->ctrl, NVME_IO_TIMEOUT);
+ nvme_wait_freeze_timeout(&dev->ctrl);
}
nvme_quiesce_io_queues(&dev->ctrl);
diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c
index f77c960f7632..6909e3542794 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);
@@ -888,7 +888,7 @@ static int nvme_rdma_configure_io_queues(struct nvme_rdma_ctrl *ctrl, bool new)
if (!new) {
nvme_start_freeze(&ctrl->ctrl);
nvme_unquiesce_io_queues(&ctrl->ctrl);
- if (!nvme_wait_freeze_timeout(&ctrl->ctrl, NVME_IO_TIMEOUT)) {
+ if (!nvme_wait_freeze_timeout(&ctrl->ctrl)) {
/*
* If we timed out waiting for freeze we are likely to
* be stuck. Fail the controller initialization just
@@ -1110,6 +1110,8 @@ static void nvme_rdma_reconnect_ctrl_work(struct work_struct *work)
dev_info(ctrl->ctrl.device, "Successfully reconnected (%d attempts)\n",
ctrl->ctrl.nr_reconnects);
+ /* accumulate reconnect attempts before resetting it to zero */
+ atomic_long_add(ctrl->ctrl.nr_reconnects, &ctrl->ctrl.acc_reconnects);
ctrl->ctrl.nr_reconnects = 0;
return;
diff --git a/drivers/nvme/host/sysfs.c b/drivers/nvme/host/sysfs.c
index e59758616f27..933a5adfb7af 100644
--- a/drivers/nvme/host/sysfs.c
+++ b/drivers/nvme/host/sysfs.c
@@ -6,6 +6,7 @@
*/
#include <linux/nvme-auth.h>
+#include <linux/blkdev.h>
#include "nvme.h"
#include "fabrics.h"
@@ -335,14 +336,7 @@ static bool multipath_sysfs_group_visible(struct kobject *kobj)
return nvme_disk_is_ns_head(dev_to_disk(dev));
}
-
-static bool multipath_sysfs_attr_visible(struct kobject *kobj,
- struct attribute *attr, int n)
-{
- return false;
-}
-
-DEFINE_SYSFS_GROUP_VISIBLE(multipath_sysfs)
+DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(multipath_sysfs)
const struct attribute_group nvme_ns_mpath_attr_group = {
.name = "multipath",
@@ -351,11 +345,114 @@ const struct attribute_group nvme_ns_mpath_attr_group = {
};
#endif
+static ssize_t command_retries_count_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct nvme_ns *ns = nvme_get_ns_from_dev(dev);
+
+ return sysfs_emit(buf, "%lu\n", atomic_long_read(&ns->retries));
+}
+
+static ssize_t command_retries_count_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ unsigned long retries;
+ int err;
+ struct nvme_ns *ns = nvme_get_ns_from_dev(dev);
+
+ err = kstrtoul(buf, 0, &retries);
+ if (err)
+ return -EINVAL;
+
+ atomic_long_set(&ns->retries, retries);
+
+ return count;
+}
+static DEVICE_ATTR_RW(command_retries_count);
+
+static ssize_t nvme_io_errors_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct nvme_ns *ns = nvme_get_ns_from_dev(dev);
+
+ return sysfs_emit(buf, "%lu\n", atomic_long_read(&ns->errors));
+}
+
+static ssize_t nvme_io_errors_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ unsigned long errors;
+ int err;
+ struct nvme_ns *ns = nvme_get_ns_from_dev(dev);
+
+ err = kstrtoul(buf, 0, &errors);
+ if (err)
+ return -EINVAL;
+
+ atomic_long_set(&ns->errors, errors);
+
+ return count;
+}
+
+struct device_attribute dev_attr_io_errors =
+ __ATTR(command_error_count, 0644,
+ nvme_io_errors_show, nvme_io_errors_store);
+
+static struct attribute *nvme_ns_diag_attrs[] = {
+ &dev_attr_command_retries_count.attr,
+ &dev_attr_io_errors.attr,
+#ifdef CONFIG_NVME_MULTIPATH
+ &dev_attr_multipath_failover_count.attr,
+ &dev_attr_io_requeue_no_usable_path_count.attr,
+ &dev_attr_io_fail_no_available_path_count.attr,
+#endif
+ NULL,
+};
+
+static umode_t nvme_ns_diag_attrs_are_visible(struct kobject *kobj,
+ struct attribute *a, int n)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+
+ if (a == &dev_attr_command_retries_count.attr) {
+ if (nvme_disk_is_ns_head(dev_to_disk(dev)))
+ return 0;
+ }
+ if (a == &dev_attr_io_errors.attr) {
+ struct gendisk *disk = dev_to_disk(dev);
+
+ if (nvme_disk_is_ns_head(disk))
+ return 0;
+ }
+#ifdef CONFIG_NVME_MULTIPATH
+ if (a == &dev_attr_multipath_failover_count.attr) {
+ if (nvme_disk_is_ns_head(dev_to_disk(dev)))
+ return 0;
+ }
+ if (a == &dev_attr_io_requeue_no_usable_path_count.attr) {
+ if (!nvme_disk_is_ns_head(dev_to_disk(dev)))
+ return 0;
+ }
+ if (a == &dev_attr_io_fail_no_available_path_count.attr) {
+ if (!nvme_disk_is_ns_head(dev_to_disk(dev)))
+ return 0;
+ }
+#endif
+ return a->mode;
+}
+
+const struct attribute_group nvme_ns_diag_attr_group = {
+ .name = "diag",
+ .attrs = nvme_ns_diag_attrs,
+ .is_visible = nvme_ns_diag_attrs_are_visible,
+};
+
const struct attribute_group *nvme_ns_attr_groups[] = {
&nvme_ns_attr_group,
#ifdef CONFIG_NVME_MULTIPATH
&nvme_ns_mpath_attr_group,
#endif
+ &nvme_ns_diag_attr_group,
NULL,
};
@@ -623,6 +720,92 @@ static ssize_t quirks_show(struct device *dev, struct device_attribute *attr,
}
static DEVICE_ATTR_RO(quirks);
+static ssize_t nvme_admin_timeout_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
+
+ return sysfs_emit(buf, "%u\n",
+ jiffies_to_msecs(ctrl->admin_timeout));
+}
+
+static ssize_t nvme_admin_timeout_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
+ u32 timeout;
+ int err;
+
+ /*
+ * Wait until the controller reaches the LIVE state to be sure that
+ * admin_q and fabrics_q are properly initialized.
+ */
+ if (!test_bit(NVME_CTRL_STARTED_ONCE, &ctrl->flags))
+ return -EBUSY;
+
+ err = kstrtou32(buf, 10, &timeout);
+ if (err || !timeout)
+ return -EINVAL;
+
+ ctrl->admin_timeout = msecs_to_jiffies(timeout);
+
+ blk_queue_rq_timeout(ctrl->admin_q, ctrl->admin_timeout);
+ if (ctrl->fabrics_q)
+ blk_queue_rq_timeout(ctrl->fabrics_q, ctrl->admin_timeout);
+
+ return count;
+}
+
+static DEVICE_ATTR(admin_timeout, S_IRUGO | S_IWUSR,
+ nvme_admin_timeout_show, nvme_admin_timeout_store);
+
+static ssize_t nvme_io_timeout_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
+
+ return sysfs_emit(buf, "%u\n", jiffies_to_msecs(ctrl->io_timeout));
+}
+
+static ssize_t nvme_io_timeout_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
+ struct nvme_ns *ns;
+ u32 timeout;
+ int err;
+
+ /*
+ * Wait until the controller reaches the LIVE state to be sure that
+ * connect_q is properly initialized.
+ */
+ if (!test_bit(NVME_CTRL_STARTED_ONCE, &ctrl->flags))
+ return -EBUSY;
+
+ err = kstrtou32(buf, 10, &timeout);
+ if (err || !timeout)
+ return -EINVAL;
+
+ /* Take the namespaces_lock to avoid racing against nvme_alloc_ns() */
+ mutex_lock(&ctrl->namespaces_lock);
+
+ ctrl->io_timeout = msecs_to_jiffies(timeout);
+ list_for_each_entry(ns, &ctrl->namespaces, list)
+ blk_queue_rq_timeout(ns->queue, ctrl->io_timeout);
+
+ mutex_unlock(&ctrl->namespaces_lock);
+
+ if (ctrl->connect_q)
+ blk_queue_rq_timeout(ctrl->connect_q, ctrl->io_timeout);
+
+ return count;
+}
+
+static DEVICE_ATTR(io_timeout, S_IRUGO | S_IWUSR,
+ nvme_io_timeout_show, nvme_io_timeout_store);
+
#ifdef CONFIG_NVME_HOST_AUTH
static ssize_t nvme_ctrl_dhchap_secret_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -765,6 +948,8 @@ static struct attribute *nvme_dev_attrs[] = {
&dev_attr_cntrltype.attr,
&dev_attr_dctype.attr,
&dev_attr_quirks.attr,
+ &dev_attr_admin_timeout.attr,
+ &dev_attr_io_timeout.attr,
#ifdef CONFIG_NVME_HOST_AUTH
&dev_attr_dhchap_secret.attr,
&dev_attr_dhchap_ctrl_secret.attr,
@@ -937,11 +1122,121 @@ static const struct attribute_group nvme_tls_attrs_group = {
};
#endif
+static ssize_t nvme_adm_errors_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
+
+ return sysfs_emit(buf, "%lu\n",
+ (unsigned long)atomic_long_read(&ctrl->errors));
+}
+
+static ssize_t nvme_adm_errors_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ unsigned long errors;
+ int err;
+ struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
+
+ err = kstrtoul(buf, 0, &errors);
+ if (err)
+ return -EINVAL;
+
+ atomic_long_set(&ctrl->errors, errors);
+
+ return count;
+}
+
+struct device_attribute dev_attr_adm_errors =
+ __ATTR(command_error_count, 0644,
+ nvme_adm_errors_show, nvme_adm_errors_store);
+
+static ssize_t reset_count_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
+
+ return sysfs_emit(buf, "%lu\n", atomic_long_read(&ctrl->nr_reset));
+}
+
+static ssize_t reset_count_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int err;
+ unsigned long reset_cnt;
+ struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
+
+ err = kstrtoul(buf, 0, &reset_cnt);
+ if (err)
+ return -EINVAL;
+
+ atomic_long_set(&ctrl->nr_reset, reset_cnt);
+
+ return count;
+}
+
+static ssize_t reconnect_count_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
+
+ return sysfs_emit(buf, "%lu\n",
+ atomic_long_read(&ctrl->acc_reconnects) +
+ ctrl->nr_reconnects);
+}
+
+static ssize_t reconnect_count_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int err;
+ unsigned long reconnect_cnt;
+ struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
+
+ err = kstrtoul(buf, 0, &reconnect_cnt);
+ if (err)
+ return -EINVAL;
+
+ atomic_long_set(&ctrl->acc_reconnects, reconnect_cnt);
+
+ return count;
+}
+
+static DEVICE_ATTR_RW(reconnect_count);
+
+static DEVICE_ATTR_RW(reset_count);
+
+static struct attribute *nvme_dev_diag_attrs[] = {
+ &dev_attr_adm_errors.attr,
+ &dev_attr_reset_count.attr,
+ &dev_attr_reconnect_count.attr,
+ NULL,
+};
+
+static umode_t nvme_dev_diag_attrs_are_visible(struct kobject *kobj,
+ struct attribute *a, int n)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
+
+ if (a == &dev_attr_reconnect_count.attr && !ctrl->opts)
+ return 0;
+
+ return a->mode;
+}
+
+const struct attribute_group nvme_dev_diag_attrs_group = {
+ .name = "diag",
+ .attrs = nvme_dev_diag_attrs,
+ .is_visible = nvme_dev_diag_attrs_are_visible,
+};
+EXPORT_SYMBOL_GPL(nvme_dev_diag_attrs_group);
+
const struct attribute_group *nvme_dev_attr_groups[] = {
&nvme_dev_attrs_group,
#ifdef CONFIG_NVME_TCP_TLS
&nvme_tls_attrs_group,
#endif
+ &nvme_dev_diag_attrs_group,
NULL,
};
diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
index 68a1d7640494..ba5c7b3e2a7c 100644
--- a/drivers/nvme/host/tcp.c
+++ b/drivers/nvme/host/tcp.c
@@ -56,44 +56,6 @@ MODULE_PARM_DESC(tls_handshake_timeout,
static atomic_t nvme_tcp_cpu_queues[NR_CPUS];
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
-/* lockdep can detect a circular dependency of the form
- * sk_lock -> mmap_lock (page fault) -> fs locks -> sk_lock
- * because dependencies are tracked for both nvme-tcp and user contexts. Using
- * a separate class prevents lockdep from conflating nvme-tcp socket use with
- * user-space socket API use.
- */
-static struct lock_class_key nvme_tcp_sk_key[2];
-static struct lock_class_key nvme_tcp_slock_key[2];
-
-static void nvme_tcp_reclassify_socket(struct socket *sock)
-{
- struct sock *sk = sock->sk;
-
- if (WARN_ON_ONCE(!sock_allow_reclassification(sk)))
- return;
-
- switch (sk->sk_family) {
- case AF_INET:
- sock_lock_init_class_and_name(sk, "slock-AF_INET-NVME",
- &nvme_tcp_slock_key[0],
- "sk_lock-AF_INET-NVME",
- &nvme_tcp_sk_key[0]);
- break;
- case AF_INET6:
- sock_lock_init_class_and_name(sk, "slock-AF_INET6-NVME",
- &nvme_tcp_slock_key[1],
- "sk_lock-AF_INET6-NVME",
- &nvme_tcp_sk_key[1]);
- break;
- default:
- WARN_ON_ONCE(1);
- }
-}
-#else
-static void nvme_tcp_reclassify_socket(struct socket *sock) { }
-#endif
-
enum nvme_tcp_send_state {
NVME_TCP_SEND_CMD_PDU = 0,
NVME_TCP_SEND_H2C_PDU,
@@ -180,6 +142,11 @@ struct nvme_tcp_queue {
void (*state_change)(struct sock *);
void (*data_ready)(struct sock *);
void (*write_space)(struct sock *);
+
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+ struct lock_class_key nvme_tcp_sk_key;
+ struct lock_class_key nvme_tcp_slock_key;
+#endif
};
struct nvme_tcp_ctrl {
@@ -207,6 +174,39 @@ static const struct blk_mq_ops nvme_tcp_mq_ops;
static const struct blk_mq_ops nvme_tcp_admin_mq_ops;
static int nvme_tcp_try_send(struct nvme_tcp_queue *queue);
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+/* lockdep can detect a circular dependency of the form
+ * sk_lock -> mmap_lock (page fault) -> fs locks -> sk_lock
+ * because dependencies are tracked for both nvme-tcp and user contexts. Using
+ * a separate class prevents lockdep from conflating nvme-tcp socket use with
+ * user-space socket API use.
+ */
+static void nvme_tcp_reclassify_socket(struct nvme_tcp_queue *queue)
+{
+ struct sock *sk = queue->sock->sk;
+
+ if (WARN_ON_ONCE(!sock_allow_reclassification(sk)))
+ return;
+
+ switch (sk->sk_family) {
+ case AF_INET:
+ sock_lock_init_class_and_name(sk, "slock-AF_INET-NVME",
+ &queue->nvme_tcp_slock_key,
+ "sk_lock-AF_INET-NVME",
+ &queue->nvme_tcp_sk_key);
+ break;
+ case AF_INET6:
+ sock_lock_init_class_and_name(sk, "slock-AF_INET6-NVME",
+ &queue->nvme_tcp_slock_key,
+ "sk_lock-AF_INET6-NVME",
+ &queue->nvme_tcp_sk_key);
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ }
+}
+#endif
+
static inline struct nvme_tcp_ctrl *to_tcp_ctrl(struct nvme_ctrl *ctrl)
{
return container_of(ctrl, struct nvme_tcp_ctrl, ctrl);
@@ -340,32 +340,25 @@ static void nvme_tcp_init_iter(struct nvme_tcp_request *req,
unsigned int dir)
{
struct request *rq = blk_mq_rq_from_pdu(req);
- struct bio_vec *vec;
- unsigned int size;
- int nr_bvec;
- size_t offset;
if (rq->rq_flags & RQF_SPECIAL_PAYLOAD) {
- vec = &rq->special_vec;
- nr_bvec = 1;
- size = blk_rq_payload_bytes(rq);
- offset = 0;
+ iov_iter_bvec(&req->iter, dir, &rq->special_vec, 1,
+ blk_rq_payload_bytes(rq));
+ req->iter.iov_offset = 0;
} else {
struct bio *bio = req->curr_bio;
struct bvec_iter bi;
struct bio_vec bv;
+ int nr_bvec = 0;
- vec = __bvec_iter_bvec(bio->bi_io_vec, bio->bi_iter);
- nr_bvec = 0;
- bio_for_each_bvec(bv, bio, bi) {
+ bio_for_each_bvec(bv, bio, bi)
nr_bvec++;
- }
- size = bio->bi_iter.bi_size;
- offset = bio->bi_iter.bi_bvec_done;
- }
- iov_iter_bvec(&req->iter, dir, vec, nr_bvec, size);
- req->iter.iov_offset = offset;
+ iov_iter_bvec(&req->iter, dir,
+ __bvec_iter_bvec(bio->bi_io_vec, bio->bi_iter), nr_bvec,
+ bio->bi_iter.bi_size);
+ req->iter.iov_offset = bio->bi_iter.bi_bvec_done;
+ }
}
static inline void nvme_tcp_advance_req(struct nvme_tcp_request *req,
@@ -548,7 +541,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);
@@ -1468,6 +1461,11 @@ static void nvme_tcp_free_queue(struct nvme_ctrl *nctrl, int qid)
kfree(queue->pdu);
mutex_destroy(&queue->send_mutex);
mutex_destroy(&queue->queue_lock);
+
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+ lockdep_unregister_key(&queue->nvme_tcp_sk_key);
+ lockdep_unregister_key(&queue->nvme_tcp_slock_key);
+#endif
}
static int nvme_tcp_init_connection(struct nvme_tcp_queue *queue)
@@ -1813,7 +1811,12 @@ static int nvme_tcp_alloc_queue(struct nvme_ctrl *nctrl, int qid,
}
sk_net_refcnt_upgrade(queue->sock->sk);
- nvme_tcp_reclassify_socket(queue->sock);
+
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+ lockdep_register_key(&queue->nvme_tcp_sk_key);
+ lockdep_register_key(&queue->nvme_tcp_slock_key);
+ nvme_tcp_reclassify_socket(queue);
+#endif
/* Single syn retry */
tcp_sock_set_syncnt(queue->sock->sk, 1);
@@ -1918,6 +1921,10 @@ err_sock:
/* Use sync variant - see nvme_tcp_free_queue() for explanation */
__fput_sync(queue->sock->file);
queue->sock = NULL;
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+ lockdep_unregister_key(&queue->nvme_tcp_sk_key);
+ lockdep_unregister_key(&queue->nvme_tcp_slock_key);
+#endif
err_destroy_mutex:
mutex_destroy(&queue->send_mutex);
mutex_destroy(&queue->queue_lock);
@@ -2208,7 +2215,7 @@ static int nvme_tcp_configure_io_queues(struct nvme_ctrl *ctrl, bool new)
if (!new) {
nvme_start_freeze(ctrl);
nvme_unquiesce_io_queues(ctrl);
- if (!nvme_wait_freeze_timeout(ctrl, NVME_IO_TIMEOUT)) {
+ if (!nvme_wait_freeze_timeout(ctrl)) {
/*
* If we timed out waiting for freeze we are likely to
* be stuck. Fail the controller initialization just
@@ -2475,6 +2482,8 @@ static void nvme_tcp_reconnect_ctrl_work(struct work_struct *work)
dev_info(ctrl->device, "Successfully reconnected (attempt %d/%d)\n",
ctrl->nr_reconnects, ctrl->opts->max_reconnects);
+ /* accumulate reconnect attempts before resetting it to zero */
+ atomic_long_add(ctrl->nr_reconnects, &ctrl->acc_reconnects);
ctrl->nr_reconnects = 0;
return;
@@ -3053,6 +3062,8 @@ static int __init nvme_tcp_init_module(void)
if (wq_unbound)
wq_flags |= WQ_UNBOUND;
+ else
+ wq_flags |= WQ_PERCPU;
nvme_tcp_wq = alloc_workqueue("nvme_tcp_wq", wq_flags, 0);
if (!nvme_tcp_wq)
diff --git a/drivers/nvme/target/discovery.c b/drivers/nvme/target/discovery.c
index e9b35549e254..114869d16a1f 100644
--- a/drivers/nvme/target/discovery.c
+++ b/drivers/nvme/target/discovery.c
@@ -166,6 +166,7 @@ static void nvmet_execute_disc_get_log_page(struct nvmet_req *req)
u64 offset = nvmet_get_log_page_offset(req->cmd);
size_t data_len = nvmet_get_log_page_len(req->cmd);
size_t alloc_len;
+ size_t copy_len;
struct nvmet_subsys_link *p;
struct nvmet_port *r;
u32 numrec = 0;
@@ -242,7 +243,27 @@ static void nvmet_execute_disc_get_log_page(struct nvmet_req *req)
up_read(&nvmet_config_sem);
- status = nvmet_copy_to_sgl(req, 0, buffer + offset, data_len);
+ /*
+ * Validate the host-supplied log page offset before copying out.
+ * Without this check, the host controls a 64-bit byte offset into
+ * a small kzalloc'd buffer: a value past the log page lets the
+ * subsequent memcpy read adjacent kernel heap, and a value aimed
+ * at unmapped kernel memory faults the in-kernel copy and crashes
+ * the target host. The Discovery controller is unauthenticated,
+ * so the bug is reachable from any reachable fabric peer.
+ */
+ if (offset > alloc_len) {
+ req->error_loc =
+ offsetof(struct nvme_get_log_page_command, lpo);
+ status = NVME_SC_INVALID_FIELD | NVME_STATUS_DNR;
+ goto out_free_buffer;
+ }
+
+ copy_len = min_t(size_t, data_len, alloc_len - offset);
+ status = nvmet_copy_to_sgl(req, 0, buffer + offset, copy_len);
+ if (!status && copy_len < data_len)
+ status = nvmet_zero_sgl(req, copy_len, data_len - copy_len);
+out_free_buffer:
kfree(buffer);
out:
nvmet_req_complete(req, status);
diff --git a/drivers/nvme/target/fabrics-cmd-auth.c b/drivers/nvme/target/fabrics-cmd-auth.c
index f1e613e7c63e..0a85acf1e5c7 100644
--- a/drivers/nvme/target/fabrics-cmd-auth.c
+++ b/drivers/nvme/target/fabrics-cmd-auth.c
@@ -132,13 +132,22 @@ static u8 nvmet_auth_negotiate(struct nvmet_req *req, void *d)
return 0;
}
-static u8 nvmet_auth_reply(struct nvmet_req *req, void *d)
+static u8 nvmet_auth_reply(struct nvmet_req *req, void *d, u32 tl)
{
struct nvmet_ctrl *ctrl = req->sq->ctrl;
struct nvmf_auth_dhchap_reply_data *data = d;
- u16 dhvlen = le16_to_cpu(data->dhvlen);
+ u16 dhvlen;
u8 *response;
+ if (tl < sizeof(*data))
+ return NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD;
+
+ dhvlen = le16_to_cpu(data->dhvlen);
+
+ /* Validate that hl and dhvlen fit within the transfer length */
+ if (sizeof(*data) + 2 * (size_t)data->hl + dhvlen > tl)
+ return NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD;
+
pr_debug("%s: ctrl %d qid %d: data hl %d cvalid %d dhvlen %u\n",
__func__, ctrl->cntlid, req->sq->qid,
data->hl, data->cvalid, dhvlen);
@@ -338,7 +347,7 @@ void nvmet_execute_auth_send(struct nvmet_req *req)
switch (data->auth_id) {
case NVME_AUTH_DHCHAP_MESSAGE_REPLY:
- dhchap_status = nvmet_auth_reply(req, d);
+ dhchap_status = nvmet_auth_reply(req, d, tl);
if (dhchap_status == 0)
req->sq->dhchap_step =
NVME_AUTH_DHCHAP_MESSAGE_SUCCESS1;
diff --git a/drivers/nvme/target/loop.c b/drivers/nvme/target/loop.c
index d98d0cdc5d6f..fcb1f8186fdd 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);
@@ -274,7 +274,6 @@ static void nvme_loop_destroy_admin_queue(struct nvme_loop_ctrl *ctrl)
nvmet_sq_destroy(&ctrl->queues[0].nvme_sq);
nvmet_cq_put(&ctrl->queues[0].nvme_cq);
- nvme_remove_admin_tag_set(&ctrl->ctrl);
}
static void nvme_loop_free_ctrl(struct nvme_ctrl *nctrl)
@@ -375,25 +374,18 @@ static int nvme_loop_configure_admin_queue(struct nvme_loop_ctrl *ctrl)
}
ctrl->ctrl.queue_count = 1;
- error = nvme_alloc_admin_tag_set(&ctrl->ctrl, &ctrl->admin_tag_set,
- &nvme_loop_admin_mq_ops,
- sizeof(struct nvme_loop_iod) +
- NVME_INLINE_SG_CNT * sizeof(struct scatterlist));
- if (error)
- goto out_free_sq;
-
/* reset stopped state for the fresh admin queue */
clear_bit(NVME_CTRL_ADMIN_Q_STOPPED, &ctrl->ctrl.flags);
error = nvmf_connect_admin_queue(&ctrl->ctrl);
if (error)
- goto out_cleanup_tagset;
+ goto out_free_sq;
set_bit(NVME_LOOP_Q_LIVE, &ctrl->queues[0].flags);
error = nvme_enable_ctrl(&ctrl->ctrl);
if (error)
- goto out_cleanup_tagset;
+ goto out_free_sq;
ctrl->ctrl.max_hw_sectors =
(NVME_LOOP_MAX_SEGMENTS - 1) << PAGE_SECTORS_SHIFT;
@@ -402,14 +394,12 @@ static int nvme_loop_configure_admin_queue(struct nvme_loop_ctrl *ctrl)
error = nvme_init_ctrl_finish(&ctrl->ctrl, false);
if (error)
- goto out_cleanup_tagset;
+ goto out_free_sq;
return 0;
-out_cleanup_tagset:
- clear_bit(NVME_LOOP_Q_LIVE, &ctrl->queues[0].flags);
- nvme_remove_admin_tag_set(&ctrl->ctrl);
out_free_sq:
+ clear_bit(NVME_LOOP_Q_LIVE, &ctrl->queues[0].flags);
nvmet_sq_destroy(&ctrl->queues[0].nvme_sq);
nvmet_cq_put(&ctrl->queues[0].nvme_cq);
return error;
@@ -432,6 +422,7 @@ static void nvme_loop_shutdown_ctrl(struct nvme_loop_ctrl *ctrl)
static void nvme_loop_delete_ctrl_host(struct nvme_ctrl *ctrl)
{
nvme_loop_shutdown_ctrl(to_loop_ctrl(ctrl));
+ nvme_remove_admin_tag_set(ctrl);
}
static void nvme_loop_delete_ctrl(struct nvmet_ctrl *nctrl)
@@ -494,6 +485,7 @@ out_destroy_admin:
nvme_cancel_admin_tagset(&ctrl->ctrl);
nvme_loop_destroy_admin_queue(ctrl);
out_disable:
+ nvme_remove_admin_tag_set(&ctrl->ctrl);
dev_warn(ctrl->ctrl.device, "Removing after reset failure\n");
nvme_uninit_ctrl(&ctrl->ctrl);
}
@@ -594,10 +586,17 @@ static struct nvme_ctrl *nvme_loop_create_ctrl(struct device *dev,
if (!ctrl->queues)
goto out_uninit_ctrl;
- ret = nvme_loop_configure_admin_queue(ctrl);
+ ret = nvme_alloc_admin_tag_set(&ctrl->ctrl, &ctrl->admin_tag_set,
+ &nvme_loop_admin_mq_ops,
+ sizeof(struct nvme_loop_iod) +
+ NVME_INLINE_SG_CNT * sizeof(struct scatterlist));
if (ret)
goto out_free_queues;
+ ret = nvme_loop_configure_admin_queue(ctrl);
+ if (ret)
+ goto out_remove_admin_tagset;
+
if (opts->queue_size > ctrl->ctrl.maxcmd) {
/* warn if maxcmd is lower than queue_size */
dev_warn(ctrl->ctrl.device,
@@ -633,6 +632,8 @@ out_remove_admin_queue:
nvme_quiesce_admin_queue(&ctrl->ctrl);
nvme_cancel_admin_tagset(&ctrl->ctrl);
nvme_loop_destroy_admin_queue(ctrl);
+out_remove_admin_tagset:
+ nvme_remove_admin_tag_set(&ctrl->ctrl);
out_free_queues:
kfree(ctrl->queues);
out_uninit_ctrl:
diff --git a/drivers/nvme/target/rdma.c b/drivers/nvme/target/rdma.c
index e6e2c3f9afdf..ac26f4f774c4 100644
--- a/drivers/nvme/target/rdma.c
+++ b/drivers/nvme/target/rdma.c
@@ -1598,8 +1598,10 @@ static int nvmet_rdma_queue_connect(struct rdma_cm_id *cm_id,
pending++;
}
mutex_unlock(&nvmet_rdma_queue_mutex);
- if (pending > NVMET_RDMA_BACKLOG)
- return NVME_SC_CONNECT_CTRL_BUSY;
+ if (pending > NVMET_RDMA_BACKLOG) {
+ ret = NVME_SC_CONNECT_CTRL_BUSY;
+ goto put_device;
+ }
}
ret = nvmet_rdma_cm_accept(cm_id, queue, &event->param.conn);
diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c
index 20f150d17a96..15c52f1f95f1 100644
--- a/drivers/nvme/target/tcp.c
+++ b/drivers/nvme/target/tcp.c
@@ -1844,10 +1844,11 @@ static void nvmet_tcp_tls_handshake_done(void *data, int status,
if (!status)
status = nvmet_tcp_tls_key_lookup(queue, peerid);
+ if (!status)
+ status = nvmet_tcp_set_queue_sock(queue);
+
if (status)
nvmet_tcp_schedule_release_queue(queue);
- else
- nvmet_tcp_set_queue_sock(queue);
kref_put(&queue->kref, nvmet_tcp_release_queue);
}
@@ -1999,6 +2000,12 @@ out_free_connect:
nvmet_tcp_free_cmd(&queue->connect);
out_ida_remove:
ida_free(&nvmet_tcp_queue_ida, queue->idx);
+ /*
+ * Drain the page fragment cache if any allocations were done.
+ * The first allocation using pf_cache is nvmet_tcp_alloc_cmd()
+ * for queue->connect after ida_alloc().
+ */
+ page_frag_cache_drain(&queue->pf_cache);
out_sock:
fput(queue->sock->file);
out_free_queue:
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 85eef401925a..22e2e3223440 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -1973,7 +1973,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);