18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci drbd_nl.c 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci This file is part of DRBD by Philipp Reisner and Lars Ellenberg. 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci Copyright (C) 2001-2008, LINBIT Information Technologies GmbH. 88c2ecf20Sopenharmony_ci Copyright (C) 1999-2008, Philipp Reisner <philipp.reisner@linbit.com>. 98c2ecf20Sopenharmony_ci Copyright (C) 2002-2008, Lars Ellenberg <lars.ellenberg@linbit.com>. 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <linux/module.h> 178c2ecf20Sopenharmony_ci#include <linux/drbd.h> 188c2ecf20Sopenharmony_ci#include <linux/in.h> 198c2ecf20Sopenharmony_ci#include <linux/fs.h> 208c2ecf20Sopenharmony_ci#include <linux/file.h> 218c2ecf20Sopenharmony_ci#include <linux/slab.h> 228c2ecf20Sopenharmony_ci#include <linux/blkpg.h> 238c2ecf20Sopenharmony_ci#include <linux/cpumask.h> 248c2ecf20Sopenharmony_ci#include "drbd_int.h" 258c2ecf20Sopenharmony_ci#include "drbd_protocol.h" 268c2ecf20Sopenharmony_ci#include "drbd_req.h" 278c2ecf20Sopenharmony_ci#include "drbd_state_change.h" 288c2ecf20Sopenharmony_ci#include <asm/unaligned.h> 298c2ecf20Sopenharmony_ci#include <linux/drbd_limits.h> 308c2ecf20Sopenharmony_ci#include <linux/kthread.h> 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#include <net/genetlink.h> 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci/* .doit */ 358c2ecf20Sopenharmony_ci// int drbd_adm_create_resource(struct sk_buff *skb, struct genl_info *info); 368c2ecf20Sopenharmony_ci// int drbd_adm_delete_resource(struct sk_buff *skb, struct genl_info *info); 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ciint drbd_adm_new_minor(struct sk_buff *skb, struct genl_info *info); 398c2ecf20Sopenharmony_ciint drbd_adm_del_minor(struct sk_buff *skb, struct genl_info *info); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ciint drbd_adm_new_resource(struct sk_buff *skb, struct genl_info *info); 428c2ecf20Sopenharmony_ciint drbd_adm_del_resource(struct sk_buff *skb, struct genl_info *info); 438c2ecf20Sopenharmony_ciint drbd_adm_down(struct sk_buff *skb, struct genl_info *info); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ciint drbd_adm_set_role(struct sk_buff *skb, struct genl_info *info); 468c2ecf20Sopenharmony_ciint drbd_adm_attach(struct sk_buff *skb, struct genl_info *info); 478c2ecf20Sopenharmony_ciint drbd_adm_disk_opts(struct sk_buff *skb, struct genl_info *info); 488c2ecf20Sopenharmony_ciint drbd_adm_detach(struct sk_buff *skb, struct genl_info *info); 498c2ecf20Sopenharmony_ciint drbd_adm_connect(struct sk_buff *skb, struct genl_info *info); 508c2ecf20Sopenharmony_ciint drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info); 518c2ecf20Sopenharmony_ciint drbd_adm_resize(struct sk_buff *skb, struct genl_info *info); 528c2ecf20Sopenharmony_ciint drbd_adm_start_ov(struct sk_buff *skb, struct genl_info *info); 538c2ecf20Sopenharmony_ciint drbd_adm_new_c_uuid(struct sk_buff *skb, struct genl_info *info); 548c2ecf20Sopenharmony_ciint drbd_adm_disconnect(struct sk_buff *skb, struct genl_info *info); 558c2ecf20Sopenharmony_ciint drbd_adm_invalidate(struct sk_buff *skb, struct genl_info *info); 568c2ecf20Sopenharmony_ciint drbd_adm_invalidate_peer(struct sk_buff *skb, struct genl_info *info); 578c2ecf20Sopenharmony_ciint drbd_adm_pause_sync(struct sk_buff *skb, struct genl_info *info); 588c2ecf20Sopenharmony_ciint drbd_adm_resume_sync(struct sk_buff *skb, struct genl_info *info); 598c2ecf20Sopenharmony_ciint drbd_adm_suspend_io(struct sk_buff *skb, struct genl_info *info); 608c2ecf20Sopenharmony_ciint drbd_adm_resume_io(struct sk_buff *skb, struct genl_info *info); 618c2ecf20Sopenharmony_ciint drbd_adm_outdate(struct sk_buff *skb, struct genl_info *info); 628c2ecf20Sopenharmony_ciint drbd_adm_resource_opts(struct sk_buff *skb, struct genl_info *info); 638c2ecf20Sopenharmony_ciint drbd_adm_get_status(struct sk_buff *skb, struct genl_info *info); 648c2ecf20Sopenharmony_ciint drbd_adm_get_timeout_type(struct sk_buff *skb, struct genl_info *info); 658c2ecf20Sopenharmony_ci/* .dumpit */ 668c2ecf20Sopenharmony_ciint drbd_adm_get_status_all(struct sk_buff *skb, struct netlink_callback *cb); 678c2ecf20Sopenharmony_ciint drbd_adm_dump_resources(struct sk_buff *skb, struct netlink_callback *cb); 688c2ecf20Sopenharmony_ciint drbd_adm_dump_devices(struct sk_buff *skb, struct netlink_callback *cb); 698c2ecf20Sopenharmony_ciint drbd_adm_dump_devices_done(struct netlink_callback *cb); 708c2ecf20Sopenharmony_ciint drbd_adm_dump_connections(struct sk_buff *skb, struct netlink_callback *cb); 718c2ecf20Sopenharmony_ciint drbd_adm_dump_connections_done(struct netlink_callback *cb); 728c2ecf20Sopenharmony_ciint drbd_adm_dump_peer_devices(struct sk_buff *skb, struct netlink_callback *cb); 738c2ecf20Sopenharmony_ciint drbd_adm_dump_peer_devices_done(struct netlink_callback *cb); 748c2ecf20Sopenharmony_ciint drbd_adm_get_initial_state(struct sk_buff *skb, struct netlink_callback *cb); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci#include <linux/drbd_genl_api.h> 778c2ecf20Sopenharmony_ci#include "drbd_nla.h" 788c2ecf20Sopenharmony_ci#include <linux/genl_magic_func.h> 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistatic atomic_t drbd_genl_seq = ATOMIC_INIT(2); /* two. */ 818c2ecf20Sopenharmony_cistatic atomic_t notify_genl_seq = ATOMIC_INIT(2); /* two. */ 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ciDEFINE_MUTEX(notification_mutex); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci/* used blkdev_get_by_path, to claim our meta data device(s) */ 868c2ecf20Sopenharmony_cistatic char *drbd_m_holder = "Hands off! this is DRBD's meta data device."; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic void drbd_adm_send_reply(struct sk_buff *skb, struct genl_info *info) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci genlmsg_end(skb, genlmsg_data(nlmsg_data(nlmsg_hdr(skb)))); 918c2ecf20Sopenharmony_ci if (genlmsg_reply(skb, info)) 928c2ecf20Sopenharmony_ci pr_err("error sending genl reply\n"); 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci/* Used on a fresh "drbd_adm_prepare"d reply_skb, this cannot fail: The only 968c2ecf20Sopenharmony_ci * reason it could fail was no space in skb, and there are 4k available. */ 978c2ecf20Sopenharmony_cistatic int drbd_msg_put_info(struct sk_buff *skb, const char *info) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci struct nlattr *nla; 1008c2ecf20Sopenharmony_ci int err = -EMSGSIZE; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci if (!info || !info[0]) 1038c2ecf20Sopenharmony_ci return 0; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci nla = nla_nest_start_noflag(skb, DRBD_NLA_CFG_REPLY); 1068c2ecf20Sopenharmony_ci if (!nla) 1078c2ecf20Sopenharmony_ci return err; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci err = nla_put_string(skb, T_info_text, info); 1108c2ecf20Sopenharmony_ci if (err) { 1118c2ecf20Sopenharmony_ci nla_nest_cancel(skb, nla); 1128c2ecf20Sopenharmony_ci return err; 1138c2ecf20Sopenharmony_ci } else 1148c2ecf20Sopenharmony_ci nla_nest_end(skb, nla); 1158c2ecf20Sopenharmony_ci return 0; 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci__printf(2, 3) 1198c2ecf20Sopenharmony_cistatic int drbd_msg_sprintf_info(struct sk_buff *skb, const char *fmt, ...) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci va_list args; 1228c2ecf20Sopenharmony_ci struct nlattr *nla, *txt; 1238c2ecf20Sopenharmony_ci int err = -EMSGSIZE; 1248c2ecf20Sopenharmony_ci int len; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci nla = nla_nest_start_noflag(skb, DRBD_NLA_CFG_REPLY); 1278c2ecf20Sopenharmony_ci if (!nla) 1288c2ecf20Sopenharmony_ci return err; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci txt = nla_reserve(skb, T_info_text, 256); 1318c2ecf20Sopenharmony_ci if (!txt) { 1328c2ecf20Sopenharmony_ci nla_nest_cancel(skb, nla); 1338c2ecf20Sopenharmony_ci return err; 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci va_start(args, fmt); 1368c2ecf20Sopenharmony_ci len = vscnprintf(nla_data(txt), 256, fmt, args); 1378c2ecf20Sopenharmony_ci va_end(args); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci /* maybe: retry with larger reserve, if truncated */ 1408c2ecf20Sopenharmony_ci txt->nla_len = nla_attr_size(len+1); 1418c2ecf20Sopenharmony_ci nlmsg_trim(skb, (char*)txt + NLA_ALIGN(txt->nla_len)); 1428c2ecf20Sopenharmony_ci nla_nest_end(skb, nla); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci return 0; 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci/* This would be a good candidate for a "pre_doit" hook, 1488c2ecf20Sopenharmony_ci * and per-family private info->pointers. 1498c2ecf20Sopenharmony_ci * But we need to stay compatible with older kernels. 1508c2ecf20Sopenharmony_ci * If it returns successfully, adm_ctx members are valid. 1518c2ecf20Sopenharmony_ci * 1528c2ecf20Sopenharmony_ci * At this point, we still rely on the global genl_lock(). 1538c2ecf20Sopenharmony_ci * If we want to avoid that, and allow "genl_family.parallel_ops", we may need 1548c2ecf20Sopenharmony_ci * to add additional synchronization against object destruction/modification. 1558c2ecf20Sopenharmony_ci */ 1568c2ecf20Sopenharmony_ci#define DRBD_ADM_NEED_MINOR 1 1578c2ecf20Sopenharmony_ci#define DRBD_ADM_NEED_RESOURCE 2 1588c2ecf20Sopenharmony_ci#define DRBD_ADM_NEED_CONNECTION 4 1598c2ecf20Sopenharmony_cistatic int drbd_adm_prepare(struct drbd_config_context *adm_ctx, 1608c2ecf20Sopenharmony_ci struct sk_buff *skb, struct genl_info *info, unsigned flags) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci struct drbd_genlmsghdr *d_in = info->userhdr; 1638c2ecf20Sopenharmony_ci const u8 cmd = info->genlhdr->cmd; 1648c2ecf20Sopenharmony_ci int err; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci memset(adm_ctx, 0, sizeof(*adm_ctx)); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci /* genl_rcv_msg only checks for CAP_NET_ADMIN on "GENL_ADMIN_PERM" :( */ 1698c2ecf20Sopenharmony_ci if (cmd != DRBD_ADM_GET_STATUS && !capable(CAP_NET_ADMIN)) 1708c2ecf20Sopenharmony_ci return -EPERM; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci adm_ctx->reply_skb = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); 1738c2ecf20Sopenharmony_ci if (!adm_ctx->reply_skb) { 1748c2ecf20Sopenharmony_ci err = -ENOMEM; 1758c2ecf20Sopenharmony_ci goto fail; 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci adm_ctx->reply_dh = genlmsg_put_reply(adm_ctx->reply_skb, 1798c2ecf20Sopenharmony_ci info, &drbd_genl_family, 0, cmd); 1808c2ecf20Sopenharmony_ci /* put of a few bytes into a fresh skb of >= 4k will always succeed. 1818c2ecf20Sopenharmony_ci * but anyways */ 1828c2ecf20Sopenharmony_ci if (!adm_ctx->reply_dh) { 1838c2ecf20Sopenharmony_ci err = -ENOMEM; 1848c2ecf20Sopenharmony_ci goto fail; 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci adm_ctx->reply_dh->minor = d_in->minor; 1888c2ecf20Sopenharmony_ci adm_ctx->reply_dh->ret_code = NO_ERROR; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci adm_ctx->volume = VOLUME_UNSPECIFIED; 1918c2ecf20Sopenharmony_ci if (info->attrs[DRBD_NLA_CFG_CONTEXT]) { 1928c2ecf20Sopenharmony_ci struct nlattr *nla; 1938c2ecf20Sopenharmony_ci /* parse and validate only */ 1948c2ecf20Sopenharmony_ci err = drbd_cfg_context_from_attrs(NULL, info); 1958c2ecf20Sopenharmony_ci if (err) 1968c2ecf20Sopenharmony_ci goto fail; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci /* It was present, and valid, 1998c2ecf20Sopenharmony_ci * copy it over to the reply skb. */ 2008c2ecf20Sopenharmony_ci err = nla_put_nohdr(adm_ctx->reply_skb, 2018c2ecf20Sopenharmony_ci info->attrs[DRBD_NLA_CFG_CONTEXT]->nla_len, 2028c2ecf20Sopenharmony_ci info->attrs[DRBD_NLA_CFG_CONTEXT]); 2038c2ecf20Sopenharmony_ci if (err) 2048c2ecf20Sopenharmony_ci goto fail; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci /* and assign stuff to the adm_ctx */ 2078c2ecf20Sopenharmony_ci nla = nested_attr_tb[__nla_type(T_ctx_volume)]; 2088c2ecf20Sopenharmony_ci if (nla) 2098c2ecf20Sopenharmony_ci adm_ctx->volume = nla_get_u32(nla); 2108c2ecf20Sopenharmony_ci nla = nested_attr_tb[__nla_type(T_ctx_resource_name)]; 2118c2ecf20Sopenharmony_ci if (nla) 2128c2ecf20Sopenharmony_ci adm_ctx->resource_name = nla_data(nla); 2138c2ecf20Sopenharmony_ci adm_ctx->my_addr = nested_attr_tb[__nla_type(T_ctx_my_addr)]; 2148c2ecf20Sopenharmony_ci adm_ctx->peer_addr = nested_attr_tb[__nla_type(T_ctx_peer_addr)]; 2158c2ecf20Sopenharmony_ci if ((adm_ctx->my_addr && 2168c2ecf20Sopenharmony_ci nla_len(adm_ctx->my_addr) > sizeof(adm_ctx->connection->my_addr)) || 2178c2ecf20Sopenharmony_ci (adm_ctx->peer_addr && 2188c2ecf20Sopenharmony_ci nla_len(adm_ctx->peer_addr) > sizeof(adm_ctx->connection->peer_addr))) { 2198c2ecf20Sopenharmony_ci err = -EINVAL; 2208c2ecf20Sopenharmony_ci goto fail; 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci } 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci adm_ctx->minor = d_in->minor; 2258c2ecf20Sopenharmony_ci adm_ctx->device = minor_to_device(d_in->minor); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci /* We are protected by the global genl_lock(). 2288c2ecf20Sopenharmony_ci * But we may explicitly drop it/retake it in drbd_adm_set_role(), 2298c2ecf20Sopenharmony_ci * so make sure this object stays around. */ 2308c2ecf20Sopenharmony_ci if (adm_ctx->device) 2318c2ecf20Sopenharmony_ci kref_get(&adm_ctx->device->kref); 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci if (adm_ctx->resource_name) { 2348c2ecf20Sopenharmony_ci adm_ctx->resource = drbd_find_resource(adm_ctx->resource_name); 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci if (!adm_ctx->device && (flags & DRBD_ADM_NEED_MINOR)) { 2388c2ecf20Sopenharmony_ci drbd_msg_put_info(adm_ctx->reply_skb, "unknown minor"); 2398c2ecf20Sopenharmony_ci return ERR_MINOR_INVALID; 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci if (!adm_ctx->resource && (flags & DRBD_ADM_NEED_RESOURCE)) { 2428c2ecf20Sopenharmony_ci drbd_msg_put_info(adm_ctx->reply_skb, "unknown resource"); 2438c2ecf20Sopenharmony_ci if (adm_ctx->resource_name) 2448c2ecf20Sopenharmony_ci return ERR_RES_NOT_KNOWN; 2458c2ecf20Sopenharmony_ci return ERR_INVALID_REQUEST; 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci if (flags & DRBD_ADM_NEED_CONNECTION) { 2498c2ecf20Sopenharmony_ci if (adm_ctx->resource) { 2508c2ecf20Sopenharmony_ci drbd_msg_put_info(adm_ctx->reply_skb, "no resource name expected"); 2518c2ecf20Sopenharmony_ci return ERR_INVALID_REQUEST; 2528c2ecf20Sopenharmony_ci } 2538c2ecf20Sopenharmony_ci if (adm_ctx->device) { 2548c2ecf20Sopenharmony_ci drbd_msg_put_info(adm_ctx->reply_skb, "no minor number expected"); 2558c2ecf20Sopenharmony_ci return ERR_INVALID_REQUEST; 2568c2ecf20Sopenharmony_ci } 2578c2ecf20Sopenharmony_ci if (adm_ctx->my_addr && adm_ctx->peer_addr) 2588c2ecf20Sopenharmony_ci adm_ctx->connection = conn_get_by_addrs(nla_data(adm_ctx->my_addr), 2598c2ecf20Sopenharmony_ci nla_len(adm_ctx->my_addr), 2608c2ecf20Sopenharmony_ci nla_data(adm_ctx->peer_addr), 2618c2ecf20Sopenharmony_ci nla_len(adm_ctx->peer_addr)); 2628c2ecf20Sopenharmony_ci if (!adm_ctx->connection) { 2638c2ecf20Sopenharmony_ci drbd_msg_put_info(adm_ctx->reply_skb, "unknown connection"); 2648c2ecf20Sopenharmony_ci return ERR_INVALID_REQUEST; 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci } 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci /* some more paranoia, if the request was over-determined */ 2698c2ecf20Sopenharmony_ci if (adm_ctx->device && adm_ctx->resource && 2708c2ecf20Sopenharmony_ci adm_ctx->device->resource != adm_ctx->resource) { 2718c2ecf20Sopenharmony_ci pr_warn("request: minor=%u, resource=%s; but that minor belongs to resource %s\n", 2728c2ecf20Sopenharmony_ci adm_ctx->minor, adm_ctx->resource->name, 2738c2ecf20Sopenharmony_ci adm_ctx->device->resource->name); 2748c2ecf20Sopenharmony_ci drbd_msg_put_info(adm_ctx->reply_skb, "minor exists in different resource"); 2758c2ecf20Sopenharmony_ci return ERR_INVALID_REQUEST; 2768c2ecf20Sopenharmony_ci } 2778c2ecf20Sopenharmony_ci if (adm_ctx->device && 2788c2ecf20Sopenharmony_ci adm_ctx->volume != VOLUME_UNSPECIFIED && 2798c2ecf20Sopenharmony_ci adm_ctx->volume != adm_ctx->device->vnr) { 2808c2ecf20Sopenharmony_ci pr_warn("request: minor=%u, volume=%u; but that minor is volume %u in %s\n", 2818c2ecf20Sopenharmony_ci adm_ctx->minor, adm_ctx->volume, 2828c2ecf20Sopenharmony_ci adm_ctx->device->vnr, adm_ctx->device->resource->name); 2838c2ecf20Sopenharmony_ci drbd_msg_put_info(adm_ctx->reply_skb, "minor exists as different volume"); 2848c2ecf20Sopenharmony_ci return ERR_INVALID_REQUEST; 2858c2ecf20Sopenharmony_ci } 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci /* still, provide adm_ctx->resource always, if possible. */ 2888c2ecf20Sopenharmony_ci if (!adm_ctx->resource) { 2898c2ecf20Sopenharmony_ci adm_ctx->resource = adm_ctx->device ? adm_ctx->device->resource 2908c2ecf20Sopenharmony_ci : adm_ctx->connection ? adm_ctx->connection->resource : NULL; 2918c2ecf20Sopenharmony_ci if (adm_ctx->resource) 2928c2ecf20Sopenharmony_ci kref_get(&adm_ctx->resource->kref); 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci return NO_ERROR; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_cifail: 2988c2ecf20Sopenharmony_ci nlmsg_free(adm_ctx->reply_skb); 2998c2ecf20Sopenharmony_ci adm_ctx->reply_skb = NULL; 3008c2ecf20Sopenharmony_ci return err; 3018c2ecf20Sopenharmony_ci} 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_cistatic int drbd_adm_finish(struct drbd_config_context *adm_ctx, 3048c2ecf20Sopenharmony_ci struct genl_info *info, int retcode) 3058c2ecf20Sopenharmony_ci{ 3068c2ecf20Sopenharmony_ci if (adm_ctx->device) { 3078c2ecf20Sopenharmony_ci kref_put(&adm_ctx->device->kref, drbd_destroy_device); 3088c2ecf20Sopenharmony_ci adm_ctx->device = NULL; 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci if (adm_ctx->connection) { 3118c2ecf20Sopenharmony_ci kref_put(&adm_ctx->connection->kref, &drbd_destroy_connection); 3128c2ecf20Sopenharmony_ci adm_ctx->connection = NULL; 3138c2ecf20Sopenharmony_ci } 3148c2ecf20Sopenharmony_ci if (adm_ctx->resource) { 3158c2ecf20Sopenharmony_ci kref_put(&adm_ctx->resource->kref, drbd_destroy_resource); 3168c2ecf20Sopenharmony_ci adm_ctx->resource = NULL; 3178c2ecf20Sopenharmony_ci } 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci if (!adm_ctx->reply_skb) 3208c2ecf20Sopenharmony_ci return -ENOMEM; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci adm_ctx->reply_dh->ret_code = retcode; 3238c2ecf20Sopenharmony_ci drbd_adm_send_reply(adm_ctx->reply_skb, info); 3248c2ecf20Sopenharmony_ci return 0; 3258c2ecf20Sopenharmony_ci} 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_cistatic void setup_khelper_env(struct drbd_connection *connection, char **envp) 3288c2ecf20Sopenharmony_ci{ 3298c2ecf20Sopenharmony_ci char *afs; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci /* FIXME: A future version will not allow this case. */ 3328c2ecf20Sopenharmony_ci if (connection->my_addr_len == 0 || connection->peer_addr_len == 0) 3338c2ecf20Sopenharmony_ci return; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci switch (((struct sockaddr *)&connection->peer_addr)->sa_family) { 3368c2ecf20Sopenharmony_ci case AF_INET6: 3378c2ecf20Sopenharmony_ci afs = "ipv6"; 3388c2ecf20Sopenharmony_ci snprintf(envp[4], 60, "DRBD_PEER_ADDRESS=%pI6", 3398c2ecf20Sopenharmony_ci &((struct sockaddr_in6 *)&connection->peer_addr)->sin6_addr); 3408c2ecf20Sopenharmony_ci break; 3418c2ecf20Sopenharmony_ci case AF_INET: 3428c2ecf20Sopenharmony_ci afs = "ipv4"; 3438c2ecf20Sopenharmony_ci snprintf(envp[4], 60, "DRBD_PEER_ADDRESS=%pI4", 3448c2ecf20Sopenharmony_ci &((struct sockaddr_in *)&connection->peer_addr)->sin_addr); 3458c2ecf20Sopenharmony_ci break; 3468c2ecf20Sopenharmony_ci default: 3478c2ecf20Sopenharmony_ci afs = "ssocks"; 3488c2ecf20Sopenharmony_ci snprintf(envp[4], 60, "DRBD_PEER_ADDRESS=%pI4", 3498c2ecf20Sopenharmony_ci &((struct sockaddr_in *)&connection->peer_addr)->sin_addr); 3508c2ecf20Sopenharmony_ci } 3518c2ecf20Sopenharmony_ci snprintf(envp[3], 20, "DRBD_PEER_AF=%s", afs); 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ciint drbd_khelper(struct drbd_device *device, char *cmd) 3558c2ecf20Sopenharmony_ci{ 3568c2ecf20Sopenharmony_ci char *envp[] = { "HOME=/", 3578c2ecf20Sopenharmony_ci "TERM=linux", 3588c2ecf20Sopenharmony_ci "PATH=/sbin:/usr/sbin:/bin:/usr/bin", 3598c2ecf20Sopenharmony_ci (char[20]) { }, /* address family */ 3608c2ecf20Sopenharmony_ci (char[60]) { }, /* address */ 3618c2ecf20Sopenharmony_ci NULL }; 3628c2ecf20Sopenharmony_ci char mb[14]; 3638c2ecf20Sopenharmony_ci char *argv[] = {drbd_usermode_helper, cmd, mb, NULL }; 3648c2ecf20Sopenharmony_ci struct drbd_connection *connection = first_peer_device(device)->connection; 3658c2ecf20Sopenharmony_ci struct sib_info sib; 3668c2ecf20Sopenharmony_ci int ret; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci if (current == connection->worker.task) 3698c2ecf20Sopenharmony_ci set_bit(CALLBACK_PENDING, &connection->flags); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci snprintf(mb, 14, "minor-%d", device_to_minor(device)); 3728c2ecf20Sopenharmony_ci setup_khelper_env(connection, envp); 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci /* The helper may take some time. 3758c2ecf20Sopenharmony_ci * write out any unsynced meta data changes now */ 3768c2ecf20Sopenharmony_ci drbd_md_sync(device); 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci drbd_info(device, "helper command: %s %s %s\n", drbd_usermode_helper, cmd, mb); 3798c2ecf20Sopenharmony_ci sib.sib_reason = SIB_HELPER_PRE; 3808c2ecf20Sopenharmony_ci sib.helper_name = cmd; 3818c2ecf20Sopenharmony_ci drbd_bcast_event(device, &sib); 3828c2ecf20Sopenharmony_ci notify_helper(NOTIFY_CALL, device, connection, cmd, 0); 3838c2ecf20Sopenharmony_ci ret = call_usermodehelper(drbd_usermode_helper, argv, envp, UMH_WAIT_PROC); 3848c2ecf20Sopenharmony_ci if (ret) 3858c2ecf20Sopenharmony_ci drbd_warn(device, "helper command: %s %s %s exit code %u (0x%x)\n", 3868c2ecf20Sopenharmony_ci drbd_usermode_helper, cmd, mb, 3878c2ecf20Sopenharmony_ci (ret >> 8) & 0xff, ret); 3888c2ecf20Sopenharmony_ci else 3898c2ecf20Sopenharmony_ci drbd_info(device, "helper command: %s %s %s exit code %u (0x%x)\n", 3908c2ecf20Sopenharmony_ci drbd_usermode_helper, cmd, mb, 3918c2ecf20Sopenharmony_ci (ret >> 8) & 0xff, ret); 3928c2ecf20Sopenharmony_ci sib.sib_reason = SIB_HELPER_POST; 3938c2ecf20Sopenharmony_ci sib.helper_exit_code = ret; 3948c2ecf20Sopenharmony_ci drbd_bcast_event(device, &sib); 3958c2ecf20Sopenharmony_ci notify_helper(NOTIFY_RESPONSE, device, connection, cmd, ret); 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci if (current == connection->worker.task) 3988c2ecf20Sopenharmony_ci clear_bit(CALLBACK_PENDING, &connection->flags); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci if (ret < 0) /* Ignore any ERRNOs we got. */ 4018c2ecf20Sopenharmony_ci ret = 0; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci return ret; 4048c2ecf20Sopenharmony_ci} 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_cienum drbd_peer_state conn_khelper(struct drbd_connection *connection, char *cmd) 4078c2ecf20Sopenharmony_ci{ 4088c2ecf20Sopenharmony_ci char *envp[] = { "HOME=/", 4098c2ecf20Sopenharmony_ci "TERM=linux", 4108c2ecf20Sopenharmony_ci "PATH=/sbin:/usr/sbin:/bin:/usr/bin", 4118c2ecf20Sopenharmony_ci (char[20]) { }, /* address family */ 4128c2ecf20Sopenharmony_ci (char[60]) { }, /* address */ 4138c2ecf20Sopenharmony_ci NULL }; 4148c2ecf20Sopenharmony_ci char *resource_name = connection->resource->name; 4158c2ecf20Sopenharmony_ci char *argv[] = {drbd_usermode_helper, cmd, resource_name, NULL }; 4168c2ecf20Sopenharmony_ci int ret; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci setup_khelper_env(connection, envp); 4198c2ecf20Sopenharmony_ci conn_md_sync(connection); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci drbd_info(connection, "helper command: %s %s %s\n", drbd_usermode_helper, cmd, resource_name); 4228c2ecf20Sopenharmony_ci /* TODO: conn_bcast_event() ?? */ 4238c2ecf20Sopenharmony_ci notify_helper(NOTIFY_CALL, NULL, connection, cmd, 0); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci ret = call_usermodehelper(drbd_usermode_helper, argv, envp, UMH_WAIT_PROC); 4268c2ecf20Sopenharmony_ci if (ret) 4278c2ecf20Sopenharmony_ci drbd_warn(connection, "helper command: %s %s %s exit code %u (0x%x)\n", 4288c2ecf20Sopenharmony_ci drbd_usermode_helper, cmd, resource_name, 4298c2ecf20Sopenharmony_ci (ret >> 8) & 0xff, ret); 4308c2ecf20Sopenharmony_ci else 4318c2ecf20Sopenharmony_ci drbd_info(connection, "helper command: %s %s %s exit code %u (0x%x)\n", 4328c2ecf20Sopenharmony_ci drbd_usermode_helper, cmd, resource_name, 4338c2ecf20Sopenharmony_ci (ret >> 8) & 0xff, ret); 4348c2ecf20Sopenharmony_ci /* TODO: conn_bcast_event() ?? */ 4358c2ecf20Sopenharmony_ci notify_helper(NOTIFY_RESPONSE, NULL, connection, cmd, ret); 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci if (ret < 0) /* Ignore any ERRNOs we got. */ 4388c2ecf20Sopenharmony_ci ret = 0; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci return ret; 4418c2ecf20Sopenharmony_ci} 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_cistatic enum drbd_fencing_p highest_fencing_policy(struct drbd_connection *connection) 4448c2ecf20Sopenharmony_ci{ 4458c2ecf20Sopenharmony_ci enum drbd_fencing_p fp = FP_NOT_AVAIL; 4468c2ecf20Sopenharmony_ci struct drbd_peer_device *peer_device; 4478c2ecf20Sopenharmony_ci int vnr; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci rcu_read_lock(); 4508c2ecf20Sopenharmony_ci idr_for_each_entry(&connection->peer_devices, peer_device, vnr) { 4518c2ecf20Sopenharmony_ci struct drbd_device *device = peer_device->device; 4528c2ecf20Sopenharmony_ci if (get_ldev_if_state(device, D_CONSISTENT)) { 4538c2ecf20Sopenharmony_ci struct disk_conf *disk_conf = 4548c2ecf20Sopenharmony_ci rcu_dereference(peer_device->device->ldev->disk_conf); 4558c2ecf20Sopenharmony_ci fp = max_t(enum drbd_fencing_p, fp, disk_conf->fencing); 4568c2ecf20Sopenharmony_ci put_ldev(device); 4578c2ecf20Sopenharmony_ci } 4588c2ecf20Sopenharmony_ci } 4598c2ecf20Sopenharmony_ci rcu_read_unlock(); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci return fp; 4628c2ecf20Sopenharmony_ci} 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_cistatic bool resource_is_supended(struct drbd_resource *resource) 4658c2ecf20Sopenharmony_ci{ 4668c2ecf20Sopenharmony_ci return resource->susp || resource->susp_fen || resource->susp_nod; 4678c2ecf20Sopenharmony_ci} 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_cibool conn_try_outdate_peer(struct drbd_connection *connection) 4708c2ecf20Sopenharmony_ci{ 4718c2ecf20Sopenharmony_ci struct drbd_resource * const resource = connection->resource; 4728c2ecf20Sopenharmony_ci unsigned int connect_cnt; 4738c2ecf20Sopenharmony_ci union drbd_state mask = { }; 4748c2ecf20Sopenharmony_ci union drbd_state val = { }; 4758c2ecf20Sopenharmony_ci enum drbd_fencing_p fp; 4768c2ecf20Sopenharmony_ci char *ex_to_string; 4778c2ecf20Sopenharmony_ci int r; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci spin_lock_irq(&resource->req_lock); 4808c2ecf20Sopenharmony_ci if (connection->cstate >= C_WF_REPORT_PARAMS) { 4818c2ecf20Sopenharmony_ci drbd_err(connection, "Expected cstate < C_WF_REPORT_PARAMS\n"); 4828c2ecf20Sopenharmony_ci spin_unlock_irq(&resource->req_lock); 4838c2ecf20Sopenharmony_ci return false; 4848c2ecf20Sopenharmony_ci } 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci connect_cnt = connection->connect_cnt; 4878c2ecf20Sopenharmony_ci spin_unlock_irq(&resource->req_lock); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci fp = highest_fencing_policy(connection); 4908c2ecf20Sopenharmony_ci switch (fp) { 4918c2ecf20Sopenharmony_ci case FP_NOT_AVAIL: 4928c2ecf20Sopenharmony_ci drbd_warn(connection, "Not fencing peer, I'm not even Consistent myself.\n"); 4938c2ecf20Sopenharmony_ci spin_lock_irq(&resource->req_lock); 4948c2ecf20Sopenharmony_ci if (connection->cstate < C_WF_REPORT_PARAMS) { 4958c2ecf20Sopenharmony_ci _conn_request_state(connection, 4968c2ecf20Sopenharmony_ci (union drbd_state) { { .susp_fen = 1 } }, 4978c2ecf20Sopenharmony_ci (union drbd_state) { { .susp_fen = 0 } }, 4988c2ecf20Sopenharmony_ci CS_VERBOSE | CS_HARD | CS_DC_SUSP); 4998c2ecf20Sopenharmony_ci /* We are no longer suspended due to the fencing policy. 5008c2ecf20Sopenharmony_ci * We may still be suspended due to the on-no-data-accessible policy. 5018c2ecf20Sopenharmony_ci * If that was OND_IO_ERROR, fail pending requests. */ 5028c2ecf20Sopenharmony_ci if (!resource_is_supended(resource)) 5038c2ecf20Sopenharmony_ci _tl_restart(connection, CONNECTION_LOST_WHILE_PENDING); 5048c2ecf20Sopenharmony_ci } 5058c2ecf20Sopenharmony_ci /* Else: in case we raced with a connection handshake, 5068c2ecf20Sopenharmony_ci * let the handshake figure out if we maybe can RESEND, 5078c2ecf20Sopenharmony_ci * and do not resume/fail pending requests here. 5088c2ecf20Sopenharmony_ci * Worst case is we stay suspended for now, which may be 5098c2ecf20Sopenharmony_ci * resolved by either re-establishing the replication link, or 5108c2ecf20Sopenharmony_ci * the next link failure, or eventually the administrator. */ 5118c2ecf20Sopenharmony_ci spin_unlock_irq(&resource->req_lock); 5128c2ecf20Sopenharmony_ci return false; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci case FP_DONT_CARE: 5158c2ecf20Sopenharmony_ci return true; 5168c2ecf20Sopenharmony_ci default: ; 5178c2ecf20Sopenharmony_ci } 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci r = conn_khelper(connection, "fence-peer"); 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci switch ((r>>8) & 0xff) { 5228c2ecf20Sopenharmony_ci case P_INCONSISTENT: /* peer is inconsistent */ 5238c2ecf20Sopenharmony_ci ex_to_string = "peer is inconsistent or worse"; 5248c2ecf20Sopenharmony_ci mask.pdsk = D_MASK; 5258c2ecf20Sopenharmony_ci val.pdsk = D_INCONSISTENT; 5268c2ecf20Sopenharmony_ci break; 5278c2ecf20Sopenharmony_ci case P_OUTDATED: /* peer got outdated, or was already outdated */ 5288c2ecf20Sopenharmony_ci ex_to_string = "peer was fenced"; 5298c2ecf20Sopenharmony_ci mask.pdsk = D_MASK; 5308c2ecf20Sopenharmony_ci val.pdsk = D_OUTDATED; 5318c2ecf20Sopenharmony_ci break; 5328c2ecf20Sopenharmony_ci case P_DOWN: /* peer was down */ 5338c2ecf20Sopenharmony_ci if (conn_highest_disk(connection) == D_UP_TO_DATE) { 5348c2ecf20Sopenharmony_ci /* we will(have) create(d) a new UUID anyways... */ 5358c2ecf20Sopenharmony_ci ex_to_string = "peer is unreachable, assumed to be dead"; 5368c2ecf20Sopenharmony_ci mask.pdsk = D_MASK; 5378c2ecf20Sopenharmony_ci val.pdsk = D_OUTDATED; 5388c2ecf20Sopenharmony_ci } else { 5398c2ecf20Sopenharmony_ci ex_to_string = "peer unreachable, doing nothing since disk != UpToDate"; 5408c2ecf20Sopenharmony_ci } 5418c2ecf20Sopenharmony_ci break; 5428c2ecf20Sopenharmony_ci case P_PRIMARY: /* Peer is primary, voluntarily outdate myself. 5438c2ecf20Sopenharmony_ci * This is useful when an unconnected R_SECONDARY is asked to 5448c2ecf20Sopenharmony_ci * become R_PRIMARY, but finds the other peer being active. */ 5458c2ecf20Sopenharmony_ci ex_to_string = "peer is active"; 5468c2ecf20Sopenharmony_ci drbd_warn(connection, "Peer is primary, outdating myself.\n"); 5478c2ecf20Sopenharmony_ci mask.disk = D_MASK; 5488c2ecf20Sopenharmony_ci val.disk = D_OUTDATED; 5498c2ecf20Sopenharmony_ci break; 5508c2ecf20Sopenharmony_ci case P_FENCING: 5518c2ecf20Sopenharmony_ci /* THINK: do we need to handle this 5528c2ecf20Sopenharmony_ci * like case 4, or more like case 5? */ 5538c2ecf20Sopenharmony_ci if (fp != FP_STONITH) 5548c2ecf20Sopenharmony_ci drbd_err(connection, "fence-peer() = 7 && fencing != Stonith !!!\n"); 5558c2ecf20Sopenharmony_ci ex_to_string = "peer was stonithed"; 5568c2ecf20Sopenharmony_ci mask.pdsk = D_MASK; 5578c2ecf20Sopenharmony_ci val.pdsk = D_OUTDATED; 5588c2ecf20Sopenharmony_ci break; 5598c2ecf20Sopenharmony_ci default: 5608c2ecf20Sopenharmony_ci /* The script is broken ... */ 5618c2ecf20Sopenharmony_ci drbd_err(connection, "fence-peer helper broken, returned %d\n", (r>>8)&0xff); 5628c2ecf20Sopenharmony_ci return false; /* Eventually leave IO frozen */ 5638c2ecf20Sopenharmony_ci } 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci drbd_info(connection, "fence-peer helper returned %d (%s)\n", 5668c2ecf20Sopenharmony_ci (r>>8) & 0xff, ex_to_string); 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci /* Not using 5698c2ecf20Sopenharmony_ci conn_request_state(connection, mask, val, CS_VERBOSE); 5708c2ecf20Sopenharmony_ci here, because we might were able to re-establish the connection in the 5718c2ecf20Sopenharmony_ci meantime. */ 5728c2ecf20Sopenharmony_ci spin_lock_irq(&resource->req_lock); 5738c2ecf20Sopenharmony_ci if (connection->cstate < C_WF_REPORT_PARAMS && !test_bit(STATE_SENT, &connection->flags)) { 5748c2ecf20Sopenharmony_ci if (connection->connect_cnt != connect_cnt) 5758c2ecf20Sopenharmony_ci /* In case the connection was established and droped 5768c2ecf20Sopenharmony_ci while the fence-peer handler was running, ignore it */ 5778c2ecf20Sopenharmony_ci drbd_info(connection, "Ignoring fence-peer exit code\n"); 5788c2ecf20Sopenharmony_ci else 5798c2ecf20Sopenharmony_ci _conn_request_state(connection, mask, val, CS_VERBOSE); 5808c2ecf20Sopenharmony_ci } 5818c2ecf20Sopenharmony_ci spin_unlock_irq(&resource->req_lock); 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci return conn_highest_pdsk(connection) <= D_OUTDATED; 5848c2ecf20Sopenharmony_ci} 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_cistatic int _try_outdate_peer_async(void *data) 5878c2ecf20Sopenharmony_ci{ 5888c2ecf20Sopenharmony_ci struct drbd_connection *connection = (struct drbd_connection *)data; 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci conn_try_outdate_peer(connection); 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci kref_put(&connection->kref, drbd_destroy_connection); 5938c2ecf20Sopenharmony_ci return 0; 5948c2ecf20Sopenharmony_ci} 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_civoid conn_try_outdate_peer_async(struct drbd_connection *connection) 5978c2ecf20Sopenharmony_ci{ 5988c2ecf20Sopenharmony_ci struct task_struct *opa; 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci kref_get(&connection->kref); 6018c2ecf20Sopenharmony_ci /* We may have just sent a signal to this thread 6028c2ecf20Sopenharmony_ci * to get it out of some blocking network function. 6038c2ecf20Sopenharmony_ci * Clear signals; otherwise kthread_run(), which internally uses 6048c2ecf20Sopenharmony_ci * wait_on_completion_killable(), will mistake our pending signal 6058c2ecf20Sopenharmony_ci * for a new fatal signal and fail. */ 6068c2ecf20Sopenharmony_ci flush_signals(current); 6078c2ecf20Sopenharmony_ci opa = kthread_run(_try_outdate_peer_async, connection, "drbd_async_h"); 6088c2ecf20Sopenharmony_ci if (IS_ERR(opa)) { 6098c2ecf20Sopenharmony_ci drbd_err(connection, "out of mem, failed to invoke fence-peer helper\n"); 6108c2ecf20Sopenharmony_ci kref_put(&connection->kref, drbd_destroy_connection); 6118c2ecf20Sopenharmony_ci } 6128c2ecf20Sopenharmony_ci} 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_cienum drbd_state_rv 6158c2ecf20Sopenharmony_cidrbd_set_role(struct drbd_device *const device, enum drbd_role new_role, int force) 6168c2ecf20Sopenharmony_ci{ 6178c2ecf20Sopenharmony_ci struct drbd_peer_device *const peer_device = first_peer_device(device); 6188c2ecf20Sopenharmony_ci struct drbd_connection *const connection = peer_device ? peer_device->connection : NULL; 6198c2ecf20Sopenharmony_ci const int max_tries = 4; 6208c2ecf20Sopenharmony_ci enum drbd_state_rv rv = SS_UNKNOWN_ERROR; 6218c2ecf20Sopenharmony_ci struct net_conf *nc; 6228c2ecf20Sopenharmony_ci int try = 0; 6238c2ecf20Sopenharmony_ci int forced = 0; 6248c2ecf20Sopenharmony_ci union drbd_state mask, val; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci if (new_role == R_PRIMARY) { 6278c2ecf20Sopenharmony_ci struct drbd_connection *connection; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci /* Detect dead peers as soon as possible. */ 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci rcu_read_lock(); 6328c2ecf20Sopenharmony_ci for_each_connection(connection, device->resource) 6338c2ecf20Sopenharmony_ci request_ping(connection); 6348c2ecf20Sopenharmony_ci rcu_read_unlock(); 6358c2ecf20Sopenharmony_ci } 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci mutex_lock(device->state_mutex); 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci mask.i = 0; mask.role = R_MASK; 6408c2ecf20Sopenharmony_ci val.i = 0; val.role = new_role; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci while (try++ < max_tries) { 6438c2ecf20Sopenharmony_ci rv = _drbd_request_state_holding_state_mutex(device, mask, val, CS_WAIT_COMPLETE); 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci /* in case we first succeeded to outdate, 6468c2ecf20Sopenharmony_ci * but now suddenly could establish a connection */ 6478c2ecf20Sopenharmony_ci if (rv == SS_CW_FAILED_BY_PEER && mask.pdsk != 0) { 6488c2ecf20Sopenharmony_ci val.pdsk = 0; 6498c2ecf20Sopenharmony_ci mask.pdsk = 0; 6508c2ecf20Sopenharmony_ci continue; 6518c2ecf20Sopenharmony_ci } 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci if (rv == SS_NO_UP_TO_DATE_DISK && force && 6548c2ecf20Sopenharmony_ci (device->state.disk < D_UP_TO_DATE && 6558c2ecf20Sopenharmony_ci device->state.disk >= D_INCONSISTENT)) { 6568c2ecf20Sopenharmony_ci mask.disk = D_MASK; 6578c2ecf20Sopenharmony_ci val.disk = D_UP_TO_DATE; 6588c2ecf20Sopenharmony_ci forced = 1; 6598c2ecf20Sopenharmony_ci continue; 6608c2ecf20Sopenharmony_ci } 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci if (rv == SS_NO_UP_TO_DATE_DISK && 6638c2ecf20Sopenharmony_ci device->state.disk == D_CONSISTENT && mask.pdsk == 0) { 6648c2ecf20Sopenharmony_ci D_ASSERT(device, device->state.pdsk == D_UNKNOWN); 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci if (conn_try_outdate_peer(connection)) { 6678c2ecf20Sopenharmony_ci val.disk = D_UP_TO_DATE; 6688c2ecf20Sopenharmony_ci mask.disk = D_MASK; 6698c2ecf20Sopenharmony_ci } 6708c2ecf20Sopenharmony_ci continue; 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci if (rv == SS_NOTHING_TO_DO) 6748c2ecf20Sopenharmony_ci goto out; 6758c2ecf20Sopenharmony_ci if (rv == SS_PRIMARY_NOP && mask.pdsk == 0) { 6768c2ecf20Sopenharmony_ci if (!conn_try_outdate_peer(connection) && force) { 6778c2ecf20Sopenharmony_ci drbd_warn(device, "Forced into split brain situation!\n"); 6788c2ecf20Sopenharmony_ci mask.pdsk = D_MASK; 6798c2ecf20Sopenharmony_ci val.pdsk = D_OUTDATED; 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci } 6828c2ecf20Sopenharmony_ci continue; 6838c2ecf20Sopenharmony_ci } 6848c2ecf20Sopenharmony_ci if (rv == SS_TWO_PRIMARIES) { 6858c2ecf20Sopenharmony_ci /* Maybe the peer is detected as dead very soon... 6868c2ecf20Sopenharmony_ci retry at most once more in this case. */ 6878c2ecf20Sopenharmony_ci if (try < max_tries) { 6888c2ecf20Sopenharmony_ci int timeo; 6898c2ecf20Sopenharmony_ci try = max_tries - 1; 6908c2ecf20Sopenharmony_ci rcu_read_lock(); 6918c2ecf20Sopenharmony_ci nc = rcu_dereference(connection->net_conf); 6928c2ecf20Sopenharmony_ci timeo = nc ? (nc->ping_timeo + 1) * HZ / 10 : 1; 6938c2ecf20Sopenharmony_ci rcu_read_unlock(); 6948c2ecf20Sopenharmony_ci schedule_timeout_interruptible(timeo); 6958c2ecf20Sopenharmony_ci } 6968c2ecf20Sopenharmony_ci continue; 6978c2ecf20Sopenharmony_ci } 6988c2ecf20Sopenharmony_ci if (rv < SS_SUCCESS) { 6998c2ecf20Sopenharmony_ci rv = _drbd_request_state(device, mask, val, 7008c2ecf20Sopenharmony_ci CS_VERBOSE + CS_WAIT_COMPLETE); 7018c2ecf20Sopenharmony_ci if (rv < SS_SUCCESS) 7028c2ecf20Sopenharmony_ci goto out; 7038c2ecf20Sopenharmony_ci } 7048c2ecf20Sopenharmony_ci break; 7058c2ecf20Sopenharmony_ci } 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci if (rv < SS_SUCCESS) 7088c2ecf20Sopenharmony_ci goto out; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci if (forced) 7118c2ecf20Sopenharmony_ci drbd_warn(device, "Forced to consider local data as UpToDate!\n"); 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci /* Wait until nothing is on the fly :) */ 7148c2ecf20Sopenharmony_ci wait_event(device->misc_wait, atomic_read(&device->ap_pending_cnt) == 0); 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci /* FIXME also wait for all pending P_BARRIER_ACK? */ 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci if (new_role == R_SECONDARY) { 7198c2ecf20Sopenharmony_ci if (get_ldev(device)) { 7208c2ecf20Sopenharmony_ci device->ldev->md.uuid[UI_CURRENT] &= ~(u64)1; 7218c2ecf20Sopenharmony_ci put_ldev(device); 7228c2ecf20Sopenharmony_ci } 7238c2ecf20Sopenharmony_ci } else { 7248c2ecf20Sopenharmony_ci mutex_lock(&device->resource->conf_update); 7258c2ecf20Sopenharmony_ci nc = connection->net_conf; 7268c2ecf20Sopenharmony_ci if (nc) 7278c2ecf20Sopenharmony_ci nc->discard_my_data = 0; /* without copy; single bit op is atomic */ 7288c2ecf20Sopenharmony_ci mutex_unlock(&device->resource->conf_update); 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci if (get_ldev(device)) { 7318c2ecf20Sopenharmony_ci if (((device->state.conn < C_CONNECTED || 7328c2ecf20Sopenharmony_ci device->state.pdsk <= D_FAILED) 7338c2ecf20Sopenharmony_ci && device->ldev->md.uuid[UI_BITMAP] == 0) || forced) 7348c2ecf20Sopenharmony_ci drbd_uuid_new_current(device); 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci device->ldev->md.uuid[UI_CURRENT] |= (u64)1; 7378c2ecf20Sopenharmony_ci put_ldev(device); 7388c2ecf20Sopenharmony_ci } 7398c2ecf20Sopenharmony_ci } 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci /* writeout of activity log covered areas of the bitmap 7428c2ecf20Sopenharmony_ci * to stable storage done in after state change already */ 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci if (device->state.conn >= C_WF_REPORT_PARAMS) { 7458c2ecf20Sopenharmony_ci /* if this was forced, we should consider sync */ 7468c2ecf20Sopenharmony_ci if (forced) 7478c2ecf20Sopenharmony_ci drbd_send_uuids(peer_device); 7488c2ecf20Sopenharmony_ci drbd_send_current_state(peer_device); 7498c2ecf20Sopenharmony_ci } 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci drbd_md_sync(device); 7528c2ecf20Sopenharmony_ci set_disk_ro(device->vdisk, new_role == R_SECONDARY); 7538c2ecf20Sopenharmony_ci kobject_uevent(&disk_to_dev(device->vdisk)->kobj, KOBJ_CHANGE); 7548c2ecf20Sopenharmony_ciout: 7558c2ecf20Sopenharmony_ci mutex_unlock(device->state_mutex); 7568c2ecf20Sopenharmony_ci return rv; 7578c2ecf20Sopenharmony_ci} 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_cistatic const char *from_attrs_err_to_txt(int err) 7608c2ecf20Sopenharmony_ci{ 7618c2ecf20Sopenharmony_ci return err == -ENOMSG ? "required attribute missing" : 7628c2ecf20Sopenharmony_ci err == -EOPNOTSUPP ? "unknown mandatory attribute" : 7638c2ecf20Sopenharmony_ci err == -EEXIST ? "can not change invariant setting" : 7648c2ecf20Sopenharmony_ci "invalid attribute value"; 7658c2ecf20Sopenharmony_ci} 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ciint drbd_adm_set_role(struct sk_buff *skb, struct genl_info *info) 7688c2ecf20Sopenharmony_ci{ 7698c2ecf20Sopenharmony_ci struct drbd_config_context adm_ctx; 7708c2ecf20Sopenharmony_ci struct set_role_parms parms; 7718c2ecf20Sopenharmony_ci int err; 7728c2ecf20Sopenharmony_ci enum drbd_ret_code retcode; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_MINOR); 7758c2ecf20Sopenharmony_ci if (!adm_ctx.reply_skb) 7768c2ecf20Sopenharmony_ci return retcode; 7778c2ecf20Sopenharmony_ci if (retcode != NO_ERROR) 7788c2ecf20Sopenharmony_ci goto out; 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci memset(&parms, 0, sizeof(parms)); 7818c2ecf20Sopenharmony_ci if (info->attrs[DRBD_NLA_SET_ROLE_PARMS]) { 7828c2ecf20Sopenharmony_ci err = set_role_parms_from_attrs(&parms, info); 7838c2ecf20Sopenharmony_ci if (err) { 7848c2ecf20Sopenharmony_ci retcode = ERR_MANDATORY_TAG; 7858c2ecf20Sopenharmony_ci drbd_msg_put_info(adm_ctx.reply_skb, from_attrs_err_to_txt(err)); 7868c2ecf20Sopenharmony_ci goto out; 7878c2ecf20Sopenharmony_ci } 7888c2ecf20Sopenharmony_ci } 7898c2ecf20Sopenharmony_ci genl_unlock(); 7908c2ecf20Sopenharmony_ci mutex_lock(&adm_ctx.resource->adm_mutex); 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci if (info->genlhdr->cmd == DRBD_ADM_PRIMARY) 7938c2ecf20Sopenharmony_ci retcode = (enum drbd_ret_code)drbd_set_role(adm_ctx.device, 7948c2ecf20Sopenharmony_ci R_PRIMARY, parms.assume_uptodate); 7958c2ecf20Sopenharmony_ci else 7968c2ecf20Sopenharmony_ci retcode = (enum drbd_ret_code)drbd_set_role(adm_ctx.device, 7978c2ecf20Sopenharmony_ci R_SECONDARY, 0); 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci mutex_unlock(&adm_ctx.resource->adm_mutex); 8008c2ecf20Sopenharmony_ci genl_lock(); 8018c2ecf20Sopenharmony_ciout: 8028c2ecf20Sopenharmony_ci drbd_adm_finish(&adm_ctx, info, retcode); 8038c2ecf20Sopenharmony_ci return 0; 8048c2ecf20Sopenharmony_ci} 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci/* Initializes the md.*_offset members, so we are able to find 8078c2ecf20Sopenharmony_ci * the on disk meta data. 8088c2ecf20Sopenharmony_ci * 8098c2ecf20Sopenharmony_ci * We currently have two possible layouts: 8108c2ecf20Sopenharmony_ci * external: 8118c2ecf20Sopenharmony_ci * |----------- md_size_sect ------------------| 8128c2ecf20Sopenharmony_ci * [ 4k superblock ][ activity log ][ Bitmap ] 8138c2ecf20Sopenharmony_ci * | al_offset == 8 | 8148c2ecf20Sopenharmony_ci * | bm_offset = al_offset + X | 8158c2ecf20Sopenharmony_ci * ==> bitmap sectors = md_size_sect - bm_offset 8168c2ecf20Sopenharmony_ci * 8178c2ecf20Sopenharmony_ci * internal: 8188c2ecf20Sopenharmony_ci * |----------- md_size_sect ------------------| 8198c2ecf20Sopenharmony_ci * [data.....][ Bitmap ][ activity log ][ 4k superblock ] 8208c2ecf20Sopenharmony_ci * | al_offset < 0 | 8218c2ecf20Sopenharmony_ci * | bm_offset = al_offset - Y | 8228c2ecf20Sopenharmony_ci * ==> bitmap sectors = Y = al_offset - bm_offset 8238c2ecf20Sopenharmony_ci * 8248c2ecf20Sopenharmony_ci * Activity log size used to be fixed 32kB, 8258c2ecf20Sopenharmony_ci * but is about to become configurable. 8268c2ecf20Sopenharmony_ci */ 8278c2ecf20Sopenharmony_cistatic void drbd_md_set_sector_offsets(struct drbd_device *device, 8288c2ecf20Sopenharmony_ci struct drbd_backing_dev *bdev) 8298c2ecf20Sopenharmony_ci{ 8308c2ecf20Sopenharmony_ci sector_t md_size_sect = 0; 8318c2ecf20Sopenharmony_ci unsigned int al_size_sect = bdev->md.al_size_4k * 8; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci bdev->md.md_offset = drbd_md_ss(bdev); 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci switch (bdev->md.meta_dev_idx) { 8368c2ecf20Sopenharmony_ci default: 8378c2ecf20Sopenharmony_ci /* v07 style fixed size indexed meta data */ 8388c2ecf20Sopenharmony_ci bdev->md.md_size_sect = MD_128MB_SECT; 8398c2ecf20Sopenharmony_ci bdev->md.al_offset = MD_4kB_SECT; 8408c2ecf20Sopenharmony_ci bdev->md.bm_offset = MD_4kB_SECT + al_size_sect; 8418c2ecf20Sopenharmony_ci break; 8428c2ecf20Sopenharmony_ci case DRBD_MD_INDEX_FLEX_EXT: 8438c2ecf20Sopenharmony_ci /* just occupy the full device; unit: sectors */ 8448c2ecf20Sopenharmony_ci bdev->md.md_size_sect = drbd_get_capacity(bdev->md_bdev); 8458c2ecf20Sopenharmony_ci bdev->md.al_offset = MD_4kB_SECT; 8468c2ecf20Sopenharmony_ci bdev->md.bm_offset = MD_4kB_SECT + al_size_sect; 8478c2ecf20Sopenharmony_ci break; 8488c2ecf20Sopenharmony_ci case DRBD_MD_INDEX_INTERNAL: 8498c2ecf20Sopenharmony_ci case DRBD_MD_INDEX_FLEX_INT: 8508c2ecf20Sopenharmony_ci /* al size is still fixed */ 8518c2ecf20Sopenharmony_ci bdev->md.al_offset = -al_size_sect; 8528c2ecf20Sopenharmony_ci /* we need (slightly less than) ~ this much bitmap sectors: */ 8538c2ecf20Sopenharmony_ci md_size_sect = drbd_get_capacity(bdev->backing_bdev); 8548c2ecf20Sopenharmony_ci md_size_sect = ALIGN(md_size_sect, BM_SECT_PER_EXT); 8558c2ecf20Sopenharmony_ci md_size_sect = BM_SECT_TO_EXT(md_size_sect); 8568c2ecf20Sopenharmony_ci md_size_sect = ALIGN(md_size_sect, 8); 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci /* plus the "drbd meta data super block", 8598c2ecf20Sopenharmony_ci * and the activity log; */ 8608c2ecf20Sopenharmony_ci md_size_sect += MD_4kB_SECT + al_size_sect; 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci bdev->md.md_size_sect = md_size_sect; 8638c2ecf20Sopenharmony_ci /* bitmap offset is adjusted by 'super' block size */ 8648c2ecf20Sopenharmony_ci bdev->md.bm_offset = -md_size_sect + MD_4kB_SECT; 8658c2ecf20Sopenharmony_ci break; 8668c2ecf20Sopenharmony_ci } 8678c2ecf20Sopenharmony_ci} 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci/* input size is expected to be in KB */ 8708c2ecf20Sopenharmony_cichar *ppsize(char *buf, unsigned long long size) 8718c2ecf20Sopenharmony_ci{ 8728c2ecf20Sopenharmony_ci /* Needs 9 bytes at max including trailing NUL: 8738c2ecf20Sopenharmony_ci * -1ULL ==> "16384 EB" */ 8748c2ecf20Sopenharmony_ci static char units[] = { 'K', 'M', 'G', 'T', 'P', 'E' }; 8758c2ecf20Sopenharmony_ci int base = 0; 8768c2ecf20Sopenharmony_ci while (size >= 10000 && base < sizeof(units)-1) { 8778c2ecf20Sopenharmony_ci /* shift + round */ 8788c2ecf20Sopenharmony_ci size = (size >> 10) + !!(size & (1<<9)); 8798c2ecf20Sopenharmony_ci base++; 8808c2ecf20Sopenharmony_ci } 8818c2ecf20Sopenharmony_ci sprintf(buf, "%u %cB", (unsigned)size, units[base]); 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci return buf; 8848c2ecf20Sopenharmony_ci} 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci/* there is still a theoretical deadlock when called from receiver 8878c2ecf20Sopenharmony_ci * on an D_INCONSISTENT R_PRIMARY: 8888c2ecf20Sopenharmony_ci * remote READ does inc_ap_bio, receiver would need to receive answer 8898c2ecf20Sopenharmony_ci * packet from remote to dec_ap_bio again. 8908c2ecf20Sopenharmony_ci * receiver receive_sizes(), comes here, 8918c2ecf20Sopenharmony_ci * waits for ap_bio_cnt == 0. -> deadlock. 8928c2ecf20Sopenharmony_ci * but this cannot happen, actually, because: 8938c2ecf20Sopenharmony_ci * R_PRIMARY D_INCONSISTENT, and peer's disk is unreachable 8948c2ecf20Sopenharmony_ci * (not connected, or bad/no disk on peer): 8958c2ecf20Sopenharmony_ci * see drbd_fail_request_early, ap_bio_cnt is zero. 8968c2ecf20Sopenharmony_ci * R_PRIMARY D_INCONSISTENT, and C_SYNC_TARGET: 8978c2ecf20Sopenharmony_ci * peer may not initiate a resize. 8988c2ecf20Sopenharmony_ci */ 8998c2ecf20Sopenharmony_ci/* Note these are not to be confused with 9008c2ecf20Sopenharmony_ci * drbd_adm_suspend_io/drbd_adm_resume_io, 9018c2ecf20Sopenharmony_ci * which are (sub) state changes triggered by admin (drbdsetup), 9028c2ecf20Sopenharmony_ci * and can be long lived. 9038c2ecf20Sopenharmony_ci * This changes an device->flag, is triggered by drbd internals, 9048c2ecf20Sopenharmony_ci * and should be short-lived. */ 9058c2ecf20Sopenharmony_ci/* It needs to be a counter, since multiple threads might 9068c2ecf20Sopenharmony_ci independently suspend and resume IO. */ 9078c2ecf20Sopenharmony_civoid drbd_suspend_io(struct drbd_device *device) 9088c2ecf20Sopenharmony_ci{ 9098c2ecf20Sopenharmony_ci atomic_inc(&device->suspend_cnt); 9108c2ecf20Sopenharmony_ci if (drbd_suspended(device)) 9118c2ecf20Sopenharmony_ci return; 9128c2ecf20Sopenharmony_ci wait_event(device->misc_wait, !atomic_read(&device->ap_bio_cnt)); 9138c2ecf20Sopenharmony_ci} 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_civoid drbd_resume_io(struct drbd_device *device) 9168c2ecf20Sopenharmony_ci{ 9178c2ecf20Sopenharmony_ci if (atomic_dec_and_test(&device->suspend_cnt)) 9188c2ecf20Sopenharmony_ci wake_up(&device->misc_wait); 9198c2ecf20Sopenharmony_ci} 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci/** 9228c2ecf20Sopenharmony_ci * drbd_determine_dev_size() - Sets the right device size obeying all constraints 9238c2ecf20Sopenharmony_ci * @device: DRBD device. 9248c2ecf20Sopenharmony_ci * 9258c2ecf20Sopenharmony_ci * Returns 0 on success, negative return values indicate errors. 9268c2ecf20Sopenharmony_ci * You should call drbd_md_sync() after calling this function. 9278c2ecf20Sopenharmony_ci */ 9288c2ecf20Sopenharmony_cienum determine_dev_size 9298c2ecf20Sopenharmony_cidrbd_determine_dev_size(struct drbd_device *device, enum dds_flags flags, struct resize_parms *rs) __must_hold(local) 9308c2ecf20Sopenharmony_ci{ 9318c2ecf20Sopenharmony_ci struct md_offsets_and_sizes { 9328c2ecf20Sopenharmony_ci u64 last_agreed_sect; 9338c2ecf20Sopenharmony_ci u64 md_offset; 9348c2ecf20Sopenharmony_ci s32 al_offset; 9358c2ecf20Sopenharmony_ci s32 bm_offset; 9368c2ecf20Sopenharmony_ci u32 md_size_sect; 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci u32 al_stripes; 9398c2ecf20Sopenharmony_ci u32 al_stripe_size_4k; 9408c2ecf20Sopenharmony_ci } prev; 9418c2ecf20Sopenharmony_ci sector_t u_size, size; 9428c2ecf20Sopenharmony_ci struct drbd_md *md = &device->ldev->md; 9438c2ecf20Sopenharmony_ci void *buffer; 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci int md_moved, la_size_changed; 9468c2ecf20Sopenharmony_ci enum determine_dev_size rv = DS_UNCHANGED; 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci /* We may change the on-disk offsets of our meta data below. Lock out 9498c2ecf20Sopenharmony_ci * anything that may cause meta data IO, to avoid acting on incomplete 9508c2ecf20Sopenharmony_ci * layout changes or scribbling over meta data that is in the process 9518c2ecf20Sopenharmony_ci * of being moved. 9528c2ecf20Sopenharmony_ci * 9538c2ecf20Sopenharmony_ci * Move is not exactly correct, btw, currently we have all our meta 9548c2ecf20Sopenharmony_ci * data in core memory, to "move" it we just write it all out, there 9558c2ecf20Sopenharmony_ci * are no reads. */ 9568c2ecf20Sopenharmony_ci drbd_suspend_io(device); 9578c2ecf20Sopenharmony_ci buffer = drbd_md_get_buffer(device, __func__); /* Lock meta-data IO */ 9588c2ecf20Sopenharmony_ci if (!buffer) { 9598c2ecf20Sopenharmony_ci drbd_resume_io(device); 9608c2ecf20Sopenharmony_ci return DS_ERROR; 9618c2ecf20Sopenharmony_ci } 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci /* remember current offset and sizes */ 9648c2ecf20Sopenharmony_ci prev.last_agreed_sect = md->la_size_sect; 9658c2ecf20Sopenharmony_ci prev.md_offset = md->md_offset; 9668c2ecf20Sopenharmony_ci prev.al_offset = md->al_offset; 9678c2ecf20Sopenharmony_ci prev.bm_offset = md->bm_offset; 9688c2ecf20Sopenharmony_ci prev.md_size_sect = md->md_size_sect; 9698c2ecf20Sopenharmony_ci prev.al_stripes = md->al_stripes; 9708c2ecf20Sopenharmony_ci prev.al_stripe_size_4k = md->al_stripe_size_4k; 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci if (rs) { 9738c2ecf20Sopenharmony_ci /* rs is non NULL if we should change the AL layout only */ 9748c2ecf20Sopenharmony_ci md->al_stripes = rs->al_stripes; 9758c2ecf20Sopenharmony_ci md->al_stripe_size_4k = rs->al_stripe_size / 4; 9768c2ecf20Sopenharmony_ci md->al_size_4k = (u64)rs->al_stripes * rs->al_stripe_size / 4; 9778c2ecf20Sopenharmony_ci } 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci drbd_md_set_sector_offsets(device, device->ldev); 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci rcu_read_lock(); 9828c2ecf20Sopenharmony_ci u_size = rcu_dereference(device->ldev->disk_conf)->disk_size; 9838c2ecf20Sopenharmony_ci rcu_read_unlock(); 9848c2ecf20Sopenharmony_ci size = drbd_new_dev_size(device, device->ldev, u_size, flags & DDSF_FORCED); 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci if (size < prev.last_agreed_sect) { 9878c2ecf20Sopenharmony_ci if (rs && u_size == 0) { 9888c2ecf20Sopenharmony_ci /* Remove "rs &&" later. This check should always be active, but 9898c2ecf20Sopenharmony_ci right now the receiver expects the permissive behavior */ 9908c2ecf20Sopenharmony_ci drbd_warn(device, "Implicit shrink not allowed. " 9918c2ecf20Sopenharmony_ci "Use --size=%llus for explicit shrink.\n", 9928c2ecf20Sopenharmony_ci (unsigned long long)size); 9938c2ecf20Sopenharmony_ci rv = DS_ERROR_SHRINK; 9948c2ecf20Sopenharmony_ci } 9958c2ecf20Sopenharmony_ci if (u_size > size) 9968c2ecf20Sopenharmony_ci rv = DS_ERROR_SPACE_MD; 9978c2ecf20Sopenharmony_ci if (rv != DS_UNCHANGED) 9988c2ecf20Sopenharmony_ci goto err_out; 9998c2ecf20Sopenharmony_ci } 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci if (get_capacity(device->vdisk) != size || 10028c2ecf20Sopenharmony_ci drbd_bm_capacity(device) != size) { 10038c2ecf20Sopenharmony_ci int err; 10048c2ecf20Sopenharmony_ci err = drbd_bm_resize(device, size, !(flags & DDSF_NO_RESYNC)); 10058c2ecf20Sopenharmony_ci if (unlikely(err)) { 10068c2ecf20Sopenharmony_ci /* currently there is only one error: ENOMEM! */ 10078c2ecf20Sopenharmony_ci size = drbd_bm_capacity(device); 10088c2ecf20Sopenharmony_ci if (size == 0) { 10098c2ecf20Sopenharmony_ci drbd_err(device, "OUT OF MEMORY! " 10108c2ecf20Sopenharmony_ci "Could not allocate bitmap!\n"); 10118c2ecf20Sopenharmony_ci } else { 10128c2ecf20Sopenharmony_ci drbd_err(device, "BM resizing failed. " 10138c2ecf20Sopenharmony_ci "Leaving size unchanged\n"); 10148c2ecf20Sopenharmony_ci } 10158c2ecf20Sopenharmony_ci rv = DS_ERROR; 10168c2ecf20Sopenharmony_ci } 10178c2ecf20Sopenharmony_ci /* racy, see comments above. */ 10188c2ecf20Sopenharmony_ci drbd_set_my_capacity(device, size); 10198c2ecf20Sopenharmony_ci md->la_size_sect = size; 10208c2ecf20Sopenharmony_ci } 10218c2ecf20Sopenharmony_ci if (rv <= DS_ERROR) 10228c2ecf20Sopenharmony_ci goto err_out; 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci la_size_changed = (prev.last_agreed_sect != md->la_size_sect); 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci md_moved = prev.md_offset != md->md_offset 10278c2ecf20Sopenharmony_ci || prev.md_size_sect != md->md_size_sect; 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci if (la_size_changed || md_moved || rs) { 10308c2ecf20Sopenharmony_ci u32 prev_flags; 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci /* We do some synchronous IO below, which may take some time. 10338c2ecf20Sopenharmony_ci * Clear the timer, to avoid scary "timer expired!" messages, 10348c2ecf20Sopenharmony_ci * "Superblock" is written out at least twice below, anyways. */ 10358c2ecf20Sopenharmony_ci del_timer(&device->md_sync_timer); 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci /* We won't change the "al-extents" setting, we just may need 10388c2ecf20Sopenharmony_ci * to move the on-disk location of the activity log ringbuffer. 10398c2ecf20Sopenharmony_ci * Lock for transaction is good enough, it may well be "dirty" 10408c2ecf20Sopenharmony_ci * or even "starving". */ 10418c2ecf20Sopenharmony_ci wait_event(device->al_wait, lc_try_lock_for_transaction(device->act_log)); 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci /* mark current on-disk bitmap and activity log as unreliable */ 10448c2ecf20Sopenharmony_ci prev_flags = md->flags; 10458c2ecf20Sopenharmony_ci md->flags |= MDF_FULL_SYNC | MDF_AL_DISABLED; 10468c2ecf20Sopenharmony_ci drbd_md_write(device, buffer); 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci drbd_al_initialize(device, buffer); 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci drbd_info(device, "Writing the whole bitmap, %s\n", 10518c2ecf20Sopenharmony_ci la_size_changed && md_moved ? "size changed and md moved" : 10528c2ecf20Sopenharmony_ci la_size_changed ? "size changed" : "md moved"); 10538c2ecf20Sopenharmony_ci /* next line implicitly does drbd_suspend_io()+drbd_resume_io() */ 10548c2ecf20Sopenharmony_ci drbd_bitmap_io(device, md_moved ? &drbd_bm_write_all : &drbd_bm_write, 10558c2ecf20Sopenharmony_ci "size changed", BM_LOCKED_MASK); 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci /* on-disk bitmap and activity log is authoritative again 10588c2ecf20Sopenharmony_ci * (unless there was an IO error meanwhile...) */ 10598c2ecf20Sopenharmony_ci md->flags = prev_flags; 10608c2ecf20Sopenharmony_ci drbd_md_write(device, buffer); 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci if (rs) 10638c2ecf20Sopenharmony_ci drbd_info(device, "Changed AL layout to al-stripes = %d, al-stripe-size-kB = %d\n", 10648c2ecf20Sopenharmony_ci md->al_stripes, md->al_stripe_size_4k * 4); 10658c2ecf20Sopenharmony_ci } 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci if (size > prev.last_agreed_sect) 10688c2ecf20Sopenharmony_ci rv = prev.last_agreed_sect ? DS_GREW : DS_GREW_FROM_ZERO; 10698c2ecf20Sopenharmony_ci if (size < prev.last_agreed_sect) 10708c2ecf20Sopenharmony_ci rv = DS_SHRUNK; 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci if (0) { 10738c2ecf20Sopenharmony_ci err_out: 10748c2ecf20Sopenharmony_ci /* restore previous offset and sizes */ 10758c2ecf20Sopenharmony_ci md->la_size_sect = prev.last_agreed_sect; 10768c2ecf20Sopenharmony_ci md->md_offset = prev.md_offset; 10778c2ecf20Sopenharmony_ci md->al_offset = prev.al_offset; 10788c2ecf20Sopenharmony_ci md->bm_offset = prev.bm_offset; 10798c2ecf20Sopenharmony_ci md->md_size_sect = prev.md_size_sect; 10808c2ecf20Sopenharmony_ci md->al_stripes = prev.al_stripes; 10818c2ecf20Sopenharmony_ci md->al_stripe_size_4k = prev.al_stripe_size_4k; 10828c2ecf20Sopenharmony_ci md->al_size_4k = (u64)prev.al_stripes * prev.al_stripe_size_4k; 10838c2ecf20Sopenharmony_ci } 10848c2ecf20Sopenharmony_ci lc_unlock(device->act_log); 10858c2ecf20Sopenharmony_ci wake_up(&device->al_wait); 10868c2ecf20Sopenharmony_ci drbd_md_put_buffer(device); 10878c2ecf20Sopenharmony_ci drbd_resume_io(device); 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci return rv; 10908c2ecf20Sopenharmony_ci} 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_cisector_t 10938c2ecf20Sopenharmony_cidrbd_new_dev_size(struct drbd_device *device, struct drbd_backing_dev *bdev, 10948c2ecf20Sopenharmony_ci sector_t u_size, int assume_peer_has_space) 10958c2ecf20Sopenharmony_ci{ 10968c2ecf20Sopenharmony_ci sector_t p_size = device->p_size; /* partner's disk size. */ 10978c2ecf20Sopenharmony_ci sector_t la_size_sect = bdev->md.la_size_sect; /* last agreed size. */ 10988c2ecf20Sopenharmony_ci sector_t m_size; /* my size */ 10998c2ecf20Sopenharmony_ci sector_t size = 0; 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci m_size = drbd_get_max_capacity(bdev); 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci if (device->state.conn < C_CONNECTED && assume_peer_has_space) { 11048c2ecf20Sopenharmony_ci drbd_warn(device, "Resize while not connected was forced by the user!\n"); 11058c2ecf20Sopenharmony_ci p_size = m_size; 11068c2ecf20Sopenharmony_ci } 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci if (p_size && m_size) { 11098c2ecf20Sopenharmony_ci size = min_t(sector_t, p_size, m_size); 11108c2ecf20Sopenharmony_ci } else { 11118c2ecf20Sopenharmony_ci if (la_size_sect) { 11128c2ecf20Sopenharmony_ci size = la_size_sect; 11138c2ecf20Sopenharmony_ci if (m_size && m_size < size) 11148c2ecf20Sopenharmony_ci size = m_size; 11158c2ecf20Sopenharmony_ci if (p_size && p_size < size) 11168c2ecf20Sopenharmony_ci size = p_size; 11178c2ecf20Sopenharmony_ci } else { 11188c2ecf20Sopenharmony_ci if (m_size) 11198c2ecf20Sopenharmony_ci size = m_size; 11208c2ecf20Sopenharmony_ci if (p_size) 11218c2ecf20Sopenharmony_ci size = p_size; 11228c2ecf20Sopenharmony_ci } 11238c2ecf20Sopenharmony_ci } 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci if (size == 0) 11268c2ecf20Sopenharmony_ci drbd_err(device, "Both nodes diskless!\n"); 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci if (u_size) { 11298c2ecf20Sopenharmony_ci if (u_size > size) 11308c2ecf20Sopenharmony_ci drbd_err(device, "Requested disk size is too big (%lu > %lu)\n", 11318c2ecf20Sopenharmony_ci (unsigned long)u_size>>1, (unsigned long)size>>1); 11328c2ecf20Sopenharmony_ci else 11338c2ecf20Sopenharmony_ci size = u_size; 11348c2ecf20Sopenharmony_ci } 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci return size; 11378c2ecf20Sopenharmony_ci} 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci/** 11408c2ecf20Sopenharmony_ci * drbd_check_al_size() - Ensures that the AL is of the right size 11418c2ecf20Sopenharmony_ci * @device: DRBD device. 11428c2ecf20Sopenharmony_ci * 11438c2ecf20Sopenharmony_ci * Returns -EBUSY if current al lru is still used, -ENOMEM when allocation 11448c2ecf20Sopenharmony_ci * failed, and 0 on success. You should call drbd_md_sync() after you called 11458c2ecf20Sopenharmony_ci * this function. 11468c2ecf20Sopenharmony_ci */ 11478c2ecf20Sopenharmony_cistatic int drbd_check_al_size(struct drbd_device *device, struct disk_conf *dc) 11488c2ecf20Sopenharmony_ci{ 11498c2ecf20Sopenharmony_ci struct lru_cache *n, *t; 11508c2ecf20Sopenharmony_ci struct lc_element *e; 11518c2ecf20Sopenharmony_ci unsigned int in_use; 11528c2ecf20Sopenharmony_ci int i; 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci if (device->act_log && 11558c2ecf20Sopenharmony_ci device->act_log->nr_elements == dc->al_extents) 11568c2ecf20Sopenharmony_ci return 0; 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci in_use = 0; 11598c2ecf20Sopenharmony_ci t = device->act_log; 11608c2ecf20Sopenharmony_ci n = lc_create("act_log", drbd_al_ext_cache, AL_UPDATES_PER_TRANSACTION, 11618c2ecf20Sopenharmony_ci dc->al_extents, sizeof(struct lc_element), 0); 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci if (n == NULL) { 11648c2ecf20Sopenharmony_ci drbd_err(device, "Cannot allocate act_log lru!\n"); 11658c2ecf20Sopenharmony_ci return -ENOMEM; 11668c2ecf20Sopenharmony_ci } 11678c2ecf20Sopenharmony_ci spin_lock_irq(&device->al_lock); 11688c2ecf20Sopenharmony_ci if (t) { 11698c2ecf20Sopenharmony_ci for (i = 0; i < t->nr_elements; i++) { 11708c2ecf20Sopenharmony_ci e = lc_element_by_index(t, i); 11718c2ecf20Sopenharmony_ci if (e->refcnt) 11728c2ecf20Sopenharmony_ci drbd_err(device, "refcnt(%d)==%d\n", 11738c2ecf20Sopenharmony_ci e->lc_number, e->refcnt); 11748c2ecf20Sopenharmony_ci in_use += e->refcnt; 11758c2ecf20Sopenharmony_ci } 11768c2ecf20Sopenharmony_ci } 11778c2ecf20Sopenharmony_ci if (!in_use) 11788c2ecf20Sopenharmony_ci device->act_log = n; 11798c2ecf20Sopenharmony_ci spin_unlock_irq(&device->al_lock); 11808c2ecf20Sopenharmony_ci if (in_use) { 11818c2ecf20Sopenharmony_ci drbd_err(device, "Activity log still in use!\n"); 11828c2ecf20Sopenharmony_ci lc_destroy(n); 11838c2ecf20Sopenharmony_ci return -EBUSY; 11848c2ecf20Sopenharmony_ci } else { 11858c2ecf20Sopenharmony_ci lc_destroy(t); 11868c2ecf20Sopenharmony_ci } 11878c2ecf20Sopenharmony_ci drbd_md_mark_dirty(device); /* we changed device->act_log->nr_elemens */ 11888c2ecf20Sopenharmony_ci return 0; 11898c2ecf20Sopenharmony_ci} 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_cistatic void blk_queue_discard_granularity(struct request_queue *q, unsigned int granularity) 11928c2ecf20Sopenharmony_ci{ 11938c2ecf20Sopenharmony_ci q->limits.discard_granularity = granularity; 11948c2ecf20Sopenharmony_ci} 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_cistatic unsigned int drbd_max_discard_sectors(struct drbd_connection *connection) 11978c2ecf20Sopenharmony_ci{ 11988c2ecf20Sopenharmony_ci /* when we introduced REQ_WRITE_SAME support, we also bumped 11998c2ecf20Sopenharmony_ci * our maximum supported batch bio size used for discards. */ 12008c2ecf20Sopenharmony_ci if (connection->agreed_features & DRBD_FF_WSAME) 12018c2ecf20Sopenharmony_ci return DRBD_MAX_BBIO_SECTORS; 12028c2ecf20Sopenharmony_ci /* before, with DRBD <= 8.4.6, we only allowed up to one AL_EXTENT_SIZE. */ 12038c2ecf20Sopenharmony_ci return AL_EXTENT_SIZE >> 9; 12048c2ecf20Sopenharmony_ci} 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_cistatic void decide_on_discard_support(struct drbd_device *device, 12078c2ecf20Sopenharmony_ci struct request_queue *q, 12088c2ecf20Sopenharmony_ci struct request_queue *b, 12098c2ecf20Sopenharmony_ci bool discard_zeroes_if_aligned) 12108c2ecf20Sopenharmony_ci{ 12118c2ecf20Sopenharmony_ci /* q = drbd device queue (device->rq_queue) 12128c2ecf20Sopenharmony_ci * b = backing device queue (device->ldev->backing_bdev->bd_disk->queue), 12138c2ecf20Sopenharmony_ci * or NULL if diskless 12148c2ecf20Sopenharmony_ci */ 12158c2ecf20Sopenharmony_ci struct drbd_connection *connection = first_peer_device(device)->connection; 12168c2ecf20Sopenharmony_ci bool can_do = b ? blk_queue_discard(b) : true; 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci if (can_do && connection->cstate >= C_CONNECTED && !(connection->agreed_features & DRBD_FF_TRIM)) { 12198c2ecf20Sopenharmony_ci can_do = false; 12208c2ecf20Sopenharmony_ci drbd_info(connection, "peer DRBD too old, does not support TRIM: disabling discards\n"); 12218c2ecf20Sopenharmony_ci } 12228c2ecf20Sopenharmony_ci if (can_do) { 12238c2ecf20Sopenharmony_ci /* We don't care for the granularity, really. 12248c2ecf20Sopenharmony_ci * Stacking limits below should fix it for the local 12258c2ecf20Sopenharmony_ci * device. Whether or not it is a suitable granularity 12268c2ecf20Sopenharmony_ci * on the remote device is not our problem, really. If 12278c2ecf20Sopenharmony_ci * you care, you need to use devices with similar 12288c2ecf20Sopenharmony_ci * topology on all peers. */ 12298c2ecf20Sopenharmony_ci blk_queue_discard_granularity(q, 512); 12308c2ecf20Sopenharmony_ci q->limits.max_discard_sectors = drbd_max_discard_sectors(connection); 12318c2ecf20Sopenharmony_ci blk_queue_flag_set(QUEUE_FLAG_DISCARD, q); 12328c2ecf20Sopenharmony_ci q->limits.max_write_zeroes_sectors = drbd_max_discard_sectors(connection); 12338c2ecf20Sopenharmony_ci } else { 12348c2ecf20Sopenharmony_ci blk_queue_flag_clear(QUEUE_FLAG_DISCARD, q); 12358c2ecf20Sopenharmony_ci blk_queue_discard_granularity(q, 0); 12368c2ecf20Sopenharmony_ci q->limits.max_discard_sectors = 0; 12378c2ecf20Sopenharmony_ci q->limits.max_write_zeroes_sectors = 0; 12388c2ecf20Sopenharmony_ci } 12398c2ecf20Sopenharmony_ci} 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_cistatic void fixup_discard_if_not_supported(struct request_queue *q) 12428c2ecf20Sopenharmony_ci{ 12438c2ecf20Sopenharmony_ci /* To avoid confusion, if this queue does not support discard, clear 12448c2ecf20Sopenharmony_ci * max_discard_sectors, which is what lsblk -D reports to the user. 12458c2ecf20Sopenharmony_ci * Older kernels got this wrong in "stack limits". 12468c2ecf20Sopenharmony_ci * */ 12478c2ecf20Sopenharmony_ci if (!blk_queue_discard(q)) { 12488c2ecf20Sopenharmony_ci blk_queue_max_discard_sectors(q, 0); 12498c2ecf20Sopenharmony_ci blk_queue_discard_granularity(q, 0); 12508c2ecf20Sopenharmony_ci } 12518c2ecf20Sopenharmony_ci} 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_cistatic void fixup_write_zeroes(struct drbd_device *device, struct request_queue *q) 12548c2ecf20Sopenharmony_ci{ 12558c2ecf20Sopenharmony_ci /* Fixup max_write_zeroes_sectors after blk_stack_limits(): 12568c2ecf20Sopenharmony_ci * if we can handle "zeroes" efficiently on the protocol, 12578c2ecf20Sopenharmony_ci * we want to do that, even if our backend does not announce 12588c2ecf20Sopenharmony_ci * max_write_zeroes_sectors itself. */ 12598c2ecf20Sopenharmony_ci struct drbd_connection *connection = first_peer_device(device)->connection; 12608c2ecf20Sopenharmony_ci /* If the peer announces WZEROES support, use it. Otherwise, rather 12618c2ecf20Sopenharmony_ci * send explicit zeroes than rely on some discard-zeroes-data magic. */ 12628c2ecf20Sopenharmony_ci if (connection->agreed_features & DRBD_FF_WZEROES) 12638c2ecf20Sopenharmony_ci q->limits.max_write_zeroes_sectors = DRBD_MAX_BBIO_SECTORS; 12648c2ecf20Sopenharmony_ci else 12658c2ecf20Sopenharmony_ci q->limits.max_write_zeroes_sectors = 0; 12668c2ecf20Sopenharmony_ci} 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_cistatic void decide_on_write_same_support(struct drbd_device *device, 12698c2ecf20Sopenharmony_ci struct request_queue *q, 12708c2ecf20Sopenharmony_ci struct request_queue *b, struct o_qlim *o, 12718c2ecf20Sopenharmony_ci bool disable_write_same) 12728c2ecf20Sopenharmony_ci{ 12738c2ecf20Sopenharmony_ci struct drbd_peer_device *peer_device = first_peer_device(device); 12748c2ecf20Sopenharmony_ci struct drbd_connection *connection = peer_device->connection; 12758c2ecf20Sopenharmony_ci bool can_do = b ? b->limits.max_write_same_sectors : true; 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci if (can_do && disable_write_same) { 12788c2ecf20Sopenharmony_ci can_do = false; 12798c2ecf20Sopenharmony_ci drbd_info(peer_device, "WRITE_SAME disabled by config\n"); 12808c2ecf20Sopenharmony_ci } 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_ci if (can_do && connection->cstate >= C_CONNECTED && !(connection->agreed_features & DRBD_FF_WSAME)) { 12838c2ecf20Sopenharmony_ci can_do = false; 12848c2ecf20Sopenharmony_ci drbd_info(peer_device, "peer does not support WRITE_SAME\n"); 12858c2ecf20Sopenharmony_ci } 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_ci if (o) { 12888c2ecf20Sopenharmony_ci /* logical block size; queue_logical_block_size(NULL) is 512 */ 12898c2ecf20Sopenharmony_ci unsigned int peer_lbs = be32_to_cpu(o->logical_block_size); 12908c2ecf20Sopenharmony_ci unsigned int me_lbs_b = queue_logical_block_size(b); 12918c2ecf20Sopenharmony_ci unsigned int me_lbs = queue_logical_block_size(q); 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci if (me_lbs_b != me_lbs) { 12948c2ecf20Sopenharmony_ci drbd_warn(device, 12958c2ecf20Sopenharmony_ci "logical block size of local backend does not match (drbd:%u, backend:%u); was this a late attach?\n", 12968c2ecf20Sopenharmony_ci me_lbs, me_lbs_b); 12978c2ecf20Sopenharmony_ci /* rather disable write same than trigger some BUG_ON later in the scsi layer. */ 12988c2ecf20Sopenharmony_ci can_do = false; 12998c2ecf20Sopenharmony_ci } 13008c2ecf20Sopenharmony_ci if (me_lbs_b != peer_lbs) { 13018c2ecf20Sopenharmony_ci drbd_warn(peer_device, "logical block sizes do not match (me:%u, peer:%u); this may cause problems.\n", 13028c2ecf20Sopenharmony_ci me_lbs, peer_lbs); 13038c2ecf20Sopenharmony_ci if (can_do) { 13048c2ecf20Sopenharmony_ci drbd_dbg(peer_device, "logical block size mismatch: WRITE_SAME disabled.\n"); 13058c2ecf20Sopenharmony_ci can_do = false; 13068c2ecf20Sopenharmony_ci } 13078c2ecf20Sopenharmony_ci me_lbs = max(me_lbs, me_lbs_b); 13088c2ecf20Sopenharmony_ci /* We cannot change the logical block size of an in-use queue. 13098c2ecf20Sopenharmony_ci * We can only hope that access happens to be properly aligned. 13108c2ecf20Sopenharmony_ci * If not, the peer will likely produce an IO error, and detach. */ 13118c2ecf20Sopenharmony_ci if (peer_lbs > me_lbs) { 13128c2ecf20Sopenharmony_ci if (device->state.role != R_PRIMARY) { 13138c2ecf20Sopenharmony_ci blk_queue_logical_block_size(q, peer_lbs); 13148c2ecf20Sopenharmony_ci drbd_warn(peer_device, "logical block size set to %u\n", peer_lbs); 13158c2ecf20Sopenharmony_ci } else { 13168c2ecf20Sopenharmony_ci drbd_warn(peer_device, 13178c2ecf20Sopenharmony_ci "current Primary must NOT adjust logical block size (%u -> %u); hope for the best.\n", 13188c2ecf20Sopenharmony_ci me_lbs, peer_lbs); 13198c2ecf20Sopenharmony_ci } 13208c2ecf20Sopenharmony_ci } 13218c2ecf20Sopenharmony_ci } 13228c2ecf20Sopenharmony_ci if (can_do && !o->write_same_capable) { 13238c2ecf20Sopenharmony_ci /* If we introduce an open-coded write-same loop on the receiving side, 13248c2ecf20Sopenharmony_ci * the peer would present itself as "capable". */ 13258c2ecf20Sopenharmony_ci drbd_dbg(peer_device, "WRITE_SAME disabled (peer device not capable)\n"); 13268c2ecf20Sopenharmony_ci can_do = false; 13278c2ecf20Sopenharmony_ci } 13288c2ecf20Sopenharmony_ci } 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci blk_queue_max_write_same_sectors(q, can_do ? DRBD_MAX_BBIO_SECTORS : 0); 13318c2ecf20Sopenharmony_ci} 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_cistatic void drbd_setup_queue_param(struct drbd_device *device, struct drbd_backing_dev *bdev, 13348c2ecf20Sopenharmony_ci unsigned int max_bio_size, struct o_qlim *o) 13358c2ecf20Sopenharmony_ci{ 13368c2ecf20Sopenharmony_ci struct request_queue * const q = device->rq_queue; 13378c2ecf20Sopenharmony_ci unsigned int max_hw_sectors = max_bio_size >> 9; 13388c2ecf20Sopenharmony_ci unsigned int max_segments = 0; 13398c2ecf20Sopenharmony_ci struct request_queue *b = NULL; 13408c2ecf20Sopenharmony_ci struct disk_conf *dc; 13418c2ecf20Sopenharmony_ci bool discard_zeroes_if_aligned = true; 13428c2ecf20Sopenharmony_ci bool disable_write_same = false; 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_ci if (bdev) { 13458c2ecf20Sopenharmony_ci b = bdev->backing_bdev->bd_disk->queue; 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci max_hw_sectors = min(queue_max_hw_sectors(b), max_bio_size >> 9); 13488c2ecf20Sopenharmony_ci rcu_read_lock(); 13498c2ecf20Sopenharmony_ci dc = rcu_dereference(device->ldev->disk_conf); 13508c2ecf20Sopenharmony_ci max_segments = dc->max_bio_bvecs; 13518c2ecf20Sopenharmony_ci discard_zeroes_if_aligned = dc->discard_zeroes_if_aligned; 13528c2ecf20Sopenharmony_ci disable_write_same = dc->disable_write_same; 13538c2ecf20Sopenharmony_ci rcu_read_unlock(); 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci blk_set_stacking_limits(&q->limits); 13568c2ecf20Sopenharmony_ci } 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci blk_queue_max_hw_sectors(q, max_hw_sectors); 13598c2ecf20Sopenharmony_ci /* This is the workaround for "bio would need to, but cannot, be split" */ 13608c2ecf20Sopenharmony_ci blk_queue_max_segments(q, max_segments ? max_segments : BLK_MAX_SEGMENTS); 13618c2ecf20Sopenharmony_ci blk_queue_segment_boundary(q, PAGE_SIZE-1); 13628c2ecf20Sopenharmony_ci decide_on_discard_support(device, q, b, discard_zeroes_if_aligned); 13638c2ecf20Sopenharmony_ci decide_on_write_same_support(device, q, b, o, disable_write_same); 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci if (b) { 13668c2ecf20Sopenharmony_ci blk_stack_limits(&q->limits, &b->limits, 0); 13678c2ecf20Sopenharmony_ci blk_queue_update_readahead(q); 13688c2ecf20Sopenharmony_ci } 13698c2ecf20Sopenharmony_ci fixup_discard_if_not_supported(q); 13708c2ecf20Sopenharmony_ci fixup_write_zeroes(device, q); 13718c2ecf20Sopenharmony_ci} 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_civoid drbd_reconsider_queue_parameters(struct drbd_device *device, struct drbd_backing_dev *bdev, struct o_qlim *o) 13748c2ecf20Sopenharmony_ci{ 13758c2ecf20Sopenharmony_ci unsigned int now, new, local, peer; 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_ci now = queue_max_hw_sectors(device->rq_queue) << 9; 13788c2ecf20Sopenharmony_ci local = device->local_max_bio_size; /* Eventually last known value, from volatile memory */ 13798c2ecf20Sopenharmony_ci peer = device->peer_max_bio_size; /* Eventually last known value, from meta data */ 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ci if (bdev) { 13828c2ecf20Sopenharmony_ci local = queue_max_hw_sectors(bdev->backing_bdev->bd_disk->queue) << 9; 13838c2ecf20Sopenharmony_ci device->local_max_bio_size = local; 13848c2ecf20Sopenharmony_ci } 13858c2ecf20Sopenharmony_ci local = min(local, DRBD_MAX_BIO_SIZE); 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_ci /* We may ignore peer limits if the peer is modern enough. 13888c2ecf20Sopenharmony_ci Because new from 8.3.8 onwards the peer can use multiple 13898c2ecf20Sopenharmony_ci BIOs for a single peer_request */ 13908c2ecf20Sopenharmony_ci if (device->state.conn >= C_WF_REPORT_PARAMS) { 13918c2ecf20Sopenharmony_ci if (first_peer_device(device)->connection->agreed_pro_version < 94) 13928c2ecf20Sopenharmony_ci peer = min(device->peer_max_bio_size, DRBD_MAX_SIZE_H80_PACKET); 13938c2ecf20Sopenharmony_ci /* Correct old drbd (up to 8.3.7) if it believes it can do more than 32KiB */ 13948c2ecf20Sopenharmony_ci else if (first_peer_device(device)->connection->agreed_pro_version == 94) 13958c2ecf20Sopenharmony_ci peer = DRBD_MAX_SIZE_H80_PACKET; 13968c2ecf20Sopenharmony_ci else if (first_peer_device(device)->connection->agreed_pro_version < 100) 13978c2ecf20Sopenharmony_ci peer = DRBD_MAX_BIO_SIZE_P95; /* drbd 8.3.8 onwards, before 8.4.0 */ 13988c2ecf20Sopenharmony_ci else 13998c2ecf20Sopenharmony_ci peer = DRBD_MAX_BIO_SIZE; 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_ci /* We may later detach and re-attach on a disconnected Primary. 14028c2ecf20Sopenharmony_ci * Avoid this setting to jump back in that case. 14038c2ecf20Sopenharmony_ci * We want to store what we know the peer DRBD can handle, 14048c2ecf20Sopenharmony_ci * not what the peer IO backend can handle. */ 14058c2ecf20Sopenharmony_ci if (peer > device->peer_max_bio_size) 14068c2ecf20Sopenharmony_ci device->peer_max_bio_size = peer; 14078c2ecf20Sopenharmony_ci } 14088c2ecf20Sopenharmony_ci new = min(local, peer); 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci if (device->state.role == R_PRIMARY && new < now) 14118c2ecf20Sopenharmony_ci drbd_err(device, "ASSERT FAILED new < now; (%u < %u)\n", new, now); 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ci if (new != now) 14148c2ecf20Sopenharmony_ci drbd_info(device, "max BIO size = %u\n", new); 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_ci drbd_setup_queue_param(device, bdev, new, o); 14178c2ecf20Sopenharmony_ci} 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci/* Starts the worker thread */ 14208c2ecf20Sopenharmony_cistatic void conn_reconfig_start(struct drbd_connection *connection) 14218c2ecf20Sopenharmony_ci{ 14228c2ecf20Sopenharmony_ci drbd_thread_start(&connection->worker); 14238c2ecf20Sopenharmony_ci drbd_flush_workqueue(&connection->sender_work); 14248c2ecf20Sopenharmony_ci} 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci/* if still unconfigured, stops worker again. */ 14278c2ecf20Sopenharmony_cistatic void conn_reconfig_done(struct drbd_connection *connection) 14288c2ecf20Sopenharmony_ci{ 14298c2ecf20Sopenharmony_ci bool stop_threads; 14308c2ecf20Sopenharmony_ci spin_lock_irq(&connection->resource->req_lock); 14318c2ecf20Sopenharmony_ci stop_threads = conn_all_vols_unconf(connection) && 14328c2ecf20Sopenharmony_ci connection->cstate == C_STANDALONE; 14338c2ecf20Sopenharmony_ci spin_unlock_irq(&connection->resource->req_lock); 14348c2ecf20Sopenharmony_ci if (stop_threads) { 14358c2ecf20Sopenharmony_ci /* ack_receiver thread and ack_sender workqueue are implicitly 14368c2ecf20Sopenharmony_ci * stopped by receiver in conn_disconnect() */ 14378c2ecf20Sopenharmony_ci drbd_thread_stop(&connection->receiver); 14388c2ecf20Sopenharmony_ci drbd_thread_stop(&connection->worker); 14398c2ecf20Sopenharmony_ci } 14408c2ecf20Sopenharmony_ci} 14418c2ecf20Sopenharmony_ci 14428c2ecf20Sopenharmony_ci/* Make sure IO is suspended before calling this function(). */ 14438c2ecf20Sopenharmony_cistatic void drbd_suspend_al(struct drbd_device *device) 14448c2ecf20Sopenharmony_ci{ 14458c2ecf20Sopenharmony_ci int s = 0; 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ci if (!lc_try_lock(device->act_log)) { 14488c2ecf20Sopenharmony_ci drbd_warn(device, "Failed to lock al in drbd_suspend_al()\n"); 14498c2ecf20Sopenharmony_ci return; 14508c2ecf20Sopenharmony_ci } 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci drbd_al_shrink(device); 14538c2ecf20Sopenharmony_ci spin_lock_irq(&device->resource->req_lock); 14548c2ecf20Sopenharmony_ci if (device->state.conn < C_CONNECTED) 14558c2ecf20Sopenharmony_ci s = !test_and_set_bit(AL_SUSPENDED, &device->flags); 14568c2ecf20Sopenharmony_ci spin_unlock_irq(&device->resource->req_lock); 14578c2ecf20Sopenharmony_ci lc_unlock(device->act_log); 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_ci if (s) 14608c2ecf20Sopenharmony_ci drbd_info(device, "Suspended AL updates\n"); 14618c2ecf20Sopenharmony_ci} 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_cistatic bool should_set_defaults(struct genl_info *info) 14658c2ecf20Sopenharmony_ci{ 14668c2ecf20Sopenharmony_ci unsigned flags = ((struct drbd_genlmsghdr*)info->userhdr)->flags; 14678c2ecf20Sopenharmony_ci return 0 != (flags & DRBD_GENL_F_SET_DEFAULTS); 14688c2ecf20Sopenharmony_ci} 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_cistatic unsigned int drbd_al_extents_max(struct drbd_backing_dev *bdev) 14718c2ecf20Sopenharmony_ci{ 14728c2ecf20Sopenharmony_ci /* This is limited by 16 bit "slot" numbers, 14738c2ecf20Sopenharmony_ci * and by available on-disk context storage. 14748c2ecf20Sopenharmony_ci * 14758c2ecf20Sopenharmony_ci * Also (u16)~0 is special (denotes a "free" extent). 14768c2ecf20Sopenharmony_ci * 14778c2ecf20Sopenharmony_ci * One transaction occupies one 4kB on-disk block, 14788c2ecf20Sopenharmony_ci * we have n such blocks in the on disk ring buffer, 14798c2ecf20Sopenharmony_ci * the "current" transaction may fail (n-1), 14808c2ecf20Sopenharmony_ci * and there is 919 slot numbers context information per transaction. 14818c2ecf20Sopenharmony_ci * 14828c2ecf20Sopenharmony_ci * 72 transaction blocks amounts to more than 2**16 context slots, 14838c2ecf20Sopenharmony_ci * so cap there first. 14848c2ecf20Sopenharmony_ci */ 14858c2ecf20Sopenharmony_ci const unsigned int max_al_nr = DRBD_AL_EXTENTS_MAX; 14868c2ecf20Sopenharmony_ci const unsigned int sufficient_on_disk = 14878c2ecf20Sopenharmony_ci (max_al_nr + AL_CONTEXT_PER_TRANSACTION -1) 14888c2ecf20Sopenharmony_ci /AL_CONTEXT_PER_TRANSACTION; 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_ci unsigned int al_size_4k = bdev->md.al_size_4k; 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_ci if (al_size_4k > sufficient_on_disk) 14938c2ecf20Sopenharmony_ci return max_al_nr; 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_ci return (al_size_4k - 1) * AL_CONTEXT_PER_TRANSACTION; 14968c2ecf20Sopenharmony_ci} 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_cistatic bool write_ordering_changed(struct disk_conf *a, struct disk_conf *b) 14998c2ecf20Sopenharmony_ci{ 15008c2ecf20Sopenharmony_ci return a->disk_barrier != b->disk_barrier || 15018c2ecf20Sopenharmony_ci a->disk_flushes != b->disk_flushes || 15028c2ecf20Sopenharmony_ci a->disk_drain != b->disk_drain; 15038c2ecf20Sopenharmony_ci} 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_cistatic void sanitize_disk_conf(struct drbd_device *device, struct disk_conf *disk_conf, 15068c2ecf20Sopenharmony_ci struct drbd_backing_dev *nbc) 15078c2ecf20Sopenharmony_ci{ 15088c2ecf20Sopenharmony_ci struct request_queue * const q = nbc->backing_bdev->bd_disk->queue; 15098c2ecf20Sopenharmony_ci 15108c2ecf20Sopenharmony_ci if (disk_conf->al_extents < DRBD_AL_EXTENTS_MIN) 15118c2ecf20Sopenharmony_ci disk_conf->al_extents = DRBD_AL_EXTENTS_MIN; 15128c2ecf20Sopenharmony_ci if (disk_conf->al_extents > drbd_al_extents_max(nbc)) 15138c2ecf20Sopenharmony_ci disk_conf->al_extents = drbd_al_extents_max(nbc); 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci if (!blk_queue_discard(q)) { 15168c2ecf20Sopenharmony_ci if (disk_conf->rs_discard_granularity) { 15178c2ecf20Sopenharmony_ci disk_conf->rs_discard_granularity = 0; /* disable feature */ 15188c2ecf20Sopenharmony_ci drbd_info(device, "rs_discard_granularity feature disabled\n"); 15198c2ecf20Sopenharmony_ci } 15208c2ecf20Sopenharmony_ci } 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ci if (disk_conf->rs_discard_granularity) { 15238c2ecf20Sopenharmony_ci int orig_value = disk_conf->rs_discard_granularity; 15248c2ecf20Sopenharmony_ci int remainder; 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_ci if (q->limits.discard_granularity > disk_conf->rs_discard_granularity) 15278c2ecf20Sopenharmony_ci disk_conf->rs_discard_granularity = q->limits.discard_granularity; 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_ci remainder = disk_conf->rs_discard_granularity % q->limits.discard_granularity; 15308c2ecf20Sopenharmony_ci disk_conf->rs_discard_granularity += remainder; 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_ci if (disk_conf->rs_discard_granularity > q->limits.max_discard_sectors << 9) 15338c2ecf20Sopenharmony_ci disk_conf->rs_discard_granularity = q->limits.max_discard_sectors << 9; 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_ci if (disk_conf->rs_discard_granularity != orig_value) 15368c2ecf20Sopenharmony_ci drbd_info(device, "rs_discard_granularity changed to %d\n", 15378c2ecf20Sopenharmony_ci disk_conf->rs_discard_granularity); 15388c2ecf20Sopenharmony_ci } 15398c2ecf20Sopenharmony_ci} 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_cistatic int disk_opts_check_al_size(struct drbd_device *device, struct disk_conf *dc) 15428c2ecf20Sopenharmony_ci{ 15438c2ecf20Sopenharmony_ci int err = -EBUSY; 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_ci if (device->act_log && 15468c2ecf20Sopenharmony_ci device->act_log->nr_elements == dc->al_extents) 15478c2ecf20Sopenharmony_ci return 0; 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci drbd_suspend_io(device); 15508c2ecf20Sopenharmony_ci /* If IO completion is currently blocked, we would likely wait 15518c2ecf20Sopenharmony_ci * "forever" for the activity log to become unused. So we don't. */ 15528c2ecf20Sopenharmony_ci if (atomic_read(&device->ap_bio_cnt)) 15538c2ecf20Sopenharmony_ci goto out; 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci wait_event(device->al_wait, lc_try_lock(device->act_log)); 15568c2ecf20Sopenharmony_ci drbd_al_shrink(device); 15578c2ecf20Sopenharmony_ci err = drbd_check_al_size(device, dc); 15588c2ecf20Sopenharmony_ci lc_unlock(device->act_log); 15598c2ecf20Sopenharmony_ci wake_up(&device->al_wait); 15608c2ecf20Sopenharmony_ciout: 15618c2ecf20Sopenharmony_ci drbd_resume_io(device); 15628c2ecf20Sopenharmony_ci return err; 15638c2ecf20Sopenharmony_ci} 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_ciint drbd_adm_disk_opts(struct sk_buff *skb, struct genl_info *info) 15668c2ecf20Sopenharmony_ci{ 15678c2ecf20Sopenharmony_ci struct drbd_config_context adm_ctx; 15688c2ecf20Sopenharmony_ci enum drbd_ret_code retcode; 15698c2ecf20Sopenharmony_ci struct drbd_device *device; 15708c2ecf20Sopenharmony_ci struct disk_conf *new_disk_conf, *old_disk_conf; 15718c2ecf20Sopenharmony_ci struct fifo_buffer *old_plan = NULL, *new_plan = NULL; 15728c2ecf20Sopenharmony_ci int err; 15738c2ecf20Sopenharmony_ci unsigned int fifo_size; 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_ci retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_MINOR); 15768c2ecf20Sopenharmony_ci if (!adm_ctx.reply_skb) 15778c2ecf20Sopenharmony_ci return retcode; 15788c2ecf20Sopenharmony_ci if (retcode != NO_ERROR) 15798c2ecf20Sopenharmony_ci goto finish; 15808c2ecf20Sopenharmony_ci 15818c2ecf20Sopenharmony_ci device = adm_ctx.device; 15828c2ecf20Sopenharmony_ci mutex_lock(&adm_ctx.resource->adm_mutex); 15838c2ecf20Sopenharmony_ci 15848c2ecf20Sopenharmony_ci /* we also need a disk 15858c2ecf20Sopenharmony_ci * to change the options on */ 15868c2ecf20Sopenharmony_ci if (!get_ldev(device)) { 15878c2ecf20Sopenharmony_ci retcode = ERR_NO_DISK; 15888c2ecf20Sopenharmony_ci goto out; 15898c2ecf20Sopenharmony_ci } 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_ci new_disk_conf = kmalloc(sizeof(struct disk_conf), GFP_KERNEL); 15928c2ecf20Sopenharmony_ci if (!new_disk_conf) { 15938c2ecf20Sopenharmony_ci retcode = ERR_NOMEM; 15948c2ecf20Sopenharmony_ci goto fail; 15958c2ecf20Sopenharmony_ci } 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci mutex_lock(&device->resource->conf_update); 15988c2ecf20Sopenharmony_ci old_disk_conf = device->ldev->disk_conf; 15998c2ecf20Sopenharmony_ci *new_disk_conf = *old_disk_conf; 16008c2ecf20Sopenharmony_ci if (should_set_defaults(info)) 16018c2ecf20Sopenharmony_ci set_disk_conf_defaults(new_disk_conf); 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci err = disk_conf_from_attrs_for_change(new_disk_conf, info); 16048c2ecf20Sopenharmony_ci if (err && err != -ENOMSG) { 16058c2ecf20Sopenharmony_ci retcode = ERR_MANDATORY_TAG; 16068c2ecf20Sopenharmony_ci drbd_msg_put_info(adm_ctx.reply_skb, from_attrs_err_to_txt(err)); 16078c2ecf20Sopenharmony_ci goto fail_unlock; 16088c2ecf20Sopenharmony_ci } 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_ci if (!expect(new_disk_conf->resync_rate >= 1)) 16118c2ecf20Sopenharmony_ci new_disk_conf->resync_rate = 1; 16128c2ecf20Sopenharmony_ci 16138c2ecf20Sopenharmony_ci sanitize_disk_conf(device, new_disk_conf, device->ldev); 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_ci if (new_disk_conf->c_plan_ahead > DRBD_C_PLAN_AHEAD_MAX) 16168c2ecf20Sopenharmony_ci new_disk_conf->c_plan_ahead = DRBD_C_PLAN_AHEAD_MAX; 16178c2ecf20Sopenharmony_ci 16188c2ecf20Sopenharmony_ci fifo_size = (new_disk_conf->c_plan_ahead * 10 * SLEEP_TIME) / HZ; 16198c2ecf20Sopenharmony_ci if (fifo_size != device->rs_plan_s->size) { 16208c2ecf20Sopenharmony_ci new_plan = fifo_alloc(fifo_size); 16218c2ecf20Sopenharmony_ci if (!new_plan) { 16228c2ecf20Sopenharmony_ci drbd_err(device, "kmalloc of fifo_buffer failed"); 16238c2ecf20Sopenharmony_ci retcode = ERR_NOMEM; 16248c2ecf20Sopenharmony_ci goto fail_unlock; 16258c2ecf20Sopenharmony_ci } 16268c2ecf20Sopenharmony_ci } 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci err = disk_opts_check_al_size(device, new_disk_conf); 16298c2ecf20Sopenharmony_ci if (err) { 16308c2ecf20Sopenharmony_ci /* Could be just "busy". Ignore? 16318c2ecf20Sopenharmony_ci * Introduce dedicated error code? */ 16328c2ecf20Sopenharmony_ci drbd_msg_put_info(adm_ctx.reply_skb, 16338c2ecf20Sopenharmony_ci "Try again without changing current al-extents setting"); 16348c2ecf20Sopenharmony_ci retcode = ERR_NOMEM; 16358c2ecf20Sopenharmony_ci goto fail_unlock; 16368c2ecf20Sopenharmony_ci } 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci lock_all_resources(); 16398c2ecf20Sopenharmony_ci retcode = drbd_resync_after_valid(device, new_disk_conf->resync_after); 16408c2ecf20Sopenharmony_ci if (retcode == NO_ERROR) { 16418c2ecf20Sopenharmony_ci rcu_assign_pointer(device->ldev->disk_conf, new_disk_conf); 16428c2ecf20Sopenharmony_ci drbd_resync_after_changed(device); 16438c2ecf20Sopenharmony_ci } 16448c2ecf20Sopenharmony_ci unlock_all_resources(); 16458c2ecf20Sopenharmony_ci 16468c2ecf20Sopenharmony_ci if (retcode != NO_ERROR) 16478c2ecf20Sopenharmony_ci goto fail_unlock; 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci if (new_plan) { 16508c2ecf20Sopenharmony_ci old_plan = device->rs_plan_s; 16518c2ecf20Sopenharmony_ci rcu_assign_pointer(device->rs_plan_s, new_plan); 16528c2ecf20Sopenharmony_ci } 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_ci mutex_unlock(&device->resource->conf_update); 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_ci if (new_disk_conf->al_updates) 16578c2ecf20Sopenharmony_ci device->ldev->md.flags &= ~MDF_AL_DISABLED; 16588c2ecf20Sopenharmony_ci else 16598c2ecf20Sopenharmony_ci device->ldev->md.flags |= MDF_AL_DISABLED; 16608c2ecf20Sopenharmony_ci 16618c2ecf20Sopenharmony_ci if (new_disk_conf->md_flushes) 16628c2ecf20Sopenharmony_ci clear_bit(MD_NO_FUA, &device->flags); 16638c2ecf20Sopenharmony_ci else 16648c2ecf20Sopenharmony_ci set_bit(MD_NO_FUA, &device->flags); 16658c2ecf20Sopenharmony_ci 16668c2ecf20Sopenharmony_ci if (write_ordering_changed(old_disk_conf, new_disk_conf)) 16678c2ecf20Sopenharmony_ci drbd_bump_write_ordering(device->resource, NULL, WO_BDEV_FLUSH); 16688c2ecf20Sopenharmony_ci 16698c2ecf20Sopenharmony_ci if (old_disk_conf->discard_zeroes_if_aligned != new_disk_conf->discard_zeroes_if_aligned 16708c2ecf20Sopenharmony_ci || old_disk_conf->disable_write_same != new_disk_conf->disable_write_same) 16718c2ecf20Sopenharmony_ci drbd_reconsider_queue_parameters(device, device->ldev, NULL); 16728c2ecf20Sopenharmony_ci 16738c2ecf20Sopenharmony_ci drbd_md_sync(device); 16748c2ecf20Sopenharmony_ci 16758c2ecf20Sopenharmony_ci if (device->state.conn >= C_CONNECTED) { 16768c2ecf20Sopenharmony_ci struct drbd_peer_device *peer_device; 16778c2ecf20Sopenharmony_ci 16788c2ecf20Sopenharmony_ci for_each_peer_device(peer_device, device) 16798c2ecf20Sopenharmony_ci drbd_send_sync_param(peer_device); 16808c2ecf20Sopenharmony_ci } 16818c2ecf20Sopenharmony_ci 16828c2ecf20Sopenharmony_ci synchronize_rcu(); 16838c2ecf20Sopenharmony_ci kfree(old_disk_conf); 16848c2ecf20Sopenharmony_ci kfree(old_plan); 16858c2ecf20Sopenharmony_ci mod_timer(&device->request_timer, jiffies + HZ); 16868c2ecf20Sopenharmony_ci goto success; 16878c2ecf20Sopenharmony_ci 16888c2ecf20Sopenharmony_cifail_unlock: 16898c2ecf20Sopenharmony_ci mutex_unlock(&device->resource->conf_update); 16908c2ecf20Sopenharmony_ci fail: 16918c2ecf20Sopenharmony_ci kfree(new_disk_conf); 16928c2ecf20Sopenharmony_ci kfree(new_plan); 16938c2ecf20Sopenharmony_cisuccess: 16948c2ecf20Sopenharmony_ci put_ldev(device); 16958c2ecf20Sopenharmony_ci out: 16968c2ecf20Sopenharmony_ci mutex_unlock(&adm_ctx.resource->adm_mutex); 16978c2ecf20Sopenharmony_ci finish: 16988c2ecf20Sopenharmony_ci drbd_adm_finish(&adm_ctx, info, retcode); 16998c2ecf20Sopenharmony_ci return 0; 17008c2ecf20Sopenharmony_ci} 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_cistatic struct block_device *open_backing_dev(struct drbd_device *device, 17038c2ecf20Sopenharmony_ci const char *bdev_path, void *claim_ptr, bool do_bd_link) 17048c2ecf20Sopenharmony_ci{ 17058c2ecf20Sopenharmony_ci struct block_device *bdev; 17068c2ecf20Sopenharmony_ci int err = 0; 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_ci bdev = blkdev_get_by_path(bdev_path, 17098c2ecf20Sopenharmony_ci FMODE_READ | FMODE_WRITE | FMODE_EXCL, claim_ptr); 17108c2ecf20Sopenharmony_ci if (IS_ERR(bdev)) { 17118c2ecf20Sopenharmony_ci drbd_err(device, "open(\"%s\") failed with %ld\n", 17128c2ecf20Sopenharmony_ci bdev_path, PTR_ERR(bdev)); 17138c2ecf20Sopenharmony_ci return bdev; 17148c2ecf20Sopenharmony_ci } 17158c2ecf20Sopenharmony_ci 17168c2ecf20Sopenharmony_ci if (!do_bd_link) 17178c2ecf20Sopenharmony_ci return bdev; 17188c2ecf20Sopenharmony_ci 17198c2ecf20Sopenharmony_ci err = bd_link_disk_holder(bdev, device->vdisk); 17208c2ecf20Sopenharmony_ci if (err) { 17218c2ecf20Sopenharmony_ci blkdev_put(bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL); 17228c2ecf20Sopenharmony_ci drbd_err(device, "bd_link_disk_holder(\"%s\", ...) failed with %d\n", 17238c2ecf20Sopenharmony_ci bdev_path, err); 17248c2ecf20Sopenharmony_ci bdev = ERR_PTR(err); 17258c2ecf20Sopenharmony_ci } 17268c2ecf20Sopenharmony_ci return bdev; 17278c2ecf20Sopenharmony_ci} 17288c2ecf20Sopenharmony_ci 17298c2ecf20Sopenharmony_cistatic int open_backing_devices(struct drbd_device *device, 17308c2ecf20Sopenharmony_ci struct disk_conf *new_disk_conf, 17318c2ecf20Sopenharmony_ci struct drbd_backing_dev *nbc) 17328c2ecf20Sopenharmony_ci{ 17338c2ecf20Sopenharmony_ci struct block_device *bdev; 17348c2ecf20Sopenharmony_ci 17358c2ecf20Sopenharmony_ci bdev = open_backing_dev(device, new_disk_conf->backing_dev, device, true); 17368c2ecf20Sopenharmony_ci if (IS_ERR(bdev)) 17378c2ecf20Sopenharmony_ci return ERR_OPEN_DISK; 17388c2ecf20Sopenharmony_ci nbc->backing_bdev = bdev; 17398c2ecf20Sopenharmony_ci 17408c2ecf20Sopenharmony_ci /* 17418c2ecf20Sopenharmony_ci * meta_dev_idx >= 0: external fixed size, possibly multiple 17428c2ecf20Sopenharmony_ci * drbd sharing one meta device. TODO in that case, paranoia 17438c2ecf20Sopenharmony_ci * check that [md_bdev, meta_dev_idx] is not yet used by some 17448c2ecf20Sopenharmony_ci * other drbd minor! (if you use drbd.conf + drbdadm, that 17458c2ecf20Sopenharmony_ci * should check it for you already; but if you don't, or 17468c2ecf20Sopenharmony_ci * someone fooled it, we need to double check here) 17478c2ecf20Sopenharmony_ci */ 17488c2ecf20Sopenharmony_ci bdev = open_backing_dev(device, new_disk_conf->meta_dev, 17498c2ecf20Sopenharmony_ci /* claim ptr: device, if claimed exclusively; shared drbd_m_holder, 17508c2ecf20Sopenharmony_ci * if potentially shared with other drbd minors */ 17518c2ecf20Sopenharmony_ci (new_disk_conf->meta_dev_idx < 0) ? (void*)device : (void*)drbd_m_holder, 17528c2ecf20Sopenharmony_ci /* avoid double bd_claim_by_disk() for the same (source,target) tuple, 17538c2ecf20Sopenharmony_ci * as would happen with internal metadata. */ 17548c2ecf20Sopenharmony_ci (new_disk_conf->meta_dev_idx != DRBD_MD_INDEX_FLEX_INT && 17558c2ecf20Sopenharmony_ci new_disk_conf->meta_dev_idx != DRBD_MD_INDEX_INTERNAL)); 17568c2ecf20Sopenharmony_ci if (IS_ERR(bdev)) 17578c2ecf20Sopenharmony_ci return ERR_OPEN_MD_DISK; 17588c2ecf20Sopenharmony_ci nbc->md_bdev = bdev; 17598c2ecf20Sopenharmony_ci return NO_ERROR; 17608c2ecf20Sopenharmony_ci} 17618c2ecf20Sopenharmony_ci 17628c2ecf20Sopenharmony_cistatic void close_backing_dev(struct drbd_device *device, struct block_device *bdev, 17638c2ecf20Sopenharmony_ci bool do_bd_unlink) 17648c2ecf20Sopenharmony_ci{ 17658c2ecf20Sopenharmony_ci if (!bdev) 17668c2ecf20Sopenharmony_ci return; 17678c2ecf20Sopenharmony_ci if (do_bd_unlink) 17688c2ecf20Sopenharmony_ci bd_unlink_disk_holder(bdev, device->vdisk); 17698c2ecf20Sopenharmony_ci blkdev_put(bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL); 17708c2ecf20Sopenharmony_ci} 17718c2ecf20Sopenharmony_ci 17728c2ecf20Sopenharmony_civoid drbd_backing_dev_free(struct drbd_device *device, struct drbd_backing_dev *ldev) 17738c2ecf20Sopenharmony_ci{ 17748c2ecf20Sopenharmony_ci if (ldev == NULL) 17758c2ecf20Sopenharmony_ci return; 17768c2ecf20Sopenharmony_ci 17778c2ecf20Sopenharmony_ci close_backing_dev(device, ldev->md_bdev, ldev->md_bdev != ldev->backing_bdev); 17788c2ecf20Sopenharmony_ci close_backing_dev(device, ldev->backing_bdev, true); 17798c2ecf20Sopenharmony_ci 17808c2ecf20Sopenharmony_ci kfree(ldev->disk_conf); 17818c2ecf20Sopenharmony_ci kfree(ldev); 17828c2ecf20Sopenharmony_ci} 17838c2ecf20Sopenharmony_ci 17848c2ecf20Sopenharmony_ciint drbd_adm_attach(struct sk_buff *skb, struct genl_info *info) 17858c2ecf20Sopenharmony_ci{ 17868c2ecf20Sopenharmony_ci struct drbd_config_context adm_ctx; 17878c2ecf20Sopenharmony_ci struct drbd_device *device; 17888c2ecf20Sopenharmony_ci struct drbd_peer_device *peer_device; 17898c2ecf20Sopenharmony_ci struct drbd_connection *connection; 17908c2ecf20Sopenharmony_ci int err; 17918c2ecf20Sopenharmony_ci enum drbd_ret_code retcode; 17928c2ecf20Sopenharmony_ci enum determine_dev_size dd; 17938c2ecf20Sopenharmony_ci sector_t max_possible_sectors; 17948c2ecf20Sopenharmony_ci sector_t min_md_device_sectors; 17958c2ecf20Sopenharmony_ci struct drbd_backing_dev *nbc = NULL; /* new_backing_conf */ 17968c2ecf20Sopenharmony_ci struct disk_conf *new_disk_conf = NULL; 17978c2ecf20Sopenharmony_ci struct lru_cache *resync_lru = NULL; 17988c2ecf20Sopenharmony_ci struct fifo_buffer *new_plan = NULL; 17998c2ecf20Sopenharmony_ci union drbd_state ns, os; 18008c2ecf20Sopenharmony_ci enum drbd_state_rv rv; 18018c2ecf20Sopenharmony_ci struct net_conf *nc; 18028c2ecf20Sopenharmony_ci 18038c2ecf20Sopenharmony_ci retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_MINOR); 18048c2ecf20Sopenharmony_ci if (!adm_ctx.reply_skb) 18058c2ecf20Sopenharmony_ci return retcode; 18068c2ecf20Sopenharmony_ci if (retcode != NO_ERROR) 18078c2ecf20Sopenharmony_ci goto finish; 18088c2ecf20Sopenharmony_ci 18098c2ecf20Sopenharmony_ci device = adm_ctx.device; 18108c2ecf20Sopenharmony_ci mutex_lock(&adm_ctx.resource->adm_mutex); 18118c2ecf20Sopenharmony_ci peer_device = first_peer_device(device); 18128c2ecf20Sopenharmony_ci connection = peer_device->connection; 18138c2ecf20Sopenharmony_ci conn_reconfig_start(connection); 18148c2ecf20Sopenharmony_ci 18158c2ecf20Sopenharmony_ci /* if you want to reconfigure, please tear down first */ 18168c2ecf20Sopenharmony_ci if (device->state.disk > D_DISKLESS) { 18178c2ecf20Sopenharmony_ci retcode = ERR_DISK_CONFIGURED; 18188c2ecf20Sopenharmony_ci goto fail; 18198c2ecf20Sopenharmony_ci } 18208c2ecf20Sopenharmony_ci /* It may just now have detached because of IO error. Make sure 18218c2ecf20Sopenharmony_ci * drbd_ldev_destroy is done already, we may end up here very fast, 18228c2ecf20Sopenharmony_ci * e.g. if someone calls attach from the on-io-error handler, 18238c2ecf20Sopenharmony_ci * to realize a "hot spare" feature (not that I'd recommend that) */ 18248c2ecf20Sopenharmony_ci wait_event(device->misc_wait, !test_bit(GOING_DISKLESS, &device->flags)); 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_ci /* make sure there is no leftover from previous force-detach attempts */ 18278c2ecf20Sopenharmony_ci clear_bit(FORCE_DETACH, &device->flags); 18288c2ecf20Sopenharmony_ci clear_bit(WAS_IO_ERROR, &device->flags); 18298c2ecf20Sopenharmony_ci clear_bit(WAS_READ_ERROR, &device->flags); 18308c2ecf20Sopenharmony_ci 18318c2ecf20Sopenharmony_ci /* and no leftover from previously aborted resync or verify, either */ 18328c2ecf20Sopenharmony_ci device->rs_total = 0; 18338c2ecf20Sopenharmony_ci device->rs_failed = 0; 18348c2ecf20Sopenharmony_ci atomic_set(&device->rs_pending_cnt, 0); 18358c2ecf20Sopenharmony_ci 18368c2ecf20Sopenharmony_ci /* allocation not in the IO path, drbdsetup context */ 18378c2ecf20Sopenharmony_ci nbc = kzalloc(sizeof(struct drbd_backing_dev), GFP_KERNEL); 18388c2ecf20Sopenharmony_ci if (!nbc) { 18398c2ecf20Sopenharmony_ci retcode = ERR_NOMEM; 18408c2ecf20Sopenharmony_ci goto fail; 18418c2ecf20Sopenharmony_ci } 18428c2ecf20Sopenharmony_ci spin_lock_init(&nbc->md.uuid_lock); 18438c2ecf20Sopenharmony_ci 18448c2ecf20Sopenharmony_ci new_disk_conf = kzalloc(sizeof(struct disk_conf), GFP_KERNEL); 18458c2ecf20Sopenharmony_ci if (!new_disk_conf) { 18468c2ecf20Sopenharmony_ci retcode = ERR_NOMEM; 18478c2ecf20Sopenharmony_ci goto fail; 18488c2ecf20Sopenharmony_ci } 18498c2ecf20Sopenharmony_ci nbc->disk_conf = new_disk_conf; 18508c2ecf20Sopenharmony_ci 18518c2ecf20Sopenharmony_ci set_disk_conf_defaults(new_disk_conf); 18528c2ecf20Sopenharmony_ci err = disk_conf_from_attrs(new_disk_conf, info); 18538c2ecf20Sopenharmony_ci if (err) { 18548c2ecf20Sopenharmony_ci retcode = ERR_MANDATORY_TAG; 18558c2ecf20Sopenharmony_ci drbd_msg_put_info(adm_ctx.reply_skb, from_attrs_err_to_txt(err)); 18568c2ecf20Sopenharmony_ci goto fail; 18578c2ecf20Sopenharmony_ci } 18588c2ecf20Sopenharmony_ci 18598c2ecf20Sopenharmony_ci if (new_disk_conf->c_plan_ahead > DRBD_C_PLAN_AHEAD_MAX) 18608c2ecf20Sopenharmony_ci new_disk_conf->c_plan_ahead = DRBD_C_PLAN_AHEAD_MAX; 18618c2ecf20Sopenharmony_ci 18628c2ecf20Sopenharmony_ci new_plan = fifo_alloc((new_disk_conf->c_plan_ahead * 10 * SLEEP_TIME) / HZ); 18638c2ecf20Sopenharmony_ci if (!new_plan) { 18648c2ecf20Sopenharmony_ci retcode = ERR_NOMEM; 18658c2ecf20Sopenharmony_ci goto fail; 18668c2ecf20Sopenharmony_ci } 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_ci if (new_disk_conf->meta_dev_idx < DRBD_MD_INDEX_FLEX_INT) { 18698c2ecf20Sopenharmony_ci retcode = ERR_MD_IDX_INVALID; 18708c2ecf20Sopenharmony_ci goto fail; 18718c2ecf20Sopenharmony_ci } 18728c2ecf20Sopenharmony_ci 18738c2ecf20Sopenharmony_ci rcu_read_lock(); 18748c2ecf20Sopenharmony_ci nc = rcu_dereference(connection->net_conf); 18758c2ecf20Sopenharmony_ci if (nc) { 18768c2ecf20Sopenharmony_ci if (new_disk_conf->fencing == FP_STONITH && nc->wire_protocol == DRBD_PROT_A) { 18778c2ecf20Sopenharmony_ci rcu_read_unlock(); 18788c2ecf20Sopenharmony_ci retcode = ERR_STONITH_AND_PROT_A; 18798c2ecf20Sopenharmony_ci goto fail; 18808c2ecf20Sopenharmony_ci } 18818c2ecf20Sopenharmony_ci } 18828c2ecf20Sopenharmony_ci rcu_read_unlock(); 18838c2ecf20Sopenharmony_ci 18848c2ecf20Sopenharmony_ci retcode = open_backing_devices(device, new_disk_conf, nbc); 18858c2ecf20Sopenharmony_ci if (retcode != NO_ERROR) 18868c2ecf20Sopenharmony_ci goto fail; 18878c2ecf20Sopenharmony_ci 18888c2ecf20Sopenharmony_ci if ((nbc->backing_bdev == nbc->md_bdev) != 18898c2ecf20Sopenharmony_ci (new_disk_conf->meta_dev_idx == DRBD_MD_INDEX_INTERNAL || 18908c2ecf20Sopenharmony_ci new_disk_conf->meta_dev_idx == DRBD_MD_INDEX_FLEX_INT)) { 18918c2ecf20Sopenharmony_ci retcode = ERR_MD_IDX_INVALID; 18928c2ecf20Sopenharmony_ci goto fail; 18938c2ecf20Sopenharmony_ci } 18948c2ecf20Sopenharmony_ci 18958c2ecf20Sopenharmony_ci resync_lru = lc_create("resync", drbd_bm_ext_cache, 18968c2ecf20Sopenharmony_ci 1, 61, sizeof(struct bm_extent), 18978c2ecf20Sopenharmony_ci offsetof(struct bm_extent, lce)); 18988c2ecf20Sopenharmony_ci if (!resync_lru) { 18998c2ecf20Sopenharmony_ci retcode = ERR_NOMEM; 19008c2ecf20Sopenharmony_ci goto fail; 19018c2ecf20Sopenharmony_ci } 19028c2ecf20Sopenharmony_ci 19038c2ecf20Sopenharmony_ci /* Read our meta data super block early. 19048c2ecf20Sopenharmony_ci * This also sets other on-disk offsets. */ 19058c2ecf20Sopenharmony_ci retcode = drbd_md_read(device, nbc); 19068c2ecf20Sopenharmony_ci if (retcode != NO_ERROR) 19078c2ecf20Sopenharmony_ci goto fail; 19088c2ecf20Sopenharmony_ci 19098c2ecf20Sopenharmony_ci sanitize_disk_conf(device, new_disk_conf, nbc); 19108c2ecf20Sopenharmony_ci 19118c2ecf20Sopenharmony_ci if (drbd_get_max_capacity(nbc) < new_disk_conf->disk_size) { 19128c2ecf20Sopenharmony_ci drbd_err(device, "max capacity %llu smaller than disk size %llu\n", 19138c2ecf20Sopenharmony_ci (unsigned long long) drbd_get_max_capacity(nbc), 19148c2ecf20Sopenharmony_ci (unsigned long long) new_disk_conf->disk_size); 19158c2ecf20Sopenharmony_ci retcode = ERR_DISK_TOO_SMALL; 19168c2ecf20Sopenharmony_ci goto fail; 19178c2ecf20Sopenharmony_ci } 19188c2ecf20Sopenharmony_ci 19198c2ecf20Sopenharmony_ci if (new_disk_conf->meta_dev_idx < 0) { 19208c2ecf20Sopenharmony_ci max_possible_sectors = DRBD_MAX_SECTORS_FLEX; 19218c2ecf20Sopenharmony_ci /* at least one MB, otherwise it does not make sense */ 19228c2ecf20Sopenharmony_ci min_md_device_sectors = (2<<10); 19238c2ecf20Sopenharmony_ci } else { 19248c2ecf20Sopenharmony_ci max_possible_sectors = DRBD_MAX_SECTORS; 19258c2ecf20Sopenharmony_ci min_md_device_sectors = MD_128MB_SECT * (new_disk_conf->meta_dev_idx + 1); 19268c2ecf20Sopenharmony_ci } 19278c2ecf20Sopenharmony_ci 19288c2ecf20Sopenharmony_ci if (drbd_get_capacity(nbc->md_bdev) < min_md_device_sectors) { 19298c2ecf20Sopenharmony_ci retcode = ERR_MD_DISK_TOO_SMALL; 19308c2ecf20Sopenharmony_ci drbd_warn(device, "refusing attach: md-device too small, " 19318c2ecf20Sopenharmony_ci "at least %llu sectors needed for this meta-disk type\n", 19328c2ecf20Sopenharmony_ci (unsigned long long) min_md_device_sectors); 19338c2ecf20Sopenharmony_ci goto fail; 19348c2ecf20Sopenharmony_ci } 19358c2ecf20Sopenharmony_ci 19368c2ecf20Sopenharmony_ci /* Make sure the new disk is big enough 19378c2ecf20Sopenharmony_ci * (we may currently be R_PRIMARY with no local disk...) */ 19388c2ecf20Sopenharmony_ci if (drbd_get_max_capacity(nbc) < get_capacity(device->vdisk)) { 19398c2ecf20Sopenharmony_ci retcode = ERR_DISK_TOO_SMALL; 19408c2ecf20Sopenharmony_ci goto fail; 19418c2ecf20Sopenharmony_ci } 19428c2ecf20Sopenharmony_ci 19438c2ecf20Sopenharmony_ci nbc->known_size = drbd_get_capacity(nbc->backing_bdev); 19448c2ecf20Sopenharmony_ci 19458c2ecf20Sopenharmony_ci if (nbc->known_size > max_possible_sectors) { 19468c2ecf20Sopenharmony_ci drbd_warn(device, "==> truncating very big lower level device " 19478c2ecf20Sopenharmony_ci "to currently maximum possible %llu sectors <==\n", 19488c2ecf20Sopenharmony_ci (unsigned long long) max_possible_sectors); 19498c2ecf20Sopenharmony_ci if (new_disk_conf->meta_dev_idx >= 0) 19508c2ecf20Sopenharmony_ci drbd_warn(device, "==>> using internal or flexible " 19518c2ecf20Sopenharmony_ci "meta data may help <<==\n"); 19528c2ecf20Sopenharmony_ci } 19538c2ecf20Sopenharmony_ci 19548c2ecf20Sopenharmony_ci drbd_suspend_io(device); 19558c2ecf20Sopenharmony_ci /* also wait for the last barrier ack. */ 19568c2ecf20Sopenharmony_ci /* FIXME see also https://daiquiri.linbit/cgi-bin/bugzilla/show_bug.cgi?id=171 19578c2ecf20Sopenharmony_ci * We need a way to either ignore barrier acks for barriers sent before a device 19588c2ecf20Sopenharmony_ci * was attached, or a way to wait for all pending barrier acks to come in. 19598c2ecf20Sopenharmony_ci * As barriers are counted per resource, 19608c2ecf20Sopenharmony_ci * we'd need to suspend io on all devices of a resource. 19618c2ecf20Sopenharmony_ci */ 19628c2ecf20Sopenharmony_ci wait_event(device->misc_wait, !atomic_read(&device->ap_pending_cnt) || drbd_suspended(device)); 19638c2ecf20Sopenharmony_ci /* and for any other previously queued work */ 19648c2ecf20Sopenharmony_ci drbd_flush_workqueue(&connection->sender_work); 19658c2ecf20Sopenharmony_ci 19668c2ecf20Sopenharmony_ci rv = _drbd_request_state(device, NS(disk, D_ATTACHING), CS_VERBOSE); 19678c2ecf20Sopenharmony_ci retcode = (enum drbd_ret_code)rv; 19688c2ecf20Sopenharmony_ci drbd_resume_io(device); 19698c2ecf20Sopenharmony_ci if (rv < SS_SUCCESS) 19708c2ecf20Sopenharmony_ci goto fail; 19718c2ecf20Sopenharmony_ci 19728c2ecf20Sopenharmony_ci if (!get_ldev_if_state(device, D_ATTACHING)) 19738c2ecf20Sopenharmony_ci goto force_diskless; 19748c2ecf20Sopenharmony_ci 19758c2ecf20Sopenharmony_ci if (!device->bitmap) { 19768c2ecf20Sopenharmony_ci if (drbd_bm_init(device)) { 19778c2ecf20Sopenharmony_ci retcode = ERR_NOMEM; 19788c2ecf20Sopenharmony_ci goto force_diskless_dec; 19798c2ecf20Sopenharmony_ci } 19808c2ecf20Sopenharmony_ci } 19818c2ecf20Sopenharmony_ci 19828c2ecf20Sopenharmony_ci if (device->state.pdsk != D_UP_TO_DATE && device->ed_uuid && 19838c2ecf20Sopenharmony_ci (device->state.role == R_PRIMARY || device->state.peer == R_PRIMARY) && 19848c2ecf20Sopenharmony_ci (device->ed_uuid & ~((u64)1)) != (nbc->md.uuid[UI_CURRENT] & ~((u64)1))) { 19858c2ecf20Sopenharmony_ci drbd_err(device, "Can only attach to data with current UUID=%016llX\n", 19868c2ecf20Sopenharmony_ci (unsigned long long)device->ed_uuid); 19878c2ecf20Sopenharmony_ci retcode = ERR_DATA_NOT_CURRENT; 19888c2ecf20Sopenharmony_ci goto force_diskless_dec; 19898c2ecf20Sopenharmony_ci } 19908c2ecf20Sopenharmony_ci 19918c2ecf20Sopenharmony_ci /* Since we are diskless, fix the activity log first... */ 19928c2ecf20Sopenharmony_ci if (drbd_check_al_size(device, new_disk_conf)) { 19938c2ecf20Sopenharmony_ci retcode = ERR_NOMEM; 19948c2ecf20Sopenharmony_ci goto force_diskless_dec; 19958c2ecf20Sopenharmony_ci } 19968c2ecf20Sopenharmony_ci 19978c2ecf20Sopenharmony_ci /* Prevent shrinking of consistent devices ! */ 19988c2ecf20Sopenharmony_ci { 19998c2ecf20Sopenharmony_ci unsigned long long nsz = drbd_new_dev_size(device, nbc, nbc->disk_conf->disk_size, 0); 20008c2ecf20Sopenharmony_ci unsigned long long eff = nbc->md.la_size_sect; 20018c2ecf20Sopenharmony_ci if (drbd_md_test_flag(nbc, MDF_CONSISTENT) && nsz < eff) { 20028c2ecf20Sopenharmony_ci if (nsz == nbc->disk_conf->disk_size) { 20038c2ecf20Sopenharmony_ci drbd_warn(device, "truncating a consistent device during attach (%llu < %llu)\n", nsz, eff); 20048c2ecf20Sopenharmony_ci } else { 20058c2ecf20Sopenharmony_ci drbd_warn(device, "refusing to truncate a consistent device (%llu < %llu)\n", nsz, eff); 20068c2ecf20Sopenharmony_ci drbd_msg_sprintf_info(adm_ctx.reply_skb, 20078c2ecf20Sopenharmony_ci "To-be-attached device has last effective > current size, and is consistent\n" 20088c2ecf20Sopenharmony_ci "(%llu > %llu sectors). Refusing to attach.", eff, nsz); 20098c2ecf20Sopenharmony_ci retcode = ERR_IMPLICIT_SHRINK; 20108c2ecf20Sopenharmony_ci goto force_diskless_dec; 20118c2ecf20Sopenharmony_ci } 20128c2ecf20Sopenharmony_ci } 20138c2ecf20Sopenharmony_ci } 20148c2ecf20Sopenharmony_ci 20158c2ecf20Sopenharmony_ci lock_all_resources(); 20168c2ecf20Sopenharmony_ci retcode = drbd_resync_after_valid(device, new_disk_conf->resync_after); 20178c2ecf20Sopenharmony_ci if (retcode != NO_ERROR) { 20188c2ecf20Sopenharmony_ci unlock_all_resources(); 20198c2ecf20Sopenharmony_ci goto force_diskless_dec; 20208c2ecf20Sopenharmony_ci } 20218c2ecf20Sopenharmony_ci 20228c2ecf20Sopenharmony_ci /* Reset the "barriers don't work" bits here, then force meta data to 20238c2ecf20Sopenharmony_ci * be written, to ensure we determine if barriers are supported. */ 20248c2ecf20Sopenharmony_ci if (new_disk_conf->md_flushes) 20258c2ecf20Sopenharmony_ci clear_bit(MD_NO_FUA, &device->flags); 20268c2ecf20Sopenharmony_ci else 20278c2ecf20Sopenharmony_ci set_bit(MD_NO_FUA, &device->flags); 20288c2ecf20Sopenharmony_ci 20298c2ecf20Sopenharmony_ci /* Point of no return reached. 20308c2ecf20Sopenharmony_ci * Devices and memory are no longer released by error cleanup below. 20318c2ecf20Sopenharmony_ci * now device takes over responsibility, and the state engine should 20328c2ecf20Sopenharmony_ci * clean it up somewhere. */ 20338c2ecf20Sopenharmony_ci D_ASSERT(device, device->ldev == NULL); 20348c2ecf20Sopenharmony_ci device->ldev = nbc; 20358c2ecf20Sopenharmony_ci device->resync = resync_lru; 20368c2ecf20Sopenharmony_ci device->rs_plan_s = new_plan; 20378c2ecf20Sopenharmony_ci nbc = NULL; 20388c2ecf20Sopenharmony_ci resync_lru = NULL; 20398c2ecf20Sopenharmony_ci new_disk_conf = NULL; 20408c2ecf20Sopenharmony_ci new_plan = NULL; 20418c2ecf20Sopenharmony_ci 20428c2ecf20Sopenharmony_ci drbd_resync_after_changed(device); 20438c2ecf20Sopenharmony_ci drbd_bump_write_ordering(device->resource, device->ldev, WO_BDEV_FLUSH); 20448c2ecf20Sopenharmony_ci unlock_all_resources(); 20458c2ecf20Sopenharmony_ci 20468c2ecf20Sopenharmony_ci if (drbd_md_test_flag(device->ldev, MDF_CRASHED_PRIMARY)) 20478c2ecf20Sopenharmony_ci set_bit(CRASHED_PRIMARY, &device->flags); 20488c2ecf20Sopenharmony_ci else 20498c2ecf20Sopenharmony_ci clear_bit(CRASHED_PRIMARY, &device->flags); 20508c2ecf20Sopenharmony_ci 20518c2ecf20Sopenharmony_ci if (drbd_md_test_flag(device->ldev, MDF_PRIMARY_IND) && 20528c2ecf20Sopenharmony_ci !(device->state.role == R_PRIMARY && device->resource->susp_nod)) 20538c2ecf20Sopenharmony_ci set_bit(CRASHED_PRIMARY, &device->flags); 20548c2ecf20Sopenharmony_ci 20558c2ecf20Sopenharmony_ci device->send_cnt = 0; 20568c2ecf20Sopenharmony_ci device->recv_cnt = 0; 20578c2ecf20Sopenharmony_ci device->read_cnt = 0; 20588c2ecf20Sopenharmony_ci device->writ_cnt = 0; 20598c2ecf20Sopenharmony_ci 20608c2ecf20Sopenharmony_ci drbd_reconsider_queue_parameters(device, device->ldev, NULL); 20618c2ecf20Sopenharmony_ci 20628c2ecf20Sopenharmony_ci /* If I am currently not R_PRIMARY, 20638c2ecf20Sopenharmony_ci * but meta data primary indicator is set, 20648c2ecf20Sopenharmony_ci * I just now recover from a hard crash, 20658c2ecf20Sopenharmony_ci * and have been R_PRIMARY before that crash. 20668c2ecf20Sopenharmony_ci * 20678c2ecf20Sopenharmony_ci * Now, if I had no connection before that crash 20688c2ecf20Sopenharmony_ci * (have been degraded R_PRIMARY), chances are that 20698c2ecf20Sopenharmony_ci * I won't find my peer now either. 20708c2ecf20Sopenharmony_ci * 20718c2ecf20Sopenharmony_ci * In that case, and _only_ in that case, 20728c2ecf20Sopenharmony_ci * we use the degr-wfc-timeout instead of the default, 20738c2ecf20Sopenharmony_ci * so we can automatically recover from a crash of a 20748c2ecf20Sopenharmony_ci * degraded but active "cluster" after a certain timeout. 20758c2ecf20Sopenharmony_ci */ 20768c2ecf20Sopenharmony_ci clear_bit(USE_DEGR_WFC_T, &device->flags); 20778c2ecf20Sopenharmony_ci if (device->state.role != R_PRIMARY && 20788c2ecf20Sopenharmony_ci drbd_md_test_flag(device->ldev, MDF_PRIMARY_IND) && 20798c2ecf20Sopenharmony_ci !drbd_md_test_flag(device->ldev, MDF_CONNECTED_IND)) 20808c2ecf20Sopenharmony_ci set_bit(USE_DEGR_WFC_T, &device->flags); 20818c2ecf20Sopenharmony_ci 20828c2ecf20Sopenharmony_ci dd = drbd_determine_dev_size(device, 0, NULL); 20838c2ecf20Sopenharmony_ci if (dd <= DS_ERROR) { 20848c2ecf20Sopenharmony_ci retcode = ERR_NOMEM_BITMAP; 20858c2ecf20Sopenharmony_ci goto force_diskless_dec; 20868c2ecf20Sopenharmony_ci } else if (dd == DS_GREW) 20878c2ecf20Sopenharmony_ci set_bit(RESYNC_AFTER_NEG, &device->flags); 20888c2ecf20Sopenharmony_ci 20898c2ecf20Sopenharmony_ci if (drbd_md_test_flag(device->ldev, MDF_FULL_SYNC) || 20908c2ecf20Sopenharmony_ci (test_bit(CRASHED_PRIMARY, &device->flags) && 20918c2ecf20Sopenharmony_ci drbd_md_test_flag(device->ldev, MDF_AL_DISABLED))) { 20928c2ecf20Sopenharmony_ci drbd_info(device, "Assuming that all blocks are out of sync " 20938c2ecf20Sopenharmony_ci "(aka FullSync)\n"); 20948c2ecf20Sopenharmony_ci if (drbd_bitmap_io(device, &drbd_bmio_set_n_write, 20958c2ecf20Sopenharmony_ci "set_n_write from attaching", BM_LOCKED_MASK)) { 20968c2ecf20Sopenharmony_ci retcode = ERR_IO_MD_DISK; 20978c2ecf20Sopenharmony_ci goto force_diskless_dec; 20988c2ecf20Sopenharmony_ci } 20998c2ecf20Sopenharmony_ci } else { 21008c2ecf20Sopenharmony_ci if (drbd_bitmap_io(device, &drbd_bm_read, 21018c2ecf20Sopenharmony_ci "read from attaching", BM_LOCKED_MASK)) { 21028c2ecf20Sopenharmony_ci retcode = ERR_IO_MD_DISK; 21038c2ecf20Sopenharmony_ci goto force_diskless_dec; 21048c2ecf20Sopenharmony_ci } 21058c2ecf20Sopenharmony_ci } 21068c2ecf20Sopenharmony_ci 21078c2ecf20Sopenharmony_ci if (_drbd_bm_total_weight(device) == drbd_bm_bits(device)) 21088c2ecf20Sopenharmony_ci drbd_suspend_al(device); /* IO is still suspended here... */ 21098c2ecf20Sopenharmony_ci 21108c2ecf20Sopenharmony_ci spin_lock_irq(&device->resource->req_lock); 21118c2ecf20Sopenharmony_ci os = drbd_read_state(device); 21128c2ecf20Sopenharmony_ci ns = os; 21138c2ecf20Sopenharmony_ci /* If MDF_CONSISTENT is not set go into inconsistent state, 21148c2ecf20Sopenharmony_ci otherwise investigate MDF_WasUpToDate... 21158c2ecf20Sopenharmony_ci If MDF_WAS_UP_TO_DATE is not set go into D_OUTDATED disk state, 21168c2ecf20Sopenharmony_ci otherwise into D_CONSISTENT state. 21178c2ecf20Sopenharmony_ci */ 21188c2ecf20Sopenharmony_ci if (drbd_md_test_flag(device->ldev, MDF_CONSISTENT)) { 21198c2ecf20Sopenharmony_ci if (drbd_md_test_flag(device->ldev, MDF_WAS_UP_TO_DATE)) 21208c2ecf20Sopenharmony_ci ns.disk = D_CONSISTENT; 21218c2ecf20Sopenharmony_ci else 21228c2ecf20Sopenharmony_ci ns.disk = D_OUTDATED; 21238c2ecf20Sopenharmony_ci } else { 21248c2ecf20Sopenharmony_ci ns.disk = D_INCONSISTENT; 21258c2ecf20Sopenharmony_ci } 21268c2ecf20Sopenharmony_ci 21278c2ecf20Sopenharmony_ci if (drbd_md_test_flag(device->ldev, MDF_PEER_OUT_DATED)) 21288c2ecf20Sopenharmony_ci ns.pdsk = D_OUTDATED; 21298c2ecf20Sopenharmony_ci 21308c2ecf20Sopenharmony_ci rcu_read_lock(); 21318c2ecf20Sopenharmony_ci if (ns.disk == D_CONSISTENT && 21328c2ecf20Sopenharmony_ci (ns.pdsk == D_OUTDATED || rcu_dereference(device->ldev->disk_conf)->fencing == FP_DONT_CARE)) 21338c2ecf20Sopenharmony_ci ns.disk = D_UP_TO_DATE; 21348c2ecf20Sopenharmony_ci 21358c2ecf20Sopenharmony_ci /* All tests on MDF_PRIMARY_IND, MDF_CONNECTED_IND, 21368c2ecf20Sopenharmony_ci MDF_CONSISTENT and MDF_WAS_UP_TO_DATE must happen before 21378c2ecf20Sopenharmony_ci this point, because drbd_request_state() modifies these 21388c2ecf20Sopenharmony_ci flags. */ 21398c2ecf20Sopenharmony_ci 21408c2ecf20Sopenharmony_ci if (rcu_dereference(device->ldev->disk_conf)->al_updates) 21418c2ecf20Sopenharmony_ci device->ldev->md.flags &= ~MDF_AL_DISABLED; 21428c2ecf20Sopenharmony_ci else 21438c2ecf20Sopenharmony_ci device->ldev->md.flags |= MDF_AL_DISABLED; 21448c2ecf20Sopenharmony_ci 21458c2ecf20Sopenharmony_ci rcu_read_unlock(); 21468c2ecf20Sopenharmony_ci 21478c2ecf20Sopenharmony_ci /* In case we are C_CONNECTED postpone any decision on the new disk 21488c2ecf20Sopenharmony_ci state after the negotiation phase. */ 21498c2ecf20Sopenharmony_ci if (device->state.conn == C_CONNECTED) { 21508c2ecf20Sopenharmony_ci device->new_state_tmp.i = ns.i; 21518c2ecf20Sopenharmony_ci ns.i = os.i; 21528c2ecf20Sopenharmony_ci ns.disk = D_NEGOTIATING; 21538c2ecf20Sopenharmony_ci 21548c2ecf20Sopenharmony_ci /* We expect to receive up-to-date UUIDs soon. 21558c2ecf20Sopenharmony_ci To avoid a race in receive_state, free p_uuid while 21568c2ecf20Sopenharmony_ci holding req_lock. I.e. atomic with the state change */ 21578c2ecf20Sopenharmony_ci kfree(device->p_uuid); 21588c2ecf20Sopenharmony_ci device->p_uuid = NULL; 21598c2ecf20Sopenharmony_ci } 21608c2ecf20Sopenharmony_ci 21618c2ecf20Sopenharmony_ci rv = _drbd_set_state(device, ns, CS_VERBOSE, NULL); 21628c2ecf20Sopenharmony_ci spin_unlock_irq(&device->resource->req_lock); 21638c2ecf20Sopenharmony_ci 21648c2ecf20Sopenharmony_ci if (rv < SS_SUCCESS) 21658c2ecf20Sopenharmony_ci goto force_diskless_dec; 21668c2ecf20Sopenharmony_ci 21678c2ecf20Sopenharmony_ci mod_timer(&device->request_timer, jiffies + HZ); 21688c2ecf20Sopenharmony_ci 21698c2ecf20Sopenharmony_ci if (device->state.role == R_PRIMARY) 21708c2ecf20Sopenharmony_ci device->ldev->md.uuid[UI_CURRENT] |= (u64)1; 21718c2ecf20Sopenharmony_ci else 21728c2ecf20Sopenharmony_ci device->ldev->md.uuid[UI_CURRENT] &= ~(u64)1; 21738c2ecf20Sopenharmony_ci 21748c2ecf20Sopenharmony_ci drbd_md_mark_dirty(device); 21758c2ecf20Sopenharmony_ci drbd_md_sync(device); 21768c2ecf20Sopenharmony_ci 21778c2ecf20Sopenharmony_ci kobject_uevent(&disk_to_dev(device->vdisk)->kobj, KOBJ_CHANGE); 21788c2ecf20Sopenharmony_ci put_ldev(device); 21798c2ecf20Sopenharmony_ci conn_reconfig_done(connection); 21808c2ecf20Sopenharmony_ci mutex_unlock(&adm_ctx.resource->adm_mutex); 21818c2ecf20Sopenharmony_ci drbd_adm_finish(&adm_ctx, info, retcode); 21828c2ecf20Sopenharmony_ci return 0; 21838c2ecf20Sopenharmony_ci 21848c2ecf20Sopenharmony_ci force_diskless_dec: 21858c2ecf20Sopenharmony_ci put_ldev(device); 21868c2ecf20Sopenharmony_ci force_diskless: 21878c2ecf20Sopenharmony_ci drbd_force_state(device, NS(disk, D_DISKLESS)); 21888c2ecf20Sopenharmony_ci drbd_md_sync(device); 21898c2ecf20Sopenharmony_ci fail: 21908c2ecf20Sopenharmony_ci conn_reconfig_done(connection); 21918c2ecf20Sopenharmony_ci if (nbc) { 21928c2ecf20Sopenharmony_ci close_backing_dev(device, nbc->md_bdev, nbc->md_bdev != nbc->backing_bdev); 21938c2ecf20Sopenharmony_ci close_backing_dev(device, nbc->backing_bdev, true); 21948c2ecf20Sopenharmony_ci kfree(nbc); 21958c2ecf20Sopenharmony_ci } 21968c2ecf20Sopenharmony_ci kfree(new_disk_conf); 21978c2ecf20Sopenharmony_ci lc_destroy(resync_lru); 21988c2ecf20Sopenharmony_ci kfree(new_plan); 21998c2ecf20Sopenharmony_ci mutex_unlock(&adm_ctx.resource->adm_mutex); 22008c2ecf20Sopenharmony_ci finish: 22018c2ecf20Sopenharmony_ci drbd_adm_finish(&adm_ctx, info, retcode); 22028c2ecf20Sopenharmony_ci return 0; 22038c2ecf20Sopenharmony_ci} 22048c2ecf20Sopenharmony_ci 22058c2ecf20Sopenharmony_cistatic int adm_detach(struct drbd_device *device, int force) 22068c2ecf20Sopenharmony_ci{ 22078c2ecf20Sopenharmony_ci if (force) { 22088c2ecf20Sopenharmony_ci set_bit(FORCE_DETACH, &device->flags); 22098c2ecf20Sopenharmony_ci drbd_force_state(device, NS(disk, D_FAILED)); 22108c2ecf20Sopenharmony_ci return SS_SUCCESS; 22118c2ecf20Sopenharmony_ci } 22128c2ecf20Sopenharmony_ci 22138c2ecf20Sopenharmony_ci return drbd_request_detach_interruptible(device); 22148c2ecf20Sopenharmony_ci} 22158c2ecf20Sopenharmony_ci 22168c2ecf20Sopenharmony_ci/* Detaching the disk is a process in multiple stages. First we need to lock 22178c2ecf20Sopenharmony_ci * out application IO, in-flight IO, IO stuck in drbd_al_begin_io. 22188c2ecf20Sopenharmony_ci * Then we transition to D_DISKLESS, and wait for put_ldev() to return all 22198c2ecf20Sopenharmony_ci * internal references as well. 22208c2ecf20Sopenharmony_ci * Only then we have finally detached. */ 22218c2ecf20Sopenharmony_ciint drbd_adm_detach(struct sk_buff *skb, struct genl_info *info) 22228c2ecf20Sopenharmony_ci{ 22238c2ecf20Sopenharmony_ci struct drbd_config_context adm_ctx; 22248c2ecf20Sopenharmony_ci enum drbd_ret_code retcode; 22258c2ecf20Sopenharmony_ci struct detach_parms parms = { }; 22268c2ecf20Sopenharmony_ci int err; 22278c2ecf20Sopenharmony_ci 22288c2ecf20Sopenharmony_ci retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_MINOR); 22298c2ecf20Sopenharmony_ci if (!adm_ctx.reply_skb) 22308c2ecf20Sopenharmony_ci return retcode; 22318c2ecf20Sopenharmony_ci if (retcode != NO_ERROR) 22328c2ecf20Sopenharmony_ci goto out; 22338c2ecf20Sopenharmony_ci 22348c2ecf20Sopenharmony_ci if (info->attrs[DRBD_NLA_DETACH_PARMS]) { 22358c2ecf20Sopenharmony_ci err = detach_parms_from_attrs(&parms, info); 22368c2ecf20Sopenharmony_ci if (err) { 22378c2ecf20Sopenharmony_ci retcode = ERR_MANDATORY_TAG; 22388c2ecf20Sopenharmony_ci drbd_msg_put_info(adm_ctx.reply_skb, from_attrs_err_to_txt(err)); 22398c2ecf20Sopenharmony_ci goto out; 22408c2ecf20Sopenharmony_ci } 22418c2ecf20Sopenharmony_ci } 22428c2ecf20Sopenharmony_ci 22438c2ecf20Sopenharmony_ci mutex_lock(&adm_ctx.resource->adm_mutex); 22448c2ecf20Sopenharmony_ci retcode = adm_detach(adm_ctx.device, parms.force_detach); 22458c2ecf20Sopenharmony_ci mutex_unlock(&adm_ctx.resource->adm_mutex); 22468c2ecf20Sopenharmony_ciout: 22478c2ecf20Sopenharmony_ci drbd_adm_finish(&adm_ctx, info, retcode); 22488c2ecf20Sopenharmony_ci return 0; 22498c2ecf20Sopenharmony_ci} 22508c2ecf20Sopenharmony_ci 22518c2ecf20Sopenharmony_cistatic bool conn_resync_running(struct drbd_connection *connection) 22528c2ecf20Sopenharmony_ci{ 22538c2ecf20Sopenharmony_ci struct drbd_peer_device *peer_device; 22548c2ecf20Sopenharmony_ci bool rv = false; 22558c2ecf20Sopenharmony_ci int vnr; 22568c2ecf20Sopenharmony_ci 22578c2ecf20Sopenharmony_ci rcu_read_lock(); 22588c2ecf20Sopenharmony_ci idr_for_each_entry(&connection->peer_devices, peer_device, vnr) { 22598c2ecf20Sopenharmony_ci struct drbd_device *device = peer_device->device; 22608c2ecf20Sopenharmony_ci if (device->state.conn == C_SYNC_SOURCE || 22618c2ecf20Sopenharmony_ci device->state.conn == C_SYNC_TARGET || 22628c2ecf20Sopenharmony_ci device->state.conn == C_PAUSED_SYNC_S || 22638c2ecf20Sopenharmony_ci device->state.conn == C_PAUSED_SYNC_T) { 22648c2ecf20Sopenharmony_ci rv = true; 22658c2ecf20Sopenharmony_ci break; 22668c2ecf20Sopenharmony_ci } 22678c2ecf20Sopenharmony_ci } 22688c2ecf20Sopenharmony_ci rcu_read_unlock(); 22698c2ecf20Sopenharmony_ci 22708c2ecf20Sopenharmony_ci return rv; 22718c2ecf20Sopenharmony_ci} 22728c2ecf20Sopenharmony_ci 22738c2ecf20Sopenharmony_cistatic bool conn_ov_running(struct drbd_connection *connection) 22748c2ecf20Sopenharmony_ci{ 22758c2ecf20Sopenharmony_ci struct drbd_peer_device *peer_device; 22768c2ecf20Sopenharmony_ci bool rv = false; 22778c2ecf20Sopenharmony_ci int vnr; 22788c2ecf20Sopenharmony_ci 22798c2ecf20Sopenharmony_ci rcu_read_lock(); 22808c2ecf20Sopenharmony_ci idr_for_each_entry(&connection->peer_devices, peer_device, vnr) { 22818c2ecf20Sopenharmony_ci struct drbd_device *device = peer_device->device; 22828c2ecf20Sopenharmony_ci if (device->state.conn == C_VERIFY_S || 22838c2ecf20Sopenharmony_ci device->state.conn == C_VERIFY_T) { 22848c2ecf20Sopenharmony_ci rv = true; 22858c2ecf20Sopenharmony_ci break; 22868c2ecf20Sopenharmony_ci } 22878c2ecf20Sopenharmony_ci } 22888c2ecf20Sopenharmony_ci rcu_read_unlock(); 22898c2ecf20Sopenharmony_ci 22908c2ecf20Sopenharmony_ci return rv; 22918c2ecf20Sopenharmony_ci} 22928c2ecf20Sopenharmony_ci 22938c2ecf20Sopenharmony_cistatic enum drbd_ret_code 22948c2ecf20Sopenharmony_ci_check_net_options(struct drbd_connection *connection, struct net_conf *old_net_conf, struct net_conf *new_net_conf) 22958c2ecf20Sopenharmony_ci{ 22968c2ecf20Sopenharmony_ci struct drbd_peer_device *peer_device; 22978c2ecf20Sopenharmony_ci int i; 22988c2ecf20Sopenharmony_ci 22998c2ecf20Sopenharmony_ci if (old_net_conf && connection->cstate == C_WF_REPORT_PARAMS && connection->agreed_pro_version < 100) { 23008c2ecf20Sopenharmony_ci if (new_net_conf->wire_protocol != old_net_conf->wire_protocol) 23018c2ecf20Sopenharmony_ci return ERR_NEED_APV_100; 23028c2ecf20Sopenharmony_ci 23038c2ecf20Sopenharmony_ci if (new_net_conf->two_primaries != old_net_conf->two_primaries) 23048c2ecf20Sopenharmony_ci return ERR_NEED_APV_100; 23058c2ecf20Sopenharmony_ci 23068c2ecf20Sopenharmony_ci if (strcmp(new_net_conf->integrity_alg, old_net_conf->integrity_alg)) 23078c2ecf20Sopenharmony_ci return ERR_NEED_APV_100; 23088c2ecf20Sopenharmony_ci } 23098c2ecf20Sopenharmony_ci 23108c2ecf20Sopenharmony_ci if (!new_net_conf->two_primaries && 23118c2ecf20Sopenharmony_ci conn_highest_role(connection) == R_PRIMARY && 23128c2ecf20Sopenharmony_ci conn_highest_peer(connection) == R_PRIMARY) 23138c2ecf20Sopenharmony_ci return ERR_NEED_ALLOW_TWO_PRI; 23148c2ecf20Sopenharmony_ci 23158c2ecf20Sopenharmony_ci if (new_net_conf->two_primaries && 23168c2ecf20Sopenharmony_ci (new_net_conf->wire_protocol != DRBD_PROT_C)) 23178c2ecf20Sopenharmony_ci return ERR_NOT_PROTO_C; 23188c2ecf20Sopenharmony_ci 23198c2ecf20Sopenharmony_ci idr_for_each_entry(&connection->peer_devices, peer_device, i) { 23208c2ecf20Sopenharmony_ci struct drbd_device *device = peer_device->device; 23218c2ecf20Sopenharmony_ci if (get_ldev(device)) { 23228c2ecf20Sopenharmony_ci enum drbd_fencing_p fp = rcu_dereference(device->ldev->disk_conf)->fencing; 23238c2ecf20Sopenharmony_ci put_ldev(device); 23248c2ecf20Sopenharmony_ci if (new_net_conf->wire_protocol == DRBD_PROT_A && fp == FP_STONITH) 23258c2ecf20Sopenharmony_ci return ERR_STONITH_AND_PROT_A; 23268c2ecf20Sopenharmony_ci } 23278c2ecf20Sopenharmony_ci if (device->state.role == R_PRIMARY && new_net_conf->discard_my_data) 23288c2ecf20Sopenharmony_ci return ERR_DISCARD_IMPOSSIBLE; 23298c2ecf20Sopenharmony_ci } 23308c2ecf20Sopenharmony_ci 23318c2ecf20Sopenharmony_ci if (new_net_conf->on_congestion != OC_BLOCK && new_net_conf->wire_protocol != DRBD_PROT_A) 23328c2ecf20Sopenharmony_ci return ERR_CONG_NOT_PROTO_A; 23338c2ecf20Sopenharmony_ci 23348c2ecf20Sopenharmony_ci return NO_ERROR; 23358c2ecf20Sopenharmony_ci} 23368c2ecf20Sopenharmony_ci 23378c2ecf20Sopenharmony_cistatic enum drbd_ret_code 23388c2ecf20Sopenharmony_cicheck_net_options(struct drbd_connection *connection, struct net_conf *new_net_conf) 23398c2ecf20Sopenharmony_ci{ 23408c2ecf20Sopenharmony_ci enum drbd_ret_code rv; 23418c2ecf20Sopenharmony_ci struct drbd_peer_device *peer_device; 23428c2ecf20Sopenharmony_ci int i; 23438c2ecf20Sopenharmony_ci 23448c2ecf20Sopenharmony_ci rcu_read_lock(); 23458c2ecf20Sopenharmony_ci rv = _check_net_options(connection, rcu_dereference(connection->net_conf), new_net_conf); 23468c2ecf20Sopenharmony_ci rcu_read_unlock(); 23478c2ecf20Sopenharmony_ci 23488c2ecf20Sopenharmony_ci /* connection->peer_devices protected by genl_lock() here */ 23498c2ecf20Sopenharmony_ci idr_for_each_entry(&connection->peer_devices, peer_device, i) { 23508c2ecf20Sopenharmony_ci struct drbd_device *device = peer_device->device; 23518c2ecf20Sopenharmony_ci if (!device->bitmap) { 23528c2ecf20Sopenharmony_ci if (drbd_bm_init(device)) 23538c2ecf20Sopenharmony_ci return ERR_NOMEM; 23548c2ecf20Sopenharmony_ci } 23558c2ecf20Sopenharmony_ci } 23568c2ecf20Sopenharmony_ci 23578c2ecf20Sopenharmony_ci return rv; 23588c2ecf20Sopenharmony_ci} 23598c2ecf20Sopenharmony_ci 23608c2ecf20Sopenharmony_cistruct crypto { 23618c2ecf20Sopenharmony_ci struct crypto_shash *verify_tfm; 23628c2ecf20Sopenharmony_ci struct crypto_shash *csums_tfm; 23638c2ecf20Sopenharmony_ci struct crypto_shash *cram_hmac_tfm; 23648c2ecf20Sopenharmony_ci struct crypto_shash *integrity_tfm; 23658c2ecf20Sopenharmony_ci}; 23668c2ecf20Sopenharmony_ci 23678c2ecf20Sopenharmony_cistatic int 23688c2ecf20Sopenharmony_cialloc_shash(struct crypto_shash **tfm, char *tfm_name, int err_alg) 23698c2ecf20Sopenharmony_ci{ 23708c2ecf20Sopenharmony_ci if (!tfm_name[0]) 23718c2ecf20Sopenharmony_ci return NO_ERROR; 23728c2ecf20Sopenharmony_ci 23738c2ecf20Sopenharmony_ci *tfm = crypto_alloc_shash(tfm_name, 0, 0); 23748c2ecf20Sopenharmony_ci if (IS_ERR(*tfm)) { 23758c2ecf20Sopenharmony_ci *tfm = NULL; 23768c2ecf20Sopenharmony_ci return err_alg; 23778c2ecf20Sopenharmony_ci } 23788c2ecf20Sopenharmony_ci 23798c2ecf20Sopenharmony_ci return NO_ERROR; 23808c2ecf20Sopenharmony_ci} 23818c2ecf20Sopenharmony_ci 23828c2ecf20Sopenharmony_cistatic enum drbd_ret_code 23838c2ecf20Sopenharmony_cialloc_crypto(struct crypto *crypto, struct net_conf *new_net_conf) 23848c2ecf20Sopenharmony_ci{ 23858c2ecf20Sopenharmony_ci char hmac_name[CRYPTO_MAX_ALG_NAME]; 23868c2ecf20Sopenharmony_ci enum drbd_ret_code rv; 23878c2ecf20Sopenharmony_ci 23888c2ecf20Sopenharmony_ci rv = alloc_shash(&crypto->csums_tfm, new_net_conf->csums_alg, 23898c2ecf20Sopenharmony_ci ERR_CSUMS_ALG); 23908c2ecf20Sopenharmony_ci if (rv != NO_ERROR) 23918c2ecf20Sopenharmony_ci return rv; 23928c2ecf20Sopenharmony_ci rv = alloc_shash(&crypto->verify_tfm, new_net_conf->verify_alg, 23938c2ecf20Sopenharmony_ci ERR_VERIFY_ALG); 23948c2ecf20Sopenharmony_ci if (rv != NO_ERROR) 23958c2ecf20Sopenharmony_ci return rv; 23968c2ecf20Sopenharmony_ci rv = alloc_shash(&crypto->integrity_tfm, new_net_conf->integrity_alg, 23978c2ecf20Sopenharmony_ci ERR_INTEGRITY_ALG); 23988c2ecf20Sopenharmony_ci if (rv != NO_ERROR) 23998c2ecf20Sopenharmony_ci return rv; 24008c2ecf20Sopenharmony_ci if (new_net_conf->cram_hmac_alg[0] != 0) { 24018c2ecf20Sopenharmony_ci snprintf(hmac_name, CRYPTO_MAX_ALG_NAME, "hmac(%s)", 24028c2ecf20Sopenharmony_ci new_net_conf->cram_hmac_alg); 24038c2ecf20Sopenharmony_ci 24048c2ecf20Sopenharmony_ci rv = alloc_shash(&crypto->cram_hmac_tfm, hmac_name, 24058c2ecf20Sopenharmony_ci ERR_AUTH_ALG); 24068c2ecf20Sopenharmony_ci } 24078c2ecf20Sopenharmony_ci 24088c2ecf20Sopenharmony_ci return rv; 24098c2ecf20Sopenharmony_ci} 24108c2ecf20Sopenharmony_ci 24118c2ecf20Sopenharmony_cistatic void free_crypto(struct crypto *crypto) 24128c2ecf20Sopenharmony_ci{ 24138c2ecf20Sopenharmony_ci crypto_free_shash(crypto->cram_hmac_tfm); 24148c2ecf20Sopenharmony_ci crypto_free_shash(crypto->integrity_tfm); 24158c2ecf20Sopenharmony_ci crypto_free_shash(crypto->csums_tfm); 24168c2ecf20Sopenharmony_ci crypto_free_shash(crypto->verify_tfm); 24178c2ecf20Sopenharmony_ci} 24188c2ecf20Sopenharmony_ci 24198c2ecf20Sopenharmony_ciint drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info) 24208c2ecf20Sopenharmony_ci{ 24218c2ecf20Sopenharmony_ci struct drbd_config_context adm_ctx; 24228c2ecf20Sopenharmony_ci enum drbd_ret_code retcode; 24238c2ecf20Sopenharmony_ci struct drbd_connection *connection; 24248c2ecf20Sopenharmony_ci struct net_conf *old_net_conf, *new_net_conf = NULL; 24258c2ecf20Sopenharmony_ci int err; 24268c2ecf20Sopenharmony_ci int ovr; /* online verify running */ 24278c2ecf20Sopenharmony_ci int rsr; /* re-sync running */ 24288c2ecf20Sopenharmony_ci struct crypto crypto = { }; 24298c2ecf20Sopenharmony_ci 24308c2ecf20Sopenharmony_ci retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_CONNECTION); 24318c2ecf20Sopenharmony_ci if (!adm_ctx.reply_skb) 24328c2ecf20Sopenharmony_ci return retcode; 24338c2ecf20Sopenharmony_ci if (retcode != NO_ERROR) 24348c2ecf20Sopenharmony_ci goto finish; 24358c2ecf20Sopenharmony_ci 24368c2ecf20Sopenharmony_ci connection = adm_ctx.connection; 24378c2ecf20Sopenharmony_ci mutex_lock(&adm_ctx.resource->adm_mutex); 24388c2ecf20Sopenharmony_ci 24398c2ecf20Sopenharmony_ci new_net_conf = kzalloc(sizeof(struct net_conf), GFP_KERNEL); 24408c2ecf20Sopenharmony_ci if (!new_net_conf) { 24418c2ecf20Sopenharmony_ci retcode = ERR_NOMEM; 24428c2ecf20Sopenharmony_ci goto out; 24438c2ecf20Sopenharmony_ci } 24448c2ecf20Sopenharmony_ci 24458c2ecf20Sopenharmony_ci conn_reconfig_start(connection); 24468c2ecf20Sopenharmony_ci 24478c2ecf20Sopenharmony_ci mutex_lock(&connection->data.mutex); 24488c2ecf20Sopenharmony_ci mutex_lock(&connection->resource->conf_update); 24498c2ecf20Sopenharmony_ci old_net_conf = connection->net_conf; 24508c2ecf20Sopenharmony_ci 24518c2ecf20Sopenharmony_ci if (!old_net_conf) { 24528c2ecf20Sopenharmony_ci drbd_msg_put_info(adm_ctx.reply_skb, "net conf missing, try connect"); 24538c2ecf20Sopenharmony_ci retcode = ERR_INVALID_REQUEST; 24548c2ecf20Sopenharmony_ci goto fail; 24558c2ecf20Sopenharmony_ci } 24568c2ecf20Sopenharmony_ci 24578c2ecf20Sopenharmony_ci *new_net_conf = *old_net_conf; 24588c2ecf20Sopenharmony_ci if (should_set_defaults(info)) 24598c2ecf20Sopenharmony_ci set_net_conf_defaults(new_net_conf); 24608c2ecf20Sopenharmony_ci 24618c2ecf20Sopenharmony_ci err = net_conf_from_attrs_for_change(new_net_conf, info); 24628c2ecf20Sopenharmony_ci if (err && err != -ENOMSG) { 24638c2ecf20Sopenharmony_ci retcode = ERR_MANDATORY_TAG; 24648c2ecf20Sopenharmony_ci drbd_msg_put_info(adm_ctx.reply_skb, from_attrs_err_to_txt(err)); 24658c2ecf20Sopenharmony_ci goto fail; 24668c2ecf20Sopenharmony_ci } 24678c2ecf20Sopenharmony_ci 24688c2ecf20Sopenharmony_ci retcode = check_net_options(connection, new_net_conf); 24698c2ecf20Sopenharmony_ci if (retcode != NO_ERROR) 24708c2ecf20Sopenharmony_ci goto fail; 24718c2ecf20Sopenharmony_ci 24728c2ecf20Sopenharmony_ci /* re-sync running */ 24738c2ecf20Sopenharmony_ci rsr = conn_resync_running(connection); 24748c2ecf20Sopenharmony_ci if (rsr && strcmp(new_net_conf->csums_alg, old_net_conf->csums_alg)) { 24758c2ecf20Sopenharmony_ci retcode = ERR_CSUMS_RESYNC_RUNNING; 24768c2ecf20Sopenharmony_ci goto fail; 24778c2ecf20Sopenharmony_ci } 24788c2ecf20Sopenharmony_ci 24798c2ecf20Sopenharmony_ci /* online verify running */ 24808c2ecf20Sopenharmony_ci ovr = conn_ov_running(connection); 24818c2ecf20Sopenharmony_ci if (ovr && strcmp(new_net_conf->verify_alg, old_net_conf->verify_alg)) { 24828c2ecf20Sopenharmony_ci retcode = ERR_VERIFY_RUNNING; 24838c2ecf20Sopenharmony_ci goto fail; 24848c2ecf20Sopenharmony_ci } 24858c2ecf20Sopenharmony_ci 24868c2ecf20Sopenharmony_ci retcode = alloc_crypto(&crypto, new_net_conf); 24878c2ecf20Sopenharmony_ci if (retcode != NO_ERROR) 24888c2ecf20Sopenharmony_ci goto fail; 24898c2ecf20Sopenharmony_ci 24908c2ecf20Sopenharmony_ci rcu_assign_pointer(connection->net_conf, new_net_conf); 24918c2ecf20Sopenharmony_ci 24928c2ecf20Sopenharmony_ci if (!rsr) { 24938c2ecf20Sopenharmony_ci crypto_free_shash(connection->csums_tfm); 24948c2ecf20Sopenharmony_ci connection->csums_tfm = crypto.csums_tfm; 24958c2ecf20Sopenharmony_ci crypto.csums_tfm = NULL; 24968c2ecf20Sopenharmony_ci } 24978c2ecf20Sopenharmony_ci if (!ovr) { 24988c2ecf20Sopenharmony_ci crypto_free_shash(connection->verify_tfm); 24998c2ecf20Sopenharmony_ci connection->verify_tfm = crypto.verify_tfm; 25008c2ecf20Sopenharmony_ci crypto.verify_tfm = NULL; 25018c2ecf20Sopenharmony_ci } 25028c2ecf20Sopenharmony_ci 25038c2ecf20Sopenharmony_ci crypto_free_shash(connection->integrity_tfm); 25048c2ecf20Sopenharmony_ci connection->integrity_tfm = crypto.integrity_tfm; 25058c2ecf20Sopenharmony_ci if (connection->cstate >= C_WF_REPORT_PARAMS && connection->agreed_pro_version >= 100) 25068c2ecf20Sopenharmony_ci /* Do this without trying to take connection->data.mutex again. */ 25078c2ecf20Sopenharmony_ci __drbd_send_protocol(connection, P_PROTOCOL_UPDATE); 25088c2ecf20Sopenharmony_ci 25098c2ecf20Sopenharmony_ci crypto_free_shash(connection->cram_hmac_tfm); 25108c2ecf20Sopenharmony_ci connection->cram_hmac_tfm = crypto.cram_hmac_tfm; 25118c2ecf20Sopenharmony_ci 25128c2ecf20Sopenharmony_ci mutex_unlock(&connection->resource->conf_update); 25138c2ecf20Sopenharmony_ci mutex_unlock(&connection->data.mutex); 25148c2ecf20Sopenharmony_ci synchronize_rcu(); 25158c2ecf20Sopenharmony_ci kfree(old_net_conf); 25168c2ecf20Sopenharmony_ci 25178c2ecf20Sopenharmony_ci if (connection->cstate >= C_WF_REPORT_PARAMS) { 25188c2ecf20Sopenharmony_ci struct drbd_peer_device *peer_device; 25198c2ecf20Sopenharmony_ci int vnr; 25208c2ecf20Sopenharmony_ci 25218c2ecf20Sopenharmony_ci idr_for_each_entry(&connection->peer_devices, peer_device, vnr) 25228c2ecf20Sopenharmony_ci drbd_send_sync_param(peer_device); 25238c2ecf20Sopenharmony_ci } 25248c2ecf20Sopenharmony_ci 25258c2ecf20Sopenharmony_ci goto done; 25268c2ecf20Sopenharmony_ci 25278c2ecf20Sopenharmony_ci fail: 25288c2ecf20Sopenharmony_ci mutex_unlock(&connection->resource->conf_update); 25298c2ecf20Sopenharmony_ci mutex_unlock(&connection->data.mutex); 25308c2ecf20Sopenharmony_ci free_crypto(&crypto); 25318c2ecf20Sopenharmony_ci kfree(new_net_conf); 25328c2ecf20Sopenharmony_ci done: 25338c2ecf20Sopenharmony_ci conn_reconfig_done(connection); 25348c2ecf20Sopenharmony_ci out: 25358c2ecf20Sopenharmony_ci mutex_unlock(&adm_ctx.resource->adm_mutex); 25368c2ecf20Sopenharmony_ci finish: 25378c2ecf20Sopenharmony_ci drbd_adm_finish(&adm_ctx, info, retcode); 25388c2ecf20Sopenharmony_ci return 0; 25398c2ecf20Sopenharmony_ci} 25408c2ecf20Sopenharmony_ci 25418c2ecf20Sopenharmony_cistatic void connection_to_info(struct connection_info *info, 25428c2ecf20Sopenharmony_ci struct drbd_connection *connection) 25438c2ecf20Sopenharmony_ci{ 25448c2ecf20Sopenharmony_ci info->conn_connection_state = connection->cstate; 25458c2ecf20Sopenharmony_ci info->conn_role = conn_highest_peer(connection); 25468c2ecf20Sopenharmony_ci} 25478c2ecf20Sopenharmony_ci 25488c2ecf20Sopenharmony_cistatic void peer_device_to_info(struct peer_device_info *info, 25498c2ecf20Sopenharmony_ci struct drbd_peer_device *peer_device) 25508c2ecf20Sopenharmony_ci{ 25518c2ecf20Sopenharmony_ci struct drbd_device *device = peer_device->device; 25528c2ecf20Sopenharmony_ci 25538c2ecf20Sopenharmony_ci info->peer_repl_state = 25548c2ecf20Sopenharmony_ci max_t(enum drbd_conns, C_WF_REPORT_PARAMS, device->state.conn); 25558c2ecf20Sopenharmony_ci info->peer_disk_state = device->state.pdsk; 25568c2ecf20Sopenharmony_ci info->peer_resync_susp_user = device->state.user_isp; 25578c2ecf20Sopenharmony_ci info->peer_resync_susp_peer = device->state.peer_isp; 25588c2ecf20Sopenharmony_ci info->peer_resync_susp_dependency = device->state.aftr_isp; 25598c2ecf20Sopenharmony_ci} 25608c2ecf20Sopenharmony_ci 25618c2ecf20Sopenharmony_ciint drbd_adm_connect(struct sk_buff *skb, struct genl_info *info) 25628c2ecf20Sopenharmony_ci{ 25638c2ecf20Sopenharmony_ci struct connection_info connection_info; 25648c2ecf20Sopenharmony_ci enum drbd_notification_type flags; 25658c2ecf20Sopenharmony_ci unsigned int peer_devices = 0; 25668c2ecf20Sopenharmony_ci struct drbd_config_context adm_ctx; 25678c2ecf20Sopenharmony_ci struct drbd_peer_device *peer_device; 25688c2ecf20Sopenharmony_ci struct net_conf *old_net_conf, *new_net_conf = NULL; 25698c2ecf20Sopenharmony_ci struct crypto crypto = { }; 25708c2ecf20Sopenharmony_ci struct drbd_resource *resource; 25718c2ecf20Sopenharmony_ci struct drbd_connection *connection; 25728c2ecf20Sopenharmony_ci enum drbd_ret_code retcode; 25738c2ecf20Sopenharmony_ci int i; 25748c2ecf20Sopenharmony_ci int err; 25758c2ecf20Sopenharmony_ci 25768c2ecf20Sopenharmony_ci retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_RESOURCE); 25778c2ecf20Sopenharmony_ci 25788c2ecf20Sopenharmony_ci if (!adm_ctx.reply_skb) 25798c2ecf20Sopenharmony_ci return retcode; 25808c2ecf20Sopenharmony_ci if (retcode != NO_ERROR) 25818c2ecf20Sopenharmony_ci goto out; 25828c2ecf20Sopenharmony_ci if (!(adm_ctx.my_addr && adm_ctx.peer_addr)) { 25838c2ecf20Sopenharmony_ci drbd_msg_put_info(adm_ctx.reply_skb, "connection endpoint(s) missing"); 25848c2ecf20Sopenharmony_ci retcode = ERR_INVALID_REQUEST; 25858c2ecf20Sopenharmony_ci goto out; 25868c2ecf20Sopenharmony_ci } 25878c2ecf20Sopenharmony_ci 25888c2ecf20Sopenharmony_ci /* No need for _rcu here. All reconfiguration is 25898c2ecf20Sopenharmony_ci * strictly serialized on genl_lock(). We are protected against 25908c2ecf20Sopenharmony_ci * concurrent reconfiguration/addition/deletion */ 25918c2ecf20Sopenharmony_ci for_each_resource(resource, &drbd_resources) { 25928c2ecf20Sopenharmony_ci for_each_connection(connection, resource) { 25938c2ecf20Sopenharmony_ci if (nla_len(adm_ctx.my_addr) == connection->my_addr_len && 25948c2ecf20Sopenharmony_ci !memcmp(nla_data(adm_ctx.my_addr), &connection->my_addr, 25958c2ecf20Sopenharmony_ci connection->my_addr_len)) { 25968c2ecf20Sopenharmony_ci retcode = ERR_LOCAL_ADDR; 25978c2ecf20Sopenharmony_ci goto out; 25988c2ecf20Sopenharmony_ci } 25998c2ecf20Sopenharmony_ci 26008c2ecf20Sopenharmony_ci if (nla_len(adm_ctx.peer_addr) == connection->peer_addr_len && 26018c2ecf20Sopenharmony_ci !memcmp(nla_data(adm_ctx.peer_addr), &connection->peer_addr, 26028c2ecf20Sopenharmony_ci connection->peer_addr_len)) { 26038c2ecf20Sopenharmony_ci retcode = ERR_PEER_ADDR; 26048c2ecf20Sopenharmony_ci goto out; 26058c2ecf20Sopenharmony_ci } 26068c2ecf20Sopenharmony_ci } 26078c2ecf20Sopenharmony_ci } 26088c2ecf20Sopenharmony_ci 26098c2ecf20Sopenharmony_ci mutex_lock(&adm_ctx.resource->adm_mutex); 26108c2ecf20Sopenharmony_ci connection = first_connection(adm_ctx.resource); 26118c2ecf20Sopenharmony_ci conn_reconfig_start(connection); 26128c2ecf20Sopenharmony_ci 26138c2ecf20Sopenharmony_ci if (connection->cstate > C_STANDALONE) { 26148c2ecf20Sopenharmony_ci retcode = ERR_NET_CONFIGURED; 26158c2ecf20Sopenharmony_ci goto fail; 26168c2ecf20Sopenharmony_ci } 26178c2ecf20Sopenharmony_ci 26188c2ecf20Sopenharmony_ci /* allocation not in the IO path, drbdsetup / netlink process context */ 26198c2ecf20Sopenharmony_ci new_net_conf = kzalloc(sizeof(*new_net_conf), GFP_KERNEL); 26208c2ecf20Sopenharmony_ci if (!new_net_conf) { 26218c2ecf20Sopenharmony_ci retcode = ERR_NOMEM; 26228c2ecf20Sopenharmony_ci goto fail; 26238c2ecf20Sopenharmony_ci } 26248c2ecf20Sopenharmony_ci 26258c2ecf20Sopenharmony_ci set_net_conf_defaults(new_net_conf); 26268c2ecf20Sopenharmony_ci 26278c2ecf20Sopenharmony_ci err = net_conf_from_attrs(new_net_conf, info); 26288c2ecf20Sopenharmony_ci if (err && err != -ENOMSG) { 26298c2ecf20Sopenharmony_ci retcode = ERR_MANDATORY_TAG; 26308c2ecf20Sopenharmony_ci drbd_msg_put_info(adm_ctx.reply_skb, from_attrs_err_to_txt(err)); 26318c2ecf20Sopenharmony_ci goto fail; 26328c2ecf20Sopenharmony_ci } 26338c2ecf20Sopenharmony_ci 26348c2ecf20Sopenharmony_ci retcode = check_net_options(connection, new_net_conf); 26358c2ecf20Sopenharmony_ci if (retcode != NO_ERROR) 26368c2ecf20Sopenharmony_ci goto fail; 26378c2ecf20Sopenharmony_ci 26388c2ecf20Sopenharmony_ci retcode = alloc_crypto(&crypto, new_net_conf); 26398c2ecf20Sopenharmony_ci if (retcode != NO_ERROR) 26408c2ecf20Sopenharmony_ci goto fail; 26418c2ecf20Sopenharmony_ci 26428c2ecf20Sopenharmony_ci ((char *)new_net_conf->shared_secret)[SHARED_SECRET_MAX-1] = 0; 26438c2ecf20Sopenharmony_ci 26448c2ecf20Sopenharmony_ci drbd_flush_workqueue(&connection->sender_work); 26458c2ecf20Sopenharmony_ci 26468c2ecf20Sopenharmony_ci mutex_lock(&adm_ctx.resource->conf_update); 26478c2ecf20Sopenharmony_ci old_net_conf = connection->net_conf; 26488c2ecf20Sopenharmony_ci if (old_net_conf) { 26498c2ecf20Sopenharmony_ci retcode = ERR_NET_CONFIGURED; 26508c2ecf20Sopenharmony_ci mutex_unlock(&adm_ctx.resource->conf_update); 26518c2ecf20Sopenharmony_ci goto fail; 26528c2ecf20Sopenharmony_ci } 26538c2ecf20Sopenharmony_ci rcu_assign_pointer(connection->net_conf, new_net_conf); 26548c2ecf20Sopenharmony_ci 26558c2ecf20Sopenharmony_ci conn_free_crypto(connection); 26568c2ecf20Sopenharmony_ci connection->cram_hmac_tfm = crypto.cram_hmac_tfm; 26578c2ecf20Sopenharmony_ci connection->integrity_tfm = crypto.integrity_tfm; 26588c2ecf20Sopenharmony_ci connection->csums_tfm = crypto.csums_tfm; 26598c2ecf20Sopenharmony_ci connection->verify_tfm = crypto.verify_tfm; 26608c2ecf20Sopenharmony_ci 26618c2ecf20Sopenharmony_ci connection->my_addr_len = nla_len(adm_ctx.my_addr); 26628c2ecf20Sopenharmony_ci memcpy(&connection->my_addr, nla_data(adm_ctx.my_addr), connection->my_addr_len); 26638c2ecf20Sopenharmony_ci connection->peer_addr_len = nla_len(adm_ctx.peer_addr); 26648c2ecf20Sopenharmony_ci memcpy(&connection->peer_addr, nla_data(adm_ctx.peer_addr), connection->peer_addr_len); 26658c2ecf20Sopenharmony_ci 26668c2ecf20Sopenharmony_ci idr_for_each_entry(&connection->peer_devices, peer_device, i) { 26678c2ecf20Sopenharmony_ci peer_devices++; 26688c2ecf20Sopenharmony_ci } 26698c2ecf20Sopenharmony_ci 26708c2ecf20Sopenharmony_ci connection_to_info(&connection_info, connection); 26718c2ecf20Sopenharmony_ci flags = (peer_devices--) ? NOTIFY_CONTINUES : 0; 26728c2ecf20Sopenharmony_ci mutex_lock(¬ification_mutex); 26738c2ecf20Sopenharmony_ci notify_connection_state(NULL, 0, connection, &connection_info, NOTIFY_CREATE | flags); 26748c2ecf20Sopenharmony_ci idr_for_each_entry(&connection->peer_devices, peer_device, i) { 26758c2ecf20Sopenharmony_ci struct peer_device_info peer_device_info; 26768c2ecf20Sopenharmony_ci 26778c2ecf20Sopenharmony_ci peer_device_to_info(&peer_device_info, peer_device); 26788c2ecf20Sopenharmony_ci flags = (peer_devices--) ? NOTIFY_CONTINUES : 0; 26798c2ecf20Sopenharmony_ci notify_peer_device_state(NULL, 0, peer_device, &peer_device_info, NOTIFY_CREATE | flags); 26808c2ecf20Sopenharmony_ci } 26818c2ecf20Sopenharmony_ci mutex_unlock(¬ification_mutex); 26828c2ecf20Sopenharmony_ci mutex_unlock(&adm_ctx.resource->conf_update); 26838c2ecf20Sopenharmony_ci 26848c2ecf20Sopenharmony_ci rcu_read_lock(); 26858c2ecf20Sopenharmony_ci idr_for_each_entry(&connection->peer_devices, peer_device, i) { 26868c2ecf20Sopenharmony_ci struct drbd_device *device = peer_device->device; 26878c2ecf20Sopenharmony_ci device->send_cnt = 0; 26888c2ecf20Sopenharmony_ci device->recv_cnt = 0; 26898c2ecf20Sopenharmony_ci } 26908c2ecf20Sopenharmony_ci rcu_read_unlock(); 26918c2ecf20Sopenharmony_ci 26928c2ecf20Sopenharmony_ci retcode = (enum drbd_ret_code)conn_request_state(connection, 26938c2ecf20Sopenharmony_ci NS(conn, C_UNCONNECTED), CS_VERBOSE); 26948c2ecf20Sopenharmony_ci 26958c2ecf20Sopenharmony_ci conn_reconfig_done(connection); 26968c2ecf20Sopenharmony_ci mutex_unlock(&adm_ctx.resource->adm_mutex); 26978c2ecf20Sopenharmony_ci drbd_adm_finish(&adm_ctx, info, retcode); 26988c2ecf20Sopenharmony_ci return 0; 26998c2ecf20Sopenharmony_ci 27008c2ecf20Sopenharmony_cifail: 27018c2ecf20Sopenharmony_ci free_crypto(&crypto); 27028c2ecf20Sopenharmony_ci kfree(new_net_conf); 27038c2ecf20Sopenharmony_ci 27048c2ecf20Sopenharmony_ci conn_reconfig_done(connection); 27058c2ecf20Sopenharmony_ci mutex_unlock(&adm_ctx.resource->adm_mutex); 27068c2ecf20Sopenharmony_ciout: 27078c2ecf20Sopenharmony_ci drbd_adm_finish(&adm_ctx, info, retcode); 27088c2ecf20Sopenharmony_ci return 0; 27098c2ecf20Sopenharmony_ci} 27108c2ecf20Sopenharmony_ci 27118c2ecf20Sopenharmony_cistatic enum drbd_state_rv conn_try_disconnect(struct drbd_connection *connection, bool force) 27128c2ecf20Sopenharmony_ci{ 27138c2ecf20Sopenharmony_ci enum drbd_conns cstate; 27148c2ecf20Sopenharmony_ci enum drbd_state_rv rv; 27158c2ecf20Sopenharmony_ci 27168c2ecf20Sopenharmony_cirepeat: 27178c2ecf20Sopenharmony_ci rv = conn_request_state(connection, NS(conn, C_DISCONNECTING), 27188c2ecf20Sopenharmony_ci force ? CS_HARD : 0); 27198c2ecf20Sopenharmony_ci 27208c2ecf20Sopenharmony_ci switch (rv) { 27218c2ecf20Sopenharmony_ci case SS_NOTHING_TO_DO: 27228c2ecf20Sopenharmony_ci break; 27238c2ecf20Sopenharmony_ci case SS_ALREADY_STANDALONE: 27248c2ecf20Sopenharmony_ci return SS_SUCCESS; 27258c2ecf20Sopenharmony_ci case SS_PRIMARY_NOP: 27268c2ecf20Sopenharmony_ci /* Our state checking code wants to see the peer outdated. */ 27278c2ecf20Sopenharmony_ci rv = conn_request_state(connection, NS2(conn, C_DISCONNECTING, pdsk, D_OUTDATED), 0); 27288c2ecf20Sopenharmony_ci 27298c2ecf20Sopenharmony_ci if (rv == SS_OUTDATE_WO_CONN) /* lost connection before graceful disconnect succeeded */ 27308c2ecf20Sopenharmony_ci rv = conn_request_state(connection, NS(conn, C_DISCONNECTING), CS_VERBOSE); 27318c2ecf20Sopenharmony_ci 27328c2ecf20Sopenharmony_ci break; 27338c2ecf20Sopenharmony_ci case SS_CW_FAILED_BY_PEER: 27348c2ecf20Sopenharmony_ci spin_lock_irq(&connection->resource->req_lock); 27358c2ecf20Sopenharmony_ci cstate = connection->cstate; 27368c2ecf20Sopenharmony_ci spin_unlock_irq(&connection->resource->req_lock); 27378c2ecf20Sopenharmony_ci if (cstate <= C_WF_CONNECTION) 27388c2ecf20Sopenharmony_ci goto repeat; 27398c2ecf20Sopenharmony_ci /* The peer probably wants to see us outdated. */ 27408c2ecf20Sopenharmony_ci rv = conn_request_state(connection, NS2(conn, C_DISCONNECTING, 27418c2ecf20Sopenharmony_ci disk, D_OUTDATED), 0); 27428c2ecf20Sopenharmony_ci if (rv == SS_IS_DISKLESS || rv == SS_LOWER_THAN_OUTDATED) { 27438c2ecf20Sopenharmony_ci rv = conn_request_state(connection, NS(conn, C_DISCONNECTING), 27448c2ecf20Sopenharmony_ci CS_HARD); 27458c2ecf20Sopenharmony_ci } 27468c2ecf20Sopenharmony_ci break; 27478c2ecf20Sopenharmony_ci default:; 27488c2ecf20Sopenharmony_ci /* no special handling necessary */ 27498c2ecf20Sopenharmony_ci } 27508c2ecf20Sopenharmony_ci 27518c2ecf20Sopenharmony_ci if (rv >= SS_SUCCESS) { 27528c2ecf20Sopenharmony_ci enum drbd_state_rv rv2; 27538c2ecf20Sopenharmony_ci /* No one else can reconfigure the network while I am here. 27548c2ecf20Sopenharmony_ci * The state handling only uses drbd_thread_stop_nowait(), 27558c2ecf20Sopenharmony_ci * we want to really wait here until the receiver is no more. 27568c2ecf20Sopenharmony_ci */ 27578c2ecf20Sopenharmony_ci drbd_thread_stop(&connection->receiver); 27588c2ecf20Sopenharmony_ci 27598c2ecf20Sopenharmony_ci /* Race breaker. This additional state change request may be 27608c2ecf20Sopenharmony_ci * necessary, if this was a forced disconnect during a receiver 27618c2ecf20Sopenharmony_ci * restart. We may have "killed" the receiver thread just 27628c2ecf20Sopenharmony_ci * after drbd_receiver() returned. Typically, we should be 27638c2ecf20Sopenharmony_ci * C_STANDALONE already, now, and this becomes a no-op. 27648c2ecf20Sopenharmony_ci */ 27658c2ecf20Sopenharmony_ci rv2 = conn_request_state(connection, NS(conn, C_STANDALONE), 27668c2ecf20Sopenharmony_ci CS_VERBOSE | CS_HARD); 27678c2ecf20Sopenharmony_ci if (rv2 < SS_SUCCESS) 27688c2ecf20Sopenharmony_ci drbd_err(connection, 27698c2ecf20Sopenharmony_ci "unexpected rv2=%d in conn_try_disconnect()\n", 27708c2ecf20Sopenharmony_ci rv2); 27718c2ecf20Sopenharmony_ci /* Unlike in DRBD 9, the state engine has generated 27728c2ecf20Sopenharmony_ci * NOTIFY_DESTROY events before clearing connection->net_conf. */ 27738c2ecf20Sopenharmony_ci } 27748c2ecf20Sopenharmony_ci return rv; 27758c2ecf20Sopenharmony_ci} 27768c2ecf20Sopenharmony_ci 27778c2ecf20Sopenharmony_ciint drbd_adm_disconnect(struct sk_buff *skb, struct genl_info *info) 27788c2ecf20Sopenharmony_ci{ 27798c2ecf20Sopenharmony_ci struct drbd_config_context adm_ctx; 27808c2ecf20Sopenharmony_ci struct disconnect_parms parms; 27818c2ecf20Sopenharmony_ci struct drbd_connection *connection; 27828c2ecf20Sopenharmony_ci enum drbd_state_rv rv; 27838c2ecf20Sopenharmony_ci enum drbd_ret_code retcode; 27848c2ecf20Sopenharmony_ci int err; 27858c2ecf20Sopenharmony_ci 27868c2ecf20Sopenharmony_ci retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_CONNECTION); 27878c2ecf20Sopenharmony_ci if (!adm_ctx.reply_skb) 27888c2ecf20Sopenharmony_ci return retcode; 27898c2ecf20Sopenharmony_ci if (retcode != NO_ERROR) 27908c2ecf20Sopenharmony_ci goto fail; 27918c2ecf20Sopenharmony_ci 27928c2ecf20Sopenharmony_ci connection = adm_ctx.connection; 27938c2ecf20Sopenharmony_ci memset(&parms, 0, sizeof(parms)); 27948c2ecf20Sopenharmony_ci if (info->attrs[DRBD_NLA_DISCONNECT_PARMS]) { 27958c2ecf20Sopenharmony_ci err = disconnect_parms_from_attrs(&parms, info); 27968c2ecf20Sopenharmony_ci if (err) { 27978c2ecf20Sopenharmony_ci retcode = ERR_MANDATORY_TAG; 27988c2ecf20Sopenharmony_ci drbd_msg_put_info(adm_ctx.reply_skb, from_attrs_err_to_txt(err)); 27998c2ecf20Sopenharmony_ci goto fail; 28008c2ecf20Sopenharmony_ci } 28018c2ecf20Sopenharmony_ci } 28028c2ecf20Sopenharmony_ci 28038c2ecf20Sopenharmony_ci mutex_lock(&adm_ctx.resource->adm_mutex); 28048c2ecf20Sopenharmony_ci rv = conn_try_disconnect(connection, parms.force_disconnect); 28058c2ecf20Sopenharmony_ci if (rv < SS_SUCCESS) 28068c2ecf20Sopenharmony_ci retcode = (enum drbd_ret_code)rv; 28078c2ecf20Sopenharmony_ci else 28088c2ecf20Sopenharmony_ci retcode = NO_ERROR; 28098c2ecf20Sopenharmony_ci mutex_unlock(&adm_ctx.resource->adm_mutex); 28108c2ecf20Sopenharmony_ci fail: 28118c2ecf20Sopenharmony_ci drbd_adm_finish(&adm_ctx, info, retcode); 28128c2ecf20Sopenharmony_ci return 0; 28138c2ecf20Sopenharmony_ci} 28148c2ecf20Sopenharmony_ci 28158c2ecf20Sopenharmony_civoid resync_after_online_grow(struct drbd_device *device) 28168c2ecf20Sopenharmony_ci{ 28178c2ecf20Sopenharmony_ci int iass; /* I am sync source */ 28188c2ecf20Sopenharmony_ci 28198c2ecf20Sopenharmony_ci drbd_info(device, "Resync of new storage after online grow\n"); 28208c2ecf20Sopenharmony_ci if (device->state.role != device->state.peer) 28218c2ecf20Sopenharmony_ci iass = (device->state.role == R_PRIMARY); 28228c2ecf20Sopenharmony_ci else 28238c2ecf20Sopenharmony_ci iass = test_bit(RESOLVE_CONFLICTS, &first_peer_device(device)->connection->flags); 28248c2ecf20Sopenharmony_ci 28258c2ecf20Sopenharmony_ci if (iass) 28268c2ecf20Sopenharmony_ci drbd_start_resync(device, C_SYNC_SOURCE); 28278c2ecf20Sopenharmony_ci else 28288c2ecf20Sopenharmony_ci _drbd_request_state(device, NS(conn, C_WF_SYNC_UUID), CS_VERBOSE + CS_SERIALIZE); 28298c2ecf20Sopenharmony_ci} 28308c2ecf20Sopenharmony_ci 28318c2ecf20Sopenharmony_ciint drbd_adm_resize(struct sk_buff *skb, struct genl_info *info) 28328c2ecf20Sopenharmony_ci{ 28338c2ecf20Sopenharmony_ci struct drbd_config_context adm_ctx; 28348c2ecf20Sopenharmony_ci struct disk_conf *old_disk_conf, *new_disk_conf = NULL; 28358c2ecf20Sopenharmony_ci struct resize_parms rs; 28368c2ecf20Sopenharmony_ci struct drbd_device *device; 28378c2ecf20Sopenharmony_ci enum drbd_ret_code retcode; 28388c2ecf20Sopenharmony_ci enum determine_dev_size dd; 28398c2ecf20Sopenharmony_ci bool change_al_layout = false; 28408c2ecf20Sopenharmony_ci enum dds_flags ddsf; 28418c2ecf20Sopenharmony_ci sector_t u_size; 28428c2ecf20Sopenharmony_ci int err; 28438c2ecf20Sopenharmony_ci 28448c2ecf20Sopenharmony_ci retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_MINOR); 28458c2ecf20Sopenharmony_ci if (!adm_ctx.reply_skb) 28468c2ecf20Sopenharmony_ci return retcode; 28478c2ecf20Sopenharmony_ci if (retcode != NO_ERROR) 28488c2ecf20Sopenharmony_ci goto finish; 28498c2ecf20Sopenharmony_ci 28508c2ecf20Sopenharmony_ci mutex_lock(&adm_ctx.resource->adm_mutex); 28518c2ecf20Sopenharmony_ci device = adm_ctx.device; 28528c2ecf20Sopenharmony_ci if (!get_ldev(device)) { 28538c2ecf20Sopenharmony_ci retcode = ERR_NO_DISK; 28548c2ecf20Sopenharmony_ci goto fail; 28558c2ecf20Sopenharmony_ci } 28568c2ecf20Sopenharmony_ci 28578c2ecf20Sopenharmony_ci memset(&rs, 0, sizeof(struct resize_parms)); 28588c2ecf20Sopenharmony_ci rs.al_stripes = device->ldev->md.al_stripes; 28598c2ecf20Sopenharmony_ci rs.al_stripe_size = device->ldev->md.al_stripe_size_4k * 4; 28608c2ecf20Sopenharmony_ci if (info->attrs[DRBD_NLA_RESIZE_PARMS]) { 28618c2ecf20Sopenharmony_ci err = resize_parms_from_attrs(&rs, info); 28628c2ecf20Sopenharmony_ci if (err) { 28638c2ecf20Sopenharmony_ci retcode = ERR_MANDATORY_TAG; 28648c2ecf20Sopenharmony_ci drbd_msg_put_info(adm_ctx.reply_skb, from_attrs_err_to_txt(err)); 28658c2ecf20Sopenharmony_ci goto fail_ldev; 28668c2ecf20Sopenharmony_ci } 28678c2ecf20Sopenharmony_ci } 28688c2ecf20Sopenharmony_ci 28698c2ecf20Sopenharmony_ci if (device->state.conn > C_CONNECTED) { 28708c2ecf20Sopenharmony_ci retcode = ERR_RESIZE_RESYNC; 28718c2ecf20Sopenharmony_ci goto fail_ldev; 28728c2ecf20Sopenharmony_ci } 28738c2ecf20Sopenharmony_ci 28748c2ecf20Sopenharmony_ci if (device->state.role == R_SECONDARY && 28758c2ecf20Sopenharmony_ci device->state.peer == R_SECONDARY) { 28768c2ecf20Sopenharmony_ci retcode = ERR_NO_PRIMARY; 28778c2ecf20Sopenharmony_ci goto fail_ldev; 28788c2ecf20Sopenharmony_ci } 28798c2ecf20Sopenharmony_ci 28808c2ecf20Sopenharmony_ci if (rs.no_resync && first_peer_device(device)->connection->agreed_pro_version < 93) { 28818c2ecf20Sopenharmony_ci retcode = ERR_NEED_APV_93; 28828c2ecf20Sopenharmony_ci goto fail_ldev; 28838c2ecf20Sopenharmony_ci } 28848c2ecf20Sopenharmony_ci 28858c2ecf20Sopenharmony_ci rcu_read_lock(); 28868c2ecf20Sopenharmony_ci u_size = rcu_dereference(device->ldev->disk_conf)->disk_size; 28878c2ecf20Sopenharmony_ci rcu_read_unlock(); 28888c2ecf20Sopenharmony_ci if (u_size != (sector_t)rs.resize_size) { 28898c2ecf20Sopenharmony_ci new_disk_conf = kmalloc(sizeof(struct disk_conf), GFP_KERNEL); 28908c2ecf20Sopenharmony_ci if (!new_disk_conf) { 28918c2ecf20Sopenharmony_ci retcode = ERR_NOMEM; 28928c2ecf20Sopenharmony_ci goto fail_ldev; 28938c2ecf20Sopenharmony_ci } 28948c2ecf20Sopenharmony_ci } 28958c2ecf20Sopenharmony_ci 28968c2ecf20Sopenharmony_ci if (device->ldev->md.al_stripes != rs.al_stripes || 28978c2ecf20Sopenharmony_ci device->ldev->md.al_stripe_size_4k != rs.al_stripe_size / 4) { 28988c2ecf20Sopenharmony_ci u32 al_size_k = rs.al_stripes * rs.al_stripe_size; 28998c2ecf20Sopenharmony_ci 29008c2ecf20Sopenharmony_ci if (al_size_k > (16 * 1024 * 1024)) { 29018c2ecf20Sopenharmony_ci retcode = ERR_MD_LAYOUT_TOO_BIG; 29028c2ecf20Sopenharmony_ci goto fail_ldev; 29038c2ecf20Sopenharmony_ci } 29048c2ecf20Sopenharmony_ci 29058c2ecf20Sopenharmony_ci if (al_size_k < MD_32kB_SECT/2) { 29068c2ecf20Sopenharmony_ci retcode = ERR_MD_LAYOUT_TOO_SMALL; 29078c2ecf20Sopenharmony_ci goto fail_ldev; 29088c2ecf20Sopenharmony_ci } 29098c2ecf20Sopenharmony_ci 29108c2ecf20Sopenharmony_ci if (device->state.conn != C_CONNECTED && !rs.resize_force) { 29118c2ecf20Sopenharmony_ci retcode = ERR_MD_LAYOUT_CONNECTED; 29128c2ecf20Sopenharmony_ci goto fail_ldev; 29138c2ecf20Sopenharmony_ci } 29148c2ecf20Sopenharmony_ci 29158c2ecf20Sopenharmony_ci change_al_layout = true; 29168c2ecf20Sopenharmony_ci } 29178c2ecf20Sopenharmony_ci 29188c2ecf20Sopenharmony_ci if (device->ldev->known_size != drbd_get_capacity(device->ldev->backing_bdev)) 29198c2ecf20Sopenharmony_ci device->ldev->known_size = drbd_get_capacity(device->ldev->backing_bdev); 29208c2ecf20Sopenharmony_ci 29218c2ecf20Sopenharmony_ci if (new_disk_conf) { 29228c2ecf20Sopenharmony_ci mutex_lock(&device->resource->conf_update); 29238c2ecf20Sopenharmony_ci old_disk_conf = device->ldev->disk_conf; 29248c2ecf20Sopenharmony_ci *new_disk_conf = *old_disk_conf; 29258c2ecf20Sopenharmony_ci new_disk_conf->disk_size = (sector_t)rs.resize_size; 29268c2ecf20Sopenharmony_ci rcu_assign_pointer(device->ldev->disk_conf, new_disk_conf); 29278c2ecf20Sopenharmony_ci mutex_unlock(&device->resource->conf_update); 29288c2ecf20Sopenharmony_ci synchronize_rcu(); 29298c2ecf20Sopenharmony_ci kfree(old_disk_conf); 29308c2ecf20Sopenharmony_ci new_disk_conf = NULL; 29318c2ecf20Sopenharmony_ci } 29328c2ecf20Sopenharmony_ci 29338c2ecf20Sopenharmony_ci ddsf = (rs.resize_force ? DDSF_FORCED : 0) | (rs.no_resync ? DDSF_NO_RESYNC : 0); 29348c2ecf20Sopenharmony_ci dd = drbd_determine_dev_size(device, ddsf, change_al_layout ? &rs : NULL); 29358c2ecf20Sopenharmony_ci drbd_md_sync(device); 29368c2ecf20Sopenharmony_ci put_ldev(device); 29378c2ecf20Sopenharmony_ci if (dd == DS_ERROR) { 29388c2ecf20Sopenharmony_ci retcode = ERR_NOMEM_BITMAP; 29398c2ecf20Sopenharmony_ci goto fail; 29408c2ecf20Sopenharmony_ci } else if (dd == DS_ERROR_SPACE_MD) { 29418c2ecf20Sopenharmony_ci retcode = ERR_MD_LAYOUT_NO_FIT; 29428c2ecf20Sopenharmony_ci goto fail; 29438c2ecf20Sopenharmony_ci } else if (dd == DS_ERROR_SHRINK) { 29448c2ecf20Sopenharmony_ci retcode = ERR_IMPLICIT_SHRINK; 29458c2ecf20Sopenharmony_ci goto fail; 29468c2ecf20Sopenharmony_ci } 29478c2ecf20Sopenharmony_ci 29488c2ecf20Sopenharmony_ci if (device->state.conn == C_CONNECTED) { 29498c2ecf20Sopenharmony_ci if (dd == DS_GREW) 29508c2ecf20Sopenharmony_ci set_bit(RESIZE_PENDING, &device->flags); 29518c2ecf20Sopenharmony_ci 29528c2ecf20Sopenharmony_ci drbd_send_uuids(first_peer_device(device)); 29538c2ecf20Sopenharmony_ci drbd_send_sizes(first_peer_device(device), 1, ddsf); 29548c2ecf20Sopenharmony_ci } 29558c2ecf20Sopenharmony_ci 29568c2ecf20Sopenharmony_ci fail: 29578c2ecf20Sopenharmony_ci mutex_unlock(&adm_ctx.resource->adm_mutex); 29588c2ecf20Sopenharmony_ci finish: 29598c2ecf20Sopenharmony_ci drbd_adm_finish(&adm_ctx, info, retcode); 29608c2ecf20Sopenharmony_ci return 0; 29618c2ecf20Sopenharmony_ci 29628c2ecf20Sopenharmony_ci fail_ldev: 29638c2ecf20Sopenharmony_ci put_ldev(device); 29648c2ecf20Sopenharmony_ci kfree(new_disk_conf); 29658c2ecf20Sopenharmony_ci goto fail; 29668c2ecf20Sopenharmony_ci} 29678c2ecf20Sopenharmony_ci 29688c2ecf20Sopenharmony_ciint drbd_adm_resource_opts(struct sk_buff *skb, struct genl_info *info) 29698c2ecf20Sopenharmony_ci{ 29708c2ecf20Sopenharmony_ci struct drbd_config_context adm_ctx; 29718c2ecf20Sopenharmony_ci enum drbd_ret_code retcode; 29728c2ecf20Sopenharmony_ci struct res_opts res_opts; 29738c2ecf20Sopenharmony_ci int err; 29748c2ecf20Sopenharmony_ci 29758c2ecf20Sopenharmony_ci retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_RESOURCE); 29768c2ecf20Sopenharmony_ci if (!adm_ctx.reply_skb) 29778c2ecf20Sopenharmony_ci return retcode; 29788c2ecf20Sopenharmony_ci if (retcode != NO_ERROR) 29798c2ecf20Sopenharmony_ci goto fail; 29808c2ecf20Sopenharmony_ci 29818c2ecf20Sopenharmony_ci res_opts = adm_ctx.resource->res_opts; 29828c2ecf20Sopenharmony_ci if (should_set_defaults(info)) 29838c2ecf20Sopenharmony_ci set_res_opts_defaults(&res_opts); 29848c2ecf20Sopenharmony_ci 29858c2ecf20Sopenharmony_ci err = res_opts_from_attrs(&res_opts, info); 29868c2ecf20Sopenharmony_ci if (err && err != -ENOMSG) { 29878c2ecf20Sopenharmony_ci retcode = ERR_MANDATORY_TAG; 29888c2ecf20Sopenharmony_ci drbd_msg_put_info(adm_ctx.reply_skb, from_attrs_err_to_txt(err)); 29898c2ecf20Sopenharmony_ci goto fail; 29908c2ecf20Sopenharmony_ci } 29918c2ecf20Sopenharmony_ci 29928c2ecf20Sopenharmony_ci mutex_lock(&adm_ctx.resource->adm_mutex); 29938c2ecf20Sopenharmony_ci err = set_resource_options(adm_ctx.resource, &res_opts); 29948c2ecf20Sopenharmony_ci if (err) { 29958c2ecf20Sopenharmony_ci retcode = ERR_INVALID_REQUEST; 29968c2ecf20Sopenharmony_ci if (err == -ENOMEM) 29978c2ecf20Sopenharmony_ci retcode = ERR_NOMEM; 29988c2ecf20Sopenharmony_ci } 29998c2ecf20Sopenharmony_ci mutex_unlock(&adm_ctx.resource->adm_mutex); 30008c2ecf20Sopenharmony_ci 30018c2ecf20Sopenharmony_cifail: 30028c2ecf20Sopenharmony_ci drbd_adm_finish(&adm_ctx, info, retcode); 30038c2ecf20Sopenharmony_ci return 0; 30048c2ecf20Sopenharmony_ci} 30058c2ecf20Sopenharmony_ci 30068c2ecf20Sopenharmony_ciint drbd_adm_invalidate(struct sk_buff *skb, struct genl_info *info) 30078c2ecf20Sopenharmony_ci{ 30088c2ecf20Sopenharmony_ci struct drbd_config_context adm_ctx; 30098c2ecf20Sopenharmony_ci struct drbd_device *device; 30108c2ecf20Sopenharmony_ci int retcode; /* enum drbd_ret_code rsp. enum drbd_state_rv */ 30118c2ecf20Sopenharmony_ci 30128c2ecf20Sopenharmony_ci retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_MINOR); 30138c2ecf20Sopenharmony_ci if (!adm_ctx.reply_skb) 30148c2ecf20Sopenharmony_ci return retcode; 30158c2ecf20Sopenharmony_ci if (retcode != NO_ERROR) 30168c2ecf20Sopenharmony_ci goto out; 30178c2ecf20Sopenharmony_ci 30188c2ecf20Sopenharmony_ci device = adm_ctx.device; 30198c2ecf20Sopenharmony_ci if (!get_ldev(device)) { 30208c2ecf20Sopenharmony_ci retcode = ERR_NO_DISK; 30218c2ecf20Sopenharmony_ci goto out; 30228c2ecf20Sopenharmony_ci } 30238c2ecf20Sopenharmony_ci 30248c2ecf20Sopenharmony_ci mutex_lock(&adm_ctx.resource->adm_mutex); 30258c2ecf20Sopenharmony_ci 30268c2ecf20Sopenharmony_ci /* If there is still bitmap IO pending, probably because of a previous 30278c2ecf20Sopenharmony_ci * resync just being finished, wait for it before requesting a new resync. 30288c2ecf20Sopenharmony_ci * Also wait for it's after_state_ch(). */ 30298c2ecf20Sopenharmony_ci drbd_suspend_io(device); 30308c2ecf20Sopenharmony_ci wait_event(device->misc_wait, !test_bit(BITMAP_IO, &device->flags)); 30318c2ecf20Sopenharmony_ci drbd_flush_workqueue(&first_peer_device(device)->connection->sender_work); 30328c2ecf20Sopenharmony_ci 30338c2ecf20Sopenharmony_ci /* If we happen to be C_STANDALONE R_SECONDARY, just change to 30348c2ecf20Sopenharmony_ci * D_INCONSISTENT, and set all bits in the bitmap. Otherwise, 30358c2ecf20Sopenharmony_ci * try to start a resync handshake as sync target for full sync. 30368c2ecf20Sopenharmony_ci */ 30378c2ecf20Sopenharmony_ci if (device->state.conn == C_STANDALONE && device->state.role == R_SECONDARY) { 30388c2ecf20Sopenharmony_ci retcode = drbd_request_state(device, NS(disk, D_INCONSISTENT)); 30398c2ecf20Sopenharmony_ci if (retcode >= SS_SUCCESS) { 30408c2ecf20Sopenharmony_ci if (drbd_bitmap_io(device, &drbd_bmio_set_n_write, 30418c2ecf20Sopenharmony_ci "set_n_write from invalidate", BM_LOCKED_MASK)) 30428c2ecf20Sopenharmony_ci retcode = ERR_IO_MD_DISK; 30438c2ecf20Sopenharmony_ci } 30448c2ecf20Sopenharmony_ci } else 30458c2ecf20Sopenharmony_ci retcode = drbd_request_state(device, NS(conn, C_STARTING_SYNC_T)); 30468c2ecf20Sopenharmony_ci drbd_resume_io(device); 30478c2ecf20Sopenharmony_ci mutex_unlock(&adm_ctx.resource->adm_mutex); 30488c2ecf20Sopenharmony_ci put_ldev(device); 30498c2ecf20Sopenharmony_ciout: 30508c2ecf20Sopenharmony_ci drbd_adm_finish(&adm_ctx, info, retcode); 30518c2ecf20Sopenharmony_ci return 0; 30528c2ecf20Sopenharmony_ci} 30538c2ecf20Sopenharmony_ci 30548c2ecf20Sopenharmony_cistatic int drbd_adm_simple_request_state(struct sk_buff *skb, struct genl_info *info, 30558c2ecf20Sopenharmony_ci union drbd_state mask, union drbd_state val) 30568c2ecf20Sopenharmony_ci{ 30578c2ecf20Sopenharmony_ci struct drbd_config_context adm_ctx; 30588c2ecf20Sopenharmony_ci enum drbd_ret_code retcode; 30598c2ecf20Sopenharmony_ci 30608c2ecf20Sopenharmony_ci retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_MINOR); 30618c2ecf20Sopenharmony_ci if (!adm_ctx.reply_skb) 30628c2ecf20Sopenharmony_ci return retcode; 30638c2ecf20Sopenharmony_ci if (retcode != NO_ERROR) 30648c2ecf20Sopenharmony_ci goto out; 30658c2ecf20Sopenharmony_ci 30668c2ecf20Sopenharmony_ci mutex_lock(&adm_ctx.resource->adm_mutex); 30678c2ecf20Sopenharmony_ci retcode = drbd_request_state(adm_ctx.device, mask, val); 30688c2ecf20Sopenharmony_ci mutex_unlock(&adm_ctx.resource->adm_mutex); 30698c2ecf20Sopenharmony_ciout: 30708c2ecf20Sopenharmony_ci drbd_adm_finish(&adm_ctx, info, retcode); 30718c2ecf20Sopenharmony_ci return 0; 30728c2ecf20Sopenharmony_ci} 30738c2ecf20Sopenharmony_ci 30748c2ecf20Sopenharmony_cistatic int drbd_bmio_set_susp_al(struct drbd_device *device) __must_hold(local) 30758c2ecf20Sopenharmony_ci{ 30768c2ecf20Sopenharmony_ci int rv; 30778c2ecf20Sopenharmony_ci 30788c2ecf20Sopenharmony_ci rv = drbd_bmio_set_n_write(device); 30798c2ecf20Sopenharmony_ci drbd_suspend_al(device); 30808c2ecf20Sopenharmony_ci return rv; 30818c2ecf20Sopenharmony_ci} 30828c2ecf20Sopenharmony_ci 30838c2ecf20Sopenharmony_ciint drbd_adm_invalidate_peer(struct sk_buff *skb, struct genl_info *info) 30848c2ecf20Sopenharmony_ci{ 30858c2ecf20Sopenharmony_ci struct drbd_config_context adm_ctx; 30868c2ecf20Sopenharmony_ci int retcode; /* drbd_ret_code, drbd_state_rv */ 30878c2ecf20Sopenharmony_ci struct drbd_device *device; 30888c2ecf20Sopenharmony_ci 30898c2ecf20Sopenharmony_ci retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_MINOR); 30908c2ecf20Sopenharmony_ci if (!adm_ctx.reply_skb) 30918c2ecf20Sopenharmony_ci return retcode; 30928c2ecf20Sopenharmony_ci if (retcode != NO_ERROR) 30938c2ecf20Sopenharmony_ci goto out; 30948c2ecf20Sopenharmony_ci 30958c2ecf20Sopenharmony_ci device = adm_ctx.device; 30968c2ecf20Sopenharmony_ci if (!get_ldev(device)) { 30978c2ecf20Sopenharmony_ci retcode = ERR_NO_DISK; 30988c2ecf20Sopenharmony_ci goto out; 30998c2ecf20Sopenharmony_ci } 31008c2ecf20Sopenharmony_ci 31018c2ecf20Sopenharmony_ci mutex_lock(&adm_ctx.resource->adm_mutex); 31028c2ecf20Sopenharmony_ci 31038c2ecf20Sopenharmony_ci /* If there is still bitmap IO pending, probably because of a previous 31048c2ecf20Sopenharmony_ci * resync just being finished, wait for it before requesting a new resync. 31058c2ecf20Sopenharmony_ci * Also wait for it's after_state_ch(). */ 31068c2ecf20Sopenharmony_ci drbd_suspend_io(device); 31078c2ecf20Sopenharmony_ci wait_event(device->misc_wait, !test_bit(BITMAP_IO, &device->flags)); 31088c2ecf20Sopenharmony_ci drbd_flush_workqueue(&first_peer_device(device)->connection->sender_work); 31098c2ecf20Sopenharmony_ci 31108c2ecf20Sopenharmony_ci /* If we happen to be C_STANDALONE R_PRIMARY, just set all bits 31118c2ecf20Sopenharmony_ci * in the bitmap. Otherwise, try to start a resync handshake 31128c2ecf20Sopenharmony_ci * as sync source for full sync. 31138c2ecf20Sopenharmony_ci */ 31148c2ecf20Sopenharmony_ci if (device->state.conn == C_STANDALONE && device->state.role == R_PRIMARY) { 31158c2ecf20Sopenharmony_ci /* The peer will get a resync upon connect anyways. Just make that 31168c2ecf20Sopenharmony_ci into a full resync. */ 31178c2ecf20Sopenharmony_ci retcode = drbd_request_state(device, NS(pdsk, D_INCONSISTENT)); 31188c2ecf20Sopenharmony_ci if (retcode >= SS_SUCCESS) { 31198c2ecf20Sopenharmony_ci if (drbd_bitmap_io(device, &drbd_bmio_set_susp_al, 31208c2ecf20Sopenharmony_ci "set_n_write from invalidate_peer", 31218c2ecf20Sopenharmony_ci BM_LOCKED_SET_ALLOWED)) 31228c2ecf20Sopenharmony_ci retcode = ERR_IO_MD_DISK; 31238c2ecf20Sopenharmony_ci } 31248c2ecf20Sopenharmony_ci } else 31258c2ecf20Sopenharmony_ci retcode = drbd_request_state(device, NS(conn, C_STARTING_SYNC_S)); 31268c2ecf20Sopenharmony_ci drbd_resume_io(device); 31278c2ecf20Sopenharmony_ci mutex_unlock(&adm_ctx.resource->adm_mutex); 31288c2ecf20Sopenharmony_ci put_ldev(device); 31298c2ecf20Sopenharmony_ciout: 31308c2ecf20Sopenharmony_ci drbd_adm_finish(&adm_ctx, info, retcode); 31318c2ecf20Sopenharmony_ci return 0; 31328c2ecf20Sopenharmony_ci} 31338c2ecf20Sopenharmony_ci 31348c2ecf20Sopenharmony_ciint drbd_adm_pause_sync(struct sk_buff *skb, struct genl_info *info) 31358c2ecf20Sopenharmony_ci{ 31368c2ecf20Sopenharmony_ci struct drbd_config_context adm_ctx; 31378c2ecf20Sopenharmony_ci enum drbd_ret_code retcode; 31388c2ecf20Sopenharmony_ci 31398c2ecf20Sopenharmony_ci retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_MINOR); 31408c2ecf20Sopenharmony_ci if (!adm_ctx.reply_skb) 31418c2ecf20Sopenharmony_ci return retcode; 31428c2ecf20Sopenharmony_ci if (retcode != NO_ERROR) 31438c2ecf20Sopenharmony_ci goto out; 31448c2ecf20Sopenharmony_ci 31458c2ecf20Sopenharmony_ci mutex_lock(&adm_ctx.resource->adm_mutex); 31468c2ecf20Sopenharmony_ci if (drbd_request_state(adm_ctx.device, NS(user_isp, 1)) == SS_NOTHING_TO_DO) 31478c2ecf20Sopenharmony_ci retcode = ERR_PAUSE_IS_SET; 31488c2ecf20Sopenharmony_ci mutex_unlock(&adm_ctx.resource->adm_mutex); 31498c2ecf20Sopenharmony_ciout: 31508c2ecf20Sopenharmony_ci drbd_adm_finish(&adm_ctx, info, retcode); 31518c2ecf20Sopenharmony_ci return 0; 31528c2ecf20Sopenharmony_ci} 31538c2ecf20Sopenharmony_ci 31548c2ecf20Sopenharmony_ciint drbd_adm_resume_sync(struct sk_buff *skb, struct genl_info *info) 31558c2ecf20Sopenharmony_ci{ 31568c2ecf20Sopenharmony_ci struct drbd_config_context adm_ctx; 31578c2ecf20Sopenharmony_ci union drbd_dev_state s; 31588c2ecf20Sopenharmony_ci enum drbd_ret_code retcode; 31598c2ecf20Sopenharmony_ci 31608c2ecf20Sopenharmony_ci retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_MINOR); 31618c2ecf20Sopenharmony_ci if (!adm_ctx.reply_skb) 31628c2ecf20Sopenharmony_ci return retcode; 31638c2ecf20Sopenharmony_ci if (retcode != NO_ERROR) 31648c2ecf20Sopenharmony_ci goto out; 31658c2ecf20Sopenharmony_ci 31668c2ecf20Sopenharmony_ci mutex_lock(&adm_ctx.resource->adm_mutex); 31678c2ecf20Sopenharmony_ci if (drbd_request_state(adm_ctx.device, NS(user_isp, 0)) == SS_NOTHING_TO_DO) { 31688c2ecf20Sopenharmony_ci s = adm_ctx.device->state; 31698c2ecf20Sopenharmony_ci if (s.conn == C_PAUSED_SYNC_S || s.conn == C_PAUSED_SYNC_T) { 31708c2ecf20Sopenharmony_ci retcode = s.aftr_isp ? ERR_PIC_AFTER_DEP : 31718c2ecf20Sopenharmony_ci s.peer_isp ? ERR_PIC_PEER_DEP : ERR_PAUSE_IS_CLEAR; 31728c2ecf20Sopenharmony_ci } else { 31738c2ecf20Sopenharmony_ci retcode = ERR_PAUSE_IS_CLEAR; 31748c2ecf20Sopenharmony_ci } 31758c2ecf20Sopenharmony_ci } 31768c2ecf20Sopenharmony_ci mutex_unlock(&adm_ctx.resource->adm_mutex); 31778c2ecf20Sopenharmony_ciout: 31788c2ecf20Sopenharmony_ci drbd_adm_finish(&adm_ctx, info, retcode); 31798c2ecf20Sopenharmony_ci return 0; 31808c2ecf20Sopenharmony_ci} 31818c2ecf20Sopenharmony_ci 31828c2ecf20Sopenharmony_ciint drbd_adm_suspend_io(struct sk_buff *skb, struct genl_info *info) 31838c2ecf20Sopenharmony_ci{ 31848c2ecf20Sopenharmony_ci return drbd_adm_simple_request_state(skb, info, NS(susp, 1)); 31858c2ecf20Sopenharmony_ci} 31868c2ecf20Sopenharmony_ci 31878c2ecf20Sopenharmony_ciint drbd_adm_resume_io(struct sk_buff *skb, struct genl_info *info) 31888c2ecf20Sopenharmony_ci{ 31898c2ecf20Sopenharmony_ci struct drbd_config_context adm_ctx; 31908c2ecf20Sopenharmony_ci struct drbd_device *device; 31918c2ecf20Sopenharmony_ci int retcode; /* enum drbd_ret_code rsp. enum drbd_state_rv */ 31928c2ecf20Sopenharmony_ci 31938c2ecf20Sopenharmony_ci retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_MINOR); 31948c2ecf20Sopenharmony_ci if (!adm_ctx.reply_skb) 31958c2ecf20Sopenharmony_ci return retcode; 31968c2ecf20Sopenharmony_ci if (retcode != NO_ERROR) 31978c2ecf20Sopenharmony_ci goto out; 31988c2ecf20Sopenharmony_ci 31998c2ecf20Sopenharmony_ci mutex_lock(&adm_ctx.resource->adm_mutex); 32008c2ecf20Sopenharmony_ci device = adm_ctx.device; 32018c2ecf20Sopenharmony_ci if (test_bit(NEW_CUR_UUID, &device->flags)) { 32028c2ecf20Sopenharmony_ci if (get_ldev_if_state(device, D_ATTACHING)) { 32038c2ecf20Sopenharmony_ci drbd_uuid_new_current(device); 32048c2ecf20Sopenharmony_ci put_ldev(device); 32058c2ecf20Sopenharmony_ci } else { 32068c2ecf20Sopenharmony_ci /* This is effectively a multi-stage "forced down". 32078c2ecf20Sopenharmony_ci * The NEW_CUR_UUID bit is supposedly only set, if we 32088c2ecf20Sopenharmony_ci * lost the replication connection, and are configured 32098c2ecf20Sopenharmony_ci * to freeze IO and wait for some fence-peer handler. 32108c2ecf20Sopenharmony_ci * So we still don't have a replication connection. 32118c2ecf20Sopenharmony_ci * And now we don't have a local disk either. After 32128c2ecf20Sopenharmony_ci * resume, we will fail all pending and new IO, because 32138c2ecf20Sopenharmony_ci * we don't have any data anymore. Which means we will 32148c2ecf20Sopenharmony_ci * eventually be able to terminate all users of this 32158c2ecf20Sopenharmony_ci * device, and then take it down. By bumping the 32168c2ecf20Sopenharmony_ci * "effective" data uuid, we make sure that you really 32178c2ecf20Sopenharmony_ci * need to tear down before you reconfigure, we will 32188c2ecf20Sopenharmony_ci * the refuse to re-connect or re-attach (because no 32198c2ecf20Sopenharmony_ci * matching real data uuid exists). 32208c2ecf20Sopenharmony_ci */ 32218c2ecf20Sopenharmony_ci u64 val; 32228c2ecf20Sopenharmony_ci get_random_bytes(&val, sizeof(u64)); 32238c2ecf20Sopenharmony_ci drbd_set_ed_uuid(device, val); 32248c2ecf20Sopenharmony_ci drbd_warn(device, "Resumed without access to data; please tear down before attempting to re-configure.\n"); 32258c2ecf20Sopenharmony_ci } 32268c2ecf20Sopenharmony_ci clear_bit(NEW_CUR_UUID, &device->flags); 32278c2ecf20Sopenharmony_ci } 32288c2ecf20Sopenharmony_ci drbd_suspend_io(device); 32298c2ecf20Sopenharmony_ci retcode = drbd_request_state(device, NS3(susp, 0, susp_nod, 0, susp_fen, 0)); 32308c2ecf20Sopenharmony_ci if (retcode == SS_SUCCESS) { 32318c2ecf20Sopenharmony_ci if (device->state.conn < C_CONNECTED) 32328c2ecf20Sopenharmony_ci tl_clear(first_peer_device(device)->connection); 32338c2ecf20Sopenharmony_ci if (device->state.disk == D_DISKLESS || device->state.disk == D_FAILED) 32348c2ecf20Sopenharmony_ci tl_restart(first_peer_device(device)->connection, FAIL_FROZEN_DISK_IO); 32358c2ecf20Sopenharmony_ci } 32368c2ecf20Sopenharmony_ci drbd_resume_io(device); 32378c2ecf20Sopenharmony_ci mutex_unlock(&adm_ctx.resource->adm_mutex); 32388c2ecf20Sopenharmony_ciout: 32398c2ecf20Sopenharmony_ci drbd_adm_finish(&adm_ctx, info, retcode); 32408c2ecf20Sopenharmony_ci return 0; 32418c2ecf20Sopenharmony_ci} 32428c2ecf20Sopenharmony_ci 32438c2ecf20Sopenharmony_ciint drbd_adm_outdate(struct sk_buff *skb, struct genl_info *info) 32448c2ecf20Sopenharmony_ci{ 32458c2ecf20Sopenharmony_ci return drbd_adm_simple_request_state(skb, info, NS(disk, D_OUTDATED)); 32468c2ecf20Sopenharmony_ci} 32478c2ecf20Sopenharmony_ci 32488c2ecf20Sopenharmony_cistatic int nla_put_drbd_cfg_context(struct sk_buff *skb, 32498c2ecf20Sopenharmony_ci struct drbd_resource *resource, 32508c2ecf20Sopenharmony_ci struct drbd_connection *connection, 32518c2ecf20Sopenharmony_ci struct drbd_device *device) 32528c2ecf20Sopenharmony_ci{ 32538c2ecf20Sopenharmony_ci struct nlattr *nla; 32548c2ecf20Sopenharmony_ci nla = nla_nest_start_noflag(skb, DRBD_NLA_CFG_CONTEXT); 32558c2ecf20Sopenharmony_ci if (!nla) 32568c2ecf20Sopenharmony_ci goto nla_put_failure; 32578c2ecf20Sopenharmony_ci if (device && 32588c2ecf20Sopenharmony_ci nla_put_u32(skb, T_ctx_volume, device->vnr)) 32598c2ecf20Sopenharmony_ci goto nla_put_failure; 32608c2ecf20Sopenharmony_ci if (nla_put_string(skb, T_ctx_resource_name, resource->name)) 32618c2ecf20Sopenharmony_ci goto nla_put_failure; 32628c2ecf20Sopenharmony_ci if (connection) { 32638c2ecf20Sopenharmony_ci if (connection->my_addr_len && 32648c2ecf20Sopenharmony_ci nla_put(skb, T_ctx_my_addr, connection->my_addr_len, &connection->my_addr)) 32658c2ecf20Sopenharmony_ci goto nla_put_failure; 32668c2ecf20Sopenharmony_ci if (connection->peer_addr_len && 32678c2ecf20Sopenharmony_ci nla_put(skb, T_ctx_peer_addr, connection->peer_addr_len, &connection->peer_addr)) 32688c2ecf20Sopenharmony_ci goto nla_put_failure; 32698c2ecf20Sopenharmony_ci } 32708c2ecf20Sopenharmony_ci nla_nest_end(skb, nla); 32718c2ecf20Sopenharmony_ci return 0; 32728c2ecf20Sopenharmony_ci 32738c2ecf20Sopenharmony_cinla_put_failure: 32748c2ecf20Sopenharmony_ci if (nla) 32758c2ecf20Sopenharmony_ci nla_nest_cancel(skb, nla); 32768c2ecf20Sopenharmony_ci return -EMSGSIZE; 32778c2ecf20Sopenharmony_ci} 32788c2ecf20Sopenharmony_ci 32798c2ecf20Sopenharmony_ci/* 32808c2ecf20Sopenharmony_ci * The generic netlink dump callbacks are called outside the genl_lock(), so 32818c2ecf20Sopenharmony_ci * they cannot use the simple attribute parsing code which uses global 32828c2ecf20Sopenharmony_ci * attribute tables. 32838c2ecf20Sopenharmony_ci */ 32848c2ecf20Sopenharmony_cistatic struct nlattr *find_cfg_context_attr(const struct nlmsghdr *nlh, int attr) 32858c2ecf20Sopenharmony_ci{ 32868c2ecf20Sopenharmony_ci const unsigned hdrlen = GENL_HDRLEN + GENL_MAGIC_FAMILY_HDRSZ; 32878c2ecf20Sopenharmony_ci const int maxtype = ARRAY_SIZE(drbd_cfg_context_nl_policy) - 1; 32888c2ecf20Sopenharmony_ci struct nlattr *nla; 32898c2ecf20Sopenharmony_ci 32908c2ecf20Sopenharmony_ci nla = nla_find(nlmsg_attrdata(nlh, hdrlen), nlmsg_attrlen(nlh, hdrlen), 32918c2ecf20Sopenharmony_ci DRBD_NLA_CFG_CONTEXT); 32928c2ecf20Sopenharmony_ci if (!nla) 32938c2ecf20Sopenharmony_ci return NULL; 32948c2ecf20Sopenharmony_ci return drbd_nla_find_nested(maxtype, nla, __nla_type(attr)); 32958c2ecf20Sopenharmony_ci} 32968c2ecf20Sopenharmony_ci 32978c2ecf20Sopenharmony_cistatic void resource_to_info(struct resource_info *, struct drbd_resource *); 32988c2ecf20Sopenharmony_ci 32998c2ecf20Sopenharmony_ciint drbd_adm_dump_resources(struct sk_buff *skb, struct netlink_callback *cb) 33008c2ecf20Sopenharmony_ci{ 33018c2ecf20Sopenharmony_ci struct drbd_genlmsghdr *dh; 33028c2ecf20Sopenharmony_ci struct drbd_resource *resource; 33038c2ecf20Sopenharmony_ci struct resource_info resource_info; 33048c2ecf20Sopenharmony_ci struct resource_statistics resource_statistics; 33058c2ecf20Sopenharmony_ci int err; 33068c2ecf20Sopenharmony_ci 33078c2ecf20Sopenharmony_ci rcu_read_lock(); 33088c2ecf20Sopenharmony_ci if (cb->args[0]) { 33098c2ecf20Sopenharmony_ci for_each_resource_rcu(resource, &drbd_resources) 33108c2ecf20Sopenharmony_ci if (resource == (struct drbd_resource *)cb->args[0]) 33118c2ecf20Sopenharmony_ci goto found_resource; 33128c2ecf20Sopenharmony_ci err = 0; /* resource was probably deleted */ 33138c2ecf20Sopenharmony_ci goto out; 33148c2ecf20Sopenharmony_ci } 33158c2ecf20Sopenharmony_ci resource = list_entry(&drbd_resources, 33168c2ecf20Sopenharmony_ci struct drbd_resource, resources); 33178c2ecf20Sopenharmony_ci 33188c2ecf20Sopenharmony_cifound_resource: 33198c2ecf20Sopenharmony_ci list_for_each_entry_continue_rcu(resource, &drbd_resources, resources) { 33208c2ecf20Sopenharmony_ci goto put_result; 33218c2ecf20Sopenharmony_ci } 33228c2ecf20Sopenharmony_ci err = 0; 33238c2ecf20Sopenharmony_ci goto out; 33248c2ecf20Sopenharmony_ci 33258c2ecf20Sopenharmony_ciput_result: 33268c2ecf20Sopenharmony_ci dh = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, 33278c2ecf20Sopenharmony_ci cb->nlh->nlmsg_seq, &drbd_genl_family, 33288c2ecf20Sopenharmony_ci NLM_F_MULTI, DRBD_ADM_GET_RESOURCES); 33298c2ecf20Sopenharmony_ci err = -ENOMEM; 33308c2ecf20Sopenharmony_ci if (!dh) 33318c2ecf20Sopenharmony_ci goto out; 33328c2ecf20Sopenharmony_ci dh->minor = -1U; 33338c2ecf20Sopenharmony_ci dh->ret_code = NO_ERROR; 33348c2ecf20Sopenharmony_ci err = nla_put_drbd_cfg_context(skb, resource, NULL, NULL); 33358c2ecf20Sopenharmony_ci if (err) 33368c2ecf20Sopenharmony_ci goto out; 33378c2ecf20Sopenharmony_ci err = res_opts_to_skb(skb, &resource->res_opts, !capable(CAP_SYS_ADMIN)); 33388c2ecf20Sopenharmony_ci if (err) 33398c2ecf20Sopenharmony_ci goto out; 33408c2ecf20Sopenharmony_ci resource_to_info(&resource_info, resource); 33418c2ecf20Sopenharmony_ci err = resource_info_to_skb(skb, &resource_info, !capable(CAP_SYS_ADMIN)); 33428c2ecf20Sopenharmony_ci if (err) 33438c2ecf20Sopenharmony_ci goto out; 33448c2ecf20Sopenharmony_ci resource_statistics.res_stat_write_ordering = resource->write_ordering; 33458c2ecf20Sopenharmony_ci err = resource_statistics_to_skb(skb, &resource_statistics, !capable(CAP_SYS_ADMIN)); 33468c2ecf20Sopenharmony_ci if (err) 33478c2ecf20Sopenharmony_ci goto out; 33488c2ecf20Sopenharmony_ci cb->args[0] = (long)resource; 33498c2ecf20Sopenharmony_ci genlmsg_end(skb, dh); 33508c2ecf20Sopenharmony_ci err = 0; 33518c2ecf20Sopenharmony_ci 33528c2ecf20Sopenharmony_ciout: 33538c2ecf20Sopenharmony_ci rcu_read_unlock(); 33548c2ecf20Sopenharmony_ci if (err) 33558c2ecf20Sopenharmony_ci return err; 33568c2ecf20Sopenharmony_ci return skb->len; 33578c2ecf20Sopenharmony_ci} 33588c2ecf20Sopenharmony_ci 33598c2ecf20Sopenharmony_cistatic void device_to_statistics(struct device_statistics *s, 33608c2ecf20Sopenharmony_ci struct drbd_device *device) 33618c2ecf20Sopenharmony_ci{ 33628c2ecf20Sopenharmony_ci memset(s, 0, sizeof(*s)); 33638c2ecf20Sopenharmony_ci s->dev_upper_blocked = !may_inc_ap_bio(device); 33648c2ecf20Sopenharmony_ci if (get_ldev(device)) { 33658c2ecf20Sopenharmony_ci struct drbd_md *md = &device->ldev->md; 33668c2ecf20Sopenharmony_ci u64 *history_uuids = (u64 *)s->history_uuids; 33678c2ecf20Sopenharmony_ci int n; 33688c2ecf20Sopenharmony_ci 33698c2ecf20Sopenharmony_ci spin_lock_irq(&md->uuid_lock); 33708c2ecf20Sopenharmony_ci s->dev_current_uuid = md->uuid[UI_CURRENT]; 33718c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(s->history_uuids) < UI_HISTORY_END - UI_HISTORY_START + 1); 33728c2ecf20Sopenharmony_ci for (n = 0; n < UI_HISTORY_END - UI_HISTORY_START + 1; n++) 33738c2ecf20Sopenharmony_ci history_uuids[n] = md->uuid[UI_HISTORY_START + n]; 33748c2ecf20Sopenharmony_ci for (; n < HISTORY_UUIDS; n++) 33758c2ecf20Sopenharmony_ci history_uuids[n] = 0; 33768c2ecf20Sopenharmony_ci s->history_uuids_len = HISTORY_UUIDS; 33778c2ecf20Sopenharmony_ci spin_unlock_irq(&md->uuid_lock); 33788c2ecf20Sopenharmony_ci 33798c2ecf20Sopenharmony_ci s->dev_disk_flags = md->flags; 33808c2ecf20Sopenharmony_ci put_ldev(device); 33818c2ecf20Sopenharmony_ci } 33828c2ecf20Sopenharmony_ci s->dev_size = get_capacity(device->vdisk); 33838c2ecf20Sopenharmony_ci s->dev_read = device->read_cnt; 33848c2ecf20Sopenharmony_ci s->dev_write = device->writ_cnt; 33858c2ecf20Sopenharmony_ci s->dev_al_writes = device->al_writ_cnt; 33868c2ecf20Sopenharmony_ci s->dev_bm_writes = device->bm_writ_cnt; 33878c2ecf20Sopenharmony_ci s->dev_upper_pending = atomic_read(&device->ap_bio_cnt); 33888c2ecf20Sopenharmony_ci s->dev_lower_pending = atomic_read(&device->local_cnt); 33898c2ecf20Sopenharmony_ci s->dev_al_suspended = test_bit(AL_SUSPENDED, &device->flags); 33908c2ecf20Sopenharmony_ci s->dev_exposed_data_uuid = device->ed_uuid; 33918c2ecf20Sopenharmony_ci} 33928c2ecf20Sopenharmony_ci 33938c2ecf20Sopenharmony_cistatic int put_resource_in_arg0(struct netlink_callback *cb, int holder_nr) 33948c2ecf20Sopenharmony_ci{ 33958c2ecf20Sopenharmony_ci if (cb->args[0]) { 33968c2ecf20Sopenharmony_ci struct drbd_resource *resource = 33978c2ecf20Sopenharmony_ci (struct drbd_resource *)cb->args[0]; 33988c2ecf20Sopenharmony_ci kref_put(&resource->kref, drbd_destroy_resource); 33998c2ecf20Sopenharmony_ci } 34008c2ecf20Sopenharmony_ci 34018c2ecf20Sopenharmony_ci return 0; 34028c2ecf20Sopenharmony_ci} 34038c2ecf20Sopenharmony_ci 34048c2ecf20Sopenharmony_ciint drbd_adm_dump_devices_done(struct netlink_callback *cb) { 34058c2ecf20Sopenharmony_ci return put_resource_in_arg0(cb, 7); 34068c2ecf20Sopenharmony_ci} 34078c2ecf20Sopenharmony_ci 34088c2ecf20Sopenharmony_cistatic void device_to_info(struct device_info *, struct drbd_device *); 34098c2ecf20Sopenharmony_ci 34108c2ecf20Sopenharmony_ciint drbd_adm_dump_devices(struct sk_buff *skb, struct netlink_callback *cb) 34118c2ecf20Sopenharmony_ci{ 34128c2ecf20Sopenharmony_ci struct nlattr *resource_filter; 34138c2ecf20Sopenharmony_ci struct drbd_resource *resource; 34148c2ecf20Sopenharmony_ci struct drbd_device *device; 34158c2ecf20Sopenharmony_ci int minor, err, retcode; 34168c2ecf20Sopenharmony_ci struct drbd_genlmsghdr *dh; 34178c2ecf20Sopenharmony_ci struct device_info device_info; 34188c2ecf20Sopenharmony_ci struct device_statistics device_statistics; 34198c2ecf20Sopenharmony_ci struct idr *idr_to_search; 34208c2ecf20Sopenharmony_ci 34218c2ecf20Sopenharmony_ci resource = (struct drbd_resource *)cb->args[0]; 34228c2ecf20Sopenharmony_ci if (!cb->args[0] && !cb->args[1]) { 34238c2ecf20Sopenharmony_ci resource_filter = find_cfg_context_attr(cb->nlh, T_ctx_resource_name); 34248c2ecf20Sopenharmony_ci if (resource_filter) { 34258c2ecf20Sopenharmony_ci retcode = ERR_RES_NOT_KNOWN; 34268c2ecf20Sopenharmony_ci resource = drbd_find_resource(nla_data(resource_filter)); 34278c2ecf20Sopenharmony_ci if (!resource) 34288c2ecf20Sopenharmony_ci goto put_result; 34298c2ecf20Sopenharmony_ci cb->args[0] = (long)resource; 34308c2ecf20Sopenharmony_ci } 34318c2ecf20Sopenharmony_ci } 34328c2ecf20Sopenharmony_ci 34338c2ecf20Sopenharmony_ci rcu_read_lock(); 34348c2ecf20Sopenharmony_ci minor = cb->args[1]; 34358c2ecf20Sopenharmony_ci idr_to_search = resource ? &resource->devices : &drbd_devices; 34368c2ecf20Sopenharmony_ci device = idr_get_next(idr_to_search, &minor); 34378c2ecf20Sopenharmony_ci if (!device) { 34388c2ecf20Sopenharmony_ci err = 0; 34398c2ecf20Sopenharmony_ci goto out; 34408c2ecf20Sopenharmony_ci } 34418c2ecf20Sopenharmony_ci idr_for_each_entry_continue(idr_to_search, device, minor) { 34428c2ecf20Sopenharmony_ci retcode = NO_ERROR; 34438c2ecf20Sopenharmony_ci goto put_result; /* only one iteration */ 34448c2ecf20Sopenharmony_ci } 34458c2ecf20Sopenharmony_ci err = 0; 34468c2ecf20Sopenharmony_ci goto out; /* no more devices */ 34478c2ecf20Sopenharmony_ci 34488c2ecf20Sopenharmony_ciput_result: 34498c2ecf20Sopenharmony_ci dh = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, 34508c2ecf20Sopenharmony_ci cb->nlh->nlmsg_seq, &drbd_genl_family, 34518c2ecf20Sopenharmony_ci NLM_F_MULTI, DRBD_ADM_GET_DEVICES); 34528c2ecf20Sopenharmony_ci err = -ENOMEM; 34538c2ecf20Sopenharmony_ci if (!dh) 34548c2ecf20Sopenharmony_ci goto out; 34558c2ecf20Sopenharmony_ci dh->ret_code = retcode; 34568c2ecf20Sopenharmony_ci dh->minor = -1U; 34578c2ecf20Sopenharmony_ci if (retcode == NO_ERROR) { 34588c2ecf20Sopenharmony_ci dh->minor = device->minor; 34598c2ecf20Sopenharmony_ci err = nla_put_drbd_cfg_context(skb, device->resource, NULL, device); 34608c2ecf20Sopenharmony_ci if (err) 34618c2ecf20Sopenharmony_ci goto out; 34628c2ecf20Sopenharmony_ci if (get_ldev(device)) { 34638c2ecf20Sopenharmony_ci struct disk_conf *disk_conf = 34648c2ecf20Sopenharmony_ci rcu_dereference(device->ldev->disk_conf); 34658c2ecf20Sopenharmony_ci 34668c2ecf20Sopenharmony_ci err = disk_conf_to_skb(skb, disk_conf, !capable(CAP_SYS_ADMIN)); 34678c2ecf20Sopenharmony_ci put_ldev(device); 34688c2ecf20Sopenharmony_ci if (err) 34698c2ecf20Sopenharmony_ci goto out; 34708c2ecf20Sopenharmony_ci } 34718c2ecf20Sopenharmony_ci device_to_info(&device_info, device); 34728c2ecf20Sopenharmony_ci err = device_info_to_skb(skb, &device_info, !capable(CAP_SYS_ADMIN)); 34738c2ecf20Sopenharmony_ci if (err) 34748c2ecf20Sopenharmony_ci goto out; 34758c2ecf20Sopenharmony_ci 34768c2ecf20Sopenharmony_ci device_to_statistics(&device_statistics, device); 34778c2ecf20Sopenharmony_ci err = device_statistics_to_skb(skb, &device_statistics, !capable(CAP_SYS_ADMIN)); 34788c2ecf20Sopenharmony_ci if (err) 34798c2ecf20Sopenharmony_ci goto out; 34808c2ecf20Sopenharmony_ci cb->args[1] = minor + 1; 34818c2ecf20Sopenharmony_ci } 34828c2ecf20Sopenharmony_ci genlmsg_end(skb, dh); 34838c2ecf20Sopenharmony_ci err = 0; 34848c2ecf20Sopenharmony_ci 34858c2ecf20Sopenharmony_ciout: 34868c2ecf20Sopenharmony_ci rcu_read_unlock(); 34878c2ecf20Sopenharmony_ci if (err) 34888c2ecf20Sopenharmony_ci return err; 34898c2ecf20Sopenharmony_ci return skb->len; 34908c2ecf20Sopenharmony_ci} 34918c2ecf20Sopenharmony_ci 34928c2ecf20Sopenharmony_ciint drbd_adm_dump_connections_done(struct netlink_callback *cb) 34938c2ecf20Sopenharmony_ci{ 34948c2ecf20Sopenharmony_ci return put_resource_in_arg0(cb, 6); 34958c2ecf20Sopenharmony_ci} 34968c2ecf20Sopenharmony_ci 34978c2ecf20Sopenharmony_cienum { SINGLE_RESOURCE, ITERATE_RESOURCES }; 34988c2ecf20Sopenharmony_ci 34998c2ecf20Sopenharmony_ciint drbd_adm_dump_connections(struct sk_buff *skb, struct netlink_callback *cb) 35008c2ecf20Sopenharmony_ci{ 35018c2ecf20Sopenharmony_ci struct nlattr *resource_filter; 35028c2ecf20Sopenharmony_ci struct drbd_resource *resource = NULL, *next_resource; 35038c2ecf20Sopenharmony_ci struct drbd_connection *connection; 35048c2ecf20Sopenharmony_ci int err = 0, retcode; 35058c2ecf20Sopenharmony_ci struct drbd_genlmsghdr *dh; 35068c2ecf20Sopenharmony_ci struct connection_info connection_info; 35078c2ecf20Sopenharmony_ci struct connection_statistics connection_statistics; 35088c2ecf20Sopenharmony_ci 35098c2ecf20Sopenharmony_ci rcu_read_lock(); 35108c2ecf20Sopenharmony_ci resource = (struct drbd_resource *)cb->args[0]; 35118c2ecf20Sopenharmony_ci if (!cb->args[0]) { 35128c2ecf20Sopenharmony_ci resource_filter = find_cfg_context_attr(cb->nlh, T_ctx_resource_name); 35138c2ecf20Sopenharmony_ci if (resource_filter) { 35148c2ecf20Sopenharmony_ci retcode = ERR_RES_NOT_KNOWN; 35158c2ecf20Sopenharmony_ci resource = drbd_find_resource(nla_data(resource_filter)); 35168c2ecf20Sopenharmony_ci if (!resource) 35178c2ecf20Sopenharmony_ci goto put_result; 35188c2ecf20Sopenharmony_ci cb->args[0] = (long)resource; 35198c2ecf20Sopenharmony_ci cb->args[1] = SINGLE_RESOURCE; 35208c2ecf20Sopenharmony_ci } 35218c2ecf20Sopenharmony_ci } 35228c2ecf20Sopenharmony_ci if (!resource) { 35238c2ecf20Sopenharmony_ci if (list_empty(&drbd_resources)) 35248c2ecf20Sopenharmony_ci goto out; 35258c2ecf20Sopenharmony_ci resource = list_first_entry(&drbd_resources, struct drbd_resource, resources); 35268c2ecf20Sopenharmony_ci kref_get(&resource->kref); 35278c2ecf20Sopenharmony_ci cb->args[0] = (long)resource; 35288c2ecf20Sopenharmony_ci cb->args[1] = ITERATE_RESOURCES; 35298c2ecf20Sopenharmony_ci } 35308c2ecf20Sopenharmony_ci 35318c2ecf20Sopenharmony_ci next_resource: 35328c2ecf20Sopenharmony_ci rcu_read_unlock(); 35338c2ecf20Sopenharmony_ci mutex_lock(&resource->conf_update); 35348c2ecf20Sopenharmony_ci rcu_read_lock(); 35358c2ecf20Sopenharmony_ci if (cb->args[2]) { 35368c2ecf20Sopenharmony_ci for_each_connection_rcu(connection, resource) 35378c2ecf20Sopenharmony_ci if (connection == (struct drbd_connection *)cb->args[2]) 35388c2ecf20Sopenharmony_ci goto found_connection; 35398c2ecf20Sopenharmony_ci /* connection was probably deleted */ 35408c2ecf20Sopenharmony_ci goto no_more_connections; 35418c2ecf20Sopenharmony_ci } 35428c2ecf20Sopenharmony_ci connection = list_entry(&resource->connections, struct drbd_connection, connections); 35438c2ecf20Sopenharmony_ci 35448c2ecf20Sopenharmony_cifound_connection: 35458c2ecf20Sopenharmony_ci list_for_each_entry_continue_rcu(connection, &resource->connections, connections) { 35468c2ecf20Sopenharmony_ci if (!has_net_conf(connection)) 35478c2ecf20Sopenharmony_ci continue; 35488c2ecf20Sopenharmony_ci retcode = NO_ERROR; 35498c2ecf20Sopenharmony_ci goto put_result; /* only one iteration */ 35508c2ecf20Sopenharmony_ci } 35518c2ecf20Sopenharmony_ci 35528c2ecf20Sopenharmony_cino_more_connections: 35538c2ecf20Sopenharmony_ci if (cb->args[1] == ITERATE_RESOURCES) { 35548c2ecf20Sopenharmony_ci for_each_resource_rcu(next_resource, &drbd_resources) { 35558c2ecf20Sopenharmony_ci if (next_resource == resource) 35568c2ecf20Sopenharmony_ci goto found_resource; 35578c2ecf20Sopenharmony_ci } 35588c2ecf20Sopenharmony_ci /* resource was probably deleted */ 35598c2ecf20Sopenharmony_ci } 35608c2ecf20Sopenharmony_ci goto out; 35618c2ecf20Sopenharmony_ci 35628c2ecf20Sopenharmony_cifound_resource: 35638c2ecf20Sopenharmony_ci list_for_each_entry_continue_rcu(next_resource, &drbd_resources, resources) { 35648c2ecf20Sopenharmony_ci mutex_unlock(&resource->conf_update); 35658c2ecf20Sopenharmony_ci kref_put(&resource->kref, drbd_destroy_resource); 35668c2ecf20Sopenharmony_ci resource = next_resource; 35678c2ecf20Sopenharmony_ci kref_get(&resource->kref); 35688c2ecf20Sopenharmony_ci cb->args[0] = (long)resource; 35698c2ecf20Sopenharmony_ci cb->args[2] = 0; 35708c2ecf20Sopenharmony_ci goto next_resource; 35718c2ecf20Sopenharmony_ci } 35728c2ecf20Sopenharmony_ci goto out; /* no more resources */ 35738c2ecf20Sopenharmony_ci 35748c2ecf20Sopenharmony_ciput_result: 35758c2ecf20Sopenharmony_ci dh = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, 35768c2ecf20Sopenharmony_ci cb->nlh->nlmsg_seq, &drbd_genl_family, 35778c2ecf20Sopenharmony_ci NLM_F_MULTI, DRBD_ADM_GET_CONNECTIONS); 35788c2ecf20Sopenharmony_ci err = -ENOMEM; 35798c2ecf20Sopenharmony_ci if (!dh) 35808c2ecf20Sopenharmony_ci goto out; 35818c2ecf20Sopenharmony_ci dh->ret_code = retcode; 35828c2ecf20Sopenharmony_ci dh->minor = -1U; 35838c2ecf20Sopenharmony_ci if (retcode == NO_ERROR) { 35848c2ecf20Sopenharmony_ci struct net_conf *net_conf; 35858c2ecf20Sopenharmony_ci 35868c2ecf20Sopenharmony_ci err = nla_put_drbd_cfg_context(skb, resource, connection, NULL); 35878c2ecf20Sopenharmony_ci if (err) 35888c2ecf20Sopenharmony_ci goto out; 35898c2ecf20Sopenharmony_ci net_conf = rcu_dereference(connection->net_conf); 35908c2ecf20Sopenharmony_ci if (net_conf) { 35918c2ecf20Sopenharmony_ci err = net_conf_to_skb(skb, net_conf, !capable(CAP_SYS_ADMIN)); 35928c2ecf20Sopenharmony_ci if (err) 35938c2ecf20Sopenharmony_ci goto out; 35948c2ecf20Sopenharmony_ci } 35958c2ecf20Sopenharmony_ci connection_to_info(&connection_info, connection); 35968c2ecf20Sopenharmony_ci err = connection_info_to_skb(skb, &connection_info, !capable(CAP_SYS_ADMIN)); 35978c2ecf20Sopenharmony_ci if (err) 35988c2ecf20Sopenharmony_ci goto out; 35998c2ecf20Sopenharmony_ci connection_statistics.conn_congested = test_bit(NET_CONGESTED, &connection->flags); 36008c2ecf20Sopenharmony_ci err = connection_statistics_to_skb(skb, &connection_statistics, !capable(CAP_SYS_ADMIN)); 36018c2ecf20Sopenharmony_ci if (err) 36028c2ecf20Sopenharmony_ci goto out; 36038c2ecf20Sopenharmony_ci cb->args[2] = (long)connection; 36048c2ecf20Sopenharmony_ci } 36058c2ecf20Sopenharmony_ci genlmsg_end(skb, dh); 36068c2ecf20Sopenharmony_ci err = 0; 36078c2ecf20Sopenharmony_ci 36088c2ecf20Sopenharmony_ciout: 36098c2ecf20Sopenharmony_ci rcu_read_unlock(); 36108c2ecf20Sopenharmony_ci if (resource) 36118c2ecf20Sopenharmony_ci mutex_unlock(&resource->conf_update); 36128c2ecf20Sopenharmony_ci if (err) 36138c2ecf20Sopenharmony_ci return err; 36148c2ecf20Sopenharmony_ci return skb->len; 36158c2ecf20Sopenharmony_ci} 36168c2ecf20Sopenharmony_ci 36178c2ecf20Sopenharmony_cienum mdf_peer_flag { 36188c2ecf20Sopenharmony_ci MDF_PEER_CONNECTED = 1 << 0, 36198c2ecf20Sopenharmony_ci MDF_PEER_OUTDATED = 1 << 1, 36208c2ecf20Sopenharmony_ci MDF_PEER_FENCING = 1 << 2, 36218c2ecf20Sopenharmony_ci MDF_PEER_FULL_SYNC = 1 << 3, 36228c2ecf20Sopenharmony_ci}; 36238c2ecf20Sopenharmony_ci 36248c2ecf20Sopenharmony_cistatic void peer_device_to_statistics(struct peer_device_statistics *s, 36258c2ecf20Sopenharmony_ci struct drbd_peer_device *peer_device) 36268c2ecf20Sopenharmony_ci{ 36278c2ecf20Sopenharmony_ci struct drbd_device *device = peer_device->device; 36288c2ecf20Sopenharmony_ci 36298c2ecf20Sopenharmony_ci memset(s, 0, sizeof(*s)); 36308c2ecf20Sopenharmony_ci s->peer_dev_received = device->recv_cnt; 36318c2ecf20Sopenharmony_ci s->peer_dev_sent = device->send_cnt; 36328c2ecf20Sopenharmony_ci s->peer_dev_pending = atomic_read(&device->ap_pending_cnt) + 36338c2ecf20Sopenharmony_ci atomic_read(&device->rs_pending_cnt); 36348c2ecf20Sopenharmony_ci s->peer_dev_unacked = atomic_read(&device->unacked_cnt); 36358c2ecf20Sopenharmony_ci s->peer_dev_out_of_sync = drbd_bm_total_weight(device) << (BM_BLOCK_SHIFT - 9); 36368c2ecf20Sopenharmony_ci s->peer_dev_resync_failed = device->rs_failed << (BM_BLOCK_SHIFT - 9); 36378c2ecf20Sopenharmony_ci if (get_ldev(device)) { 36388c2ecf20Sopenharmony_ci struct drbd_md *md = &device->ldev->md; 36398c2ecf20Sopenharmony_ci 36408c2ecf20Sopenharmony_ci spin_lock_irq(&md->uuid_lock); 36418c2ecf20Sopenharmony_ci s->peer_dev_bitmap_uuid = md->uuid[UI_BITMAP]; 36428c2ecf20Sopenharmony_ci spin_unlock_irq(&md->uuid_lock); 36438c2ecf20Sopenharmony_ci s->peer_dev_flags = 36448c2ecf20Sopenharmony_ci (drbd_md_test_flag(device->ldev, MDF_CONNECTED_IND) ? 36458c2ecf20Sopenharmony_ci MDF_PEER_CONNECTED : 0) + 36468c2ecf20Sopenharmony_ci (drbd_md_test_flag(device->ldev, MDF_CONSISTENT) && 36478c2ecf20Sopenharmony_ci !drbd_md_test_flag(device->ldev, MDF_WAS_UP_TO_DATE) ? 36488c2ecf20Sopenharmony_ci MDF_PEER_OUTDATED : 0) + 36498c2ecf20Sopenharmony_ci /* FIXME: MDF_PEER_FENCING? */ 36508c2ecf20Sopenharmony_ci (drbd_md_test_flag(device->ldev, MDF_FULL_SYNC) ? 36518c2ecf20Sopenharmony_ci MDF_PEER_FULL_SYNC : 0); 36528c2ecf20Sopenharmony_ci put_ldev(device); 36538c2ecf20Sopenharmony_ci } 36548c2ecf20Sopenharmony_ci} 36558c2ecf20Sopenharmony_ci 36568c2ecf20Sopenharmony_ciint drbd_adm_dump_peer_devices_done(struct netlink_callback *cb) 36578c2ecf20Sopenharmony_ci{ 36588c2ecf20Sopenharmony_ci return put_resource_in_arg0(cb, 9); 36598c2ecf20Sopenharmony_ci} 36608c2ecf20Sopenharmony_ci 36618c2ecf20Sopenharmony_ciint drbd_adm_dump_peer_devices(struct sk_buff *skb, struct netlink_callback *cb) 36628c2ecf20Sopenharmony_ci{ 36638c2ecf20Sopenharmony_ci struct nlattr *resource_filter; 36648c2ecf20Sopenharmony_ci struct drbd_resource *resource; 36658c2ecf20Sopenharmony_ci struct drbd_device *device; 36668c2ecf20Sopenharmony_ci struct drbd_peer_device *peer_device = NULL; 36678c2ecf20Sopenharmony_ci int minor, err, retcode; 36688c2ecf20Sopenharmony_ci struct drbd_genlmsghdr *dh; 36698c2ecf20Sopenharmony_ci struct idr *idr_to_search; 36708c2ecf20Sopenharmony_ci 36718c2ecf20Sopenharmony_ci resource = (struct drbd_resource *)cb->args[0]; 36728c2ecf20Sopenharmony_ci if (!cb->args[0] && !cb->args[1]) { 36738c2ecf20Sopenharmony_ci resource_filter = find_cfg_context_attr(cb->nlh, T_ctx_resource_name); 36748c2ecf20Sopenharmony_ci if (resource_filter) { 36758c2ecf20Sopenharmony_ci retcode = ERR_RES_NOT_KNOWN; 36768c2ecf20Sopenharmony_ci resource = drbd_find_resource(nla_data(resource_filter)); 36778c2ecf20Sopenharmony_ci if (!resource) 36788c2ecf20Sopenharmony_ci goto put_result; 36798c2ecf20Sopenharmony_ci } 36808c2ecf20Sopenharmony_ci cb->args[0] = (long)resource; 36818c2ecf20Sopenharmony_ci } 36828c2ecf20Sopenharmony_ci 36838c2ecf20Sopenharmony_ci rcu_read_lock(); 36848c2ecf20Sopenharmony_ci minor = cb->args[1]; 36858c2ecf20Sopenharmony_ci idr_to_search = resource ? &resource->devices : &drbd_devices; 36868c2ecf20Sopenharmony_ci device = idr_find(idr_to_search, minor); 36878c2ecf20Sopenharmony_ci if (!device) { 36888c2ecf20Sopenharmony_cinext_device: 36898c2ecf20Sopenharmony_ci minor++; 36908c2ecf20Sopenharmony_ci cb->args[2] = 0; 36918c2ecf20Sopenharmony_ci device = idr_get_next(idr_to_search, &minor); 36928c2ecf20Sopenharmony_ci if (!device) { 36938c2ecf20Sopenharmony_ci err = 0; 36948c2ecf20Sopenharmony_ci goto out; 36958c2ecf20Sopenharmony_ci } 36968c2ecf20Sopenharmony_ci } 36978c2ecf20Sopenharmony_ci if (cb->args[2]) { 36988c2ecf20Sopenharmony_ci for_each_peer_device(peer_device, device) 36998c2ecf20Sopenharmony_ci if (peer_device == (struct drbd_peer_device *)cb->args[2]) 37008c2ecf20Sopenharmony_ci goto found_peer_device; 37018c2ecf20Sopenharmony_ci /* peer device was probably deleted */ 37028c2ecf20Sopenharmony_ci goto next_device; 37038c2ecf20Sopenharmony_ci } 37048c2ecf20Sopenharmony_ci /* Make peer_device point to the list head (not the first entry). */ 37058c2ecf20Sopenharmony_ci peer_device = list_entry(&device->peer_devices, struct drbd_peer_device, peer_devices); 37068c2ecf20Sopenharmony_ci 37078c2ecf20Sopenharmony_cifound_peer_device: 37088c2ecf20Sopenharmony_ci list_for_each_entry_continue_rcu(peer_device, &device->peer_devices, peer_devices) { 37098c2ecf20Sopenharmony_ci if (!has_net_conf(peer_device->connection)) 37108c2ecf20Sopenharmony_ci continue; 37118c2ecf20Sopenharmony_ci retcode = NO_ERROR; 37128c2ecf20Sopenharmony_ci goto put_result; /* only one iteration */ 37138c2ecf20Sopenharmony_ci } 37148c2ecf20Sopenharmony_ci goto next_device; 37158c2ecf20Sopenharmony_ci 37168c2ecf20Sopenharmony_ciput_result: 37178c2ecf20Sopenharmony_ci dh = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, 37188c2ecf20Sopenharmony_ci cb->nlh->nlmsg_seq, &drbd_genl_family, 37198c2ecf20Sopenharmony_ci NLM_F_MULTI, DRBD_ADM_GET_PEER_DEVICES); 37208c2ecf20Sopenharmony_ci err = -ENOMEM; 37218c2ecf20Sopenharmony_ci if (!dh) 37228c2ecf20Sopenharmony_ci goto out; 37238c2ecf20Sopenharmony_ci dh->ret_code = retcode; 37248c2ecf20Sopenharmony_ci dh->minor = -1U; 37258c2ecf20Sopenharmony_ci if (retcode == NO_ERROR) { 37268c2ecf20Sopenharmony_ci struct peer_device_info peer_device_info; 37278c2ecf20Sopenharmony_ci struct peer_device_statistics peer_device_statistics; 37288c2ecf20Sopenharmony_ci 37298c2ecf20Sopenharmony_ci dh->minor = minor; 37308c2ecf20Sopenharmony_ci err = nla_put_drbd_cfg_context(skb, device->resource, peer_device->connection, device); 37318c2ecf20Sopenharmony_ci if (err) 37328c2ecf20Sopenharmony_ci goto out; 37338c2ecf20Sopenharmony_ci peer_device_to_info(&peer_device_info, peer_device); 37348c2ecf20Sopenharmony_ci err = peer_device_info_to_skb(skb, &peer_device_info, !capable(CAP_SYS_ADMIN)); 37358c2ecf20Sopenharmony_ci if (err) 37368c2ecf20Sopenharmony_ci goto out; 37378c2ecf20Sopenharmony_ci peer_device_to_statistics(&peer_device_statistics, peer_device); 37388c2ecf20Sopenharmony_ci err = peer_device_statistics_to_skb(skb, &peer_device_statistics, !capable(CAP_SYS_ADMIN)); 37398c2ecf20Sopenharmony_ci if (err) 37408c2ecf20Sopenharmony_ci goto out; 37418c2ecf20Sopenharmony_ci cb->args[1] = minor; 37428c2ecf20Sopenharmony_ci cb->args[2] = (long)peer_device; 37438c2ecf20Sopenharmony_ci } 37448c2ecf20Sopenharmony_ci genlmsg_end(skb, dh); 37458c2ecf20Sopenharmony_ci err = 0; 37468c2ecf20Sopenharmony_ci 37478c2ecf20Sopenharmony_ciout: 37488c2ecf20Sopenharmony_ci rcu_read_unlock(); 37498c2ecf20Sopenharmony_ci if (err) 37508c2ecf20Sopenharmony_ci return err; 37518c2ecf20Sopenharmony_ci return skb->len; 37528c2ecf20Sopenharmony_ci} 37538c2ecf20Sopenharmony_ci/* 37548c2ecf20Sopenharmony_ci * Return the connection of @resource if @resource has exactly one connection. 37558c2ecf20Sopenharmony_ci */ 37568c2ecf20Sopenharmony_cistatic struct drbd_connection *the_only_connection(struct drbd_resource *resource) 37578c2ecf20Sopenharmony_ci{ 37588c2ecf20Sopenharmony_ci struct list_head *connections = &resource->connections; 37598c2ecf20Sopenharmony_ci 37608c2ecf20Sopenharmony_ci if (list_empty(connections) || connections->next->next != connections) 37618c2ecf20Sopenharmony_ci return NULL; 37628c2ecf20Sopenharmony_ci return list_first_entry(&resource->connections, struct drbd_connection, connections); 37638c2ecf20Sopenharmony_ci} 37648c2ecf20Sopenharmony_ci 37658c2ecf20Sopenharmony_cistatic int nla_put_status_info(struct sk_buff *skb, struct drbd_device *device, 37668c2ecf20Sopenharmony_ci const struct sib_info *sib) 37678c2ecf20Sopenharmony_ci{ 37688c2ecf20Sopenharmony_ci struct drbd_resource *resource = device->resource; 37698c2ecf20Sopenharmony_ci struct state_info *si = NULL; /* for sizeof(si->member); */ 37708c2ecf20Sopenharmony_ci struct nlattr *nla; 37718c2ecf20Sopenharmony_ci int got_ldev; 37728c2ecf20Sopenharmony_ci int err = 0; 37738c2ecf20Sopenharmony_ci int exclude_sensitive; 37748c2ecf20Sopenharmony_ci 37758c2ecf20Sopenharmony_ci /* If sib != NULL, this is drbd_bcast_event, which anyone can listen 37768c2ecf20Sopenharmony_ci * to. So we better exclude_sensitive information. 37778c2ecf20Sopenharmony_ci * 37788c2ecf20Sopenharmony_ci * If sib == NULL, this is drbd_adm_get_status, executed synchronously 37798c2ecf20Sopenharmony_ci * in the context of the requesting user process. Exclude sensitive 37808c2ecf20Sopenharmony_ci * information, unless current has superuser. 37818c2ecf20Sopenharmony_ci * 37828c2ecf20Sopenharmony_ci * NOTE: for drbd_adm_get_status_all(), this is a netlink dump, and 37838c2ecf20Sopenharmony_ci * relies on the current implementation of netlink_dump(), which 37848c2ecf20Sopenharmony_ci * executes the dump callback successively from netlink_recvmsg(), 37858c2ecf20Sopenharmony_ci * always in the context of the receiving process */ 37868c2ecf20Sopenharmony_ci exclude_sensitive = sib || !capable(CAP_SYS_ADMIN); 37878c2ecf20Sopenharmony_ci 37888c2ecf20Sopenharmony_ci got_ldev = get_ldev(device); 37898c2ecf20Sopenharmony_ci 37908c2ecf20Sopenharmony_ci /* We need to add connection name and volume number information still. 37918c2ecf20Sopenharmony_ci * Minor number is in drbd_genlmsghdr. */ 37928c2ecf20Sopenharmony_ci if (nla_put_drbd_cfg_context(skb, resource, the_only_connection(resource), device)) 37938c2ecf20Sopenharmony_ci goto nla_put_failure; 37948c2ecf20Sopenharmony_ci 37958c2ecf20Sopenharmony_ci if (res_opts_to_skb(skb, &device->resource->res_opts, exclude_sensitive)) 37968c2ecf20Sopenharmony_ci goto nla_put_failure; 37978c2ecf20Sopenharmony_ci 37988c2ecf20Sopenharmony_ci rcu_read_lock(); 37998c2ecf20Sopenharmony_ci if (got_ldev) { 38008c2ecf20Sopenharmony_ci struct disk_conf *disk_conf; 38018c2ecf20Sopenharmony_ci 38028c2ecf20Sopenharmony_ci disk_conf = rcu_dereference(device->ldev->disk_conf); 38038c2ecf20Sopenharmony_ci err = disk_conf_to_skb(skb, disk_conf, exclude_sensitive); 38048c2ecf20Sopenharmony_ci } 38058c2ecf20Sopenharmony_ci if (!err) { 38068c2ecf20Sopenharmony_ci struct net_conf *nc; 38078c2ecf20Sopenharmony_ci 38088c2ecf20Sopenharmony_ci nc = rcu_dereference(first_peer_device(device)->connection->net_conf); 38098c2ecf20Sopenharmony_ci if (nc) 38108c2ecf20Sopenharmony_ci err = net_conf_to_skb(skb, nc, exclude_sensitive); 38118c2ecf20Sopenharmony_ci } 38128c2ecf20Sopenharmony_ci rcu_read_unlock(); 38138c2ecf20Sopenharmony_ci if (err) 38148c2ecf20Sopenharmony_ci goto nla_put_failure; 38158c2ecf20Sopenharmony_ci 38168c2ecf20Sopenharmony_ci nla = nla_nest_start_noflag(skb, DRBD_NLA_STATE_INFO); 38178c2ecf20Sopenharmony_ci if (!nla) 38188c2ecf20Sopenharmony_ci goto nla_put_failure; 38198c2ecf20Sopenharmony_ci if (nla_put_u32(skb, T_sib_reason, sib ? sib->sib_reason : SIB_GET_STATUS_REPLY) || 38208c2ecf20Sopenharmony_ci nla_put_u32(skb, T_current_state, device->state.i) || 38218c2ecf20Sopenharmony_ci nla_put_u64_0pad(skb, T_ed_uuid, device->ed_uuid) || 38228c2ecf20Sopenharmony_ci nla_put_u64_0pad(skb, T_capacity, get_capacity(device->vdisk)) || 38238c2ecf20Sopenharmony_ci nla_put_u64_0pad(skb, T_send_cnt, device->send_cnt) || 38248c2ecf20Sopenharmony_ci nla_put_u64_0pad(skb, T_recv_cnt, device->recv_cnt) || 38258c2ecf20Sopenharmony_ci nla_put_u64_0pad(skb, T_read_cnt, device->read_cnt) || 38268c2ecf20Sopenharmony_ci nla_put_u64_0pad(skb, T_writ_cnt, device->writ_cnt) || 38278c2ecf20Sopenharmony_ci nla_put_u64_0pad(skb, T_al_writ_cnt, device->al_writ_cnt) || 38288c2ecf20Sopenharmony_ci nla_put_u64_0pad(skb, T_bm_writ_cnt, device->bm_writ_cnt) || 38298c2ecf20Sopenharmony_ci nla_put_u32(skb, T_ap_bio_cnt, atomic_read(&device->ap_bio_cnt)) || 38308c2ecf20Sopenharmony_ci nla_put_u32(skb, T_ap_pending_cnt, atomic_read(&device->ap_pending_cnt)) || 38318c2ecf20Sopenharmony_ci nla_put_u32(skb, T_rs_pending_cnt, atomic_read(&device->rs_pending_cnt))) 38328c2ecf20Sopenharmony_ci goto nla_put_failure; 38338c2ecf20Sopenharmony_ci 38348c2ecf20Sopenharmony_ci if (got_ldev) { 38358c2ecf20Sopenharmony_ci int err; 38368c2ecf20Sopenharmony_ci 38378c2ecf20Sopenharmony_ci spin_lock_irq(&device->ldev->md.uuid_lock); 38388c2ecf20Sopenharmony_ci err = nla_put(skb, T_uuids, sizeof(si->uuids), device->ldev->md.uuid); 38398c2ecf20Sopenharmony_ci spin_unlock_irq(&device->ldev->md.uuid_lock); 38408c2ecf20Sopenharmony_ci 38418c2ecf20Sopenharmony_ci if (err) 38428c2ecf20Sopenharmony_ci goto nla_put_failure; 38438c2ecf20Sopenharmony_ci 38448c2ecf20Sopenharmony_ci if (nla_put_u32(skb, T_disk_flags, device->ldev->md.flags) || 38458c2ecf20Sopenharmony_ci nla_put_u64_0pad(skb, T_bits_total, drbd_bm_bits(device)) || 38468c2ecf20Sopenharmony_ci nla_put_u64_0pad(skb, T_bits_oos, 38478c2ecf20Sopenharmony_ci drbd_bm_total_weight(device))) 38488c2ecf20Sopenharmony_ci goto nla_put_failure; 38498c2ecf20Sopenharmony_ci if (C_SYNC_SOURCE <= device->state.conn && 38508c2ecf20Sopenharmony_ci C_PAUSED_SYNC_T >= device->state.conn) { 38518c2ecf20Sopenharmony_ci if (nla_put_u64_0pad(skb, T_bits_rs_total, 38528c2ecf20Sopenharmony_ci device->rs_total) || 38538c2ecf20Sopenharmony_ci nla_put_u64_0pad(skb, T_bits_rs_failed, 38548c2ecf20Sopenharmony_ci device->rs_failed)) 38558c2ecf20Sopenharmony_ci goto nla_put_failure; 38568c2ecf20Sopenharmony_ci } 38578c2ecf20Sopenharmony_ci } 38588c2ecf20Sopenharmony_ci 38598c2ecf20Sopenharmony_ci if (sib) { 38608c2ecf20Sopenharmony_ci switch(sib->sib_reason) { 38618c2ecf20Sopenharmony_ci case SIB_SYNC_PROGRESS: 38628c2ecf20Sopenharmony_ci case SIB_GET_STATUS_REPLY: 38638c2ecf20Sopenharmony_ci break; 38648c2ecf20Sopenharmony_ci case SIB_STATE_CHANGE: 38658c2ecf20Sopenharmony_ci if (nla_put_u32(skb, T_prev_state, sib->os.i) || 38668c2ecf20Sopenharmony_ci nla_put_u32(skb, T_new_state, sib->ns.i)) 38678c2ecf20Sopenharmony_ci goto nla_put_failure; 38688c2ecf20Sopenharmony_ci break; 38698c2ecf20Sopenharmony_ci case SIB_HELPER_POST: 38708c2ecf20Sopenharmony_ci if (nla_put_u32(skb, T_helper_exit_code, 38718c2ecf20Sopenharmony_ci sib->helper_exit_code)) 38728c2ecf20Sopenharmony_ci goto nla_put_failure; 38738c2ecf20Sopenharmony_ci fallthrough; 38748c2ecf20Sopenharmony_ci case SIB_HELPER_PRE: 38758c2ecf20Sopenharmony_ci if (nla_put_string(skb, T_helper, sib->helper_name)) 38768c2ecf20Sopenharmony_ci goto nla_put_failure; 38778c2ecf20Sopenharmony_ci break; 38788c2ecf20Sopenharmony_ci } 38798c2ecf20Sopenharmony_ci } 38808c2ecf20Sopenharmony_ci nla_nest_end(skb, nla); 38818c2ecf20Sopenharmony_ci 38828c2ecf20Sopenharmony_ci if (0) 38838c2ecf20Sopenharmony_cinla_put_failure: 38848c2ecf20Sopenharmony_ci err = -EMSGSIZE; 38858c2ecf20Sopenharmony_ci if (got_ldev) 38868c2ecf20Sopenharmony_ci put_ldev(device); 38878c2ecf20Sopenharmony_ci return err; 38888c2ecf20Sopenharmony_ci} 38898c2ecf20Sopenharmony_ci 38908c2ecf20Sopenharmony_ciint drbd_adm_get_status(struct sk_buff *skb, struct genl_info *info) 38918c2ecf20Sopenharmony_ci{ 38928c2ecf20Sopenharmony_ci struct drbd_config_context adm_ctx; 38938c2ecf20Sopenharmony_ci enum drbd_ret_code retcode; 38948c2ecf20Sopenharmony_ci int err; 38958c2ecf20Sopenharmony_ci 38968c2ecf20Sopenharmony_ci retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_MINOR); 38978c2ecf20Sopenharmony_ci if (!adm_ctx.reply_skb) 38988c2ecf20Sopenharmony_ci return retcode; 38998c2ecf20Sopenharmony_ci if (retcode != NO_ERROR) 39008c2ecf20Sopenharmony_ci goto out; 39018c2ecf20Sopenharmony_ci 39028c2ecf20Sopenharmony_ci err = nla_put_status_info(adm_ctx.reply_skb, adm_ctx.device, NULL); 39038c2ecf20Sopenharmony_ci if (err) { 39048c2ecf20Sopenharmony_ci nlmsg_free(adm_ctx.reply_skb); 39058c2ecf20Sopenharmony_ci return err; 39068c2ecf20Sopenharmony_ci } 39078c2ecf20Sopenharmony_ciout: 39088c2ecf20Sopenharmony_ci drbd_adm_finish(&adm_ctx, info, retcode); 39098c2ecf20Sopenharmony_ci return 0; 39108c2ecf20Sopenharmony_ci} 39118c2ecf20Sopenharmony_ci 39128c2ecf20Sopenharmony_cistatic int get_one_status(struct sk_buff *skb, struct netlink_callback *cb) 39138c2ecf20Sopenharmony_ci{ 39148c2ecf20Sopenharmony_ci struct drbd_device *device; 39158c2ecf20Sopenharmony_ci struct drbd_genlmsghdr *dh; 39168c2ecf20Sopenharmony_ci struct drbd_resource *pos = (struct drbd_resource *)cb->args[0]; 39178c2ecf20Sopenharmony_ci struct drbd_resource *resource = NULL; 39188c2ecf20Sopenharmony_ci struct drbd_resource *tmp; 39198c2ecf20Sopenharmony_ci unsigned volume = cb->args[1]; 39208c2ecf20Sopenharmony_ci 39218c2ecf20Sopenharmony_ci /* Open coded, deferred, iteration: 39228c2ecf20Sopenharmony_ci * for_each_resource_safe(resource, tmp, &drbd_resources) { 39238c2ecf20Sopenharmony_ci * connection = "first connection of resource or undefined"; 39248c2ecf20Sopenharmony_ci * idr_for_each_entry(&resource->devices, device, i) { 39258c2ecf20Sopenharmony_ci * ... 39268c2ecf20Sopenharmony_ci * } 39278c2ecf20Sopenharmony_ci * } 39288c2ecf20Sopenharmony_ci * where resource is cb->args[0]; 39298c2ecf20Sopenharmony_ci * and i is cb->args[1]; 39308c2ecf20Sopenharmony_ci * 39318c2ecf20Sopenharmony_ci * cb->args[2] indicates if we shall loop over all resources, 39328c2ecf20Sopenharmony_ci * or just dump all volumes of a single resource. 39338c2ecf20Sopenharmony_ci * 39348c2ecf20Sopenharmony_ci * This may miss entries inserted after this dump started, 39358c2ecf20Sopenharmony_ci * or entries deleted before they are reached. 39368c2ecf20Sopenharmony_ci * 39378c2ecf20Sopenharmony_ci * We need to make sure the device won't disappear while 39388c2ecf20Sopenharmony_ci * we are looking at it, and revalidate our iterators 39398c2ecf20Sopenharmony_ci * on each iteration. 39408c2ecf20Sopenharmony_ci */ 39418c2ecf20Sopenharmony_ci 39428c2ecf20Sopenharmony_ci /* synchronize with conn_create()/drbd_destroy_connection() */ 39438c2ecf20Sopenharmony_ci rcu_read_lock(); 39448c2ecf20Sopenharmony_ci /* revalidate iterator position */ 39458c2ecf20Sopenharmony_ci for_each_resource_rcu(tmp, &drbd_resources) { 39468c2ecf20Sopenharmony_ci if (pos == NULL) { 39478c2ecf20Sopenharmony_ci /* first iteration */ 39488c2ecf20Sopenharmony_ci pos = tmp; 39498c2ecf20Sopenharmony_ci resource = pos; 39508c2ecf20Sopenharmony_ci break; 39518c2ecf20Sopenharmony_ci } 39528c2ecf20Sopenharmony_ci if (tmp == pos) { 39538c2ecf20Sopenharmony_ci resource = pos; 39548c2ecf20Sopenharmony_ci break; 39558c2ecf20Sopenharmony_ci } 39568c2ecf20Sopenharmony_ci } 39578c2ecf20Sopenharmony_ci if (resource) { 39588c2ecf20Sopenharmony_cinext_resource: 39598c2ecf20Sopenharmony_ci device = idr_get_next(&resource->devices, &volume); 39608c2ecf20Sopenharmony_ci if (!device) { 39618c2ecf20Sopenharmony_ci /* No more volumes to dump on this resource. 39628c2ecf20Sopenharmony_ci * Advance resource iterator. */ 39638c2ecf20Sopenharmony_ci pos = list_entry_rcu(resource->resources.next, 39648c2ecf20Sopenharmony_ci struct drbd_resource, resources); 39658c2ecf20Sopenharmony_ci /* Did we dump any volume of this resource yet? */ 39668c2ecf20Sopenharmony_ci if (volume != 0) { 39678c2ecf20Sopenharmony_ci /* If we reached the end of the list, 39688c2ecf20Sopenharmony_ci * or only a single resource dump was requested, 39698c2ecf20Sopenharmony_ci * we are done. */ 39708c2ecf20Sopenharmony_ci if (&pos->resources == &drbd_resources || cb->args[2]) 39718c2ecf20Sopenharmony_ci goto out; 39728c2ecf20Sopenharmony_ci volume = 0; 39738c2ecf20Sopenharmony_ci resource = pos; 39748c2ecf20Sopenharmony_ci goto next_resource; 39758c2ecf20Sopenharmony_ci } 39768c2ecf20Sopenharmony_ci } 39778c2ecf20Sopenharmony_ci 39788c2ecf20Sopenharmony_ci dh = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, 39798c2ecf20Sopenharmony_ci cb->nlh->nlmsg_seq, &drbd_genl_family, 39808c2ecf20Sopenharmony_ci NLM_F_MULTI, DRBD_ADM_GET_STATUS); 39818c2ecf20Sopenharmony_ci if (!dh) 39828c2ecf20Sopenharmony_ci goto out; 39838c2ecf20Sopenharmony_ci 39848c2ecf20Sopenharmony_ci if (!device) { 39858c2ecf20Sopenharmony_ci /* This is a connection without a single volume. 39868c2ecf20Sopenharmony_ci * Suprisingly enough, it may have a network 39878c2ecf20Sopenharmony_ci * configuration. */ 39888c2ecf20Sopenharmony_ci struct drbd_connection *connection; 39898c2ecf20Sopenharmony_ci 39908c2ecf20Sopenharmony_ci dh->minor = -1U; 39918c2ecf20Sopenharmony_ci dh->ret_code = NO_ERROR; 39928c2ecf20Sopenharmony_ci connection = the_only_connection(resource); 39938c2ecf20Sopenharmony_ci if (nla_put_drbd_cfg_context(skb, resource, connection, NULL)) 39948c2ecf20Sopenharmony_ci goto cancel; 39958c2ecf20Sopenharmony_ci if (connection) { 39968c2ecf20Sopenharmony_ci struct net_conf *nc; 39978c2ecf20Sopenharmony_ci 39988c2ecf20Sopenharmony_ci nc = rcu_dereference(connection->net_conf); 39998c2ecf20Sopenharmony_ci if (nc && net_conf_to_skb(skb, nc, 1) != 0) 40008c2ecf20Sopenharmony_ci goto cancel; 40018c2ecf20Sopenharmony_ci } 40028c2ecf20Sopenharmony_ci goto done; 40038c2ecf20Sopenharmony_ci } 40048c2ecf20Sopenharmony_ci 40058c2ecf20Sopenharmony_ci D_ASSERT(device, device->vnr == volume); 40068c2ecf20Sopenharmony_ci D_ASSERT(device, device->resource == resource); 40078c2ecf20Sopenharmony_ci 40088c2ecf20Sopenharmony_ci dh->minor = device_to_minor(device); 40098c2ecf20Sopenharmony_ci dh->ret_code = NO_ERROR; 40108c2ecf20Sopenharmony_ci 40118c2ecf20Sopenharmony_ci if (nla_put_status_info(skb, device, NULL)) { 40128c2ecf20Sopenharmony_cicancel: 40138c2ecf20Sopenharmony_ci genlmsg_cancel(skb, dh); 40148c2ecf20Sopenharmony_ci goto out; 40158c2ecf20Sopenharmony_ci } 40168c2ecf20Sopenharmony_cidone: 40178c2ecf20Sopenharmony_ci genlmsg_end(skb, dh); 40188c2ecf20Sopenharmony_ci } 40198c2ecf20Sopenharmony_ci 40208c2ecf20Sopenharmony_ciout: 40218c2ecf20Sopenharmony_ci rcu_read_unlock(); 40228c2ecf20Sopenharmony_ci /* where to start the next iteration */ 40238c2ecf20Sopenharmony_ci cb->args[0] = (long)pos; 40248c2ecf20Sopenharmony_ci cb->args[1] = (pos == resource) ? volume + 1 : 0; 40258c2ecf20Sopenharmony_ci 40268c2ecf20Sopenharmony_ci /* No more resources/volumes/minors found results in an empty skb. 40278c2ecf20Sopenharmony_ci * Which will terminate the dump. */ 40288c2ecf20Sopenharmony_ci return skb->len; 40298c2ecf20Sopenharmony_ci} 40308c2ecf20Sopenharmony_ci 40318c2ecf20Sopenharmony_ci/* 40328c2ecf20Sopenharmony_ci * Request status of all resources, or of all volumes within a single resource. 40338c2ecf20Sopenharmony_ci * 40348c2ecf20Sopenharmony_ci * This is a dump, as the answer may not fit in a single reply skb otherwise. 40358c2ecf20Sopenharmony_ci * Which means we cannot use the family->attrbuf or other such members, because 40368c2ecf20Sopenharmony_ci * dump is NOT protected by the genl_lock(). During dump, we only have access 40378c2ecf20Sopenharmony_ci * to the incoming skb, and need to opencode "parsing" of the nlattr payload. 40388c2ecf20Sopenharmony_ci * 40398c2ecf20Sopenharmony_ci * Once things are setup properly, we call into get_one_status(). 40408c2ecf20Sopenharmony_ci */ 40418c2ecf20Sopenharmony_ciint drbd_adm_get_status_all(struct sk_buff *skb, struct netlink_callback *cb) 40428c2ecf20Sopenharmony_ci{ 40438c2ecf20Sopenharmony_ci const unsigned hdrlen = GENL_HDRLEN + GENL_MAGIC_FAMILY_HDRSZ; 40448c2ecf20Sopenharmony_ci struct nlattr *nla; 40458c2ecf20Sopenharmony_ci const char *resource_name; 40468c2ecf20Sopenharmony_ci struct drbd_resource *resource; 40478c2ecf20Sopenharmony_ci int maxtype; 40488c2ecf20Sopenharmony_ci 40498c2ecf20Sopenharmony_ci /* Is this a followup call? */ 40508c2ecf20Sopenharmony_ci if (cb->args[0]) { 40518c2ecf20Sopenharmony_ci /* ... of a single resource dump, 40528c2ecf20Sopenharmony_ci * and the resource iterator has been advanced already? */ 40538c2ecf20Sopenharmony_ci if (cb->args[2] && cb->args[2] != cb->args[0]) 40548c2ecf20Sopenharmony_ci return 0; /* DONE. */ 40558c2ecf20Sopenharmony_ci goto dump; 40568c2ecf20Sopenharmony_ci } 40578c2ecf20Sopenharmony_ci 40588c2ecf20Sopenharmony_ci /* First call (from netlink_dump_start). We need to figure out 40598c2ecf20Sopenharmony_ci * which resource(s) the user wants us to dump. */ 40608c2ecf20Sopenharmony_ci nla = nla_find(nlmsg_attrdata(cb->nlh, hdrlen), 40618c2ecf20Sopenharmony_ci nlmsg_attrlen(cb->nlh, hdrlen), 40628c2ecf20Sopenharmony_ci DRBD_NLA_CFG_CONTEXT); 40638c2ecf20Sopenharmony_ci 40648c2ecf20Sopenharmony_ci /* No explicit context given. Dump all. */ 40658c2ecf20Sopenharmony_ci if (!nla) 40668c2ecf20Sopenharmony_ci goto dump; 40678c2ecf20Sopenharmony_ci maxtype = ARRAY_SIZE(drbd_cfg_context_nl_policy) - 1; 40688c2ecf20Sopenharmony_ci nla = drbd_nla_find_nested(maxtype, nla, __nla_type(T_ctx_resource_name)); 40698c2ecf20Sopenharmony_ci if (IS_ERR(nla)) 40708c2ecf20Sopenharmony_ci return PTR_ERR(nla); 40718c2ecf20Sopenharmony_ci /* context given, but no name present? */ 40728c2ecf20Sopenharmony_ci if (!nla) 40738c2ecf20Sopenharmony_ci return -EINVAL; 40748c2ecf20Sopenharmony_ci resource_name = nla_data(nla); 40758c2ecf20Sopenharmony_ci if (!*resource_name) 40768c2ecf20Sopenharmony_ci return -ENODEV; 40778c2ecf20Sopenharmony_ci resource = drbd_find_resource(resource_name); 40788c2ecf20Sopenharmony_ci if (!resource) 40798c2ecf20Sopenharmony_ci return -ENODEV; 40808c2ecf20Sopenharmony_ci 40818c2ecf20Sopenharmony_ci kref_put(&resource->kref, drbd_destroy_resource); /* get_one_status() revalidates the resource */ 40828c2ecf20Sopenharmony_ci 40838c2ecf20Sopenharmony_ci /* prime iterators, and set "filter" mode mark: 40848c2ecf20Sopenharmony_ci * only dump this connection. */ 40858c2ecf20Sopenharmony_ci cb->args[0] = (long)resource; 40868c2ecf20Sopenharmony_ci /* cb->args[1] = 0; passed in this way. */ 40878c2ecf20Sopenharmony_ci cb->args[2] = (long)resource; 40888c2ecf20Sopenharmony_ci 40898c2ecf20Sopenharmony_cidump: 40908c2ecf20Sopenharmony_ci return get_one_status(skb, cb); 40918c2ecf20Sopenharmony_ci} 40928c2ecf20Sopenharmony_ci 40938c2ecf20Sopenharmony_ciint drbd_adm_get_timeout_type(struct sk_buff *skb, struct genl_info *info) 40948c2ecf20Sopenharmony_ci{ 40958c2ecf20Sopenharmony_ci struct drbd_config_context adm_ctx; 40968c2ecf20Sopenharmony_ci enum drbd_ret_code retcode; 40978c2ecf20Sopenharmony_ci struct timeout_parms tp; 40988c2ecf20Sopenharmony_ci int err; 40998c2ecf20Sopenharmony_ci 41008c2ecf20Sopenharmony_ci retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_MINOR); 41018c2ecf20Sopenharmony_ci if (!adm_ctx.reply_skb) 41028c2ecf20Sopenharmony_ci return retcode; 41038c2ecf20Sopenharmony_ci if (retcode != NO_ERROR) 41048c2ecf20Sopenharmony_ci goto out; 41058c2ecf20Sopenharmony_ci 41068c2ecf20Sopenharmony_ci tp.timeout_type = 41078c2ecf20Sopenharmony_ci adm_ctx.device->state.pdsk == D_OUTDATED ? UT_PEER_OUTDATED : 41088c2ecf20Sopenharmony_ci test_bit(USE_DEGR_WFC_T, &adm_ctx.device->flags) ? UT_DEGRADED : 41098c2ecf20Sopenharmony_ci UT_DEFAULT; 41108c2ecf20Sopenharmony_ci 41118c2ecf20Sopenharmony_ci err = timeout_parms_to_priv_skb(adm_ctx.reply_skb, &tp); 41128c2ecf20Sopenharmony_ci if (err) { 41138c2ecf20Sopenharmony_ci nlmsg_free(adm_ctx.reply_skb); 41148c2ecf20Sopenharmony_ci return err; 41158c2ecf20Sopenharmony_ci } 41168c2ecf20Sopenharmony_ciout: 41178c2ecf20Sopenharmony_ci drbd_adm_finish(&adm_ctx, info, retcode); 41188c2ecf20Sopenharmony_ci return 0; 41198c2ecf20Sopenharmony_ci} 41208c2ecf20Sopenharmony_ci 41218c2ecf20Sopenharmony_ciint drbd_adm_start_ov(struct sk_buff *skb, struct genl_info *info) 41228c2ecf20Sopenharmony_ci{ 41238c2ecf20Sopenharmony_ci struct drbd_config_context adm_ctx; 41248c2ecf20Sopenharmony_ci struct drbd_device *device; 41258c2ecf20Sopenharmony_ci enum drbd_ret_code retcode; 41268c2ecf20Sopenharmony_ci struct start_ov_parms parms; 41278c2ecf20Sopenharmony_ci 41288c2ecf20Sopenharmony_ci retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_MINOR); 41298c2ecf20Sopenharmony_ci if (!adm_ctx.reply_skb) 41308c2ecf20Sopenharmony_ci return retcode; 41318c2ecf20Sopenharmony_ci if (retcode != NO_ERROR) 41328c2ecf20Sopenharmony_ci goto out; 41338c2ecf20Sopenharmony_ci 41348c2ecf20Sopenharmony_ci device = adm_ctx.device; 41358c2ecf20Sopenharmony_ci 41368c2ecf20Sopenharmony_ci /* resume from last known position, if possible */ 41378c2ecf20Sopenharmony_ci parms.ov_start_sector = device->ov_start_sector; 41388c2ecf20Sopenharmony_ci parms.ov_stop_sector = ULLONG_MAX; 41398c2ecf20Sopenharmony_ci if (info->attrs[DRBD_NLA_START_OV_PARMS]) { 41408c2ecf20Sopenharmony_ci int err = start_ov_parms_from_attrs(&parms, info); 41418c2ecf20Sopenharmony_ci if (err) { 41428c2ecf20Sopenharmony_ci retcode = ERR_MANDATORY_TAG; 41438c2ecf20Sopenharmony_ci drbd_msg_put_info(adm_ctx.reply_skb, from_attrs_err_to_txt(err)); 41448c2ecf20Sopenharmony_ci goto out; 41458c2ecf20Sopenharmony_ci } 41468c2ecf20Sopenharmony_ci } 41478c2ecf20Sopenharmony_ci mutex_lock(&adm_ctx.resource->adm_mutex); 41488c2ecf20Sopenharmony_ci 41498c2ecf20Sopenharmony_ci /* w_make_ov_request expects position to be aligned */ 41508c2ecf20Sopenharmony_ci device->ov_start_sector = parms.ov_start_sector & ~(BM_SECT_PER_BIT-1); 41518c2ecf20Sopenharmony_ci device->ov_stop_sector = parms.ov_stop_sector; 41528c2ecf20Sopenharmony_ci 41538c2ecf20Sopenharmony_ci /* If there is still bitmap IO pending, e.g. previous resync or verify 41548c2ecf20Sopenharmony_ci * just being finished, wait for it before requesting a new resync. */ 41558c2ecf20Sopenharmony_ci drbd_suspend_io(device); 41568c2ecf20Sopenharmony_ci wait_event(device->misc_wait, !test_bit(BITMAP_IO, &device->flags)); 41578c2ecf20Sopenharmony_ci retcode = drbd_request_state(device, NS(conn, C_VERIFY_S)); 41588c2ecf20Sopenharmony_ci drbd_resume_io(device); 41598c2ecf20Sopenharmony_ci 41608c2ecf20Sopenharmony_ci mutex_unlock(&adm_ctx.resource->adm_mutex); 41618c2ecf20Sopenharmony_ciout: 41628c2ecf20Sopenharmony_ci drbd_adm_finish(&adm_ctx, info, retcode); 41638c2ecf20Sopenharmony_ci return 0; 41648c2ecf20Sopenharmony_ci} 41658c2ecf20Sopenharmony_ci 41668c2ecf20Sopenharmony_ci 41678c2ecf20Sopenharmony_ciint drbd_adm_new_c_uuid(struct sk_buff *skb, struct genl_info *info) 41688c2ecf20Sopenharmony_ci{ 41698c2ecf20Sopenharmony_ci struct drbd_config_context adm_ctx; 41708c2ecf20Sopenharmony_ci struct drbd_device *device; 41718c2ecf20Sopenharmony_ci enum drbd_ret_code retcode; 41728c2ecf20Sopenharmony_ci int skip_initial_sync = 0; 41738c2ecf20Sopenharmony_ci int err; 41748c2ecf20Sopenharmony_ci struct new_c_uuid_parms args; 41758c2ecf20Sopenharmony_ci 41768c2ecf20Sopenharmony_ci retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_MINOR); 41778c2ecf20Sopenharmony_ci if (!adm_ctx.reply_skb) 41788c2ecf20Sopenharmony_ci return retcode; 41798c2ecf20Sopenharmony_ci if (retcode != NO_ERROR) 41808c2ecf20Sopenharmony_ci goto out_nolock; 41818c2ecf20Sopenharmony_ci 41828c2ecf20Sopenharmony_ci device = adm_ctx.device; 41838c2ecf20Sopenharmony_ci memset(&args, 0, sizeof(args)); 41848c2ecf20Sopenharmony_ci if (info->attrs[DRBD_NLA_NEW_C_UUID_PARMS]) { 41858c2ecf20Sopenharmony_ci err = new_c_uuid_parms_from_attrs(&args, info); 41868c2ecf20Sopenharmony_ci if (err) { 41878c2ecf20Sopenharmony_ci retcode = ERR_MANDATORY_TAG; 41888c2ecf20Sopenharmony_ci drbd_msg_put_info(adm_ctx.reply_skb, from_attrs_err_to_txt(err)); 41898c2ecf20Sopenharmony_ci goto out_nolock; 41908c2ecf20Sopenharmony_ci } 41918c2ecf20Sopenharmony_ci } 41928c2ecf20Sopenharmony_ci 41938c2ecf20Sopenharmony_ci mutex_lock(&adm_ctx.resource->adm_mutex); 41948c2ecf20Sopenharmony_ci mutex_lock(device->state_mutex); /* Protects us against serialized state changes. */ 41958c2ecf20Sopenharmony_ci 41968c2ecf20Sopenharmony_ci if (!get_ldev(device)) { 41978c2ecf20Sopenharmony_ci retcode = ERR_NO_DISK; 41988c2ecf20Sopenharmony_ci goto out; 41998c2ecf20Sopenharmony_ci } 42008c2ecf20Sopenharmony_ci 42018c2ecf20Sopenharmony_ci /* this is "skip initial sync", assume to be clean */ 42028c2ecf20Sopenharmony_ci if (device->state.conn == C_CONNECTED && 42038c2ecf20Sopenharmony_ci first_peer_device(device)->connection->agreed_pro_version >= 90 && 42048c2ecf20Sopenharmony_ci device->ldev->md.uuid[UI_CURRENT] == UUID_JUST_CREATED && args.clear_bm) { 42058c2ecf20Sopenharmony_ci drbd_info(device, "Preparing to skip initial sync\n"); 42068c2ecf20Sopenharmony_ci skip_initial_sync = 1; 42078c2ecf20Sopenharmony_ci } else if (device->state.conn != C_STANDALONE) { 42088c2ecf20Sopenharmony_ci retcode = ERR_CONNECTED; 42098c2ecf20Sopenharmony_ci goto out_dec; 42108c2ecf20Sopenharmony_ci } 42118c2ecf20Sopenharmony_ci 42128c2ecf20Sopenharmony_ci drbd_uuid_set(device, UI_BITMAP, 0); /* Rotate UI_BITMAP to History 1, etc... */ 42138c2ecf20Sopenharmony_ci drbd_uuid_new_current(device); /* New current, previous to UI_BITMAP */ 42148c2ecf20Sopenharmony_ci 42158c2ecf20Sopenharmony_ci if (args.clear_bm) { 42168c2ecf20Sopenharmony_ci err = drbd_bitmap_io(device, &drbd_bmio_clear_n_write, 42178c2ecf20Sopenharmony_ci "clear_n_write from new_c_uuid", BM_LOCKED_MASK); 42188c2ecf20Sopenharmony_ci if (err) { 42198c2ecf20Sopenharmony_ci drbd_err(device, "Writing bitmap failed with %d\n", err); 42208c2ecf20Sopenharmony_ci retcode = ERR_IO_MD_DISK; 42218c2ecf20Sopenharmony_ci } 42228c2ecf20Sopenharmony_ci if (skip_initial_sync) { 42238c2ecf20Sopenharmony_ci drbd_send_uuids_skip_initial_sync(first_peer_device(device)); 42248c2ecf20Sopenharmony_ci _drbd_uuid_set(device, UI_BITMAP, 0); 42258c2ecf20Sopenharmony_ci drbd_print_uuids(device, "cleared bitmap UUID"); 42268c2ecf20Sopenharmony_ci spin_lock_irq(&device->resource->req_lock); 42278c2ecf20Sopenharmony_ci _drbd_set_state(_NS2(device, disk, D_UP_TO_DATE, pdsk, D_UP_TO_DATE), 42288c2ecf20Sopenharmony_ci CS_VERBOSE, NULL); 42298c2ecf20Sopenharmony_ci spin_unlock_irq(&device->resource->req_lock); 42308c2ecf20Sopenharmony_ci } 42318c2ecf20Sopenharmony_ci } 42328c2ecf20Sopenharmony_ci 42338c2ecf20Sopenharmony_ci drbd_md_sync(device); 42348c2ecf20Sopenharmony_ciout_dec: 42358c2ecf20Sopenharmony_ci put_ldev(device); 42368c2ecf20Sopenharmony_ciout: 42378c2ecf20Sopenharmony_ci mutex_unlock(device->state_mutex); 42388c2ecf20Sopenharmony_ci mutex_unlock(&adm_ctx.resource->adm_mutex); 42398c2ecf20Sopenharmony_ciout_nolock: 42408c2ecf20Sopenharmony_ci drbd_adm_finish(&adm_ctx, info, retcode); 42418c2ecf20Sopenharmony_ci return 0; 42428c2ecf20Sopenharmony_ci} 42438c2ecf20Sopenharmony_ci 42448c2ecf20Sopenharmony_cistatic enum drbd_ret_code 42458c2ecf20Sopenharmony_cidrbd_check_resource_name(struct drbd_config_context *adm_ctx) 42468c2ecf20Sopenharmony_ci{ 42478c2ecf20Sopenharmony_ci const char *name = adm_ctx->resource_name; 42488c2ecf20Sopenharmony_ci if (!name || !name[0]) { 42498c2ecf20Sopenharmony_ci drbd_msg_put_info(adm_ctx->reply_skb, "resource name missing"); 42508c2ecf20Sopenharmony_ci return ERR_MANDATORY_TAG; 42518c2ecf20Sopenharmony_ci } 42528c2ecf20Sopenharmony_ci /* if we want to use these in sysfs/configfs/debugfs some day, 42538c2ecf20Sopenharmony_ci * we must not allow slashes */ 42548c2ecf20Sopenharmony_ci if (strchr(name, '/')) { 42558c2ecf20Sopenharmony_ci drbd_msg_put_info(adm_ctx->reply_skb, "invalid resource name"); 42568c2ecf20Sopenharmony_ci return ERR_INVALID_REQUEST; 42578c2ecf20Sopenharmony_ci } 42588c2ecf20Sopenharmony_ci return NO_ERROR; 42598c2ecf20Sopenharmony_ci} 42608c2ecf20Sopenharmony_ci 42618c2ecf20Sopenharmony_cistatic void resource_to_info(struct resource_info *info, 42628c2ecf20Sopenharmony_ci struct drbd_resource *resource) 42638c2ecf20Sopenharmony_ci{ 42648c2ecf20Sopenharmony_ci info->res_role = conn_highest_role(first_connection(resource)); 42658c2ecf20Sopenharmony_ci info->res_susp = resource->susp; 42668c2ecf20Sopenharmony_ci info->res_susp_nod = resource->susp_nod; 42678c2ecf20Sopenharmony_ci info->res_susp_fen = resource->susp_fen; 42688c2ecf20Sopenharmony_ci} 42698c2ecf20Sopenharmony_ci 42708c2ecf20Sopenharmony_ciint drbd_adm_new_resource(struct sk_buff *skb, struct genl_info *info) 42718c2ecf20Sopenharmony_ci{ 42728c2ecf20Sopenharmony_ci struct drbd_connection *connection; 42738c2ecf20Sopenharmony_ci struct drbd_config_context adm_ctx; 42748c2ecf20Sopenharmony_ci enum drbd_ret_code retcode; 42758c2ecf20Sopenharmony_ci struct res_opts res_opts; 42768c2ecf20Sopenharmony_ci int err; 42778c2ecf20Sopenharmony_ci 42788c2ecf20Sopenharmony_ci retcode = drbd_adm_prepare(&adm_ctx, skb, info, 0); 42798c2ecf20Sopenharmony_ci if (!adm_ctx.reply_skb) 42808c2ecf20Sopenharmony_ci return retcode; 42818c2ecf20Sopenharmony_ci if (retcode != NO_ERROR) 42828c2ecf20Sopenharmony_ci goto out; 42838c2ecf20Sopenharmony_ci 42848c2ecf20Sopenharmony_ci set_res_opts_defaults(&res_opts); 42858c2ecf20Sopenharmony_ci err = res_opts_from_attrs(&res_opts, info); 42868c2ecf20Sopenharmony_ci if (err && err != -ENOMSG) { 42878c2ecf20Sopenharmony_ci retcode = ERR_MANDATORY_TAG; 42888c2ecf20Sopenharmony_ci drbd_msg_put_info(adm_ctx.reply_skb, from_attrs_err_to_txt(err)); 42898c2ecf20Sopenharmony_ci goto out; 42908c2ecf20Sopenharmony_ci } 42918c2ecf20Sopenharmony_ci 42928c2ecf20Sopenharmony_ci retcode = drbd_check_resource_name(&adm_ctx); 42938c2ecf20Sopenharmony_ci if (retcode != NO_ERROR) 42948c2ecf20Sopenharmony_ci goto out; 42958c2ecf20Sopenharmony_ci 42968c2ecf20Sopenharmony_ci if (adm_ctx.resource) { 42978c2ecf20Sopenharmony_ci if (info->nlhdr->nlmsg_flags & NLM_F_EXCL) { 42988c2ecf20Sopenharmony_ci retcode = ERR_INVALID_REQUEST; 42998c2ecf20Sopenharmony_ci drbd_msg_put_info(adm_ctx.reply_skb, "resource exists"); 43008c2ecf20Sopenharmony_ci } 43018c2ecf20Sopenharmony_ci /* else: still NO_ERROR */ 43028c2ecf20Sopenharmony_ci goto out; 43038c2ecf20Sopenharmony_ci } 43048c2ecf20Sopenharmony_ci 43058c2ecf20Sopenharmony_ci /* not yet safe for genl_family.parallel_ops */ 43068c2ecf20Sopenharmony_ci mutex_lock(&resources_mutex); 43078c2ecf20Sopenharmony_ci connection = conn_create(adm_ctx.resource_name, &res_opts); 43088c2ecf20Sopenharmony_ci mutex_unlock(&resources_mutex); 43098c2ecf20Sopenharmony_ci 43108c2ecf20Sopenharmony_ci if (connection) { 43118c2ecf20Sopenharmony_ci struct resource_info resource_info; 43128c2ecf20Sopenharmony_ci 43138c2ecf20Sopenharmony_ci mutex_lock(¬ification_mutex); 43148c2ecf20Sopenharmony_ci resource_to_info(&resource_info, connection->resource); 43158c2ecf20Sopenharmony_ci notify_resource_state(NULL, 0, connection->resource, 43168c2ecf20Sopenharmony_ci &resource_info, NOTIFY_CREATE); 43178c2ecf20Sopenharmony_ci mutex_unlock(¬ification_mutex); 43188c2ecf20Sopenharmony_ci } else 43198c2ecf20Sopenharmony_ci retcode = ERR_NOMEM; 43208c2ecf20Sopenharmony_ci 43218c2ecf20Sopenharmony_ciout: 43228c2ecf20Sopenharmony_ci drbd_adm_finish(&adm_ctx, info, retcode); 43238c2ecf20Sopenharmony_ci return 0; 43248c2ecf20Sopenharmony_ci} 43258c2ecf20Sopenharmony_ci 43268c2ecf20Sopenharmony_cistatic void device_to_info(struct device_info *info, 43278c2ecf20Sopenharmony_ci struct drbd_device *device) 43288c2ecf20Sopenharmony_ci{ 43298c2ecf20Sopenharmony_ci info->dev_disk_state = device->state.disk; 43308c2ecf20Sopenharmony_ci} 43318c2ecf20Sopenharmony_ci 43328c2ecf20Sopenharmony_ci 43338c2ecf20Sopenharmony_ciint drbd_adm_new_minor(struct sk_buff *skb, struct genl_info *info) 43348c2ecf20Sopenharmony_ci{ 43358c2ecf20Sopenharmony_ci struct drbd_config_context adm_ctx; 43368c2ecf20Sopenharmony_ci struct drbd_genlmsghdr *dh = info->userhdr; 43378c2ecf20Sopenharmony_ci enum drbd_ret_code retcode; 43388c2ecf20Sopenharmony_ci 43398c2ecf20Sopenharmony_ci retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_RESOURCE); 43408c2ecf20Sopenharmony_ci if (!adm_ctx.reply_skb) 43418c2ecf20Sopenharmony_ci return retcode; 43428c2ecf20Sopenharmony_ci if (retcode != NO_ERROR) 43438c2ecf20Sopenharmony_ci goto out; 43448c2ecf20Sopenharmony_ci 43458c2ecf20Sopenharmony_ci if (dh->minor > MINORMASK) { 43468c2ecf20Sopenharmony_ci drbd_msg_put_info(adm_ctx.reply_skb, "requested minor out of range"); 43478c2ecf20Sopenharmony_ci retcode = ERR_INVALID_REQUEST; 43488c2ecf20Sopenharmony_ci goto out; 43498c2ecf20Sopenharmony_ci } 43508c2ecf20Sopenharmony_ci if (adm_ctx.volume > DRBD_VOLUME_MAX) { 43518c2ecf20Sopenharmony_ci drbd_msg_put_info(adm_ctx.reply_skb, "requested volume id out of range"); 43528c2ecf20Sopenharmony_ci retcode = ERR_INVALID_REQUEST; 43538c2ecf20Sopenharmony_ci goto out; 43548c2ecf20Sopenharmony_ci } 43558c2ecf20Sopenharmony_ci 43568c2ecf20Sopenharmony_ci /* drbd_adm_prepare made sure already 43578c2ecf20Sopenharmony_ci * that first_peer_device(device)->connection and device->vnr match the request. */ 43588c2ecf20Sopenharmony_ci if (adm_ctx.device) { 43598c2ecf20Sopenharmony_ci if (info->nlhdr->nlmsg_flags & NLM_F_EXCL) 43608c2ecf20Sopenharmony_ci retcode = ERR_MINOR_OR_VOLUME_EXISTS; 43618c2ecf20Sopenharmony_ci /* else: still NO_ERROR */ 43628c2ecf20Sopenharmony_ci goto out; 43638c2ecf20Sopenharmony_ci } 43648c2ecf20Sopenharmony_ci 43658c2ecf20Sopenharmony_ci mutex_lock(&adm_ctx.resource->adm_mutex); 43668c2ecf20Sopenharmony_ci retcode = drbd_create_device(&adm_ctx, dh->minor); 43678c2ecf20Sopenharmony_ci if (retcode == NO_ERROR) { 43688c2ecf20Sopenharmony_ci struct drbd_device *device; 43698c2ecf20Sopenharmony_ci struct drbd_peer_device *peer_device; 43708c2ecf20Sopenharmony_ci struct device_info info; 43718c2ecf20Sopenharmony_ci unsigned int peer_devices = 0; 43728c2ecf20Sopenharmony_ci enum drbd_notification_type flags; 43738c2ecf20Sopenharmony_ci 43748c2ecf20Sopenharmony_ci device = minor_to_device(dh->minor); 43758c2ecf20Sopenharmony_ci for_each_peer_device(peer_device, device) { 43768c2ecf20Sopenharmony_ci if (!has_net_conf(peer_device->connection)) 43778c2ecf20Sopenharmony_ci continue; 43788c2ecf20Sopenharmony_ci peer_devices++; 43798c2ecf20Sopenharmony_ci } 43808c2ecf20Sopenharmony_ci 43818c2ecf20Sopenharmony_ci device_to_info(&info, device); 43828c2ecf20Sopenharmony_ci mutex_lock(¬ification_mutex); 43838c2ecf20Sopenharmony_ci flags = (peer_devices--) ? NOTIFY_CONTINUES : 0; 43848c2ecf20Sopenharmony_ci notify_device_state(NULL, 0, device, &info, NOTIFY_CREATE | flags); 43858c2ecf20Sopenharmony_ci for_each_peer_device(peer_device, device) { 43868c2ecf20Sopenharmony_ci struct peer_device_info peer_device_info; 43878c2ecf20Sopenharmony_ci 43888c2ecf20Sopenharmony_ci if (!has_net_conf(peer_device->connection)) 43898c2ecf20Sopenharmony_ci continue; 43908c2ecf20Sopenharmony_ci peer_device_to_info(&peer_device_info, peer_device); 43918c2ecf20Sopenharmony_ci flags = (peer_devices--) ? NOTIFY_CONTINUES : 0; 43928c2ecf20Sopenharmony_ci notify_peer_device_state(NULL, 0, peer_device, &peer_device_info, 43938c2ecf20Sopenharmony_ci NOTIFY_CREATE | flags); 43948c2ecf20Sopenharmony_ci } 43958c2ecf20Sopenharmony_ci mutex_unlock(¬ification_mutex); 43968c2ecf20Sopenharmony_ci } 43978c2ecf20Sopenharmony_ci mutex_unlock(&adm_ctx.resource->adm_mutex); 43988c2ecf20Sopenharmony_ciout: 43998c2ecf20Sopenharmony_ci drbd_adm_finish(&adm_ctx, info, retcode); 44008c2ecf20Sopenharmony_ci return 0; 44018c2ecf20Sopenharmony_ci} 44028c2ecf20Sopenharmony_ci 44038c2ecf20Sopenharmony_cistatic enum drbd_ret_code adm_del_minor(struct drbd_device *device) 44048c2ecf20Sopenharmony_ci{ 44058c2ecf20Sopenharmony_ci struct drbd_peer_device *peer_device; 44068c2ecf20Sopenharmony_ci 44078c2ecf20Sopenharmony_ci if (device->state.disk == D_DISKLESS && 44088c2ecf20Sopenharmony_ci /* no need to be device->state.conn == C_STANDALONE && 44098c2ecf20Sopenharmony_ci * we may want to delete a minor from a live replication group. 44108c2ecf20Sopenharmony_ci */ 44118c2ecf20Sopenharmony_ci device->state.role == R_SECONDARY) { 44128c2ecf20Sopenharmony_ci struct drbd_connection *connection = 44138c2ecf20Sopenharmony_ci first_connection(device->resource); 44148c2ecf20Sopenharmony_ci 44158c2ecf20Sopenharmony_ci _drbd_request_state(device, NS(conn, C_WF_REPORT_PARAMS), 44168c2ecf20Sopenharmony_ci CS_VERBOSE + CS_WAIT_COMPLETE); 44178c2ecf20Sopenharmony_ci 44188c2ecf20Sopenharmony_ci /* If the state engine hasn't stopped the sender thread yet, we 44198c2ecf20Sopenharmony_ci * need to flush the sender work queue before generating the 44208c2ecf20Sopenharmony_ci * DESTROY events here. */ 44218c2ecf20Sopenharmony_ci if (get_t_state(&connection->worker) == RUNNING) 44228c2ecf20Sopenharmony_ci drbd_flush_workqueue(&connection->sender_work); 44238c2ecf20Sopenharmony_ci 44248c2ecf20Sopenharmony_ci mutex_lock(¬ification_mutex); 44258c2ecf20Sopenharmony_ci for_each_peer_device(peer_device, device) { 44268c2ecf20Sopenharmony_ci if (!has_net_conf(peer_device->connection)) 44278c2ecf20Sopenharmony_ci continue; 44288c2ecf20Sopenharmony_ci notify_peer_device_state(NULL, 0, peer_device, NULL, 44298c2ecf20Sopenharmony_ci NOTIFY_DESTROY | NOTIFY_CONTINUES); 44308c2ecf20Sopenharmony_ci } 44318c2ecf20Sopenharmony_ci notify_device_state(NULL, 0, device, NULL, NOTIFY_DESTROY); 44328c2ecf20Sopenharmony_ci mutex_unlock(¬ification_mutex); 44338c2ecf20Sopenharmony_ci 44348c2ecf20Sopenharmony_ci drbd_delete_device(device); 44358c2ecf20Sopenharmony_ci return NO_ERROR; 44368c2ecf20Sopenharmony_ci } else 44378c2ecf20Sopenharmony_ci return ERR_MINOR_CONFIGURED; 44388c2ecf20Sopenharmony_ci} 44398c2ecf20Sopenharmony_ci 44408c2ecf20Sopenharmony_ciint drbd_adm_del_minor(struct sk_buff *skb, struct genl_info *info) 44418c2ecf20Sopenharmony_ci{ 44428c2ecf20Sopenharmony_ci struct drbd_config_context adm_ctx; 44438c2ecf20Sopenharmony_ci enum drbd_ret_code retcode; 44448c2ecf20Sopenharmony_ci 44458c2ecf20Sopenharmony_ci retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_MINOR); 44468c2ecf20Sopenharmony_ci if (!adm_ctx.reply_skb) 44478c2ecf20Sopenharmony_ci return retcode; 44488c2ecf20Sopenharmony_ci if (retcode != NO_ERROR) 44498c2ecf20Sopenharmony_ci goto out; 44508c2ecf20Sopenharmony_ci 44518c2ecf20Sopenharmony_ci mutex_lock(&adm_ctx.resource->adm_mutex); 44528c2ecf20Sopenharmony_ci retcode = adm_del_minor(adm_ctx.device); 44538c2ecf20Sopenharmony_ci mutex_unlock(&adm_ctx.resource->adm_mutex); 44548c2ecf20Sopenharmony_ciout: 44558c2ecf20Sopenharmony_ci drbd_adm_finish(&adm_ctx, info, retcode); 44568c2ecf20Sopenharmony_ci return 0; 44578c2ecf20Sopenharmony_ci} 44588c2ecf20Sopenharmony_ci 44598c2ecf20Sopenharmony_cistatic int adm_del_resource(struct drbd_resource *resource) 44608c2ecf20Sopenharmony_ci{ 44618c2ecf20Sopenharmony_ci struct drbd_connection *connection; 44628c2ecf20Sopenharmony_ci 44638c2ecf20Sopenharmony_ci for_each_connection(connection, resource) { 44648c2ecf20Sopenharmony_ci if (connection->cstate > C_STANDALONE) 44658c2ecf20Sopenharmony_ci return ERR_NET_CONFIGURED; 44668c2ecf20Sopenharmony_ci } 44678c2ecf20Sopenharmony_ci if (!idr_is_empty(&resource->devices)) 44688c2ecf20Sopenharmony_ci return ERR_RES_IN_USE; 44698c2ecf20Sopenharmony_ci 44708c2ecf20Sopenharmony_ci /* The state engine has stopped the sender thread, so we don't 44718c2ecf20Sopenharmony_ci * need to flush the sender work queue before generating the 44728c2ecf20Sopenharmony_ci * DESTROY event here. */ 44738c2ecf20Sopenharmony_ci mutex_lock(¬ification_mutex); 44748c2ecf20Sopenharmony_ci notify_resource_state(NULL, 0, resource, NULL, NOTIFY_DESTROY); 44758c2ecf20Sopenharmony_ci mutex_unlock(¬ification_mutex); 44768c2ecf20Sopenharmony_ci 44778c2ecf20Sopenharmony_ci mutex_lock(&resources_mutex); 44788c2ecf20Sopenharmony_ci list_del_rcu(&resource->resources); 44798c2ecf20Sopenharmony_ci mutex_unlock(&resources_mutex); 44808c2ecf20Sopenharmony_ci /* Make sure all threads have actually stopped: state handling only 44818c2ecf20Sopenharmony_ci * does drbd_thread_stop_nowait(). */ 44828c2ecf20Sopenharmony_ci list_for_each_entry(connection, &resource->connections, connections) 44838c2ecf20Sopenharmony_ci drbd_thread_stop(&connection->worker); 44848c2ecf20Sopenharmony_ci synchronize_rcu(); 44858c2ecf20Sopenharmony_ci drbd_free_resource(resource); 44868c2ecf20Sopenharmony_ci return NO_ERROR; 44878c2ecf20Sopenharmony_ci} 44888c2ecf20Sopenharmony_ci 44898c2ecf20Sopenharmony_ciint drbd_adm_down(struct sk_buff *skb, struct genl_info *info) 44908c2ecf20Sopenharmony_ci{ 44918c2ecf20Sopenharmony_ci struct drbd_config_context adm_ctx; 44928c2ecf20Sopenharmony_ci struct drbd_resource *resource; 44938c2ecf20Sopenharmony_ci struct drbd_connection *connection; 44948c2ecf20Sopenharmony_ci struct drbd_device *device; 44958c2ecf20Sopenharmony_ci int retcode; /* enum drbd_ret_code rsp. enum drbd_state_rv */ 44968c2ecf20Sopenharmony_ci unsigned i; 44978c2ecf20Sopenharmony_ci 44988c2ecf20Sopenharmony_ci retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_RESOURCE); 44998c2ecf20Sopenharmony_ci if (!adm_ctx.reply_skb) 45008c2ecf20Sopenharmony_ci return retcode; 45018c2ecf20Sopenharmony_ci if (retcode != NO_ERROR) 45028c2ecf20Sopenharmony_ci goto finish; 45038c2ecf20Sopenharmony_ci 45048c2ecf20Sopenharmony_ci resource = adm_ctx.resource; 45058c2ecf20Sopenharmony_ci mutex_lock(&resource->adm_mutex); 45068c2ecf20Sopenharmony_ci /* demote */ 45078c2ecf20Sopenharmony_ci for_each_connection(connection, resource) { 45088c2ecf20Sopenharmony_ci struct drbd_peer_device *peer_device; 45098c2ecf20Sopenharmony_ci 45108c2ecf20Sopenharmony_ci idr_for_each_entry(&connection->peer_devices, peer_device, i) { 45118c2ecf20Sopenharmony_ci retcode = drbd_set_role(peer_device->device, R_SECONDARY, 0); 45128c2ecf20Sopenharmony_ci if (retcode < SS_SUCCESS) { 45138c2ecf20Sopenharmony_ci drbd_msg_put_info(adm_ctx.reply_skb, "failed to demote"); 45148c2ecf20Sopenharmony_ci goto out; 45158c2ecf20Sopenharmony_ci } 45168c2ecf20Sopenharmony_ci } 45178c2ecf20Sopenharmony_ci 45188c2ecf20Sopenharmony_ci retcode = conn_try_disconnect(connection, 0); 45198c2ecf20Sopenharmony_ci if (retcode < SS_SUCCESS) { 45208c2ecf20Sopenharmony_ci drbd_msg_put_info(adm_ctx.reply_skb, "failed to disconnect"); 45218c2ecf20Sopenharmony_ci goto out; 45228c2ecf20Sopenharmony_ci } 45238c2ecf20Sopenharmony_ci } 45248c2ecf20Sopenharmony_ci 45258c2ecf20Sopenharmony_ci /* detach */ 45268c2ecf20Sopenharmony_ci idr_for_each_entry(&resource->devices, device, i) { 45278c2ecf20Sopenharmony_ci retcode = adm_detach(device, 0); 45288c2ecf20Sopenharmony_ci if (retcode < SS_SUCCESS || retcode > NO_ERROR) { 45298c2ecf20Sopenharmony_ci drbd_msg_put_info(adm_ctx.reply_skb, "failed to detach"); 45308c2ecf20Sopenharmony_ci goto out; 45318c2ecf20Sopenharmony_ci } 45328c2ecf20Sopenharmony_ci } 45338c2ecf20Sopenharmony_ci 45348c2ecf20Sopenharmony_ci /* delete volumes */ 45358c2ecf20Sopenharmony_ci idr_for_each_entry(&resource->devices, device, i) { 45368c2ecf20Sopenharmony_ci retcode = adm_del_minor(device); 45378c2ecf20Sopenharmony_ci if (retcode != NO_ERROR) { 45388c2ecf20Sopenharmony_ci /* "can not happen" */ 45398c2ecf20Sopenharmony_ci drbd_msg_put_info(adm_ctx.reply_skb, "failed to delete volume"); 45408c2ecf20Sopenharmony_ci goto out; 45418c2ecf20Sopenharmony_ci } 45428c2ecf20Sopenharmony_ci } 45438c2ecf20Sopenharmony_ci 45448c2ecf20Sopenharmony_ci retcode = adm_del_resource(resource); 45458c2ecf20Sopenharmony_ciout: 45468c2ecf20Sopenharmony_ci mutex_unlock(&resource->adm_mutex); 45478c2ecf20Sopenharmony_cifinish: 45488c2ecf20Sopenharmony_ci drbd_adm_finish(&adm_ctx, info, retcode); 45498c2ecf20Sopenharmony_ci return 0; 45508c2ecf20Sopenharmony_ci} 45518c2ecf20Sopenharmony_ci 45528c2ecf20Sopenharmony_ciint drbd_adm_del_resource(struct sk_buff *skb, struct genl_info *info) 45538c2ecf20Sopenharmony_ci{ 45548c2ecf20Sopenharmony_ci struct drbd_config_context adm_ctx; 45558c2ecf20Sopenharmony_ci struct drbd_resource *resource; 45568c2ecf20Sopenharmony_ci enum drbd_ret_code retcode; 45578c2ecf20Sopenharmony_ci 45588c2ecf20Sopenharmony_ci retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_RESOURCE); 45598c2ecf20Sopenharmony_ci if (!adm_ctx.reply_skb) 45608c2ecf20Sopenharmony_ci return retcode; 45618c2ecf20Sopenharmony_ci if (retcode != NO_ERROR) 45628c2ecf20Sopenharmony_ci goto finish; 45638c2ecf20Sopenharmony_ci resource = adm_ctx.resource; 45648c2ecf20Sopenharmony_ci 45658c2ecf20Sopenharmony_ci mutex_lock(&resource->adm_mutex); 45668c2ecf20Sopenharmony_ci retcode = adm_del_resource(resource); 45678c2ecf20Sopenharmony_ci mutex_unlock(&resource->adm_mutex); 45688c2ecf20Sopenharmony_cifinish: 45698c2ecf20Sopenharmony_ci drbd_adm_finish(&adm_ctx, info, retcode); 45708c2ecf20Sopenharmony_ci return 0; 45718c2ecf20Sopenharmony_ci} 45728c2ecf20Sopenharmony_ci 45738c2ecf20Sopenharmony_civoid drbd_bcast_event(struct drbd_device *device, const struct sib_info *sib) 45748c2ecf20Sopenharmony_ci{ 45758c2ecf20Sopenharmony_ci struct sk_buff *msg; 45768c2ecf20Sopenharmony_ci struct drbd_genlmsghdr *d_out; 45778c2ecf20Sopenharmony_ci unsigned seq; 45788c2ecf20Sopenharmony_ci int err = -ENOMEM; 45798c2ecf20Sopenharmony_ci 45808c2ecf20Sopenharmony_ci seq = atomic_inc_return(&drbd_genl_seq); 45818c2ecf20Sopenharmony_ci msg = genlmsg_new(NLMSG_GOODSIZE, GFP_NOIO); 45828c2ecf20Sopenharmony_ci if (!msg) 45838c2ecf20Sopenharmony_ci goto failed; 45848c2ecf20Sopenharmony_ci 45858c2ecf20Sopenharmony_ci err = -EMSGSIZE; 45868c2ecf20Sopenharmony_ci d_out = genlmsg_put(msg, 0, seq, &drbd_genl_family, 0, DRBD_EVENT); 45878c2ecf20Sopenharmony_ci if (!d_out) /* cannot happen, but anyways. */ 45888c2ecf20Sopenharmony_ci goto nla_put_failure; 45898c2ecf20Sopenharmony_ci d_out->minor = device_to_minor(device); 45908c2ecf20Sopenharmony_ci d_out->ret_code = NO_ERROR; 45918c2ecf20Sopenharmony_ci 45928c2ecf20Sopenharmony_ci if (nla_put_status_info(msg, device, sib)) 45938c2ecf20Sopenharmony_ci goto nla_put_failure; 45948c2ecf20Sopenharmony_ci genlmsg_end(msg, d_out); 45958c2ecf20Sopenharmony_ci err = drbd_genl_multicast_events(msg, GFP_NOWAIT); 45968c2ecf20Sopenharmony_ci /* msg has been consumed or freed in netlink_broadcast() */ 45978c2ecf20Sopenharmony_ci if (err && err != -ESRCH) 45988c2ecf20Sopenharmony_ci goto failed; 45998c2ecf20Sopenharmony_ci 46008c2ecf20Sopenharmony_ci return; 46018c2ecf20Sopenharmony_ci 46028c2ecf20Sopenharmony_cinla_put_failure: 46038c2ecf20Sopenharmony_ci nlmsg_free(msg); 46048c2ecf20Sopenharmony_cifailed: 46058c2ecf20Sopenharmony_ci drbd_err(device, "Error %d while broadcasting event. " 46068c2ecf20Sopenharmony_ci "Event seq:%u sib_reason:%u\n", 46078c2ecf20Sopenharmony_ci err, seq, sib->sib_reason); 46088c2ecf20Sopenharmony_ci} 46098c2ecf20Sopenharmony_ci 46108c2ecf20Sopenharmony_cistatic int nla_put_notification_header(struct sk_buff *msg, 46118c2ecf20Sopenharmony_ci enum drbd_notification_type type) 46128c2ecf20Sopenharmony_ci{ 46138c2ecf20Sopenharmony_ci struct drbd_notification_header nh = { 46148c2ecf20Sopenharmony_ci .nh_type = type, 46158c2ecf20Sopenharmony_ci }; 46168c2ecf20Sopenharmony_ci 46178c2ecf20Sopenharmony_ci return drbd_notification_header_to_skb(msg, &nh, true); 46188c2ecf20Sopenharmony_ci} 46198c2ecf20Sopenharmony_ci 46208c2ecf20Sopenharmony_ciint notify_resource_state(struct sk_buff *skb, 46218c2ecf20Sopenharmony_ci unsigned int seq, 46228c2ecf20Sopenharmony_ci struct drbd_resource *resource, 46238c2ecf20Sopenharmony_ci struct resource_info *resource_info, 46248c2ecf20Sopenharmony_ci enum drbd_notification_type type) 46258c2ecf20Sopenharmony_ci{ 46268c2ecf20Sopenharmony_ci struct resource_statistics resource_statistics; 46278c2ecf20Sopenharmony_ci struct drbd_genlmsghdr *dh; 46288c2ecf20Sopenharmony_ci bool multicast = false; 46298c2ecf20Sopenharmony_ci int err; 46308c2ecf20Sopenharmony_ci 46318c2ecf20Sopenharmony_ci if (!skb) { 46328c2ecf20Sopenharmony_ci seq = atomic_inc_return(¬ify_genl_seq); 46338c2ecf20Sopenharmony_ci skb = genlmsg_new(NLMSG_GOODSIZE, GFP_NOIO); 46348c2ecf20Sopenharmony_ci err = -ENOMEM; 46358c2ecf20Sopenharmony_ci if (!skb) 46368c2ecf20Sopenharmony_ci goto failed; 46378c2ecf20Sopenharmony_ci multicast = true; 46388c2ecf20Sopenharmony_ci } 46398c2ecf20Sopenharmony_ci 46408c2ecf20Sopenharmony_ci err = -EMSGSIZE; 46418c2ecf20Sopenharmony_ci dh = genlmsg_put(skb, 0, seq, &drbd_genl_family, 0, DRBD_RESOURCE_STATE); 46428c2ecf20Sopenharmony_ci if (!dh) 46438c2ecf20Sopenharmony_ci goto nla_put_failure; 46448c2ecf20Sopenharmony_ci dh->minor = -1U; 46458c2ecf20Sopenharmony_ci dh->ret_code = NO_ERROR; 46468c2ecf20Sopenharmony_ci if (nla_put_drbd_cfg_context(skb, resource, NULL, NULL) || 46478c2ecf20Sopenharmony_ci nla_put_notification_header(skb, type) || 46488c2ecf20Sopenharmony_ci ((type & ~NOTIFY_FLAGS) != NOTIFY_DESTROY && 46498c2ecf20Sopenharmony_ci resource_info_to_skb(skb, resource_info, true))) 46508c2ecf20Sopenharmony_ci goto nla_put_failure; 46518c2ecf20Sopenharmony_ci resource_statistics.res_stat_write_ordering = resource->write_ordering; 46528c2ecf20Sopenharmony_ci err = resource_statistics_to_skb(skb, &resource_statistics, !capable(CAP_SYS_ADMIN)); 46538c2ecf20Sopenharmony_ci if (err) 46548c2ecf20Sopenharmony_ci goto nla_put_failure; 46558c2ecf20Sopenharmony_ci genlmsg_end(skb, dh); 46568c2ecf20Sopenharmony_ci if (multicast) { 46578c2ecf20Sopenharmony_ci err = drbd_genl_multicast_events(skb, GFP_NOWAIT); 46588c2ecf20Sopenharmony_ci /* skb has been consumed or freed in netlink_broadcast() */ 46598c2ecf20Sopenharmony_ci if (err && err != -ESRCH) 46608c2ecf20Sopenharmony_ci goto failed; 46618c2ecf20Sopenharmony_ci } 46628c2ecf20Sopenharmony_ci return 0; 46638c2ecf20Sopenharmony_ci 46648c2ecf20Sopenharmony_cinla_put_failure: 46658c2ecf20Sopenharmony_ci nlmsg_free(skb); 46668c2ecf20Sopenharmony_cifailed: 46678c2ecf20Sopenharmony_ci drbd_err(resource, "Error %d while broadcasting event. Event seq:%u\n", 46688c2ecf20Sopenharmony_ci err, seq); 46698c2ecf20Sopenharmony_ci return err; 46708c2ecf20Sopenharmony_ci} 46718c2ecf20Sopenharmony_ci 46728c2ecf20Sopenharmony_ciint notify_device_state(struct sk_buff *skb, 46738c2ecf20Sopenharmony_ci unsigned int seq, 46748c2ecf20Sopenharmony_ci struct drbd_device *device, 46758c2ecf20Sopenharmony_ci struct device_info *device_info, 46768c2ecf20Sopenharmony_ci enum drbd_notification_type type) 46778c2ecf20Sopenharmony_ci{ 46788c2ecf20Sopenharmony_ci struct device_statistics device_statistics; 46798c2ecf20Sopenharmony_ci struct drbd_genlmsghdr *dh; 46808c2ecf20Sopenharmony_ci bool multicast = false; 46818c2ecf20Sopenharmony_ci int err; 46828c2ecf20Sopenharmony_ci 46838c2ecf20Sopenharmony_ci if (!skb) { 46848c2ecf20Sopenharmony_ci seq = atomic_inc_return(¬ify_genl_seq); 46858c2ecf20Sopenharmony_ci skb = genlmsg_new(NLMSG_GOODSIZE, GFP_NOIO); 46868c2ecf20Sopenharmony_ci err = -ENOMEM; 46878c2ecf20Sopenharmony_ci if (!skb) 46888c2ecf20Sopenharmony_ci goto failed; 46898c2ecf20Sopenharmony_ci multicast = true; 46908c2ecf20Sopenharmony_ci } 46918c2ecf20Sopenharmony_ci 46928c2ecf20Sopenharmony_ci err = -EMSGSIZE; 46938c2ecf20Sopenharmony_ci dh = genlmsg_put(skb, 0, seq, &drbd_genl_family, 0, DRBD_DEVICE_STATE); 46948c2ecf20Sopenharmony_ci if (!dh) 46958c2ecf20Sopenharmony_ci goto nla_put_failure; 46968c2ecf20Sopenharmony_ci dh->minor = device->minor; 46978c2ecf20Sopenharmony_ci dh->ret_code = NO_ERROR; 46988c2ecf20Sopenharmony_ci if (nla_put_drbd_cfg_context(skb, device->resource, NULL, device) || 46998c2ecf20Sopenharmony_ci nla_put_notification_header(skb, type) || 47008c2ecf20Sopenharmony_ci ((type & ~NOTIFY_FLAGS) != NOTIFY_DESTROY && 47018c2ecf20Sopenharmony_ci device_info_to_skb(skb, device_info, true))) 47028c2ecf20Sopenharmony_ci goto nla_put_failure; 47038c2ecf20Sopenharmony_ci device_to_statistics(&device_statistics, device); 47048c2ecf20Sopenharmony_ci device_statistics_to_skb(skb, &device_statistics, !capable(CAP_SYS_ADMIN)); 47058c2ecf20Sopenharmony_ci genlmsg_end(skb, dh); 47068c2ecf20Sopenharmony_ci if (multicast) { 47078c2ecf20Sopenharmony_ci err = drbd_genl_multicast_events(skb, GFP_NOWAIT); 47088c2ecf20Sopenharmony_ci /* skb has been consumed or freed in netlink_broadcast() */ 47098c2ecf20Sopenharmony_ci if (err && err != -ESRCH) 47108c2ecf20Sopenharmony_ci goto failed; 47118c2ecf20Sopenharmony_ci } 47128c2ecf20Sopenharmony_ci return 0; 47138c2ecf20Sopenharmony_ci 47148c2ecf20Sopenharmony_cinla_put_failure: 47158c2ecf20Sopenharmony_ci nlmsg_free(skb); 47168c2ecf20Sopenharmony_cifailed: 47178c2ecf20Sopenharmony_ci drbd_err(device, "Error %d while broadcasting event. Event seq:%u\n", 47188c2ecf20Sopenharmony_ci err, seq); 47198c2ecf20Sopenharmony_ci return err; 47208c2ecf20Sopenharmony_ci} 47218c2ecf20Sopenharmony_ci 47228c2ecf20Sopenharmony_ciint notify_connection_state(struct sk_buff *skb, 47238c2ecf20Sopenharmony_ci unsigned int seq, 47248c2ecf20Sopenharmony_ci struct drbd_connection *connection, 47258c2ecf20Sopenharmony_ci struct connection_info *connection_info, 47268c2ecf20Sopenharmony_ci enum drbd_notification_type type) 47278c2ecf20Sopenharmony_ci{ 47288c2ecf20Sopenharmony_ci struct connection_statistics connection_statistics; 47298c2ecf20Sopenharmony_ci struct drbd_genlmsghdr *dh; 47308c2ecf20Sopenharmony_ci bool multicast = false; 47318c2ecf20Sopenharmony_ci int err; 47328c2ecf20Sopenharmony_ci 47338c2ecf20Sopenharmony_ci if (!skb) { 47348c2ecf20Sopenharmony_ci seq = atomic_inc_return(¬ify_genl_seq); 47358c2ecf20Sopenharmony_ci skb = genlmsg_new(NLMSG_GOODSIZE, GFP_NOIO); 47368c2ecf20Sopenharmony_ci err = -ENOMEM; 47378c2ecf20Sopenharmony_ci if (!skb) 47388c2ecf20Sopenharmony_ci goto failed; 47398c2ecf20Sopenharmony_ci multicast = true; 47408c2ecf20Sopenharmony_ci } 47418c2ecf20Sopenharmony_ci 47428c2ecf20Sopenharmony_ci err = -EMSGSIZE; 47438c2ecf20Sopenharmony_ci dh = genlmsg_put(skb, 0, seq, &drbd_genl_family, 0, DRBD_CONNECTION_STATE); 47448c2ecf20Sopenharmony_ci if (!dh) 47458c2ecf20Sopenharmony_ci goto nla_put_failure; 47468c2ecf20Sopenharmony_ci dh->minor = -1U; 47478c2ecf20Sopenharmony_ci dh->ret_code = NO_ERROR; 47488c2ecf20Sopenharmony_ci if (nla_put_drbd_cfg_context(skb, connection->resource, connection, NULL) || 47498c2ecf20Sopenharmony_ci nla_put_notification_header(skb, type) || 47508c2ecf20Sopenharmony_ci ((type & ~NOTIFY_FLAGS) != NOTIFY_DESTROY && 47518c2ecf20Sopenharmony_ci connection_info_to_skb(skb, connection_info, true))) 47528c2ecf20Sopenharmony_ci goto nla_put_failure; 47538c2ecf20Sopenharmony_ci connection_statistics.conn_congested = test_bit(NET_CONGESTED, &connection->flags); 47548c2ecf20Sopenharmony_ci connection_statistics_to_skb(skb, &connection_statistics, !capable(CAP_SYS_ADMIN)); 47558c2ecf20Sopenharmony_ci genlmsg_end(skb, dh); 47568c2ecf20Sopenharmony_ci if (multicast) { 47578c2ecf20Sopenharmony_ci err = drbd_genl_multicast_events(skb, GFP_NOWAIT); 47588c2ecf20Sopenharmony_ci /* skb has been consumed or freed in netlink_broadcast() */ 47598c2ecf20Sopenharmony_ci if (err && err != -ESRCH) 47608c2ecf20Sopenharmony_ci goto failed; 47618c2ecf20Sopenharmony_ci } 47628c2ecf20Sopenharmony_ci return 0; 47638c2ecf20Sopenharmony_ci 47648c2ecf20Sopenharmony_cinla_put_failure: 47658c2ecf20Sopenharmony_ci nlmsg_free(skb); 47668c2ecf20Sopenharmony_cifailed: 47678c2ecf20Sopenharmony_ci drbd_err(connection, "Error %d while broadcasting event. Event seq:%u\n", 47688c2ecf20Sopenharmony_ci err, seq); 47698c2ecf20Sopenharmony_ci return err; 47708c2ecf20Sopenharmony_ci} 47718c2ecf20Sopenharmony_ci 47728c2ecf20Sopenharmony_ciint notify_peer_device_state(struct sk_buff *skb, 47738c2ecf20Sopenharmony_ci unsigned int seq, 47748c2ecf20Sopenharmony_ci struct drbd_peer_device *peer_device, 47758c2ecf20Sopenharmony_ci struct peer_device_info *peer_device_info, 47768c2ecf20Sopenharmony_ci enum drbd_notification_type type) 47778c2ecf20Sopenharmony_ci{ 47788c2ecf20Sopenharmony_ci struct peer_device_statistics peer_device_statistics; 47798c2ecf20Sopenharmony_ci struct drbd_resource *resource = peer_device->device->resource; 47808c2ecf20Sopenharmony_ci struct drbd_genlmsghdr *dh; 47818c2ecf20Sopenharmony_ci bool multicast = false; 47828c2ecf20Sopenharmony_ci int err; 47838c2ecf20Sopenharmony_ci 47848c2ecf20Sopenharmony_ci if (!skb) { 47858c2ecf20Sopenharmony_ci seq = atomic_inc_return(¬ify_genl_seq); 47868c2ecf20Sopenharmony_ci skb = genlmsg_new(NLMSG_GOODSIZE, GFP_NOIO); 47878c2ecf20Sopenharmony_ci err = -ENOMEM; 47888c2ecf20Sopenharmony_ci if (!skb) 47898c2ecf20Sopenharmony_ci goto failed; 47908c2ecf20Sopenharmony_ci multicast = true; 47918c2ecf20Sopenharmony_ci } 47928c2ecf20Sopenharmony_ci 47938c2ecf20Sopenharmony_ci err = -EMSGSIZE; 47948c2ecf20Sopenharmony_ci dh = genlmsg_put(skb, 0, seq, &drbd_genl_family, 0, DRBD_PEER_DEVICE_STATE); 47958c2ecf20Sopenharmony_ci if (!dh) 47968c2ecf20Sopenharmony_ci goto nla_put_failure; 47978c2ecf20Sopenharmony_ci dh->minor = -1U; 47988c2ecf20Sopenharmony_ci dh->ret_code = NO_ERROR; 47998c2ecf20Sopenharmony_ci if (nla_put_drbd_cfg_context(skb, resource, peer_device->connection, peer_device->device) || 48008c2ecf20Sopenharmony_ci nla_put_notification_header(skb, type) || 48018c2ecf20Sopenharmony_ci ((type & ~NOTIFY_FLAGS) != NOTIFY_DESTROY && 48028c2ecf20Sopenharmony_ci peer_device_info_to_skb(skb, peer_device_info, true))) 48038c2ecf20Sopenharmony_ci goto nla_put_failure; 48048c2ecf20Sopenharmony_ci peer_device_to_statistics(&peer_device_statistics, peer_device); 48058c2ecf20Sopenharmony_ci peer_device_statistics_to_skb(skb, &peer_device_statistics, !capable(CAP_SYS_ADMIN)); 48068c2ecf20Sopenharmony_ci genlmsg_end(skb, dh); 48078c2ecf20Sopenharmony_ci if (multicast) { 48088c2ecf20Sopenharmony_ci err = drbd_genl_multicast_events(skb, GFP_NOWAIT); 48098c2ecf20Sopenharmony_ci /* skb has been consumed or freed in netlink_broadcast() */ 48108c2ecf20Sopenharmony_ci if (err && err != -ESRCH) 48118c2ecf20Sopenharmony_ci goto failed; 48128c2ecf20Sopenharmony_ci } 48138c2ecf20Sopenharmony_ci return 0; 48148c2ecf20Sopenharmony_ci 48158c2ecf20Sopenharmony_cinla_put_failure: 48168c2ecf20Sopenharmony_ci nlmsg_free(skb); 48178c2ecf20Sopenharmony_cifailed: 48188c2ecf20Sopenharmony_ci drbd_err(peer_device, "Error %d while broadcasting event. Event seq:%u\n", 48198c2ecf20Sopenharmony_ci err, seq); 48208c2ecf20Sopenharmony_ci return err; 48218c2ecf20Sopenharmony_ci} 48228c2ecf20Sopenharmony_ci 48238c2ecf20Sopenharmony_civoid notify_helper(enum drbd_notification_type type, 48248c2ecf20Sopenharmony_ci struct drbd_device *device, struct drbd_connection *connection, 48258c2ecf20Sopenharmony_ci const char *name, int status) 48268c2ecf20Sopenharmony_ci{ 48278c2ecf20Sopenharmony_ci struct drbd_resource *resource = device ? device->resource : connection->resource; 48288c2ecf20Sopenharmony_ci struct drbd_helper_info helper_info; 48298c2ecf20Sopenharmony_ci unsigned int seq = atomic_inc_return(¬ify_genl_seq); 48308c2ecf20Sopenharmony_ci struct sk_buff *skb = NULL; 48318c2ecf20Sopenharmony_ci struct drbd_genlmsghdr *dh; 48328c2ecf20Sopenharmony_ci int err; 48338c2ecf20Sopenharmony_ci 48348c2ecf20Sopenharmony_ci strlcpy(helper_info.helper_name, name, sizeof(helper_info.helper_name)); 48358c2ecf20Sopenharmony_ci helper_info.helper_name_len = min(strlen(name), sizeof(helper_info.helper_name)); 48368c2ecf20Sopenharmony_ci helper_info.helper_status = status; 48378c2ecf20Sopenharmony_ci 48388c2ecf20Sopenharmony_ci skb = genlmsg_new(NLMSG_GOODSIZE, GFP_NOIO); 48398c2ecf20Sopenharmony_ci err = -ENOMEM; 48408c2ecf20Sopenharmony_ci if (!skb) 48418c2ecf20Sopenharmony_ci goto fail; 48428c2ecf20Sopenharmony_ci 48438c2ecf20Sopenharmony_ci err = -EMSGSIZE; 48448c2ecf20Sopenharmony_ci dh = genlmsg_put(skb, 0, seq, &drbd_genl_family, 0, DRBD_HELPER); 48458c2ecf20Sopenharmony_ci if (!dh) 48468c2ecf20Sopenharmony_ci goto fail; 48478c2ecf20Sopenharmony_ci dh->minor = device ? device->minor : -1; 48488c2ecf20Sopenharmony_ci dh->ret_code = NO_ERROR; 48498c2ecf20Sopenharmony_ci mutex_lock(¬ification_mutex); 48508c2ecf20Sopenharmony_ci if (nla_put_drbd_cfg_context(skb, resource, connection, device) || 48518c2ecf20Sopenharmony_ci nla_put_notification_header(skb, type) || 48528c2ecf20Sopenharmony_ci drbd_helper_info_to_skb(skb, &helper_info, true)) 48538c2ecf20Sopenharmony_ci goto unlock_fail; 48548c2ecf20Sopenharmony_ci genlmsg_end(skb, dh); 48558c2ecf20Sopenharmony_ci err = drbd_genl_multicast_events(skb, GFP_NOWAIT); 48568c2ecf20Sopenharmony_ci skb = NULL; 48578c2ecf20Sopenharmony_ci /* skb has been consumed or freed in netlink_broadcast() */ 48588c2ecf20Sopenharmony_ci if (err && err != -ESRCH) 48598c2ecf20Sopenharmony_ci goto unlock_fail; 48608c2ecf20Sopenharmony_ci mutex_unlock(¬ification_mutex); 48618c2ecf20Sopenharmony_ci return; 48628c2ecf20Sopenharmony_ci 48638c2ecf20Sopenharmony_ciunlock_fail: 48648c2ecf20Sopenharmony_ci mutex_unlock(¬ification_mutex); 48658c2ecf20Sopenharmony_cifail: 48668c2ecf20Sopenharmony_ci nlmsg_free(skb); 48678c2ecf20Sopenharmony_ci drbd_err(resource, "Error %d while broadcasting event. Event seq:%u\n", 48688c2ecf20Sopenharmony_ci err, seq); 48698c2ecf20Sopenharmony_ci} 48708c2ecf20Sopenharmony_ci 48718c2ecf20Sopenharmony_cistatic int notify_initial_state_done(struct sk_buff *skb, unsigned int seq) 48728c2ecf20Sopenharmony_ci{ 48738c2ecf20Sopenharmony_ci struct drbd_genlmsghdr *dh; 48748c2ecf20Sopenharmony_ci int err; 48758c2ecf20Sopenharmony_ci 48768c2ecf20Sopenharmony_ci err = -EMSGSIZE; 48778c2ecf20Sopenharmony_ci dh = genlmsg_put(skb, 0, seq, &drbd_genl_family, 0, DRBD_INITIAL_STATE_DONE); 48788c2ecf20Sopenharmony_ci if (!dh) 48798c2ecf20Sopenharmony_ci goto nla_put_failure; 48808c2ecf20Sopenharmony_ci dh->minor = -1U; 48818c2ecf20Sopenharmony_ci dh->ret_code = NO_ERROR; 48828c2ecf20Sopenharmony_ci if (nla_put_notification_header(skb, NOTIFY_EXISTS)) 48838c2ecf20Sopenharmony_ci goto nla_put_failure; 48848c2ecf20Sopenharmony_ci genlmsg_end(skb, dh); 48858c2ecf20Sopenharmony_ci return 0; 48868c2ecf20Sopenharmony_ci 48878c2ecf20Sopenharmony_cinla_put_failure: 48888c2ecf20Sopenharmony_ci nlmsg_free(skb); 48898c2ecf20Sopenharmony_ci pr_err("Error %d sending event. Event seq:%u\n", err, seq); 48908c2ecf20Sopenharmony_ci return err; 48918c2ecf20Sopenharmony_ci} 48928c2ecf20Sopenharmony_ci 48938c2ecf20Sopenharmony_cistatic void free_state_changes(struct list_head *list) 48948c2ecf20Sopenharmony_ci{ 48958c2ecf20Sopenharmony_ci while (!list_empty(list)) { 48968c2ecf20Sopenharmony_ci struct drbd_state_change *state_change = 48978c2ecf20Sopenharmony_ci list_first_entry(list, struct drbd_state_change, list); 48988c2ecf20Sopenharmony_ci list_del(&state_change->list); 48998c2ecf20Sopenharmony_ci forget_state_change(state_change); 49008c2ecf20Sopenharmony_ci } 49018c2ecf20Sopenharmony_ci} 49028c2ecf20Sopenharmony_ci 49038c2ecf20Sopenharmony_cistatic unsigned int notifications_for_state_change(struct drbd_state_change *state_change) 49048c2ecf20Sopenharmony_ci{ 49058c2ecf20Sopenharmony_ci return 1 + 49068c2ecf20Sopenharmony_ci state_change->n_connections + 49078c2ecf20Sopenharmony_ci state_change->n_devices + 49088c2ecf20Sopenharmony_ci state_change->n_devices * state_change->n_connections; 49098c2ecf20Sopenharmony_ci} 49108c2ecf20Sopenharmony_ci 49118c2ecf20Sopenharmony_cistatic int get_initial_state(struct sk_buff *skb, struct netlink_callback *cb) 49128c2ecf20Sopenharmony_ci{ 49138c2ecf20Sopenharmony_ci struct drbd_state_change *state_change = (struct drbd_state_change *)cb->args[0]; 49148c2ecf20Sopenharmony_ci unsigned int seq = cb->args[2]; 49158c2ecf20Sopenharmony_ci unsigned int n; 49168c2ecf20Sopenharmony_ci enum drbd_notification_type flags = 0; 49178c2ecf20Sopenharmony_ci int err = 0; 49188c2ecf20Sopenharmony_ci 49198c2ecf20Sopenharmony_ci /* There is no need for taking notification_mutex here: it doesn't 49208c2ecf20Sopenharmony_ci matter if the initial state events mix with later state chage 49218c2ecf20Sopenharmony_ci events; we can always tell the events apart by the NOTIFY_EXISTS 49228c2ecf20Sopenharmony_ci flag. */ 49238c2ecf20Sopenharmony_ci 49248c2ecf20Sopenharmony_ci cb->args[5]--; 49258c2ecf20Sopenharmony_ci if (cb->args[5] == 1) { 49268c2ecf20Sopenharmony_ci err = notify_initial_state_done(skb, seq); 49278c2ecf20Sopenharmony_ci goto out; 49288c2ecf20Sopenharmony_ci } 49298c2ecf20Sopenharmony_ci n = cb->args[4]++; 49308c2ecf20Sopenharmony_ci if (cb->args[4] < cb->args[3]) 49318c2ecf20Sopenharmony_ci flags |= NOTIFY_CONTINUES; 49328c2ecf20Sopenharmony_ci if (n < 1) { 49338c2ecf20Sopenharmony_ci err = notify_resource_state_change(skb, seq, state_change->resource, 49348c2ecf20Sopenharmony_ci NOTIFY_EXISTS | flags); 49358c2ecf20Sopenharmony_ci goto next; 49368c2ecf20Sopenharmony_ci } 49378c2ecf20Sopenharmony_ci n--; 49388c2ecf20Sopenharmony_ci if (n < state_change->n_connections) { 49398c2ecf20Sopenharmony_ci err = notify_connection_state_change(skb, seq, &state_change->connections[n], 49408c2ecf20Sopenharmony_ci NOTIFY_EXISTS | flags); 49418c2ecf20Sopenharmony_ci goto next; 49428c2ecf20Sopenharmony_ci } 49438c2ecf20Sopenharmony_ci n -= state_change->n_connections; 49448c2ecf20Sopenharmony_ci if (n < state_change->n_devices) { 49458c2ecf20Sopenharmony_ci err = notify_device_state_change(skb, seq, &state_change->devices[n], 49468c2ecf20Sopenharmony_ci NOTIFY_EXISTS | flags); 49478c2ecf20Sopenharmony_ci goto next; 49488c2ecf20Sopenharmony_ci } 49498c2ecf20Sopenharmony_ci n -= state_change->n_devices; 49508c2ecf20Sopenharmony_ci if (n < state_change->n_devices * state_change->n_connections) { 49518c2ecf20Sopenharmony_ci err = notify_peer_device_state_change(skb, seq, &state_change->peer_devices[n], 49528c2ecf20Sopenharmony_ci NOTIFY_EXISTS | flags); 49538c2ecf20Sopenharmony_ci goto next; 49548c2ecf20Sopenharmony_ci } 49558c2ecf20Sopenharmony_ci 49568c2ecf20Sopenharmony_cinext: 49578c2ecf20Sopenharmony_ci if (cb->args[4] == cb->args[3]) { 49588c2ecf20Sopenharmony_ci struct drbd_state_change *next_state_change = 49598c2ecf20Sopenharmony_ci list_entry(state_change->list.next, 49608c2ecf20Sopenharmony_ci struct drbd_state_change, list); 49618c2ecf20Sopenharmony_ci cb->args[0] = (long)next_state_change; 49628c2ecf20Sopenharmony_ci cb->args[3] = notifications_for_state_change(next_state_change); 49638c2ecf20Sopenharmony_ci cb->args[4] = 0; 49648c2ecf20Sopenharmony_ci } 49658c2ecf20Sopenharmony_ciout: 49668c2ecf20Sopenharmony_ci if (err) 49678c2ecf20Sopenharmony_ci return err; 49688c2ecf20Sopenharmony_ci else 49698c2ecf20Sopenharmony_ci return skb->len; 49708c2ecf20Sopenharmony_ci} 49718c2ecf20Sopenharmony_ci 49728c2ecf20Sopenharmony_ciint drbd_adm_get_initial_state(struct sk_buff *skb, struct netlink_callback *cb) 49738c2ecf20Sopenharmony_ci{ 49748c2ecf20Sopenharmony_ci struct drbd_resource *resource; 49758c2ecf20Sopenharmony_ci LIST_HEAD(head); 49768c2ecf20Sopenharmony_ci 49778c2ecf20Sopenharmony_ci if (cb->args[5] >= 1) { 49788c2ecf20Sopenharmony_ci if (cb->args[5] > 1) 49798c2ecf20Sopenharmony_ci return get_initial_state(skb, cb); 49808c2ecf20Sopenharmony_ci if (cb->args[0]) { 49818c2ecf20Sopenharmony_ci struct drbd_state_change *state_change = 49828c2ecf20Sopenharmony_ci (struct drbd_state_change *)cb->args[0]; 49838c2ecf20Sopenharmony_ci 49848c2ecf20Sopenharmony_ci /* connect list to head */ 49858c2ecf20Sopenharmony_ci list_add(&head, &state_change->list); 49868c2ecf20Sopenharmony_ci free_state_changes(&head); 49878c2ecf20Sopenharmony_ci } 49888c2ecf20Sopenharmony_ci return 0; 49898c2ecf20Sopenharmony_ci } 49908c2ecf20Sopenharmony_ci 49918c2ecf20Sopenharmony_ci cb->args[5] = 2; /* number of iterations */ 49928c2ecf20Sopenharmony_ci mutex_lock(&resources_mutex); 49938c2ecf20Sopenharmony_ci for_each_resource(resource, &drbd_resources) { 49948c2ecf20Sopenharmony_ci struct drbd_state_change *state_change; 49958c2ecf20Sopenharmony_ci 49968c2ecf20Sopenharmony_ci state_change = remember_old_state(resource, GFP_KERNEL); 49978c2ecf20Sopenharmony_ci if (!state_change) { 49988c2ecf20Sopenharmony_ci if (!list_empty(&head)) 49998c2ecf20Sopenharmony_ci free_state_changes(&head); 50008c2ecf20Sopenharmony_ci mutex_unlock(&resources_mutex); 50018c2ecf20Sopenharmony_ci return -ENOMEM; 50028c2ecf20Sopenharmony_ci } 50038c2ecf20Sopenharmony_ci copy_old_to_new_state_change(state_change); 50048c2ecf20Sopenharmony_ci list_add_tail(&state_change->list, &head); 50058c2ecf20Sopenharmony_ci cb->args[5] += notifications_for_state_change(state_change); 50068c2ecf20Sopenharmony_ci } 50078c2ecf20Sopenharmony_ci mutex_unlock(&resources_mutex); 50088c2ecf20Sopenharmony_ci 50098c2ecf20Sopenharmony_ci if (!list_empty(&head)) { 50108c2ecf20Sopenharmony_ci struct drbd_state_change *state_change = 50118c2ecf20Sopenharmony_ci list_entry(head.next, struct drbd_state_change, list); 50128c2ecf20Sopenharmony_ci cb->args[0] = (long)state_change; 50138c2ecf20Sopenharmony_ci cb->args[3] = notifications_for_state_change(state_change); 50148c2ecf20Sopenharmony_ci list_del(&head); /* detach list from head */ 50158c2ecf20Sopenharmony_ci } 50168c2ecf20Sopenharmony_ci 50178c2ecf20Sopenharmony_ci cb->args[2] = cb->nlh->nlmsg_seq; 50188c2ecf20Sopenharmony_ci return get_initial_state(skb, cb); 50198c2ecf20Sopenharmony_ci} 5020